10 KiB
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
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
OperationRuncreation, mutation, or monitoring behavior changes. - Ops-UX 3-surface feedback: PASS. Not applicable because no
OperationRunworkflow changes are introduced. - Ops-UX lifecycle/service ownership: PASS. No
OperationRuntransition 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/BadgeRendererpath instead of adding local lifecycle maps. - UI naming (UI-NAMING-001): PASS. Operator vocabulary remains
Draft,Onboarding,Active, andArchived. - 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)
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)
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\TenantLifecyclewith the exact four required values and labels. - Confirmed badge semantics are already centralized through
BadgeCatalog,BadgeRenderer, andTenantStatusBadge, 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 throughTenantOperabilityServiceplusOperationRunResourceenterprise-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
- Introduce a dedicated tenant lifecycle presentation contract that sits on top of
TenantLifecycleand 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
- Keep
BadgeCatalog/BadgeRendereras the badge primitive for BADGE-001 compliance, but stop treating badge spec alone as the full lifecycle presentation contract. - 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
- 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.
- 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
TenantLifecycleand 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
OperationRunResourceenterprise-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.