TenantAtlas/specs/148-central-tenant-operability-policy/data-model.md
2026-03-17 12:47:16 +01:00

6.6 KiB

Phase 1 Data Model: Central Tenant Operability Policy

Overview

This feature does not require a new database table in its first implementation slice. The primary data-model work is the formalization of existing persistent records plus new derived domain objects that express tenant operability consistently across lanes.

Persistent Domain Entities

Tenant

Purpose: Durable workspace-owned record whose lifecycle influences operability.

Key fields:

  • id
  • workspace_id
  • external_id
  • status with canonical values draft, onboarding, active, archived
  • deleted_at for archive persistence behavior

Relationships:

  • Belongs to one workspace
  • Has many onboarding sessions, audit logs, provider connections, and tenant-owned operational records
  • May be referenced by canonical workspace records such as OperationRun

Validation rules:

  • workspace_id must match the active workspace scope for all in-scope route or action decisions
  • status must resolve through the canonical TenantLifecycle model
  • Soft-delete state is an implementation input, never the only semantic rule

State transitions relevant to this feature:

  • draftonboarding
  • onboardingactive
  • activearchived
  • archivedactive

TenantOnboardingSession

Purpose: Separate workspace-scoped workflow record used to evaluate onboarding-lane actions.

Key fields:

  • id
  • workspace_id
  • tenant_id nullable until linked
  • workflow state and lifecycle fields already used by onboarding services

Relationships:

  • Belongs to one workspace
  • Optionally belongs to one tenant

Validation rules:

  • Must be in the same workspace as any linked tenant
  • Onboarding-specific operability decisions must validate both tenant lifecycle and workflow resumability

OperationRun

Purpose: Canonical workspace-owned record that may reference a tenant without becoming subordinate to selected tenant context.

Key fields:

  • id
  • workspace_id
  • tenant_id nullable
  • type
  • status
  • outcome

Relationships:

  • Belongs to one workspace
  • May belong to one tenant reference

Validation rules:

  • Canonical route legitimacy is based on the run and workspace first
  • Tenant-linked follow-up actions must still respect tenant entitlement and operability outcomes

UserTenantPreference and WorkspaceContext Session State

Purpose: Stores remembered tenant context for the active operating lane.

Key fields:

  • user_id
  • tenant_id
  • last_used_at
  • session-scoped workspace and remembered-tenant identifiers

Validation rules:

  • Remembered tenant is valid only when workspace match, tenant existence, entitlement, and selector-lane operability all still hold

New Derived Domain Objects

TenantInteractionLane

Purpose: Explicitly identifies the lane in which the tenant is being evaluated.

Canonical values:

  • standard_active_operating
  • onboarding_workflow
  • administrative_management
  • canonical_workspace_record

Why it exists:

  • The same tenant can be selector-ineligible yet still administratively viewable or canonically referenceable

TenantOperabilityContext

Purpose: Normalized evaluation input for the central policy layer.

Fields:

  • tenant
  • actor
  • workspaceId
  • lane
  • pageCategory
  • linkedRecordType nullable
  • linkedRecordId nullable
  • onboardingDraft nullable
  • requiredCapability nullable
  • selectedTenant nullable

Context ownership:

  • Consumers normalize and pass route, record, workflow, and selected-tenant inputs into the context.
  • The central service resolves workspace membership, tenant entitlement, capability truth, lifecycle, and archived persistence state through canonical workspace, tenant, and RBAC helpers at evaluation time.
  • Consumers may request a capability-aware question, but they do not authoritatively decide membership or entitlement before evaluation.

Validation rules:

  • tenant.workspace_id must equal workspaceId
  • linked records must belong to the same workspace when tenant-linked
  • selectedTenant may be informative but never authoritative

TenantOperabilityQuestion

Purpose: Declares the exact semantic question the consumer is asking.

Canonical values:

  • selector_eligibility
  • remembered_context_validity
  • tenant_bound_viewability
  • canonical_linked_record_viewability
  • archive_eligibility
  • restore_eligibility
  • resume_onboarding_eligibility
  • onboarding_completion_eligibility
  • verification_readiness_eligibility
  • administrative_discoverability

TenantOperabilityOutcome

Purpose: Structured result returned by the central operability policy.

Fields:

  • question
  • allowed
  • lifecycle
  • lane
  • reasonCode nullable
  • requiredCapability nullable
  • discoverable boolean
  • informationalMessageKey nullable
  • metadata key-value bag for consumer-safe hints

Behavior:

  • Must be stable enough for unit assertions and UI mapping
  • May expose helper methods for common adapters, but raw outcome data remains canonical

TenantOperabilityReasonCode

Purpose: Stable denial or ineligibility reason catalog.

Initial values:

  • workspace_mismatch
  • tenant_not_entitled
  • missing_capability
  • wrong_lane
  • selector_ineligible_lifecycle
  • tenant_not_archived
  • tenant_already_archived
  • onboarding_not_resumable
  • canonical_view_followup_only
  • remembered_context_stale

Consumer Mapping

Consumer Primary question(s)
Choose-tenant page selector_eligibility
Select-tenant controller selector_eligibility, remembered_context_validity
WorkspaceContext remembered_context_validity
OperateHubShell tenant_bound_viewability, canonical_linked_record_viewability, administrative_discoverability
TenantActionPolicySurface archive_eligibility, restore_eligibility, resume_onboarding_eligibility, verification_readiness_eligibility
ManagedTenantOnboardingWizard resume_onboarding_eligibility, onboarding_completion_eligibility, verification_readiness_eligibility
TenantResource global search and admin listing administrative_discoverability
TenantlessOperationRunViewer canonical_linked_record_viewability and follow-up action questions

Migration Notes

  • No persistence migration is required for the first slice.
  • Existing boolean accessors on TenantOperabilityService may remain as compatibility adapters while consumers migrate to structured outcomes.
  • Any new enums or value objects should live under app/Support/Tenants to stay aligned with existing lifecycle, page-category, and action-surface support code.