# Implementation Plan: Structured Snapshot Rendering & Type-Agnostic Item Browser **Branch**: `130-structured-snapshot-rendering` | **Date**: 2026-03-09 | **Spec**: [spec.md](./spec.md) **Input**: Feature specification from `/specs/130-structured-snapshot-rendering/spec.md` **Note**: This template is filled in by the `/speckit.plan` command. See `.specify/scripts/` for helper scripts. ## Summary Replace the current Baseline Snapshot detail experience, which mixes a raw summary JSON block with an RBAC-only repeatable section, with a normalized presenter-driven view that renders every captured policy type through a shared summary-first inspection model. Keep the feature workspace-scoped and read-only, introduce a `BaselineSnapshotPresenter` plus a type-renderer registry and fallback renderer, preserve richer RBAC detail as an enrichment layer rather than a privileged exception, add initial structured compliance rendering for `deviceCompliancePolicy`, and deliver the UI through sectioned Filament infolist entries backed by focused feature and unit tests. ## Technical Context **Language/Version**: PHP 8.4.15 / Laravel 12 **Primary Dependencies**: Filament v5, Livewire v4.0+, Tailwind CSS v4 **Storage**: PostgreSQL via Laravel Sail using existing `baseline_snapshots`, `baseline_snapshot_items`, and JSONB presentation source fields **Testing**: Pest v4 feature and unit tests on PHPUnit 12 **Target Platform**: Laravel Sail web application with workspace-scoped admin panel at `/admin` **Project Type**: Laravel monolith / Filament web application **Performance Goals**: Snapshot detail remains DB-only at render time, snapshot items are eager-loaded once per page render, groups are collapsed by default for large snapshots, and technical payload disclosure remains secondary and bounded **Constraints**: No schema changes; no Microsoft Graph calls; preserve immutable snapshot semantics; preserve workspace-scoped authorization and 404/403 semantics on both list and detail routes; keep raw JSON non-primary; isolate per-group rendering failures; use centralized badge semantics for fidelity and gap states; keep technical detail optional and scope-safe **Scale/Scope**: One existing Filament resource detail surface, one new presenter and renderer registry layer, fallback plus initial RBAC and device-compliance enrichments, a small set of Blade infolist entry components, and focused regression tests ## Constitution Check *GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.* - Inventory-first: PASS — this feature consumes existing immutable snapshot artifacts for inspection and does not alter inventory versus snapshot ownership or semantics. - Read/write separation: PASS — the redesign is read-only and introduces no mutation flow, restore action, or audit-triggering write path. - Graph contract path: PASS — no Microsoft Graph call is added. - Deterministic capabilities: PASS — authorization continues to rely on the existing workspace capability registry and resolver with no raw capability strings. - RBAC-UX planes and isolation: PASS — the feature stays in the `/admin` workspace plane, keeps `/system` untouched, and preserves deny-as-not-found for non-members plus protected in-scope access semantics. - Workspace isolation: PASS — snapshot detail remains bound to the active workspace context and existing workspace membership checks. - RBAC-UX destructive confirmation: PASS / N/A — no destructive or mutation action is introduced. - RBAC-UX global search: PASS — the resource remains non-globally-searchable, so global-search semantics do not change. - Tenant isolation: PASS — no tenant-scoped read or cross-tenant aggregation is introduced. - Run observability: PASS / N/A — no new `OperationRun` or long-running workflow is introduced. - Ops-UX 3-surface feedback: PASS / N/A — no operation lifecycle change is involved. - Ops-UX lifecycle and summary counts: PASS / N/A — no `OperationRun` transitions or summary producers are added. - Ops-UX guards and system runs: PASS / N/A — existing operations behavior is unaffected. - Automation: PASS / N/A — no queued or scheduled behavior changes are required. - Data minimization: PASS — the page uses existing workspace-safe snapshot metadata and technical payload disclosure stays secondary. - Badge semantics (BADGE-001): PASS — fidelity and gap states will be added through centralized badge semantics rather than inline color mapping. - Filament UI Action Surface Contract: PASS — the feature modifies a view-only resource detail surface, keeps the immutable-resource exemptions already declared on the resource, and upgrades the list inspection affordance from a lone `View` row action to clickable rows or a primary linked column so the modified surface matches the constitution. - Filament UI UX-001: PASS — the design remains a sectioned infolist-style detail view with metadata, summary, grouped browser, and technical disclosure sections. - Filament v5 / Livewire v4 compliance: PASS — the design stays inside the existing Filament v5 and Livewire v4 admin panel. - Provider registration (`bootstrap/providers.php`): PASS — no panel provider change is introduced. - Global search resource rule: PASS — the resource remains not globally searchable, so the Edit/View global-search rule is unaffected. - Asset strategy: PASS — no new heavy asset bundle is required; existing deploy-time `php artisan filament:assets` behavior remains sufficient. ## Project Structure ### Documentation (this feature) ```text specs/130-structured-snapshot-rendering/ ├── plan.md ├── research.md ├── data-model.md ├── quickstart.md ├── contracts/ │ └── baseline-snapshot-rendering.openapi.yaml ├── checklists/ │ └── requirements.md └── tasks.md ``` ### Source Code (repository root) ```text app/ ├── Filament/ │ └── Resources/ │ ├── BaselineSnapshotResource.php # MODIFY — replace raw summary primary UX │ └── BaselineSnapshotResource/ │ └── Pages/ │ └── ViewBaselineSnapshot.php # MODIFY if page-level composition or eager-loading is needed ├── Services/ │ └── Baselines/ │ └── SnapshotRendering/ │ ├── BaselineSnapshotPresenter.php # NEW page-level builder │ ├── SnapshotTypeRenderer.php # NEW renderer contract │ ├── SnapshotTypeRendererRegistry.php # NEW registry/fallback resolution │ ├── RenderedSnapshot.php # NEW normalized summary DTO │ ├── RenderedSnapshotGroup.php # NEW group DTO │ ├── RenderedSnapshotItem.php # NEW item DTO │ ├── FidelityState.php # NEW fidelity enum/value object │ ├── GapSummary.php # NEW gap summary value object │ └── Renderers/ │ ├── FallbackSnapshotTypeRenderer.php # NEW minimum-contract renderer │ ├── IntuneRoleDefinitionSnapshotTypeRenderer.php # NEW extracted RBAC renderer │ └── DeviceComplianceSnapshotTypeRenderer.php # NEW initial compliance renderer └── Support/ └── Badges/ ├── BadgeDomain.php # MODIFY if new fidelity/gap domains are introduced └── Domains/ # NEW badge mapper(s) if fidelity/gap become centralized domains resources/ └── views/ └── filament/ └── infolists/ └── entries/ ├── baseline-snapshot-summary-table.blade.php # NEW summary-first rendering block ├── baseline-snapshot-groups.blade.php # NEW grouped browser with collapsed sections ├── baseline-snapshot-technical-detail.blade.php # NEW secondary technical disclosure └── snapshot-json.blade.php # MODIFY or reduce prominence if retained via partial reuse tests/ ├── Feature/ │ └── Filament/ │ ├── BaselineSnapshotFidelityVisibilityTest.php # MODIFY existing assertions for structured UI │ ├── BaselineSnapshotStructuredRenderingTest.php # NEW mixed-type summary and grouped browser coverage │ ├── BaselineSnapshotFallbackRenderingTest.php # NEW unknown-type fallback coverage │ ├── BaselineSnapshotAuthorizationTest.php # NEW or MODIFY positive/negative workspace access coverage │ └── BaselineSnapshotDegradedStateTest.php # NEW fidelity/gap and failure-isolation coverage └── Unit/ └── Baselines/ └── SnapshotRendering/ ├── BaselineSnapshotPresenterTest.php # NEW presenter/group aggregation coverage ├── SnapshotTypeRendererRegistryTest.php # NEW registry resolution coverage ├── FallbackSnapshotTypeRendererTest.php # NEW minimum-contract coverage ├── IntuneRoleDefinitionSnapshotTypeRendererTest.php # NEW RBAC contract compliance coverage └── DeviceComplianceSnapshotTypeRendererTest.php # NEW compliance rendering coverage ``` **Structure Decision**: Keep the feature inside the existing Laravel/Filament monolith. The implementation centers on the existing `BaselineSnapshotResource` view surface, a new snapshot-rendering service layer under `app/Services/Baselines`, small Blade infolist entry components for summary and grouped rendering, and focused Pest feature and unit tests. ## Complexity Tracking > No Constitution Check violations. No justifications needed. | Violation | Why Needed | Simpler Alternative Rejected Because | |-----------|------------|-------------------------------------| | — | — | — | ## Phase 0 — Research (DONE) Output: - `specs/130-structured-snapshot-rendering/research.md` Key findings captured: - Current snapshot detail uses a raw JSON summary block plus an RBAC-only repeatable section, so the shared abstraction does not exist yet. - `BaselineSnapshot.summary_jsonb` already provides snapshot-level counts by policy type, fidelity counts, and gap counts suitable for a summary-first page. - `BaselineSnapshotItem.meta_jsonb` already provides a deterministic minimum metadata shape that supports a fallback renderer for all policy types. - Existing repo patterns favor registry or normalizer strategies, centralized badge semantics, and custom `ViewEntry` Blade components inside sectioned Filament infolists. ## Phase 1 — Design & Contracts (DONE) Outputs: - `specs/130-structured-snapshot-rendering/data-model.md` - `specs/130-structured-snapshot-rendering/contracts/baseline-snapshot-rendering.openapi.yaml` - `specs/130-structured-snapshot-rendering/quickstart.md` Design highlights: - Add a page-level `BaselineSnapshotPresenter` that loads one snapshot and returns normalized summary, group, and item DTOs for the UI. - Resolve per-type enrichment through a `SnapshotTypeRendererRegistry` with a shared fallback renderer so unsupported or new types still render. - Keep the detail page inside a sectioned Filament infolist, using custom `ViewEntry` Blade components for the summary table, grouped browser, and optional technical detail disclosure. - Centralize fidelity and gap badge semantics rather than embedding ad hoc color decisions in the resource. ## Phase 1 — Agent Context Update (DONE) Run: - `.specify/scripts/bash/update-agent-context.sh copilot` ## Phase 2 — Implementation Outline (tasks created in `/speckit.tasks`) ### Step 1 — Introduce normalized snapshot presentation primitives Goal: implement FR-130-03 through FR-130-09, FR-130-15 through FR-130-18, and FR-130-22. Changes: - Create normalized DTOs or value objects for page summary, policy-type groups, rendered items, fidelity state, and gap summaries. - Implement a page-level presenter that consumes `BaselineSnapshot` plus eager-loaded `items` and emits a deterministic presentation model. - Add a renderer interface and registry with fallback resolution so every `policy_type` receives a renderer. Tests: - Add unit coverage for group aggregation, ordering, and fallback resolution. - Add unit coverage proving unknown policy types still produce valid summary and item output. ### Step 2 — Refactor RBAC rendering into the shared renderer contract Goal: implement FR-130-10 through FR-130-11 and preserve backward-compatible RBAC richness. Changes: - Extract the current `intuneRoleDefinition` detail mapping from `BaselineSnapshotResource` into a dedicated renderer class. - Preserve RBAC-specific enrichment fields such as built-in versus custom, permission block counts, identity strategy, and policy version reference. - Ensure RBAC output also satisfies the shared item contract and group shell. Tests: - Add unit coverage proving the RBAC renderer produces both common fields and enrichment fields. - Add feature coverage proving RBAC remains richly inspectable without becoming the only rendered type. ### Step 3 — Add initial compliance and fallback rendering Goal: implement FR-130-08 through FR-130-14 and FR-130-19. Changes: - Add an initial `deviceCompliancePolicy` renderer that emits minimum structured detail plus any safe first-pass enrichment such as platform and major compliance hints when present. - Implement the shared fallback renderer so all other policy types render via best available metadata. - Derive explicit fidelity and gap states at group and item level using snapshot and item metadata rather than hidden omission. Tests: - Add unit coverage for compliance rendering and fallback minimum-contract behavior. - Add feature coverage for unsupported or newly added types, partial fidelity, reference-only items, and empty or degraded groups. ### Step 4 — Rebuild the Baseline Snapshot detail layout Goal: implement FR-130-01 through FR-130-07, FR-130-20, and FR-130-21. Changes: - Replace the current raw-summary-first infolist section with a metadata section, a structured summary section, a grouped item-browser section, and a secondary technical detail section. - Render the summary through a custom `ViewEntry` or equivalent Blade component that shows one row per policy type with count, fidelity, gaps, and timing. - Render grouped items through collapsible sections that stay collapsed by default, include group header badges, and isolate failures per group. - Keep raw JSON or technical payload inspection available only through a labeled secondary disclosure. Tests: - Add feature coverage proving summary-first hierarchy, collapsed-by-default groups where testable, and secondary technical payload disclosure. - Add feature assertions proving raw JSON is no longer the primary visible content path. ### Step 5 — Centralize fidelity and gap badge semantics Goal: implement FR-130-13 through FR-130-14 and align with BADGE-001. Changes: - Introduce centralized badge semantics for fidelity and gap states, either through new `BadgeDomain` entries and mappers or an existing compatible shared domain helper. - Replace any ad hoc state-to-color logic on the detail page with centralized badge specs. Tests: - Add unit coverage for fidelity and gap badge mappings. - Add feature assertions that expected labels or badges appear for full, partial, reference-only, unsupported, and gap-present cases. ### Step 6 — Preserve authorization and regression safety Goal: satisfy the spec’s workspace-scope and regression guarantees. Changes: - Ensure the resource detail surface continues to enforce workspace membership and baseline-view capability semantics. - Keep the resource non-globally-searchable and avoid introducing new scope leakage through related references or technical payloads. - Update existing snapshot visibility tests to the new UI structure and add regression coverage for mixed-type rendering. Tests: - Add or update positive authorization coverage for an entitled workspace member. - Add or update negative authorization coverage for non-members or under-entitled users. - Add regression tests proving non-RBAC types do not disappear and one renderer failure does not break the page. ### Step 7 — Final verification and polish Goal: finish the feature within the repo’s Laravel, Filament, and testing standards. Changes: - Review section hierarchy, empty-state copy, collapsed defaults, and technical detail labeling against UX-001. - Confirm the detail surface remains view-only and consistent with the resource’s immutable-action exemptions. Tests: - Run focused Sail-based Pest coverage for unit and feature paths touched by this redesign. - Run Pint on dirty files through Sail during implementation. ## Constitution Check (Post-Design) Re-check result: PASS. - Livewire v4.0+ compliance: preserved because the design remains inside the existing Filament v5 and Livewire v4 admin panel. - Provider registration location: unchanged; the current panel provider remains registered in `bootstrap/providers.php`. - Globally searchable resources: unchanged; `BaselineSnapshotResource` remains non-globally-searchable. - Destructive actions: unchanged; the redesign introduces no destructive or mutation action, so no new `->requiresConfirmation()` surface is needed. - Asset strategy: unchanged; no new heavy or shared asset bundle is introduced, and current deploy-time `php artisan filament:assets` behavior remains sufficient. - Action-surface inspect affordance: the modified list surface will use clickable rows or a primary linked column instead of a lone `View` row action. - Testing plan: add or update focused Pest feature and unit coverage for presenter aggregation, registry resolution, fallback rendering, compliance and RBAC contract compliance, summary-first layout, fidelity and gap badges, workspace authorization semantics, and group failure isolation.