TenantAtlas/docs/product/principles.md
ahmido 3c3daae405 feat: normalize operator outcome taxonomy (#186)
## Summary
- introduce a shared operator outcome taxonomy with semantic axes, severity bands, and next-action policy
- apply the taxonomy to operations, evidence/review completeness, baseline semantics, and restore semantics
- harden badge rendering, tenant-safe filtering/search behavior, and operator-facing summary/notification wording
- add the spec kit artifacts, reference documentation, and regression coverage for diagnostic-vs-primary state handling

## Testing
- focused Pest coverage for taxonomy registry and badge guardrails
- operations presentation and notification tests
- evidence, baseline, restore, and tenant-scope regression tests

## Notes
- Livewire v4.0+ compliance is preserved in the existing Filament v5 stack
- panel provider registration remains unchanged in bootstrap/providers.php
- no new globally searchable resource was added; adopted resources remain tenant-safe and out of global search where required
- no new destructive action family was introduced; existing actions keep their current authorization and confirmation behavior
- no new frontend asset strategy was introduced; existing deploy flow with filament:assets remains unchanged

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #186
2026-03-22 12:13:34 +00:00

134 lines
4.9 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-21
---
## 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
### 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.
### 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).
### 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()`)