TenantAtlas/specs/122-empty-state-consistency/plan.md
2026-03-08 03:16:51 +01:00

12 KiB
Raw Blame History

Implementation Plan: Empty State Consistency Pass

Branch: 122-empty-state-consistency | Date: 2026-03-08 | Spec: spec.md Input: Feature specification from /specs/122-empty-state-consistency/spec.md

Note: This plan is generated by the /speckit.plan workflow and aligned to the current repository constitution.

Summary

Unify the empty-state experience across six primary Filament list pages so each empty list renders an enterprise-grade icon, heading, description, and exactly one guided CTA. The implementation will prefer resource-level table() empty-state definitions, preserve existing capability-aware CTA behavior, reuse local patterns from BaselineProfileResource and ReviewPackResource, update AlertDeliveryResources action-surface declaration to remove the empty-state exemption, document Alert Deliveries as the sole explicit UX-001 header-relocation exemption, and extend focused Pest + Livewire coverage for content, CTA outcomes, populated-state regression behavior, RBAC behavior, and action-surface guard compliance.

Technical Context

Language/Version: PHP 8.4.15 / Laravel 12
Primary Dependencies: Filament v5, Livewire v4.0+, Tailwind CSS v4, Pest v4
Storage: PostgreSQL + existing workspace/tenant session context; no schema changes
Testing: Pest v4 feature and Livewire component tests, plus manual light/dark visual QA evidence attached to PR/review
Target Platform: Laravel Sail web admin + tenant panels (/admin, /admin/t/{tenant}/...) in containerized deployment
Project Type: Laravel monolith / Filament web application
Performance Goals: No additional remote calls, no new queued work, and no material increase in list-render query cost; empty-state rendering remains a table-configuration concern only
Constraints: Preserve existing RBAC/UI enforcement, keep populated-table behavior unchanged, use exactly one empty-state CTA per surface, prefer resource table() definitions, keep screenshots out of the repo, and treat Alert Deliveries as the only explicit exemption from header CTA relocation once rows exist
Scale/Scope: 6 list surfaces, 6 resource/page empty-state retrofits, 1 action-surface declaration update for Alert Deliveries, and focused regression tests; no migrations, no new services, no new routes

Constitution Check

GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.

  • Inventory-first: PASS (feature only affects empty-state presentation on existing inventory/backup/monitoring/workspace lists; no inventory-vs-snapshot semantics change).
  • Read/write separation: PASS (no new writes or operational flows are introduced; existing mutating/create/start actions keep their current behavior).
  • Graph contract path: PASS (no Microsoft Graph endpoints, contracts, or client usage change).
  • Deterministic capabilities: PASS (no new capabilities; existing canonical capability checks and enforcement helpers remain in place).
  • RBAC-UX: PASS (non-member 404 and member-without-capability 403 semantics remain unchanged; the feature only changes empty-state presentation).
  • Workspace isolation: PASS (workspace-scoped resources remain workspace-safe; no chooser or context rules are altered).
  • Destructive confirmation: PASS / N/A (no destructive actions are added or modified).
  • Global search: PASS / N/A (no global search behavior changes).
  • Tenant isolation: PASS (tenant-owned lists stay tenant-scoped; Alert Deliveries remains entitlement-filtered in workspace context).
  • Run observability: PASS / N/A (feature introduces no new long-running, remote, or queued work; the existing policy sync CTA keeps its current operation-run behavior unchanged).
  • Ops-UX 3-surface feedback: PASS / N/A for new work; preserved for existing queue-operation CTA on policies.
  • Ops-UX lifecycle: PASS / N/A (no new OperationRun lifecycle changes).
  • Ops-UX summary counts: PASS / N/A (no new OperationRun metrics producers).
  • Ops-UX guards: PASS (existing guards remain relevant; plan includes updating action-surface guard coverage where the declared contract changes).
  • Ops-UX system runs: PASS / N/A (no system-run behavior changes).
  • Automation: PASS / N/A (no scheduled or queued logic added).
  • Data minimization: PASS (no new persisted state or logging payloads).
  • Badge semantics (BADGE-001): PASS / N/A (no new status-like badges are added; empty-state icons are not governed by BADGE-001).
  • Filament UI Action Surface Contract: PASS with required implementation update. The six in-scope list surfaces already have action surfaces; the plan must update empty-state declarations/content and remove the current AlertDeliveryResource empty-state exemption.
  • Filament UI UX-001: PASS. The feature directly advances UX-001 by ensuring each in-scope list empty state has a specific title, explanation, and one CTA.

Project Structure

Documentation (this feature)

specs/122-empty-state-consistency/
├── plan.md
├── research.md
├── data-model.md
├── quickstart.md
├── contracts/
│   └── empty-states.openapi.yaml
└── tasks.md

Source Code (repository root)

app/
├── Filament/
│   └── Resources/
│       ├── PolicyResource.php                           # MODIFY — move complete empty state into table() and keep sync CTA semantics
│       ├── BackupSetResource.php                        # MODIFY — define complete empty state in table()
│       ├── RestoreRunResource.php                       # MODIFY — define complete empty state in table()
│       ├── BackupScheduleResource.php                   # MODIFY — define complete empty state in table()
│       ├── AlertDeliveryResource.php                    # MODIFY — define complete empty state + update actionSurfaceDeclaration()
│       ├── PolicyResource/
│       │   └── Pages/
│       │       └── ListPolicies.php                     # MODIFY — reduce helper-only empty-state responsibility if needed
│       ├── BackupSetResource/
│       │   └── Pages/
│       │       └── ListBackupSets.php                   # MODIFY — align empty-state CTA ownership with resource table()
│       ├── RestoreRunResource/
│       │   └── Pages/
│       │       └── ListRestoreRuns.php                  # MODIFY — align empty-state CTA ownership with resource table()
│       ├── BackupScheduleResource/
│       │   └── Pages/
│       │       └── ListBackupSchedules.php              # MODIFY — align empty-state CTA ownership with resource table()
│       └── Workspaces/
│           ├── WorkspaceResource.php                    # MODIFY — define complete empty state in table()
│           └── Pages/
│               └── ListWorkspaces.php                   # MODIFY — align empty-state CTA ownership with resource table()

tests/
├── Feature/
│   ├── Filament/
│   │   ├── CreateCtaPlacementTest.php                   # MODIFY — preserve empty-state/header CTA relocation behavior
│   │   ├── Alerts/
│   │   │   └── AlertDeliveryViewerTest.php              # MODIFY — extend empty-state / authorization coverage for alert deliveries
│   │   └── [new or updated empty-state tests]           # ADD/MODIFY — per-resource empty-state content coverage
│   ├── BackupScheduling/
│   │   └── BackupScheduleLifecycleAuthorizationTest.php # MODIFY or reference — disabled tooltip behavior remains intact
│   ├── PolicySyncStartSurfaceTest.php                   # MODIFY or reference — policy sync CTA capability behavior remains intact
│   └── Guards/
│       └── ActionSurfaceContractTest.php                # MODIFY — cover updated AlertDelivery empty-state declaration

resources/
└── views/
  └── [no new view templates expected]                 # prefer native Filament table empty-state configuration

Structure Decision: Keep the work inside the existing Laravel/Filament monolith. The feature is a resource-level UI consistency pass with focused list-page helper cleanup and targeted Pest/Livewire regression coverage; no new base folders, services, routes, or data layer objects are needed.

Complexity Tracking

No Constitution Check violations. No justifications needed.

Violation Why Needed Simpler Alternative Rejected Because

Phase 0 — Research (output: research.md)

See: research.md

Research goals:

  • Confirm the preferred source of truth for complete Filament empty-state definitions in this repo.
  • Confirm how to preserve existing capability-aware CTA behavior without creating RBAC regressions.
  • Confirm the correct next-step CTA for the read-only Alert Deliveries surface.
  • Confirm the smallest reliable test strategy using existing Pest + Livewire patterns and existing action-surface guards.

Phase 1 — Design & Contracts (outputs: data-model.md, contracts/, quickstart.md)

See:

Design focus:

  • Model each list empty state as a UI contract over existing resource tables rather than a new domain or persistence object.
  • Move in-scope surfaces toward resource-level table() ownership of empty-state heading, description, icon, and CTA.
  • Preserve header-vs-empty-state CTA placement behavior already guarded by existing tests.
  • Update AlertDeliveryResource from an empty-state exemption to an explicit guided empty-state declaration while preserving its documented no-header-action exemption once rows exist.
  • Keep screenshots and dark-mode QA as review artifacts rather than committed documentation files.

Phase 2 — Implementation Outline (tasks created in /speckit.tasks)

Resource empty-state retrofit

  • Add or complete emptyStateHeading(), emptyStateDescription(), emptyStateIcon(), and emptyStateActions() on the six in-scope list surfaces.
  • Reuse each surfaces existing primary CTA behavior (create, navigate, or queue operation) rather than inventing new workflows.
  • Keep copy concise, enterprise-oriented, and module-specific.

Ownership consolidation

  • Move empty-state contract ownership into each resource table() configuration where Filament supports it.
  • Reduce or remove list-page helper duplication so copy, icon, and CTA do not drift across files.
  • Preserve existing empty/header CTA relocation behavior already covered by the repo.

Contract and guard alignment

  • Update AlertDeliveryResource::actionSurfaceDeclaration() to satisfy ListEmptyState rather than exempt it.
  • Verify the changed surfaces still satisfy the Action Surface Contract and do not require new baseline exemptions.

Regression protection

  • Add or extend per-resource empty-state rendering assertions for heading, description, icon-related presence, and CTA labels.
  • Add explicit CTA outcome coverage so empty-state actions are proven to navigate or queue the intended existing workflows.
  • Add populated-state regression coverage for representative create-capable surfaces plus the Alert Deliveries header-action exemption.
  • Extend capability tests so disabled or hidden CTA behavior remains aligned with the current resource-specific model.
  • Keep response/feature coverage for workspace-context and alert-delivery entitlement behavior unchanged except for the new empty-state guidance.

Verification

  • Run focused Pest suites for CTA placement, authorization behavior, alert deliveries, and action-surface guards.
  • Run Pint on dirty files through Sail.
  • Capture light/dark visual QA evidence for all affected surfaces in PR/review artifacts.

Constitution Check (Post-Design)

Re-check result: PASS. The design adds no new routes, data model changes, background work, or authorization semantics. It strengthens UX-001 compliance, preserves canonical RBAC/UI-enforcement behavior, and explicitly updates the Alert Deliveries action-surface declaration so the implemented UI stays aligned with the repositorys guard-enforced contract.