## Summary - unify empty-state UX across the six in-scope Filament list pages - move empty-state ownership toward resource `table()` definitions while preserving existing RBAC behavior - add focused Pest coverage for empty-state rendering, CTA outcomes, populated-state regression behavior, and action-surface compliance - add the Spec 122 planning artifacts and product discovery documents used for this pass ## Changed surfaces - `PolicyResource` - `BackupSetResource` - `RestoreRunResource` - `BackupScheduleResource` - `WorkspaceResource` - `AlertDeliveryResource` ## Tests - `vendor/bin/sail artisan test --compact tests/Feature/Filament/EmptyStateConsistencyTest.php` - `vendor/bin/sail artisan test --compact tests/Feature/Filament/Alerts/AlertDeliveryViewerTest.php` - `vendor/bin/sail artisan test --compact tests/Feature/Filament/CreateCtaPlacementTest.php` - `vendor/bin/sail artisan test --compact tests/Feature/PolicySyncStartSurfaceTest.php` - `vendor/bin/sail artisan test --compact tests/Feature/BackupScheduling/BackupScheduleLifecycleAuthorizationTest.php` - `vendor/bin/sail artisan test --compact tests/Feature/Filament/BackupSetUiEnforcementTest.php` - `vendor/bin/sail artisan test --compact tests/Feature/Filament/RestoreRunUiEnforcementTest.php` - `vendor/bin/sail artisan test --compact tests/Feature/Guards/ActionSurfaceContractTest.php` - `vendor/bin/sail bin pint --dirty --format agent` ## Notes - Filament v5 / Livewire v4.0+ compliance is preserved. - Panel provider registration remains unchanged in `bootstrap/providers.php`. - No new globally searchable resources were added. - Destructive actions were not introduced by this pass. - Alert Deliveries is documented as the explicit no-header-action exemption for the empty-state CTA relocation rule. - Manual light/dark visual QA evidence is still expected in the PR/review artifact set for the remaining checklist items (`T018`, `T025`). Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #148
175 lines
12 KiB
Markdown
175 lines
12 KiB
Markdown
# Implementation Plan: Empty State Consistency Pass
|
||
|
||
**Branch**: `122-empty-state-consistency` | **Date**: 2026-03-08 | **Spec**: [spec.md](./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 `AlertDeliveryResource`’s 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)
|
||
|
||
```text
|
||
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)
|
||
|
||
```text
|
||
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.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:
|
||
- [data-model.md](./data-model.md)
|
||
- [contracts/empty-states.openapi.yaml](./contracts/empty-states.openapi.yaml)
|
||
- [quickstart.md](./quickstart.md)
|
||
|
||
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 surface’s 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 repository’s guard-enforced contract.
|