TenantAtlas/specs/143-tenant-lifecycle-operability-context-semantics/research.md
ahmido 641bb4afde feat: implement tenant lifecycle operability semantics (#172)
## Summary
- implement Spec 143 tenant lifecycle, operability, and tenant-context semantics across chooser, tenant management, onboarding, and canonical operation viewers
- add centralized tenant lifecycle and operability support types, audit action coverage, and lifecycle-aware badge and action handling
- add feature and unit coverage for tenant chooser eligibility, global search scoping, canonical operation access, onboarding authorization, and lifecycle presentation

## Testing
- vendor/bin/sail artisan test --compact
- vendor/bin/sail bin pint --dirty --format agent

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #172
2026-03-15 09:08:36 +00:00

6.4 KiB
Raw Blame History

Research: Tenant Lifecycle, Operability, and Context Semantics Foundation

Decision 1: Reuse the existing Tenant lifecycle states as the canonical domain source

  • Decision: Keep draft, onboarding, active, and archived on App\Models\Tenant as the single canonical lifecycle vocabulary for tenant records, and build operability and context rules on top of that rather than introducing a second lifecycle store.
  • Rationale: Tenant already defines the lifecycle constants, soft-delete behavior, and current-selection safety (makeCurrent() rejects non-active tenants). The inconsistency is not missing states; it is inconsistent interpretation of those states across pages and helpers.
  • Alternatives considered:
    • Add a second lifecycle table or projection. Rejected because it would duplicate the same tenant-state truth and increase reconciliation complexity.
    • Derive tenant lifecycle entirely from onboarding session lifecycle. Rejected because onboarding drafts are workflow records and do not replace the durable tenant record.

Decision 2: Model operability separately from lifecycle

  • Decision: Introduce a central operability layer that answers viewability, selector eligibility, action eligibility, onboarding resumability, and canonical monitoring referenceability independently of raw lifecycle.
  • Rationale: Current code uses raw where('status', 'active'), isActive(), or soft-delete checks in selectors, controllers, and actions. That pattern conflates lifecycle with every UX and authorization choice.
  • Alternatives considered:
    • Continue using direct status === 'active' checks with better comments. Rejected because it does not prevent future divergence.
    • Encode every decision directly into policies. Rejected because selector visibility, badge presentation, and page categorization are not purely authorization concerns.

Decision 3: Treat remembered tenant context as preference state, not route legitimacy

  • Decision: Keep remembered tenant state in workspace context helpers, but treat it as filter and navigation preference only. Canonical workspace-owned record viewers must authorize by record and entitlement, not by active tenant equality.
  • Rationale: TenantlessOperationRunViewer::mount() currently aborts 404 when the active tenant differs from the run tenant even after OperationRunPolicy already authorizes the user. That is the concrete trust failure this foundation must eliminate.
  • Alternatives considered:
    • Keep the viewer mismatch 404 and document it. Rejected because it makes a valid record appear missing and violates the specs canonical-record rule.
    • Automatically switch the selected tenant when viewing a canonical record. Rejected because it mutates operator context as a side effect of inspection.

Decision 4: Keep onboarding workflow state distinct from tenant lifecycle

  • Decision: Preserve TenantOnboardingSession as the owner of workflow progression, resumability, and checkpoint semantics, while Tenant owns lifecycle semantics for the durable tenant record.
  • Rationale: The codebase already uses OnboardingLifecycleService, OnboardingDraftResolver, and TenantOnboardingSessionPolicy to manage workflow-specific state. Folding that into tenant lifecycle would blur durable domain state with wizard progression.
  • Alternatives considered:
    • Collapse onboarding lifecycle into tenant status. Rejected because checkpoint-level progress, resumability, and versioning belong to the workflow record.
    • Hide onboarding tenants until activation. Rejected because operators need to resume, inspect, and audit onboarding work before activation.

Decision 5: Extend centralized badge semantics instead of page-local mappings

  • Decision: Use BadgeCatalog and BadgeDomain as the only badge semantics extension point for tenant lifecycle presentation, and add exhaustive coverage tests there.
  • Rationale: Tenant status in TenantResource already uses BadgeRenderer::label/color/icon(BadgeDomain::TenantStatus). The fix for Unknown rendering belongs in the badge domain mapping, not in per-page string conditionals.
  • Alternatives considered:
    • Patch each affected page with its own match statement. Rejected because it recreates drift.
    • Render raw status strings without badge mapping. Rejected because it breaks BADGE-001 and current UI consistency.

Decision 6: Anchor authorization in existing policies and capability registries

  • Decision: Follow-up implementation work should keep server-side enforcement in OperationRunPolicy, tenant policies, onboarding policies, CapabilityResolver, WorkspaceCapabilityResolver, and Capabilities, with any new lifecycle-aware decisions delegated through central helpers rather than raw capability strings.
  • Rationale: The repo already has a strong split between 404 membership failures and 403 capability failures. The problem is contextual misuse, not absence of enforcement primitives.
  • Alternatives considered:
    • Introduce route-local authorization closures. Rejected because it would increase duplication and drift.
    • Rely on Filament visibility or disabling state alone. Rejected because the constitution explicitly forbids using UI as the security boundary.

Decision 7: Plan follow-up implementation around existing test clusters

  • Decision: Target follow-up validation through existing Pest suites in tests/Feature/Auth, tests/Feature/Monitoring, tests/Feature/Onboarding, tests/Feature/Filament, tests/Feature/Rbac, tests/Feature/TenantRBAC, plus focused unit coverage for onboarding and badge semantics.
  • Rationale: The repo already has dedicated tests for tenant chooser selection, tenant switcher scope, archived tenant access, onboarding authorization, canonical monitoring behavior, and operation-run viewing.
  • Alternatives considered:
    • Create a new isolated test suite just for lifecycle semantics. Rejected because the behavior is cross-cutting and should strengthen the existing regression clusters.

Filament and panel notes

  • Filament v5 runs on Livewire v4 in this repository.
  • Panel providers are registered in bootstrap/providers.php, which already contains AdminPanelProvider, TenantPanelProvider, and SystemPanelProvider.
  • Relevant searchable-resource posture in current scope:
    • TenantResource has a resource view surface and can remain globally searchable if desired.
    • OperationRunResource has global search disabled.
    • Workspace landing and onboarding wizard are pages, not resources.