TenantAtlas/specs/140-onboarding-lifecycle-operation-checkpoints-concurrency-mvp/data-model.md
ahmido d2f2c55ead feat: add onboarding lifecycle checkpoints and locking (#169)
## Summary
- add canonical onboarding lifecycle and checkpoint fields plus optimistic locking versioning for managed tenant onboarding drafts
- introduce centralized onboarding lifecycle and mutation services and route wizard mutations through version-checked writes
- convert Verify Access and Bootstrap into live checkpoint-driven wizard states with conditional polling and updated browser/feature/unit coverage
- add Spec Kit artifacts for feature 140, including spec, plan, tasks, research, data model, quickstart, checklist, and logical contract

## Validation
- branch was committed and pushed cleanly
- focused tests and formatting were updated during implementation work
- full validation was not re-run as part of this final git/PR step

## Notes
- base branch: `dev`
- feature branch: `140-onboarding-lifecycle-operation-checkpoints-concurrency-mvp`
- outstanding follow-up items, if any, remain tracked in `specs/140-onboarding-lifecycle-operation-checkpoints-concurrency-mvp/tasks.md`

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #169
2026-03-14 11:02:29 +00:00

129 lines
6.2 KiB
Markdown

# Data Model: Onboarding Lifecycle, Operation Checkpoints & Concurrency MVP
## Entity: TenantOnboardingSession
Existing persisted workflow record for managed tenant onboarding drafts.
### Fields
| Field | Type | Required | Notes |
|---|---|---|---|
| `id` | bigint | yes | Primary key |
| `workspace_id` | foreign key | yes | Workspace ownership and authorization boundary |
| `tenant_id` | foreign key nullable | conditional | May remain null before tenant identification, per constitution exception |
| `entra_tenant_id` | string | yes | Current draft identity key for resumable uniqueness |
| `current_step` | string nullable | no | Existing UI-oriented step breadcrumb; no longer canonical workflow truth |
| `state` | json nullable | no | Detailed persisted step data and run references |
| `started_by_user_id` | foreign key nullable | no | Draft creator |
| `updated_by_user_id` | foreign key nullable | no | Last mutating actor |
| `completed_at` | timestamp nullable | no | Terminal historical marker |
| `cancelled_at` | timestamp nullable | no | Terminal historical marker |
| `version` | bigint or integer | yes | Starts at `1`, increments on every relevant successful mutation |
| `lifecycle_state` | controlled string or enum | yes | Canonical workflow state |
| `current_checkpoint` | controlled string or enum nullable | no | Governing checkpoint for forward progress |
| `last_completed_checkpoint` | controlled string or enum nullable | no | Last satisfied checkpoint |
| `reason_code` | string nullable | no | Machine-readable lifecycle precision |
| `blocking_reason_code` | string nullable | no | Machine-readable explicit blocker |
| `created_at` | timestamp | yes | Existing audit chronology |
| `updated_at` | timestamp | yes | Existing audit chronology |
### Relationships
- Belongs to `Workspace`
- Belongs to `Tenant` when identified
- Belongs to `startedByUser`
- Belongs to `updatedByUser`
- References relevant verification and bootstrap `OperationRun` records through IDs stored in `state`
### Validation Rules
- `version >= 1`
- `lifecycle_state` must be one of the controlled lifecycle values
- `current_checkpoint` and `last_completed_checkpoint` must be null or one of the controlled checkpoint values
- `blocking_reason_code` must be null unless the workflow is actually blocked from forward progress
- `completed_at` and `cancelled_at` remain mutually exclusive terminal markers
- Terminal records (`completed_at` or `cancelled_at` set) are non-editable
## Entity: OnboardingLifecycleState
Controlled value set used for canonical workflow truth.
### Values
| Value | Meaning |
|---|---|
| `draft` | No active governing checkpoint run and not yet ready for activation |
| `verifying` | Relevant verification run is queued or running |
| `action_required` | Operator intervention is required before safe progression |
| `bootstrapping` | One or more selected bootstrap runs are queued or running |
| `ready_for_activation` | All gating conditions are satisfied and the workflow awaits final activation |
| `completed` | Activation succeeded and the draft is historical |
| `cancelled` | Draft was intentionally cancelled and is historical |
## Entity: OnboardingCheckpoint
Controlled checkpoint precision used for progression and UI state.
### Values
| Value | Meaning |
|---|---|
| `identify` | Tenant identity or workspace-scoped start state |
| `connect_provider` | Provider selection or connection management checkpoint |
| `verify_access` | Verify Access checkpoint |
| `bootstrap` | Optional bootstrap checkpoint |
| `complete_activate` | Final activation checkpoint |
## Entity: OnboardingReasonCode
Machine-readable precision for non-terminal workflow state.
### Expected starter values
- `verification_blocked_permissions`
- `verification_failed`
- `provider_connection_changed`
- `verification_result_stale`
- `bootstrap_failed`
- `bootstrap_partial_failure`
- `owner_activation_required`
This list is intentionally controlled and should be extended centrally rather than spread through page code.
## Entity: RelevantCheckpointRun
Derived relationship between a draft and the `OperationRun` records that currently govern progression.
### Verification invariants
- The verification run must match the currently selected provider connection.
- A queued or running verification run implies `lifecycle_state = verifying`.
- A terminal verification run only allows progression when it is current for the selected connection and satisfies readiness conditions.
### Bootstrap invariants
- Bootstrap run references remain stored in `state` as selected run metadata.
- One or more queued or running relevant bootstrap runs imply `lifecycle_state = bootstrapping`.
- Any blocking bootstrap failure moves the workflow to `action_required`.
## State Transition Model
| From | Trigger | To | Notes |
|---|---|---|---|
| `draft` | verification started | `verifying` | Relevant verification run created or reused |
| `verifying` | verification succeeds and no bootstrap selected | `ready_for_activation` | Verification must be current for selected connection |
| `verifying` | verification succeeds and bootstrap started | `bootstrapping` | Selected bootstrap runs become active |
| `verifying` | verification blocked, failed, stale, or mismatched | `action_required` | `reason_code` and optional `blocking_reason_code` set |
| `action_required` | blocker resolved by rerun or reset | `verifying`, `bootstrapping`, `ready_for_activation`, or `draft` | Chosen by centralized lifecycle recalculation |
| `bootstrapping` | all selected bootstrap runs complete successfully | `ready_for_activation` | No remaining blocker allowed |
| `bootstrapping` | selected bootstrap run fails in blocking way | `action_required` | Failure reason preserved |
| any editable state | cancel action | `cancelled` | Terminal and immutable |
| `ready_for_activation` | activation succeeds | `completed` | Terminal and immutable |
## Concurrency Contract
- Every relevant mutation must carry an expected `version`.
- The write path must compare expected version to persisted version inside the same transaction or atomic update.
- On mismatch, no lifecycle field, checkpoint field, JSON state, or related run reference may be partially written.
- Conflict rejection keeps the user on the wizard and returns a visible refresh-required error.