# Implementation Plan: Filament Table UX Standardization & List Consistency **Branch**: `125-table-ux-standardization` | **Date**: 2026-03-08 | **Spec**: `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/125-table-ux-standardization/spec.md` **Input**: Feature specification from `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/125-table-ux-standardization/spec.md` **Note**: This template is filled in by the `/speckit.plan` command. See `.specify/scripts/` for helper scripts. ## Summary Standardize the product’s Filament list surfaces with a convention-first, native-Filament rollout that keeps table behavior explicit in existing `table()` definitions, adds resource-list state persistence, normalizes default sort and empty-state behavior, and reduces default column sprawl through a documented Primary / Context / Detail model. The implementation will avoid a heavy helper framework, preserve existing action and RBAC behavior, keep centralized badge semantics intact, and allow only a tiny pagination-profile helper early in the rollout where the reuse is purely mechanical and does not hide per-surface table logic. ## Technical Context **Language/Version**: PHP 8.4.15 **Primary Dependencies**: Laravel 12, Filament 5, Livewire 4, Tailwind CSS 4, existing `BadgeCatalog` / `BadgeRenderer`, existing UI enforcement helpers, existing Filament resources, relation managers, widgets, and Livewire table components **Storage**: PostgreSQL remains unchanged; this feature is presentation-layer and behavior-layer only **Testing**: Pest 4 feature tests for critical Filament list surfaces, relation manager coverage where applicable, targeted regression tests for persistence and empty states, plus manual QA for layout calmness and overflow edge cases **Target Platform**: Laravel Sail local development, Filament admin and system panels in a web application deployed through Dokploy **Project Type**: web application **Performance Goals**: No material query regression on existing hot tables; no new obvious N+1 patterns; key list surfaces remain responsive under enterprise-sized datasets; resource-list refresh preserves state without custom client logic **Constraints**: No new plugin dependency, no macro-first strategy, no heavy base table abstraction, no action redesign, no general search redesign, no panel-wide CSS width hacks, no authorization behavior changes, no new asset pipeline work **Scale/Scope**: Approximately 36 production Filament table surfaces across resources, relation managers, widgets, custom pages, system pages, and picker tables, with a first-wave focus on critical resource lists plus the most overloaded relation-manager hotspot. Query-risk system tables remain part of the broader rollout and must be aligned conservatively with documented exceptions where needed. ## 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 | The feature changes only list presentation and interaction patterns on existing inventory-, snapshot-, and operations-related surfaces; it does not redefine storage semantics. | | Read/write separation | PASS | PASS | No new write workflows are introduced. Existing destructive or operational actions remain table-local and unchanged in behavior. | | Graph contract path | N/A | N/A | No Graph calls or contract registry changes are part of this feature. | | Deterministic capabilities | PASS | PASS | Existing capability resolution and UI enforcement remain the source of truth; the rollout does not introduce raw capability strings or role checks. | | Workspace + tenant isolation | PASS | PASS | The feature spans `/admin`, `/admin/t/{tenant}/...`, and `/system`, but keeps each surface inside its current entitlement boundary. | | RBAC-UX authorization semantics | PASS | PASS | Non-member 404 and member-without-capability 403 semantics remain unchanged; empty-state CTAs must remain capability-gated. | | Run observability / Ops-UX | N/A | N/A | No new long-running, queued, or remote work is introduced. Existing operation actions remain governed by current `OperationRun` patterns outside this feature’s scope. | | Data minimization and safe logging | PASS | PASS | The rollout changes table rendering only and does not add new payload logging or persistence. | | BADGE-001 centralized badge semantics | PASS | PASS | Existing `BadgeCatalog` / `BadgeRenderer` infrastructure stays authoritative. The standard does not create table-local badge mappings. | | Filament Action Surface Contract | PASS | PASS | Actions remain explicit per surface. The rollout standardizes list consistency without redesigning header, row, bulk, or view actions. | | UX-001 table obligations | PASS | PASS | The feature directly strengthens empty states, search/sort behavior, and table clarity while leaving create/edit/view layouts untouched. | | Filament v5 / Livewire v4 compliance | PASS | PASS | The repo already runs Filament v5 on Livewire v4, which remains unchanged by this plan. | | Panel provider registration | PASS | PASS | No panel provider changes are required; Laravel 11+ panel registration remains in `bootstrap/providers.php`. | | Global search safety for first-wave resources | PASS | PASS | Tenant, Policy, BackupSet, BackupSchedule, and Finding resources already have View or Edit pages. ProviderConnectionResource and OperationRunResource are explicitly not globally searchable. | | Asset strategy | PASS | PASS | No new assets are required. Existing deployment expectations, including `php artisan filament:assets`, remain unchanged. | ## Implementation Notes - The first-wave critical resource surfaces are `TenantResource`, `PolicyResource`, `BackupSetResource`, `BackupScheduleResource`, `ProviderConnectionResource`, `FindingResource`, `OperationRunResource`, and the most overloaded relation-backed table `BackupItemsRelationManager`. - The current codebase already uses native Filament table features such as `defaultSort()`, `toggleable()`, `emptyStateHeading()`, `emptyStateDescription()`, `emptyStateActions()`, and `paginated([...])`, but session persistence methods are effectively absent and there is no existing shared `StandardTableDefaults` helper. A narrow pagination-profile helper is acceptable as an early foundational aid because it captures only repeated page-size options and keeps search, sort, visibility, and empty-state behavior explicit in each surface. - `app/Filament/System/Pages/Directory/Workspaces.php` is a confirmed query-risk hotspot because it computes health and recent-failure metrics per row; any new sort/search behavior there must remain conservative. - `app/Filament/Resources/BackupSetResource/RelationManagers/BackupItemsRelationManager.php` is a confirmed density and action-heavy hotspot; the rollout must calm the default surface without disturbing its existing operational actions. - Destructive actions are not redesigned here. Existing destructive actions must continue to use `->requiresConfirmation()` and current UI enforcement helpers. ## Project Structure ### Documentation (this feature) ```text specs/125-table-ux-standardization/ ├── plan.md ├── research.md ├── data-model.md ├── quickstart.md ├── contracts/ │ └── filament-table-state.openapi.yaml └── tasks.md ``` ### Source Code (repository root) ```text app/ ├── Filament/ │ ├── Pages/ │ │ ├── InventoryCoverage.php │ │ └── Monitoring/Operations.php │ ├── Resources/ │ │ ├── TenantResource.php │ │ ├── PolicyResource.php │ │ ├── BackupSetResource.php │ │ ├── BackupScheduleResource.php │ │ ├── ProviderConnectionResource.php │ │ ├── FindingResource.php │ │ ├── OperationRunResource.php │ │ ├── BackupSetResource/RelationManagers/BackupItemsRelationManager.php │ │ ├── PolicyResource/RelationManagers/VersionsRelationManager.php │ │ └── Workspaces/WorkspaceResource.php │ ├── System/Pages/ │ │ ├── Directory/Tenants.php │ │ ├── Directory/Workspaces.php │ │ ├── Ops/Runs.php │ │ ├── Ops/Failures.php │ │ ├── Ops/Stuck.php │ │ └── Security/AccessLogs.php │ └── Widgets/ │ └── Dashboard/ │ ├── RecentDriftFindings.php │ └── RecentOperations.php ├── Livewire/ │ ├── BackupSetPolicyPickerTable.php │ ├── EntraGroupCachePickerTable.php │ └── SettingsCatalogSettingsTable.php └── Support/ └── Badges/ ├── BadgeCatalog.php └── BadgeRenderer.php tests/ ├── Feature/Filament/ └── Feature/Rbac/ ``` **Structure Decision**: Keep the existing single Laravel application structure and update table behavior at the current surface boundaries. If a tiny shared helper emerges as justified during implementation, it should live under `app/Support/Filament/` or an equally local support namespace and remain limited to mechanical repetition such as pagination profiles. ## Complexity Tracking | Violation | Why Needed | Simpler Alternative Rejected Because | |-----------|------------|-------------------------------------| | None | Not applicable | The design stays within the constitution and the spec’s anti-abstraction constraints |