TenantAtlas/specs/124-inventory-coverage-table/plan.md
ahmido 3971c315d8 feat: add inventory coverage interactive table (#151)
## Summary
- replace the static Inventory Coverage HTML tables with a Filament native searchable, sortable, filterable table on the existing tenant page
- normalize supported policy types and foundations into one runtime dataset while preserving centralized badge semantics and the documented read-only action-surface exemption
- add the full spec kit artifact set for feature 124 and focused Pest coverage for rendering, search, sort, filters, empty state, and regression-sensitive page copy

## Testing
- `vendor/bin/sail bin pint --dirty --format agent`
- `vendor/bin/sail artisan test --compact tests/Feature/Filament/InventoryCoverageTableTest.php tests/Feature/Filament/InventoryPagesTest.php tests/Feature/Filament/InventoryHubDbOnlyTest.php`

## Filament Notes
- Livewire v4.0+ compliance: yes, this uses Filament v5 table APIs on the existing page and does not introduce any Livewire v3 patterns
- Provider registration: unchanged; Laravel 11+ provider registration remains in `bootstrap/providers.php`
- Globally searchable resources: none changed in this feature; no Resource global-search behavior was added or modified
- Destructive actions: none; the page remains read-only and only exposes a non-destructive clear-filters empty-state action
- Asset strategy: no new panel or shared assets were added, so no `filament:assets` deployment change is required for this feature
- Testing plan delivered: focused Filament/Pest coverage for the page table surface plus existing page-load regressions

## Follow-up
- Manual dark-mode and badge-regression QA from task `T018` is still pending and should be completed before merge if that check remains mandatory in your review flow.

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #151
2026-03-08 18:33:00 +00:00

90 lines
6.0 KiB
Markdown

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