# Data Model: Tenant Lifecycle, Operability, and Context Semantics Foundation ## Core Entities ### Workspace - Purpose: Primary ownership, isolation, and session boundary. - Existing source: `App\Models\Workspace`. - Key relationships: - has many tenants - has many onboarding workflow records - has many canonical operation runs - Validation and invariants: - Workspace membership is required before any tenant or canonical record is revealed. - Workspace-owned canonical viewers may exist without tenant context in the URL. ### Tenant - Purpose: Durable workspace-owned tenant record. - Existing source: `App\Models\Tenant`. - Canonical fields relevant to this feature: - `id` - `workspace_id` - `external_id` - `name` - `status` - `deleted_at` - `is_current` - Canonical lifecycle states: - `draft` - `onboarding` - `active` - `archived` - Relationships: - belongs to workspace - has many memberships - may be linked from onboarding workflow records - may be referenced by operation runs - Validation and invariants: - Tenant lifecycle is the durable domain status, not the full workflow progression state. - Only `active` tenants may become normal tenant context. - Archived tenants remain retained for auditability and controlled restoration. ### TenantOnboardingSession - Purpose: Workspace-scoped onboarding workflow record. - Existing source: `App\Models\TenantOnboardingSession`. - Key fields relevant to this feature: - `id` - `workspace_id` - `tenant_id` - `lifecycle_state` - `current_checkpoint` - `last_completed_checkpoint` - `state` - `version` - `completed_at` - `cancelled_at` - Relationships: - belongs to workspace - optionally belongs to tenant - Validation and invariants: - Owns onboarding progression, resumability, and conflict-safe mutation. - Does not replace tenant lifecycle. - Must enforce workspace entitlement, and tenant entitlement once a tenant link exists. ### OperationRun - Purpose: Canonical workspace-owned record for long-running or operationally relevant work. - Existing source: `App\Models\OperationRun`. - Key fields relevant to this feature: - `id` - `workspace_id` - `tenant_id` nullable - `type` - `status` - `outcome` - `context` - `summary_counts` - `failure_summary` - Relationships: - belongs to workspace - optionally belongs to tenant - Validation and invariants: - A canonical viewer authorizes from the run, workspace, and entitlement checks. - Tenant mismatch against remembered context must not invalidate the run. - Status and outcome transitions remain service-owned. ### RememberedTenantContext - Purpose: Operator preference state that remembers the last tenant selection per workspace. - Existing implementation surfaces: - `App\Support\Workspaces\WorkspaceContext` - `App\Http\Controllers\SelectTenantController` - `App\Http\Controllers\ClearTenantContextController` - `App\Filament\Pages\ChooseTenant` - Data shape: - `workspace_id` - `tenant_id` - Validation and invariants: - This is not an authorization primitive. - It may prefilter workspace pages and drive convenience redirects. - It must be cleared or ignored when the selected tenant is no longer eligible for normal active context. ## Derived Domain Concepts ### TenantOperabilityDecision - Purpose: Derived policy result for what the operator may do with a tenant. - Inputs: - actor - workspace - tenant - page category - requested operation - Outputs: - `can_view_tenant_surface` - `can_select_as_context` - `can_operate` - `can_archive` - `can_restore` - `can_resume_onboarding` - `can_reference_in_workspace_monitoring` ### PageCategory - Purpose: Normalize route semantics by page type. - Canonical values: - `workspace_scoped` - `tenant_bound` - `onboarding_workflow` - `canonical_workspace_record_viewer` - Invariants: - Every in-scope route must map to one category. - Route legitimacy rules are defined by category, not by remembered tenant state. ### LifecyclePresentationSpec - Purpose: Central mapping from tenant lifecycle to operator-facing label, badge color, icon, and allowed explanatory copy. - Existing extension point: - `BadgeCatalog` - `BadgeDomain::TenantStatus` - Invariants: - All canonical lifecycle values must map explicitly. - No valid lifecycle may render as `Unknown`. ## State Transitions ### Tenant lifecycle transitions - `draft -> onboarding` - Trigger: onboarding has advanced enough that the tenant exists as an in-progress managed tenant. - `onboarding -> active` - Trigger: onboarding completion or activation flow defined by follow-up implementation specs. - `active -> archived` - Trigger: explicit archive action with authorization, confirmation, and audit logging. - `archived -> restored_state` - Trigger: explicit restore action defined by follow-up specs. - Note: current model restore behavior returns to `active`, but this foundation leaves restored-state semantics to follow-up work. ### Onboarding workflow transitions - Stay owned by `TenantOnboardingSession` lifecycle and checkpoint services. - Must not be conflated with tenant lifecycle labels or selector eligibility. ## Route-to-entity mapping - `/admin`, `/admin/choose-workspace`, `/admin/operations`: workspace plus remembered tenant preference, optionally filtered by tenant. - `/admin/choose-tenant`: workspace plus eligible tenant collection. - `/admin/tenants`, `/admin/tenants/{tenant}`: workspace plus route tenant. - `/admin/onboarding`, `/admin/onboarding/{onboardingDraft}`: workspace plus onboarding workflow record, optionally linked tenant. - `/admin/operations/{run}`: workspace plus canonical operation run, optionally linked tenant. ## Test focus derived from the model - Selector eligibility tests for all tenant lifecycle states. - Canonical run viewer tests for mismatched selected tenant versus referenced tenant. - Badge coverage tests for every canonical tenant lifecycle state. - Authorization tests asserting 404 for non-members and 403 for members missing capability. - Onboarding workflow tests proving onboarding drafts remain visible and resumable without becoming active tenant context.