# Data Model: Managed Tenant Onboarding Draft Identity & Resume Semantics

## Primary Entity: Onboarding Draft

### Backing Model

- Existing model: `App\Models\TenantOnboardingSession`
- Existing table: `managed_tenant_onboarding_sessions`
- UI language: `Onboarding draft`

## Ownership & Authorization Model

- The onboarding draft is a workspace-scoped workflow-coordination record, not a generic tenant-owned domain record.
- `workspace_id` is mandatory for every draft.
- `tenant_id` remains nullable under the constitution-approved onboarding exception because drafts can exist before tenant identification.
- Once `tenant_id` is attached, authorization must enforce both workspace entitlement and tenant entitlement for draft access.
- Before `tenant_id` is attached, workspace entitlement is sufficient.

## Entity Fields

### Existing or Required Core Fields

| Field | Type | Purpose |
|---|---|---|
| `id` | bigint | Stable draft identity used in canonical route binding |
| `workspace_id` | bigint | Workspace isolation boundary |
| `tenant_id` | bigint nullable | Managed tenant database record when identified |
| `entra_tenant_id` | string nullable | External tenant identity used before or during tenant materialization |
| `started_by_user_id` | bigint nullable | Attribution for who created the draft |
| `updated_by_user_id` | bigint nullable | Attribution for who last confirmed a change |
| `current_step` | string nullable | Diagnostic and audit marker only |
| `state` | json nullable | Confirmed non-secret draft state |
| `completed_at` | timestamp nullable | Marks the draft as completed |
| `cancelled_at` | timestamp nullable | Marks the draft as cancelled |
| `created_at` | timestamp | Created timestamp |
| `updated_at` | timestamp | Last persisted update timestamp |

### Recommended State Payload Keys

Confirmed draft state should continue to allow only non-secret, confirmed keys such as:

- `entra_tenant_id`
- `tenant_id`
- `tenant_name`
- `environment`
- `primary_domain`
- `notes`
- `provider_connection_id`
- `selected_provider_connection_id`
- `verification_operation_run_id`
- `verification_run_id`
- `bootstrap_operation_types`
- `bootstrap_operation_runs`
- `bootstrap_run_ids`

## Lifecycle Semantics

### Resumable

A draft is resumable when all of the following are true:

- It belongs to the current workspace.
- It is authorized for the current actor.
- It is not completed.
- It is not cancelled.

### Non-Resumable

A draft is non-resumable when any of the following are true:

- It is completed.
- It is cancelled.
- It is outside the current workspace.
- It is inaccessible due to authorization.

## Derived Projections

### Draft Stage

Derived from confirmed state, not only from `current_step`:

1. No identified tenant data: `identify`
2. Tenant identified but no provider connection selected: `connect-provider`
3. Provider connection selected but verification cannot proceed or is incomplete: `verify-access`
4. Verification complete but bootstrap pending: `bootstrap`
5. Bootstrap confirmed and ready for final review or activation: `review`
6. Completed: `completed`
7. Cancelled: `cancelled`

### Draft Summary Metadata

Used by the landing picker and header banner:

- Tenant display name
- External tenant identifier
- Environment
- Current stage label
- Started by display name
- Last updated by display name
- Last updated at
- Draft age
- Verification stale or blocked hint

## Sensitive Data Rule

The following values must never be stored in the draft payload for UI rehydration:

- Client secrets
- Raw credential material
- Temporary authorization tokens
- Any secret provider credential value

The draft may store references to related provider connections or verification runs, but not secrets.