TenantAtlas/specs/124-inventory-coverage-table/research.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

4.2 KiB
Raw Blame History

Research: Inventory Coverage Interactive Table

Decision 1: Use a Filament custom-data table on the existing page

  • Decision: Implement the page as a Filament HasTable / InteractsWithTable page backed by custom runtime records rather than a raw Blade <table>.
  • Rationale: Filament v5 explicitly supports custom-data tables with search, sort, filters, and pagination via records() and a paginator. That matches the current coverage source, which is derived from arrays and resolvers instead of Eloquent models.
  • Alternatives considered:
    • Keep the Blade table and add ad-hoc Alpine or JavaScript interactions: rejected because it would still sit outside the established Filament product surface and duplicate table behavior the framework already provides.
    • Introduce a database-backed coverage model: rejected because the spec explicitly excludes data-model redesign and the current source of truth is already deterministic.

Decision 2: Normalize supported policy types and foundations into one runtime dataset

  • Decision: Build one normalized collection of coverage rows with a segment field that distinguishes policy types from foundations.
  • Rationale: A single table provides one search box, one filter bar, one sorting model, and one empty-state pattern. The extra segment field preserves the existing semantic distinction without forcing duplicate controls across two separate tables.
  • Alternatives considered:
    • Keep two separate Filament tables: rejected because it would split search/filter state and make the page feel heavier while still not solving cross-surface discoverability.
    • Hide foundations in a secondary collapsible section: rejected because it weakens the current coverage storytelling and makes total support harder to scan.

Decision 3: Derive filter options from the loaded dataset and show restore filtering only when supported

  • Decision: Build category filter options from distinct category values in the normalized dataset and only register a restore-mode filter when at least one row exposes a restore value.
  • Rationale: This keeps filters honest to the current data shape, avoids dead controls, and respects the spec requirement to add restore filtering only if that attribute exists.
  • Alternatives considered:
    • Always show a restore filter with guessed default values: rejected because it would imply data fidelity that the current source may not provide.
    • Hardcode category and restore options: rejected because options already live in the metadata catalog and should remain source-driven.

Decision 4: Preserve badge semantics by reusing existing badge catalogs inside table column rendering

  • Decision: Keep all type, category, restore, and risk badge rendering delegated to the existing shared badge catalogs and render them from Filament table columns.
  • Rationale: The constitution requires centralized badge semantics. Reusing the existing catalogs keeps labels, colors, and icons aligned with the rest of the application while allowing the page layout to change.
  • Alternatives considered:
    • Rebuild badges inline inside the table columns: rejected because it would duplicate logic and risk semantic drift.
    • Replace badges with plain text for easier testing: rejected because it would degrade the trust and scanability goals of the feature.

Decision 5: Test the page as a Livewire table surface and keep manual QA only for visual concerns

  • Decision: Add a focused Pest feature/component test for the page that uses Filament table helpers to verify page load, search, category filtering, conditional restore filtering, and sorting. Keep dark-mode and badge visual validation as manual QA.
  • Rationale: Filament v5 documents searchTable(), filterTable(), and sortTable() for table verification, and the repo already uses these patterns in existing Filament tests. That gives fast regression coverage without promoting a purely visual behavior into brittle snapshot tests.
  • Alternatives considered:
    • Rely on existing page-load coverage only: rejected because the main risk in this feature is interaction regression, not route availability.
    • Browser-test the whole surface: rejected for the initial implementation because the features core interactions are already well covered by Filaments Livewire testing surface.