Implements workspace-scoped managed tenant onboarding wizard (Filament v5 / Livewire v4) with strict RBAC (404/403 semantics), resumable sessions, provider connection selection/creation, verification OperationRun, and optional bootstrap. Removes legacy onboarding entrypoints and adds Pest coverage + spec artifacts (073).
2.6 KiB
2.6 KiB
Data Model — Unified Managed Tenant Onboarding Wizard (073)
Entities
Workspace
Existing entity. Onboarding is always initiated within a selected workspace.
Tenant (Managed Tenant)
Existing model: App\Models\Tenant
Key fields (existing or to be confirmed/extended):
id(PK)workspace_id(FK to workspaces)tenant_id(string; Entra tenant ID) — spec’sentra_tenant_idexternal_id(string; globally unique route key used by Filament tenancy)name(string)domain(string|null)status(string) — v1 lifecycle:pending(created / onboarding)active(ready)archived(no longer managed)
Indexes / constraints (design intent):
- Unique:
(workspace_id, tenant_id) - Keep
external_idglobally unique (for/admin/t/{tenant}routing) and do not force it to equaltenant_id.
State transitions:
pending→activeafter successful verificationactive→archivedon soft-delete (existing behavior)archived→activeon restore (existing behavior)
ProviderConnection
Existing model: App\Models\ProviderConnection
- Belongs to
Tenant - Contains
entra_tenant_id(string) and default/active flags.
TenantOnboardingSession (new)
New model/table to persist resumable onboarding state. Must never persist or return secrets.
Proposed fields:
id(PK)workspace_id(FK)tenant_id(FK to tenants.id) — nullable until tenant is created, depending on wizard flowentra_tenant_id(string) — denormalized for upsert/idempotency before tenant existscurrent_step(string; e.g.,identify,connection,verify,bootstrap,complete)state(jsonb/json) — safe fields only (no secrets)tenant_nametenant_domainselected_provider_connection_idverification_run_id(OperationRun id)bootstrap_run_ids(array)
started_by_user_id(FK users)updated_by_user_id(FK users)completed_at(timestamp|null)- timestamps
Constraints:
- Unique:
(workspace_id, entra_tenant_id)
State transitions:
in_progress(implied bycompleted_at = null) →completed(completed_at != null)
Validation rules (high level)
entra_tenant_id(tenant_id) must be a non-empty string; validate as GUID format if enforced elsewhere.- Tenant name required to create tenant.
- ProviderConnection selection must belong to the same tenant/workspace.
Authorization boundaries
- Workspace scope: non-members denied as 404.
- Workspace member but missing onboarding capability: 403.
- Tenant scope: once tenant exists/selected, tenant membership rules apply as currently implemented.