TenantAtlas/docs/product/standards/filament-actions-ux.md
ahmido 37c6d0622c feat: implement spec 169 action surface contract v1.1 (#200)
## Summary
- implement the Action Surface Contract v1.1 runtime changes for Spec 169
- add the new explicit ActionSurfaceType contract, validator/discovery updates, and enrolled surface declarations
- update Filament action-surface documentation, focused guard tests, and spec artifacts for the completed feature

## Included
- clickable-row vs explicit-inspect enforcement across monitoring, reporting, CRUD, and system reference surfaces
- helper-first, workflow-next, destructive-last overflow ordering checks
- system panel list discovery in the primary action-surface validator
- Spec 169 artifacts: spec, plan, tasks, research, data model, quickstart, and logical contract

## Verification
- focused Pest verification pack completed for:
  - tests/Feature/Guards/ActionSurfaceValidatorTest.php
  - tests/Feature/Guards/ActionSurfaceContractTest.php
  - tests/Feature/Rbac/TenantActionSurfaceConsistencyTest.php
- integrated browser smoke test completed for admin-side reference surfaces:
  - /admin/operations
  - /admin/audit-log
  - /admin/finding-exceptions/queue
  - /admin/reviews
  - /admin/tenants

## Notes
- system panel browser smoke coverage could not be exercised in the same session because /system routes require platform authentication in the integrated browser
- Livewire target remains v4-compliant and no provider registration or asset strategy changes are introduced by this PR

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #200
2026-03-30 09:21:39 +00:00

4.8 KiB

Filament Actions UX Standard

Canonical rules for row actions, bulk actions, header actions, and inspect affordances on all Filament table surfaces. This standard consolidates the Action Surface Contract from the constitution and docs/ui/action-surface-contract.md.

Last reviewed: 2026-03-30


Governing Principle

Filament-native first. Action patterns use native Filament action APIs. The constitution's Action Surface Contract (in .specify/memory/constitution.md) is the authoritative source for safety and RBAC rules. This document provides the quick-reference standard for implementation.


Required Surfaces

Every list/table must define:

  • Header Actions — primary CTA (create, sync, etc.)
  • Row Actions — inspect + contextual operations
  • Bulk Actions — where batch operations exist
  • Empty-State CTA — exactly 1 primary action, RBAC-gated

Inspect Affordance (Required)

Every list-style surface must provide a way to open a record.

Default: clickable rows for list-first and registry surfaces

$table->recordUrl(fn ($record) => /* route to view/edit */)

Use this default for:

  • CRUD / List-first resources
  • Read-only registries / reports
  • Reporting and evidence registers such as Review Register and Evidence Overview

Explicit inspect for queue and audit surfaces

Use an Inspect row action or equivalent same-page selected detail when chronology or queue context must remain visible.

  • Audit / history pages use explicit inspect
  • Queue / review pages use explicit inspect
  • These surfaces should not also expose row click as a competing open path

Use only when clickable rows are impractical on a clickable-row surface.

  • PrimaryLinkColumn requires a non-empty declaration reason
  • It is not a fallback for queue / review or audit surfaces

Rule: no lone "View" button

If an open action is the only row action on a clickable-row surface, prefer row click and set actions([]) to avoid an unnecessary Actions column.


Row Action Limits

  • Max 2 visible row actions (typically View/Edit or Edit/Delete)
  • Everything else goes into an ActionGroup labeled "More"
  • Destructive actions must never be the primary visible action
  • On clickable-row surfaces, prefer zero inline row actions unless a single justified shortcut materially improves the workflow

Bulk Actions

  • Bulk actions must be grouped via BulkActionGroup
  • Destructive bulk actions require confirmation
  • Typed confirmation may be required for large/bulk changes
  • Do not leave an empty BulkActionGroup placeholder visible once filters, record state, or RBAC remove every effective action

Destructive Action Safety

  • All destructive actions must use ->requiresConfirmation()
  • Destructive actions must not be styled as primary
  • Confirmation text must clearly describe the consequence
  • Server-side authorization must still enforce the action regardless of UI confirmation

This is a constitution-level non-negotiable (RBAC-UX-005).


Action Consistency

Standard action labels

Action Label Icon guidance
Inspect record "Inspect" heroicon-o-eye
Edit record "Edit" heroicon-o-pencil-square
Delete record "Delete" heroicon-o-trash
Archive record "Archive" heroicon-o-archive-box
Restore record "Restore" heroicon-o-arrow-uturn-left
Force delete "Force Delete" heroicon-o-trash

Notes:

  • Clickable-row surfaces normally do not render a View or Inspect row action at all.
  • Reporting/evidence registers keep row click primary and should not add a duplicate View review-style action.

Action ordering in "More" group

  1. Navigation or inspect helpers first
  2. Non-destructive workflow or lifecycle actions next
  3. Destructive actions last
  4. Do not render an empty ActionGroup placeholder

Representative expectations:

  • Policies: Export, then Sync, then destructive ignore/delete actions
  • Backup schedules: Run now / Retry before archive or force delete
  • Workspaces: row click stays primary and the secondary Edit shortcut lives under More

RBAC Enforcement

  • Non-member access: abort(404), do not leak existence
  • Member without capability: visible but disabled with tooltip
  • Server-side must enforce via Gate::authorize(...) or Policy method
  • Missing server-side authorization is a P0 security bug

Spec / DoD Gate

Every spec with UI changes must include a UI Action Matrix listing:

  • Which actions exist on which surfaces
  • Which are destructive and how confirmation is handled
  • Which capabilities gate each action

A change is not "Done" unless the Action Surface Contract is met.


Canonical Sources

  • Constitution: .specify/memory/constitution.md → "Filament UI — Action Surface Contract"
  • Detailed reference: docs/ui/action-surface-contract.md