TenantAtlas/specs/125-table-ux-standardization/research.md
ahmido a4f5c4f122 Spec 125: standardize Filament table UX (#152)
## Summary
- standardize Filament table defaults across resources, relation managers, widgets, custom pages, and picker tables
- add shared pagination profiles, calm default column visibility, explicit empty states, and session persistence on designated critical resource lists
- complete Spec 125 artifacts, regression tests, and dashboard widget follow-up for lazy loading, sortable columns, and toggleable detail columns

## Verification
- `docker exec tenantatlas-laravel.test-1 php artisan test --compact --filter=BaselineCompareNow`
- `docker exec tenantatlas-laravel.test-1 php artisan test --compact --filter=TableStandardsBaseline`
- `docker exec tenantatlas-laravel.test-1 php artisan test --compact --filter=TableDetailVisibility`
- `docker exec tenantatlas-laravel.test-1 php artisan test --compact --filter=FilamentTableRiskExceptions`
- full suite run completed: `2017 passed, 10 failed, 8 skipped`
- manual browser QA completed on the tenant dashboard for lazy loading, sortable widget columns, toggleable hidden status columns, badges, and pagination

## Known Failures
The full suite still has 10 pre-existing failures unrelated to this branch:
- `Tests\\Unit\\OpsUx\\SummaryCountsNormalizerTest`
- `Tests\\Feature\\BackupWithAssignmentsConsistencyTest` (2 tests)
- `Tests\\Feature\\BaselineDriftEngine\\CaptureBaselineContentTest`
- `Tests\\Feature\\BaselineDriftEngine\\CompareContentEvidenceTest`
- `Tests\\Feature\\BaselineDriftEngine\\ResolverTest`
- `Tests\\Feature\\Filament\\TenantDashboardDbOnlyTest`
- `Tests\\Feature\\Operations\\ReconcileAdapterRunsJobTrackingTest`
- `Tests\\Feature\\ReviewPack\\ReviewPackRbacTest`
- `Tests\\Feature\\Verification\\VerificationReportRedactionTest`

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #152
2026-03-08 22:54:56 +00:00

66 lines
7.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Research: Filament Table UX Standardization & List Consistency
## Decision 1: Use native Filament table configuration as the primary implementation path
- Decision: Standardize behavior directly in each tables existing `table()` definition and page-level empty-state hooks, using native Filament methods as the default approach.
- Rationale: The repo already defines table behavior locally across resources, relation managers, widgets, system pages, and Livewire picker tables. Keeping the standard inline preserves clarity, aligns with the specs convention-first goal, and avoids introducing a second configuration language on top of Filament.
- Alternatives considered:
- Build a generic table DSL with primary/context/detail declarations: rejected because it would hide normal Filament behavior and create a parallel framework to maintain.
- Make macros the default rollout path: rejected because the current inconsistencies are mostly judgment and information-architecture issues, not missing framework capability.
## Decision 2: Keep shared support intentionally tiny and mechanical
- Decision: Do not introduce a large shared base class or trait hierarchy. Only allow tiny shared support where duplication is purely mechanical, with pagination-profile helpers as the most likely candidate.
- Rationale: The workspace currently has no shared `StandardTableDefaults` or equivalent helper. Introducing a broad helper layer at the same time as a repo-wide cleanup would increase migration risk and make reviews harder.
- Alternatives considered:
- Add a `StandardTableDefaults` trait and force every table through it: rejected because it would centralize too many domain-specific decisions and make exceptions harder to reason about.
- Keep every pagination and persistence setting fully duplicated forever: rejected because a very small helper for page-size arrays may be justified once the first rollout wave proves the pattern is stable.
## Decision 3: Treat resource-list persistence as mandatory and relation-manager persistence as optional
- Decision: Enable session persistence for search, sort, and filters on resource list tables in the first rollout wave. Leave relation managers, widgets, picker tables, and custom pages on an opt-in basis where the behavior fits naturally.
- Rationale: The audit gap is strongest on resource lists, and Filament-native session persistence maps directly to that need. Extending persistence to every table surface immediately would expand scope and create more state-management edge cases than the spec requires.
- Alternatives considered:
- Add persistence to every table surface immediately: rejected because it increases rollout complexity without matching the strongest user pain first.
- Skip persistence and rely only on query-string state: rejected because the spec explicitly targets keeping list context across refreshes.
## Decision 4: Use a documented Primary / Context / Detail model rather than code-level column metadata
- Decision: Express Primary, Context, and Detail as a repo review convention backed by examples, not as a new code abstraction.
- Rationale: The missing consistency is mostly a design-review problem. A documented tier model gives reviewers and implementers a common language while letting each table remain explicit and readable.
- Alternatives considered:
- Add a `primaryColumn()` / `detailColumn()` API wrapper: rejected because it would obscure normal Filament column configuration and encourage over-abstraction.
- Leave visibility choices fully ad hoc: rejected because that is the exact drift pattern the spec is meant to stop.
## Decision 5: Standardize timestamps, nulls, and IDs using native column methods
- Decision: Use native Filament column behavior for relative timestamps, placeholders, toggle-hidden detail fields, copyable identifiers, truncation, and tooltips instead of custom renderers wherever possible.
- Rationale: The repo already uses `since()`, `dateTime()`, `toggleable()`, `copyable()`, and empty-state APIs in several places. Extending those patterns is lower risk than inventing custom rendering helpers.
- Alternatives considered:
- Introduce custom Blade column views for standard timestamp and ID rendering: rejected because it would be more fragile and harder to apply consistently across many surfaces.
- Leave timestamp and null formatting untouched during rollout: rejected because inconsistent rendering is one of the audited usability defects.
## Decision 6: Preserve existing badge, action, and RBAC architecture
- Decision: Do not redesign actions, badge mappings, or authorization mechanics as part of this feature. Keep actions and empty-state CTAs table-local, preserve centralized badge rendering through `BadgeCatalog` and `BadgeRenderer`, and maintain existing UI enforcement helpers.
- Rationale: The repo already has centralized badge infrastructure and explicit action-level UI enforcement patterns. The spec explicitly excludes action redesign, and mixing that work into the rollout would create unnecessary risk.
- Alternatives considered:
- Standardize row actions and header actions in the same feature: rejected because actions are comparatively consistent and would create avoidable scope creep.
- Rebuild badges as part of a broader “table facelift”: rejected because BADGE-001 requires centralized semantics and the current badge layer already exists.
## Decision 7: Use performance exceptions deliberately and document them per table
- Decision: Any new sort or search behavior on relation-backed or computed columns requires explicit query review, and some tables may keep documented exceptions instead of forcing full compliance.
- Rationale: Direct code inspection already shows query-sensitive surfaces. `app/Filament/System/Pages/Directory/Workspaces.php` computes health and recent failures per row, and `app/Filament/Resources/BackupSetResource/RelationManagers/BackupItemsRelationManager.php` already mixes operational actions with a dense relation-backed list. The standard must not worsen those hotspots.
- Alternatives considered:
- Force every meaningful-looking column to become sortable or searchable: rejected because that would create hidden N+1 or aggregate query regressions.
- Exclude risk tables from the rollout entirely: rejected because the spec requires broad alignment, but exceptions can be documented where needed.
## Decision 8: Roll out by table class and business criticality, not alphabetically
- Decision: Implement the standard in phases: documentation and baseline, first-wave critical resource tables, then remaining resources and relation managers, then widgets, custom pages, and picker tables, followed by performance hardening.
- Rationale: The current table surface spans roughly three dozen screens with uneven complexity. A phased rollout lets the project prove the standard on high-value tables before applying it repo-wide.
- Alternatives considered:
- Update every table in one large pass: rejected because it would be hard to review and too risky for query behavior.
- Limit the effort to a small set of flagship resources: rejected because the spec is explicitly repo-wide and aims to stop future drift.