TenantAtlas/specs/126-filter-ux-standardization/spec.md
2026-03-09 11:39:36 +01:00

21 KiB
Raw Blame History

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}/..., selected low-effort Tier 3 list pages where the current filter gap is obvious and low risk, and the high-value backup-set item relation table when operator review exposes the same gap during backup inspection
  • 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:

  1. 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.
  2. 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:

  1. 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.
  2. 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.
  3. 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:

  1. Given an in-scope list drops required list-state persistence, When the guard suite runs, Then the suite fails with an actionable message.
  2. 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 users existing entitlement boundaries.

Approved Exceptions

  • No query-risk exceptions were approved for this rollout. RestoreRunResource required an explicit tenant-scoped base query during implementation so the standard could ship without weakening isolation.
  • No transitional centralized status-source exceptions were approved. FindingResource and AlertDeliveryResource both 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, and InventoryItemResource.
  • FR-004: Tier 2 resources for this standard are BackupScheduleResource, BackupSetResource, RestoreRunResource, PolicyVersionResource, ProviderConnectionResource, AlertDeliveryResource, and EntraGroupResource.
  • FR-005: Tier 3 resources and low-effort relation-manager tables may receive high-value improvements when the UX gap is obvious, but that follow-up 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: FindingResource and AlertDeliveryResource status 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, and PolicyVersionResource MUST 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, and BaselineProfileResource.
  • 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, and EntraGroupResource.
  • 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 and relation-manager follow-ups only after Tier 1 and Tier 2 consistency is stable.
  • BaselineSnapshotResource and BackupItemsRelationManager are approved examples of these follow-ups because operator review exposed immediate filtering friction on active governance and backup-inspection workflows.

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
Baseline snapshot list app/Filament/Resources/BaselineSnapshotResource.php + app/Filament/Resources/BaselineSnapshotResource/Pages/ListBaselineSnapshots.php Existing list header remains empty because snapshots are capture outputs Existing record inspection affordance retained Existing View row action retained No bulk actions by design Existing empty-state CTA structure retained Existing ViewBaselineSnapshot header remains informational Not changed by this spec Unchanged Low-effort follow-up filter-only change on a workspace-scoped governance list
Backup set items relation table app/Filament/Resources/BackupSetResource/RelationManagers/BackupItemsRelationManager.php Existing Refresh and Add Policies header actions retained Existing relation-table inspection affordance retained Existing grouped row actions retained, including destructive remove with confirmation Existing grouped bulk remove retained Existing empty-state CTA retained Uses parent backup-set view header; no new detail-header action Not changed by this spec Unchanged Low-effort follow-up filter-only change on the backup inspection table; existing authorization and confirmation behavior remain unchanged
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, and PolicyVersionResource all 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.