TenantAtlas/specs/073-unified-managed-tenant-onboarding-wizard/data-model.md
Ahmed Darrazi 7b0a383182 feat: unified managed tenant onboarding wizard
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).
2026-02-03 18:27:39 +01:00

85 lines
2.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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) — specs `entra_tenant_id`
- `external_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_id` globally unique (for `/admin/t/{tenant}` routing) and do **not** force it to equal `tenant_id`.
**State transitions:**
- `pending``active` after successful verification
- `active``archived` on soft-delete (existing behavior)
- `archived``active` on 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 flow
- `entra_tenant_id` (string) — denormalized for upsert/idempotency before tenant exists
- `current_step` (string; e.g., `identify`, `connection`, `verify`, `bootstrap`, `complete`)
- `state` (jsonb/json) — safe fields only (no secrets)
- `tenant_name`
- `tenant_domain`
- `selected_provider_connection_id`
- `verification_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 by `completed_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.