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