## Summary - standardize filter UX across key Filament resources with shared thin filter helpers for centralized option sourcing and archived/date-range presets - add persistence, essential filters, and OperationCatalog-aligned labels across the targeted resource tables - add and extend focused Pest coverage for guards, persistence, filter behavior, scope safety, and the new Spec 126 planning artifacts ## Spec 126 - add the full Spec 126 artifact set under `specs/126-filter-ux-standardization/` - align spec, plan, research, data model, quickstart, contract, checklist, and tasks for implementation readiness ## Validation - `vendor/bin/sail bin pint --dirty --format agent` - `vendor/bin/sail artisan test --compact tests/Feature/Guards/FilamentTableStandardsGuardTest.php tests/Feature/Filament/TableStatePersistenceTest.php tests/Feature/Findings/FindingsListFiltersTest.php tests/Feature/Findings/FindingsListDefaultsTest.php tests/Feature/Alerts/AlertDeliveryDeepLinkFiltersTest.php tests/Feature/Filament/Alerts/AlertDeliveryViewerTest.php tests/Feature/Filament/OperationRunListFiltersTest.php tests/Feature/Filament/PolicyVersionListFiltersTest.php tests/Feature/Filament/RestoreRunListFiltersTest.php tests/Feature/Filament/InventoryItemListFiltersTest.php tests/Feature/Filament/BaselineProfileListFiltersTest.php tests/Feature/ProviderConnections/TenantFilterOverrideTest.php tests/Feature/Rbac/InventoryItemResourceAuthorizationTest.php tests/Feature/Filament/BaselineTenantAssignmentsRelationManagerTest.php` ## Notes - no new OperationRun lifecycle or operational workflow behavior is introduced; only existing OperationRun table filter-label alignment and related coverage are in scope - existing authorization and action-surface semantics remain unchanged Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #154
19 KiB
Feature Specification: Filter UX Standardization
Feature Branch: 126-filter-ux-standardization
Created: 2026-03-09
Status: Proposed
Input: User description: "Spec 126 — Filter UX Standardization"
Spec Scope Fields (mandatory)
- Scope: workspace
- Primary Routes: Tier 1 and Tier 2 Filament resource list pages under
/admin,/admin/t/{tenant}/..., and selected low-effort Tier 3 list pages where the current filter gap is obvious and low risk - Data Ownership: Both workspace-owned and tenant-owned records are affected at the list-behavior layer only; this feature does not create new business entities or change underlying ownership
- RBAC: Existing workspace membership, tenant membership, plane separation, and capability gates remain authoritative; this feature standardizes list filtering behavior only within already-authorized surfaces
User Scenarios & Testing (mandatory)
User Story 1 - Keep Investigation Context (Priority: P1)
As an operator moving across key TenantPilot lists, I want important lists to remember my filter, search, and sort choices so I can continue an investigation without repeatedly rebuilding the same narrowed view.
Why this priority: Losing list context is the most direct source of friction identified by the audit and affects core operator workflows across inventory, monitoring, backups, and governance.
Independent Test: This can be tested independently by updating one Tier 1 or Tier 2 list to preserve its narrowed state across refresh and navigation, then verifying the same filtered result set returns within the same session.
Acceptance Scenarios:
- Given a user narrows a Tier 1 or Tier 2 list with search, sort, and filters, When the user refreshes the page, Then the same narrowed view remains active.
- Given a user narrows a Tier 1 or Tier 2 list and navigates away, When the user returns to that list within the same session, Then the previous narrowing remains in place.
User Story 2 - Filter Similar Lists the Same Way (Priority: P2)
As an operator comparing similar record types, I want archived, status, and time-based filters to behave consistently across lists so I do not need to relearn filter semantics on each screen.
Why this priority: Cross-product inconsistency weakens trust in the UI even when filtering is technically present. Consistent semantics produce immediate value on every affected list.
Independent Test: This can be tested independently by standardizing one soft-deletable list, one status-driven list, and one time-based list, then verifying that archived visibility, status labels, and date-range behavior match the shared standard.
Acceptance Scenarios:
- Given two comparable list pages that expose archived records, When the user opens their archive visibility filter, Then both pages present the same Active, All, and Archived semantics.
- Given a time-based list with records across multiple dates, When the user narrows the list to a date window, Then the list shows only records in that window and clearly displays the active date constraint.
- Given a status-driven list backed by a stable domain vocabulary, When the user opens the status filter, Then the available choices match the shared domain labels rather than list-local wording.
User Story 3 - Prevent Filter Drift (Priority: P3)
As a platform maintainer, I want automated guard coverage around the agreed filter standard so future list changes do not quietly reintroduce inconsistency.
Why this priority: The audit shows the platform drifted because conventions were only partially enforced. Lightweight automated guards keep the standard durable without introducing a filter framework.
Independent Test: This can be tested independently by extending guard coverage so it fails when a required list drops persistence, omits a required archive filter, or uses a non-standard status source where the standard requires a centralized source.
Acceptance Scenarios:
- Given an in-scope list drops required list-state persistence, When the guard suite runs, Then the suite fails with an actionable message.
- Given a soft-deletable in-scope list omits the standard archive visibility behavior, When the guard suite runs, Then the suite fails before drift reaches production.
Edge Cases
- When a list has too few records for additional filtering to provide user value, the standard allows that list to remain lightly filtered rather than forcing unnecessary controls.
- When a resource has no centralized enum or catalog yet, the rollout may retain a stable temporary option source only if replacing it would materially expand the current scope.
- When a time-based list already applies a default time window, the default must remain obvious and reversible so users do not mistake hidden records for missing data.
- When a resource uses relation-heavy or computed filters, the added filters must not weaken workspace or tenant scoping or impose disproportionate query cost.
- When a workspace-scoped monitoring list can contain tenant-bound and tenantless rows, new filters must not reveal cross-tenant values outside the user’s existing entitlement boundaries.
Approved Exceptions
- No query-risk exceptions were approved for this rollout.
RestoreRunResourcerequired an explicit tenant-scoped base query during implementation so the standard could ship without weakening isolation. - No transitional centralized status-source exceptions were approved.
FindingResourceandAlertDeliveryResourceboth moved to the thin shared option catalog during the rollout.
Requirements (mandatory)
Constitution alignment (required): This feature does not introduce Microsoft Graph calls, new write behavior, queue or schedule behavior, or new operational workflows. It standardizes list filtering behavior on existing surfaces only.
Constitution alignment (RBAC-UX): This feature touches both tenant/admin and workspace-scoped list surfaces, but it does not change authorization semantics. Non-membership remains deny-as-not-found, capability checks remain server-side on existing actions, and filter additions must not widen result visibility across workspace or tenant boundaries. The test plan must include positive and negative scope coverage on representative tenant-scoped and workspace-scoped lists.
Constitution alignment (BADGE-001): This feature may align status and outcome filter option sources with centralized enums or catalogs, but it does not create new badge vocabularies. If a centralized status source is introduced or expanded as part of rollout, related display semantics must remain centralized and covered by regression tests.
Constitution alignment (Filament Action Surfaces): The Action Surface Contract remains satisfied. This feature modifies list filtering behavior only; existing list header actions, row actions, bulk actions, inspection affordances, empty-state CTAs, and detail-page actions remain resource-local and keep their current authorization and audit behavior.
Constitution alignment (UX-001 — Layout & Information Architecture): This feature directly strengthens the table portion of UX-001 by standardizing when important lists preserve state and expose core filters. It does not redesign create, edit, or view layouts, and it does not alter existing empty-state structure beyond preserving current list compliance.
Functional Requirements
- FR-001: The system MUST define a single repo-wide filter UX standard for in-scope Filament resource lists.
- FR-002: The standard MUST apply mandatory list-state persistence to all Tier 1 and Tier 2 resource lists that expose filters.
- FR-003: Tier 1 resources for this standard are
PolicyResource,FindingResource,OperationRunResource,TenantResource, andInventoryItemResource. - FR-004: Tier 2 resources for this standard are
BackupScheduleResource,BackupSetResource,RestoreRunResource,PolicyVersionResource,ProviderConnectionResource,AlertDeliveryResource, andEntraGroupResource. - FR-005: Tier 3 resources may receive low-effort, high-value improvements, but Tier 3 work MUST NOT delay Tier 1 or Tier 2 rollout.
- FR-006: Every in-scope soft-deletable resource list MUST expose a consistent archive visibility filter using the shared Active, All, and Archived semantics.
- FR-007: Archived visibility wording MUST use “Archived” rather than resource-local alternatives such as “Trashed” or “Deleted.”
- FR-008: Status and outcome filters on prioritized resources MUST source their options from a centralized enum or domain catalog when such a source exists.
- FR-009:
FindingResourceandAlertDeliveryResourcestatus filtering MUST be aligned to centralized option sources as part of the standardization pass unless a documented transitional exception is required. - FR-010: Time-based Tier 1 and Tier 2 lists MUST expose a native date-range narrowing pattern when time is a primary investigation dimension.
- FR-011: At minimum,
FindingResource,AlertDeliveryResource,RestoreRunResource, andPolicyVersionResourceMUST gain date-range filtering aligned to their primary time field. - FR-012: Every newly added date-range filter MUST display active filter indicators so users can immediately see the applied date window.
- FR-013: The rollout MUST close the highest-value missing essential filters on
RestoreRunResource,PolicyVersionResource,InventoryItemResource, andBaselineProfileResource. - FR-014: Essential filter additions MUST prioritize domain-appropriate dimensions such as status, outcome, policy type, platform, sync freshness, and primary time windows rather than speculative filter expansion.
- FR-015: Smart defaults may be used to reduce noise on lists dominated by inactive, archived, ignored, open, or recently changed records, but every default MUST be obvious and easy to clear.
- FR-016: The standard MUST preserve existing workspace and tenant scoping behavior, including on monitoring surfaces that operate without an active tenant in the URL.
- FR-017: The standard MUST avoid introducing a new filter framework, plugin dependency, or custom grouped-filter UI layer.
- FR-018: Any shared support extracted during implementation MUST remain thin, explicit, and limited to repeated mechanical presets.
- FR-019: Guard coverage MUST be extended so required Tier 1 and Tier 2 persistence cannot regress silently.
- FR-020: Guard coverage MUST detect missing standardized archive visibility on in-scope soft-deletable resource lists.
- FR-021: Guard coverage MUST detect prioritized status filters that drift away from their required centralized option source.
- FR-022: Functional tests for changed surfaces MUST cover filter application, filter clearing, multi-filter composition, and representative scope safety.
- FR-023: The rollout MUST be phaseable, with persistence and guard coverage delivered before lower-priority polish.
Rollout Priorities
Phase 1 - Persistence and Guard Coverage
- Close the highest-value persistence gaps on
InventoryItemResource,PolicyVersionResource,RestoreRunResource,AlertDeliveryResource, andEntraGroupResource. - Extend table guard coverage so Tier 1 and Tier 2 persistence expectations are enforced consistently.
Phase 2 - Essential Filters
- Add missing status, outcome, platform, policy type, sync freshness, and date-range filters on the highest-value Tier 1 and Tier 2 lists.
- Preserve existing query scopes and tenancy boundaries while doing so.
Phase 3 - Consistency and Polish
- Align prioritized status sources to centralized enums or catalogs.
- Normalize labels on recurring dimensions such as status, outcome, archived visibility, platform, and policy type.
- Use a thin shared helper for repeated mechanical patterns such as centralized option sourcing plus archived and date-range presets.
Phase 4 - Optional Low-Priority Follow-ups
- Consider low-effort Tier 3 additions only after Tier 1 and Tier 2 consistency is stable.
UI Action Matrix (mandatory when Filament is changed)
If this feature adds/modifies any Filament Resource / RelationManager / Page, fill out the matrix below.
For each surface, list the exact action labels, whether they are destructive (confirmation? typed confirmation?), RBAC gating (capability + enforcement helper), and whether the mutation writes an audit log.
| Surface | Location | Header Actions | Inspect Affordance (List/Table) | Row Actions (max 2 visible) | Bulk Actions (grouped) | Empty-State CTA(s) | View Header Actions | Create/Edit Save+Cancel | Audit log? | Notes / Exemptions |
|---|---|---|---|---|---|---|---|---|---|---|
| Finding list | app/Filament/Resources/FindingResource.php + app/Filament/Resources/FindingResource/Pages/ListFindings.php |
Existing finding header actions retained | Existing record inspection affordance retained | Existing workflow row actions retained | Existing grouped bulk actions retained | Existing empty-state CTA structure retained | Existing ViewFinding header actions retained |
Not changed by this spec | Unchanged | Filter-only change; existing workflow actions, audit behavior, and authorization remain resource-local |
| Inventory item list | app/Filament/Resources/InventoryItemResource.php + app/Filament/Resources/InventoryItemResource/Pages/ListInventoryItems.php |
Existing resource header actions retained | Existing record inspection affordance retained | Existing row actions retained | Existing grouped bulk actions retained where supported | Existing empty-state CTA structure retained | Existing ViewInventoryItem header actions retained |
Not changed by this spec | Unchanged | Filter-only change |
| Policy version list | app/Filament/Resources/PolicyVersionResource.php + app/Filament/Resources/PolicyVersionResource/Pages/ListPolicyVersions.php |
Existing policy-version header actions retained | Existing record inspection affordance retained | Existing row actions retained | Existing grouped bulk actions retained | Existing empty-state CTA structure retained | Existing ViewPolicyVersion header actions retained |
Not changed by this spec | Unchanged | Filter-only change; existing destructive actions keep confirmation + authorization |
| Restore run list | app/Filament/Resources/RestoreRunResource.php + app/Filament/Resources/RestoreRunResource/Pages/ListRestoreRuns.php |
Existing restore-run header actions retained | Existing record inspection affordance retained | Existing row actions retained | Existing grouped bulk actions retained | Existing empty-state CTA structure retained | Existing ViewRestoreRun header actions retained |
Existing create flow retained | Unchanged | Filter-only change |
| Alert delivery list | app/Filament/Resources/AlertDeliveryResource.php + app/Filament/Resources/AlertDeliveryResource/Pages/ListAlertDeliveries.php |
Existing monitoring header actions retained | Existing record inspection affordance retained | Existing row actions retained | Existing grouped bulk actions retained where supported | Existing empty-state CTA structure retained | Existing ViewAlertDelivery header actions retained |
Not changed by this spec | Unchanged | Filter-only change; workspace-context entitlement behavior remains unchanged |
| Entra group list | app/Filament/Resources/EntraGroupResource.php + app/Filament/Resources/EntraGroupResource/Pages/ListEntraGroups.php |
Existing resource header actions retained | Existing record inspection affordance retained | Existing row actions retained | Existing grouped bulk actions retained where supported | Existing empty-state CTA structure retained | Existing ViewEntraGroup header actions retained |
Not changed by this spec | Unchanged | Filter-only change |
| Baseline profile list | app/Filament/Resources/BaselineProfileResource.php + app/Filament/Resources/BaselineProfileResource/Pages/ListBaselineProfiles.php |
Existing baseline-profile header actions retained | Existing record inspection affordance retained | Existing row actions retained | Existing grouped bulk actions retained | Existing empty-state CTA structure retained | Existing ViewBaselineProfile header actions retained |
Existing create/edit flows retained | Unchanged | Filter-only change |
| Operation run canonical table | app/Filament/Resources/OperationRunResource.php and workspace monitoring pages that reuse it |
Existing canonical page actions retained | Existing record inspection affordance retained in monitoring surfaces | Existing row actions retained | Existing grouped bulk actions retained where supported | Existing empty-state CTA structure retained | No new view/create/edit change in this spec | Not applicable | Unchanged | Filter option-label alignment only; canonical workspace view remains DB-only and entitlement-safe |
Key Entities (include if feature involves data)
- Filter UX Tier: The priority classification that decides whether a resource list requires mandatory persistence and essential filter coverage.
- Filter Behavior Profile: The combination of persistence, archive visibility, status sourcing, date-range support, defaults, labels, and active indicators expected on a given list.
- Centralized Status Source: The shared domain vocabulary used to keep status and outcome filter options consistent across comparable resources.
- Filter Guard Rule: The automated enforcement rule that protects the agreed filter standard from drifting over time.
Assumptions
- The comprehensive filter audit remains an accurate baseline for the 36 current table surfaces, even if minor counts shift during implementation.
- Existing list actions, empty states, and inspection affordances remain correct unless a separate spec changes them.
- Time-based resources already expose sufficient timestamp data to support user-visible date narrowing without introducing new data structures.
- Optional Tier 3 work is limited to clearly beneficial, low-risk additions such as simple status or state filters.
Dependencies
- The feature depends on the current audit inventory of filter coverage and persistence gaps remaining available as the planning baseline.
- The feature depends on existing centralized enums and catalogs where they already exist for status or outcome vocabularies.
- The feature depends on current workspace and tenant scoping rules remaining intact across affected list queries.
- The feature depends on existing table guard infrastructure being extended rather than replaced.
Success Criteria (mandatory)
Measurable Outcomes
- SC-001: In the post-rollout audit, 100% of Tier 1 and Tier 2 resource lists that expose filters preserve filter, search, and sort state within the same session.
- SC-002: In the post-rollout audit, 100% of in-scope soft-deletable resource lists present the same Archived visibility semantics.
- SC-003:
FindingResource,AlertDeliveryResource,RestoreRunResource, andPolicyVersionResourceall expose user-visible date-range narrowing with active indicators. - SC-004: The prioritized lists identified for this feature expose the required essential filters without introducing documented workspace or tenant scope regressions.
- SC-005: Automated guard coverage fails whenever an in-scope list drops required persistence, archive visibility, or mandated centralized status sourcing.
- SC-006: In manual QA, users can refresh or revisit an in-scope important list without reapplying their previously chosen narrowing during the same session.