4.1 KiB
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-08
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)
- Toast — intent acknowledged
- Progress — active work visible
- 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 metadataPolicyVersion.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.
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())