TenantAtlas/specs/146-central-tenant-status-presentation/plan.md
ahmido 6ca496233b feat: centralize tenant lifecycle presentation (#175)
## Summary
- add a shared tenant lifecycle presentation contract and referenced-tenant adapter for canonical lifecycle labels and helper copy
- align tenant, chooser, onboarding, archived-banner, and tenantless operation viewer surfaces with the shared lifecycle vocabulary
- add Spec 146 design artifacts, audit notes, and regression coverage for lifecycle presentation across Filament and onboarding surfaces

## Validation
- `vendor/bin/sail bin pint --dirty --format agent`
- `vendor/bin/sail artisan test --compact tests/Feature/Badges/TenantStatusBadgeTest.php tests/Unit/Badges/TenantBadgesTest.php tests/Unit/Tenants/TenantLifecycleTest.php tests/Unit/Support/Tenants/TenantLifecyclePresentationTest.php tests/Feature/Filament/TenantLifecyclePresentationAcrossTenantSurfacesTest.php tests/Feature/Filament/ReferencedTenantLifecyclePresentationTest.php tests/Feature/Filament/TenantLifecycleStatusDomainSeparationTest.php tests/Feature/Filament/TenantViewHeaderUiEnforcementTest.php tests/Feature/Onboarding/TenantLifecyclePresentationCopyTest.php tests/Feature/Onboarding/OnboardingDraftAuthorizationTest.php tests/Feature/Onboarding/OnboardingDraftLifecycleTest.php`

## Notes
- Livewire v4.0+ compliance preserved; this change is presentation-only on existing Filament v5 surfaces.
- Panel provider registration remains unchanged in `bootstrap/providers.php`.
- No global-search behavior changed; no resource was newly made globally searchable or disabled.
- No destructive actions were added or changed.
- No asset registration strategy changed; existing deploy flow for `php artisan filament:assets` remains unchanged.

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #175
2026-03-16 18:18:53 +00:00

153 lines
10 KiB
Markdown

# Implementation Plan: Central Tenant Status Presentation
**Branch**: `146-central-tenant-status-presentation` | **Date**: 2026-03-16 | **Spec**: [specs/146-central-tenant-status-presentation/spec.md](./spec.md)
**Input**: Feature specification from `/specs/146-central-tenant-status-presentation/spec.md`
**Note**: This template is filled in by the `/speckit.plan` command. See `.specify/scripts/` for helper scripts.
## Summary
Standardize tenant lifecycle rendering behind one authoritative presentation contract that extends the existing `TenantLifecycle` + `BadgeCatalog` architecture with explicit lifecycle semantics, helper copy, and invalid-data handling. Roll the shared contract through tenant list/detail summary surfaces, archived-tenant banner copy, choose-tenant and onboarding-linked surfaces, and the tenantless operations viewer plus its enterprise-detail summary payload so `draft`, `onboarding`, `active`, and `archived` always render intentionally, never as Unknown, and never get conflated with provider, verification, RBAC, or run status domains.
## Technical Context
**Language/Version**: PHP 8.4.15
**Primary Dependencies**: Laravel 12, Filament 5, Livewire 4, Tailwind CSS 4
**Storage**: PostgreSQL (existing tenant and operation records only; no schema changes planned)
**Testing**: Pest 4 feature and unit tests, including Filament and Livewire coverage
**Target Platform**: Laravel Sail web application on Filament admin and workspace-canonical UI surfaces
**Project Type**: Web application monolith
**Performance Goals**: No render-time external calls, no material query-count regression on list/detail/viewer surfaces, and no extra polling or background work introduced
**Constraints**: Preserve Spec 143 lifecycle semantics and Spec 145 action semantics; do not change authorization, lifecycle transitions, selector inclusion rules, or tenant/workspace ownership; centralize badge semantics under BADGE-001; invalid fallback must be reserved for truly non-canonical data only
**Scale/Scope**: Workspace-owned tenant lifecycle presentation across tenant management, choose-tenant, onboarding-linked tenant references, and the tenantless operations viewer plus its `OperationRunResource` enterprise-detail summary payload, plus regression coverage for the primary surfaces
## Constitution Check
*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
- Inventory-first: PASS. This is presentation-only work over existing tenant and canonical records. No snapshot/backfill/write behavior changes.
- Read/write separation: PASS. No new writes, previews, confirmations, queues, or audits are introduced.
- Graph contract path: PASS. No Microsoft Graph calls are added or changed.
- Deterministic capabilities: PASS. No capability derivation changes.
- RBAC-UX: PASS. Authorization planes, 404/403 semantics, membership checks, and capability enforcement remain unchanged. Canonical viewers continue to rely on existing record-level authorization before any tenant lifecycle is shown.
- Workspace isolation: PASS. No workspace-scoping changes.
- RBAC-UX destructive confirmation: PASS. No new destructive actions.
- RBAC-UX global search: PASS. This plan may touch global lifecycle presentation only if an already-authorized tenant result is rendered; it does not widen search behavior.
- Tenant isolation: PASS. No cross-tenant access changes.
- Run observability: PASS. No `OperationRun` creation, mutation, or monitoring behavior changes.
- Ops-UX 3-surface feedback: PASS. Not applicable because no `OperationRun` workflow changes are introduced.
- Ops-UX lifecycle/service ownership: PASS. No `OperationRun` transition changes.
- Ops-UX summary counts/guards/system runs: PASS. Not applicable.
- Automation/data minimization: PASS. No new jobs, locks, or logging paths.
- Badge semantics (BADGE-001): PASS WITH REQUIRED CENTRALIZATION. The implementation must extend the existing `BadgeCatalog` / `BadgeRenderer` path instead of adding local lifecycle maps.
- UI naming (UI-NAMING-001): PASS. Operator vocabulary remains `Draft`, `Onboarding`, `Active`, and `Archived`.
- Filament UI Action Surface Contract: PASS. Presentation-only changes on existing surfaces; no action-surface exemption needed.
- Filament UI UX-001 (Layout & IA): PASS. Existing layouts remain intact; lifecycle rendering changes must fit current table, infolist, and viewer structures.
**Post-Design Re-check**: PASS. Phase 1 design keeps lifecycle presentation read-only, tenant-safe, badge-centralized, and action-surface neutral.
## Project Structure
### Documentation (this feature)
```text
specs/146-central-tenant-status-presentation/
├── plan.md
├── research.md
├── data-model.md
├── quickstart.md
├── contracts/
│ └── tenant-lifecycle-presentation.openapi.yaml
└── tasks.md
```
### Source Code (repository root)
```text
app/
├── Filament/
│ ├── Pages/
│ │ ├── Operations/
│ │ └── Workspaces/
│ ├── Resources/
│ │ └── TenantResource.php
│ └── System/Pages/Directory/
├── Models/
│ └── Tenant.php
├── Services/
│ ├── Onboarding/
│ └── Tenants/
├── Support/
│ ├── Badges/
│ └── Tenants/
resources/
└── views/
└── filament/
├── pages/
└── widgets/
tests/
├── Feature/
│ ├── Filament/
│ ├── Onboarding/
│ └── Rbac/
└── Unit/
```
**Structure Decision**: Use the existing Laravel monolith structure and extend the current support-layer centralization points first: `app/Support/Tenants` for lifecycle semantics, `app/Support/Badges` for badge-level rendering, `app/Filament/Resources/TenantResource.php` and related pages for tenant surfaces, `app/Filament/Pages/Operations` for canonical viewer alignment, and focused Pest coverage in `tests/Feature` and `tests/Unit`.
## Phase 0 Research Summary
- Confirmed the canonical lifecycle already exists in `App\Support\Tenants\TenantLifecycle` with the exact four required values and labels.
- Confirmed badge semantics are already centralized through `BadgeCatalog`, `BadgeRenderer`, and `TenantStatusBadge`, but today that path only standardizes badge label/color/icon, not helper copy or richer cross-surface presentation density.
- Confirmed tenant list/detail and system directory tenant tables already use `BadgeDomain::TenantStatus`, while choose-tenant currently communicates lifecycle indirectly in prose, archived tenant context is surfaced through a dedicated banner view, and operation viewers derive lifecycle context through `TenantOperabilityService` plus `OperationRunResource` enterprise-detail payload data rather than a dedicated lifecycle presentation contract.
- Confirmed Filament v5 supports badge presentation through shared text/badge semantics, which aligns with continuing to feed UI badges from one renderer rather than introducing per-surface mappings.
## Phase 1 Design
### Implementation Approach
1. Introduce a dedicated tenant lifecycle presentation contract that sits on top of `TenantLifecycle` and returns:
- canonical lifecycle value
- canonical label
- badge tone/icon data
- concise helper text
- detailed helper text
- explicit invalid-data marker for non-canonical values only
2. Keep `BadgeCatalog` / `BadgeRenderer` as the badge primitive for BADGE-001 compliance, but stop treating badge spec alone as the full lifecycle presentation contract.
3. Route all in-scope lifecycle rendering through the same presentation source, with per-surface density adapters for:
- table badge only
- infolist badge plus helper text
- tenant summary and archived-banner helper copy
- selector/supporting prose
- canonical viewer referenced-tenant banner or note
4. Audit existing lifecycle render points and tenant-adjacent statuses before rollout so lifecycle remains clearly separate from provider app status, RBAC, verification, and run state and no valid-state local mapping survives outside the shared contract.
5. Add regression tests that cover all four canonical lifecycle states plus invalid-data fallback behavior, including archived-banner and canonical-view summary surfaces.
### Planned Workstreams
- **Workstream A: Central contract**
Create a single presentation object or presenter in the tenant/support layer that derives from `TenantLifecycle` and is reusable outside tables.
- **Workstream B: Tenant management surfaces**
Update tenant list/detail summary areas, archived-tenant banner content, and any onboarding-linked tenant cards/sections to use the richer contract while preserving current Filament layouts and actions.
- **Workstream C: Selector and operations viewer surfaces**
Update choose-tenant and tenantless operation viewer context copy, including referenced-tenant banners and the `OperationRunResource` enterprise-detail summary payload consumed by that viewer, to use canonical lifecycle wording when lifecycle is shown or described.
- **Workstream D: Regression hardening**
Add focused unit tests for exhaustive lifecycle mapping and feature tests for tenant index/detail summary areas, archived banner content, onboarding-linked surfaces, and operation viewers.
## Testing Strategy
- Add a focused unit test for the central lifecycle presentation contract covering `draft`, `onboarding`, `active`, `archived`, and explicit invalid fallback for non-canonical values.
- Add a focused audit pass over the existing tenant lifecycle render points before rollout so every valid-state surface is routed through the shared contract.
- Update or add tenant Filament feature tests to assert lifecycle labels on:
- tenant index table
- tenant detail identity and summary sections
- archived tenant banner copy
- choose-tenant empty or contextual copy where lifecycle is described
- Update or add canonical viewer tests to assert onboarding and archived referenced tenants render intentional lifecycle context in both the tenantless viewer banner and the `OperationRunResource`-backed summary payload rendering.
- Add at least one mixed-status assertion showing lifecycle remains distinct from provider or RBAC status on tenant detail.
- Run the minimum focused Pest suite through Sail for the touched feature and unit tests.
## Complexity Tracking
No constitution violations or exceptional complexity are planned at this stage.