## Summary - replace the baseline snapshot detail page with a structured summary-first rendering flow - add a presenter plus renderer registry with RBAC, compliance, and fallback renderers - add grouped policy-type browsing, fidelity and gap badges, and workspace authorization coverage - add Feature 130 spec, plan, contract, research, quickstart, and completed task artifacts ## Testing - focused Pest coverage was added for structured rendering, fallback behavior, degraded states, authorization, presenter logic, renderer resolution, and badge mapping - I did not rerun the full validation suite in this final PR step ## Notes - base branch: `dev` - feature branch: `130-structured-snapshot-rendering` Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #158
267 lines
18 KiB
Markdown
267 lines
18 KiB
Markdown
# 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.
|
||
|