# Implementation Plan: Inventory Coverage Interactive Table **Branch**: `124-inventory-coverage-table` | **Date**: 2026-03-08 | **Spec**: `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/124-inventory-coverage-table/spec.md` **Input**: Feature specification from `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/124-inventory-coverage-table/spec.md` **Note**: This template is filled in by the `/speckit.plan` command. See `.specify/scripts/` for helper scripts. ## Summary Convert the tenant-scoped Inventory Coverage page at `/admin/t/{tenant}/inventory/coverage` from duplicated Blade-rendered static tables into a Filament-native custom-data table backed by the existing inventory policy metadata and coverage capability resolver. The implementation will normalize supported policy types and foundation types into a single runtime dataset, preserve current badge semantics, and add native search, sorting, category filtering, conditional restore-mode filtering, and an explicit zero-results reset path without introducing new storage, routes, or permissions. ## Technical Context **Language/Version**: PHP 8.4.15 **Primary Dependencies**: Laravel 12, Filament 5, Livewire 4, Tailwind CSS 4, existing `CoverageCapabilitiesResolver`, `InventoryPolicyTypeMeta`, `BadgeCatalog`, and `TagBadgeCatalog` **Storage**: N/A for this feature; page remains read-only and uses registry/config-derived runtime data while PostgreSQL remains unchanged **Testing**: Pest 4 feature/component tests with Filament Livewire table helpers, plus manual dark-mode and badge-regression QA **Target Platform**: Laravel Sail local development, Filament admin panel, Dokploy-hosted web deployment **Project Type**: web application **Performance Goals**: Coverage page render and table interactions stay effectively instantaneous for registry-sized datasets with no external calls and no database writes **Constraints**: No data-model redesign, no new API surface, no Graph calls, no new RBAC rules, preserve badge semantics, preserve tenant-scoped access, and keep dark-mode parity **Scale/Scope**: One tenant-scoped Filament page, one interactive table, dozens of runtime-derived coverage rows spanning supported policy types and foundations ## Constitution Check *GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.* | Gate | Pre-Research | Post-Design | Notes | |------|--------------|-------------|-------| | Inventory-first / snapshots-second | PASS | PASS | Read-only inventory coverage metadata only; no backup or snapshot behavior changes. | | Read/write separation | PASS | PASS | No writes, no destructive actions, no confirmations or audit mutations introduced. | | Graph contract path | N/A | N/A | No Graph calls or contract-registry changes required. | | Deterministic capabilities | PASS | PASS | Existing coverage capability resolution stays centralized in existing resolver and metadata catalogs. | | Workspace + tenant isolation | PASS | PASS | Existing tenant-scoped page access remains unchanged and server-side gated by current membership/capability checks. | | RBAC-UX authorization semantics | PASS | PASS | No new authorization behavior; implementation keeps current tenant-view gating and avoids raw capability strings. | | Run observability / Ops-UX | N/A | N/A | No long-running, remote, queued, or scheduled work. | | Data minimization | PASS | PASS | Page remains registry-derived and read-only; no extra persistence or logging payloads. | | BADGE-001 centralized badge semantics | PASS | PASS | Existing badge catalogs remain the only source for labels, colors, and icons. | | Filament Action Surface Contract | PASS WITH EXPLICIT EXEMPTION | PASS WITH EXPLICIT EXEMPTION | Coverage rows are runtime-derived support metadata with no underlying record detail route. The design intentionally omits record inspection and row/bulk actions, and compensates with a first-class searchable/sortable/filterable table plus explicit empty-state reset behavior. | | UX-001 layout and IA | PASS | PASS | The page remains a Filament page with a native table, obvious filters, zero-result reset CTA, and dark-mode-safe presentation. | ## Implementation Notes - Restore-mode support is intentionally conditional. The implementation and test suite must use deterministic runtime fixtures for both supported branches: one dataset with restore values so the restore filter is rendered, and one dataset without restore values so the filter is omitted. ## Project Structure ### Documentation (this feature) ```text specs/124-inventory-coverage-table/ ├── plan.md ├── research.md ├── data-model.md ├── quickstart.md ├── contracts/ │ └── inventory-coverage-page.openapi.yaml └── tasks.md ``` ### Source Code (repository root) ```text app/ ├── Filament/ │ ├── Clusters/Inventory/InventoryCluster.php │ ├── Pages/InventoryCoverage.php │ └── Widgets/Inventory/InventoryKpiHeader.php ├── Services/Inventory/CoverageCapabilitiesResolver.php └── Support/Inventory/ ├── InventoryCoverage.php └── InventoryPolicyTypeMeta.php resources/ └── views/filament/pages/inventory-coverage.blade.php tests/ └── Feature/Filament/ ├── InventoryPagesTest.php └── InventoryCoverageTableTest.php ``` **Structure Decision**: Keep the existing single Laravel application structure. Implement the feature inside the current Filament page and Blade view, with no new base directories and with a focused Filament feature test added under `tests/Feature/Filament/`. ## Complexity Tracking | Violation | Why Needed | Simpler Alternative Rejected Because | |-----------|------------|-------------------------------------| | Filament table inspection-affordance exemption for coverage rows | Coverage entries are derived from runtime registry metadata rather than first-class records with a natural detail route or resource | Adding a fake detail page or inert row action would add UI ceremony without improving user value, and would conflict with the feature goal of delivering a concise searchable support matrix |