166 lines
7.2 KiB
Markdown
166 lines
7.2 KiB
Markdown
# Product Principles
|
|
|
|
> Permanent product principles that govern every spec, every UI decision, and every architectural choice.
|
|
> New specs must align with these. If a principle needs to change, update this file first.
|
|
|
|
**Last reviewed**: 2026-03-27
|
|
|
|
---
|
|
|
|
## Identity & Isolation
|
|
|
|
### Workspace-first context
|
|
Workspace is the primary session context. Every UI surface, every query, every action is workspace-scoped.
|
|
Non-members receive deny-as-not-found (404 semantics) — they never learn the resource exists.
|
|
|
|
### Tenant isolation (non-negotiable)
|
|
Every read/write is tenant-scoped. Cross-tenant views are explicit, access-checked, aggregation-based.
|
|
Non-member → 404. No cross-embedding of workspace-owned and tenant-owned data.
|
|
|
|
### SCOPE-001: Strict ownership model
|
|
- **Workspace-owned** = standards, templates, configuration, baselines
|
|
- **Tenant-owned** = observed state, evidence, artifacts, inventory
|
|
|
|
---
|
|
|
|
## Authorization & Safety
|
|
|
|
### Capability-first RBAC
|
|
Single canonical registry (`Capabilities.php`). No raw strings. CI fails on unknown capabilities.
|
|
UI visibility is never a security boundary — missing server-side auth is a P0 bug.
|
|
|
|
### Visible-but-disabled UX
|
|
Members see disabled actions with tooltip explaining the missing capability.
|
|
Non-members see nothing (404 semantics).
|
|
|
|
### Destructive actions require safe flows
|
|
All destructive actions → `requiresConfirmation()`. No exceptions.
|
|
Write operations require: preview/dry-run → confirmation → audit log → tests.
|
|
High-risk types default to `preview-only`.
|
|
|
|
---
|
|
|
|
## Operations & Observability
|
|
|
|
### 3-Surface Feedback (non-negotiable)
|
|
1. **Toast** — intent acknowledged
|
|
2. **Progress** — active work visible
|
|
3. **Terminal DB Notification** — audit record
|
|
|
|
No other feedback patterns. No silent mutations.
|
|
|
|
### OperationRun lifecycle is service-owned
|
|
All status/outcome transitions via `OperationRunService` only.
|
|
Summary counts via `OperationSummaryKeys::all()`. Flat numeric only.
|
|
|
|
### Enterprise-grade auditability
|
|
Every mutation has a trail. Backup created, restore attempted, policy change detected — logged, tenant-scoped, RBAC-respecting.
|
|
|
|
---
|
|
|
|
## Data & Architecture
|
|
|
|
### Proportionality first
|
|
New structure, layers, persistence, and semantic machinery must be justified by current release truth and current operator workflow.
|
|
If a narrower implementation can solve the current problem safely, it wins.
|
|
|
|
### No premature abstraction
|
|
No new registries, resolvers, strategy systems, orchestration layers, interfaces, or extension frameworks before at least two real concrete cases exist.
|
|
Exceptions are allowed only when security, isolation, auditability, compliance evidence, or queue correctness require them now.
|
|
|
|
### Persist only real truth
|
|
New tables or stored artifacts exist only for independent truth, lifecycle, audit, retention, compliance, routing, or durable operator workflow needs.
|
|
Convenience projections, UI helpers, and speculative artifacts stay derived.
|
|
|
|
### New state requires new behavior
|
|
Statuses, reason codes, and lifecycle labels are domain truth only when they change operator action, routing, permissioning, lifecycle, retention, audit, or retry behavior.
|
|
Otherwise they remain derived presentation.
|
|
|
|
### One truth, few layers
|
|
Avoid re-modeling the same domain truth across models, result DTOs, presenters, summaries, wrappers, and persisted mirrors.
|
|
New layers should replace old ones or prove why the old ones cannot serve.
|
|
|
|
### Inventory-first, Snapshots-second
|
|
- `InventoryItem` = last observed metadata
|
|
- `PolicyVersion.snapshot` = explicit immutable JSONB capture
|
|
- Intune remains external source of truth
|
|
|
|
### Single Contract Path to Graph
|
|
All MS Graph calls via `GraphClientInterface`. Endpoints modeled in `config/graph_contracts.php`.
|
|
No hardcoded "quick endpoints". Unknown types fail safe.
|
|
|
|
### Deterministic Capabilities
|
|
Backup/restore/risk flags derived deterministically from config via Capabilities Resolver.
|
|
Must be snapshot-testable.
|
|
|
|
### Data minimization & safe logging
|
|
Inventory = metadata only. No secrets in logs.
|
|
Monitoring relies on run records + error codes.
|
|
|
|
---
|
|
|
|
## UI & Information Architecture
|
|
|
|
### UX-001: Layout & IA Standards
|
|
Main/Aside layout. Sections required. View pages use Infolists.
|
|
Empty states with specific title + explanation + exactly 1 CTA.
|
|
|
|
### Action Surface Contract (non-negotiable)
|
|
Required surfaces per page type (list/view/create/edit).
|
|
Max 2 visible row actions. Destructive requires confirmation.
|
|
Every spec with UI changes must include a UI Action Matrix.
|
|
|
|
### Badge semantics centralized
|
|
All status badges via `BadgeCatalog` / `BadgeRenderer`. No ad-hoc badge mappings.
|
|
|
|
### Filament-native first, no ad-hoc styling
|
|
Admin and operator UI uses native Filament components or shared primitives first.
|
|
No hand-built status chips, alert cards, or local semantic color/border styling when Filament or a central primitive already expresses the meaning.
|
|
Any exception must be justified explicitly and stay minimal.
|
|
|
|
### UI semantics stay lightweight
|
|
Badges, explanation text, trust/confidence labels, and status summaries are presentation helpers until they prove they are durable product contracts.
|
|
Avoid building interpretive stacks that require multiple semantic wrapper layers before one domain truth can be shown.
|
|
|
|
### Canonical navigation and terminology
|
|
Consistent naming, consistent routing, consistent mental model.
|
|
No competing terms for the same concept.
|
|
|
|
### Operator-first surfaces
|
|
`/admin` defaults are for operators, not raw implementation visibility.
|
|
Primary content uses operator language, explicit scope, actionable status, and progressive disclosure for diagnostics.
|
|
|
|
### Distinct status and mutation semantics
|
|
Execution outcome, data completeness, governance result, and lifecycle/readiness stay separate when they all exist.
|
|
Every state-changing action tells the operator whether it affects TenantPilot only, the Microsoft tenant, or simulation only before execution.
|
|
|
|
### Page contract requirement
|
|
Every new or materially refactored operator-facing page defines its persona, surface type, primary operator question,
|
|
default-visible information, diagnostics-only information, status dimensions, mutation scope, primary actions, and dangerous actions.
|
|
|
|
---
|
|
|
|
## Process
|
|
|
|
### Spec-first workflow
|
|
Runtime behavior changes require spec update first.
|
|
Every spec must declare: scope, primary routes, data ownership, RBAC requirements (SCOPE-002).
|
|
|
|
### Mandatory proportionality review for structural additions
|
|
Any spec that adds a new enum/status family, DTO/presenter layer, persisted entity, interface/registry/resolver, or taxonomy must explain the operator problem, why existing structure is insufficient, why the implementation is the narrowest correct one, its ownership cost, the rejected simpler alternative, and whether it serves current-release truth.
|
|
|
|
### Regression guards mandatory
|
|
RBAC regression tests per role. Ops-UX regression guards prevent direct status writes and ad-hoc notifications.
|
|
Architectural guard tests enforce code-level contracts.
|
|
|
|
---
|
|
|
|
## Filament v5 Alignment
|
|
|
|
### Non-negotiables
|
|
- Livewire v4.0+
|
|
- Panel providers in `bootstrap/providers.php`
|
|
- Global search requires Edit/View page or is disabled
|
|
- Prefer render hooks + CSS hooks over publishing internal views
|
|
- Heavy assets loaded on-demand (`loadedOnRequest()`)
|