# 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.

