# Data Model: Provider-Backed Action Preflight and Dispatch Gate Unification

## Overview

This feature does not introduce new persisted entities or tables. It extends the existing provider-backed start contract around `ProviderConnection`, `OperationRun`, and onboarding draft state so every covered operator-triggered start follows the same queue-admission, conflict-protection, and operator-feedback rules.

The key design constraint is that start truth remains service-owned and derived from existing runtime records:

- provider readiness and connection identity from `ProviderConnection` plus `ProviderConnectionResolver`
- accepted or prevented work truth from `OperationRun`
- click-time queue-admission decisions from `ProviderOperationStartGate`
- onboarding bootstrap continuity from existing `TenantOnboardingSession.state`
- operator feedback from existing Ops UX helpers plus one thin shared provider-start presentation helper

## Existing Persistent Inputs

### 1. ProviderConnection

- Purpose: Tenant-owned provider credential and readiness record that defines which delegated connection a provider-backed operation can use.
- Key persisted fields used by this feature:
  - `id`
  - `tenant_id`
  - `provider`
  - `entra_tenant_id`
- Existing runtime facts consumed through current services:
  - default-vs-explicit selection
  - consent readiness
  - credential usability
  - provider identity and scope targeting
- Relationships used by this feature:
  - owning tenant
  - related operation runs through `OperationRun.context.provider_connection_id`

### 2. OperationRun

- Purpose: Canonical operational truth for queued or executed provider-backed work and for blocked preflight attempts that must remain observable.
- Key persisted fields used by this feature:
  - `id`
  - `tenant_id`
  - `type`
  - `status`
  - `outcome`
  - `reason_code`
  - `context`
  - `summary_counts`
  - `started_at`
  - `completed_at`
- Existing relationships or references used by this feature:
  - initiator user
  - tenant scope
  - canonical Monitoring → Operations detail route

### 3. TenantOnboardingSession

- Purpose: Workspace-owned onboarding workflow record that already stores onboarding progress and step state, including bootstrap operation selections and related run references.
- Key persisted fields used by this feature:
  - `id`
  - `workspace_id`
  - `tenant_id` (nullable until attached)
  - `current_step`
  - `state`
- Existing state keys used by this feature:
  - `bootstrap_operation_types`
  - `bootstrap_operation_runs`
- Relationships used by this feature:
  - workspace
  - attached tenant when present

### 4. RestoreRun

- Purpose: Tenant-owned restore execution record whose execute action becomes part of the canonical provider-backed start contract.
- Key persisted fields used by this feature:
  - `id`
  - `tenant_id`
  - restore configuration and preview state already captured before execution
- Relationships used by this feature:
  - tenant
  - backup source records and restore safety flow already owned by existing restore logic

## Existing Service-Owned Inputs

### A. ProviderOperationRegistry Entry

This is an existing logical definition, not a new persisted entity.

| Field | Meaning |
|---|---|
| `operationType` | The write-time operation type string admitted by the gate |
| `module` | Current operation family/module metadata used in run context |
| `dispatcher` | The queue-dispatch callback or equivalent start hook |
| `requiredCapability` | Capability gate required to start the operation |
| `providerScopeExpectation` | Whether the operation is connection-scoped and therefore protected by click-time conflict rules |

Rules:

- First-slice coverage adds entries for every covered action host instead of introducing a second registry.
- This feature does not normalize historical operation names; registry entries follow current write-time operation types.

### B. ProviderConnectionResolution

Logical output of `ProviderConnectionResolver` and `ProviderOperationStartGate`.

| Field | Meaning |
|---|---|
| `providerConnectionId` | Explicit resolved connection identity when admission is possible |
| `provider` | Provider family used for copy and downstream dispatch |
| `targetScope` | Current tenant/provider scope metadata for run context |
| `reasonCode` | Stable blocked reason when admission is prevented |
| `reasonMeta` | Sanitized structured detail for translation and next steps |
| `nextSteps` | Resolution path metadata used by the shared presentation helper |

Rules:

- Every accepted covered start must resolve this state before queue admission.
- Blocked resolutions never admit a queued job.

## Derived Coordination Entities

### 1. ProtectedProviderScope

This is a logical concurrency boundary, not a new table.

| Field | Meaning |
|---|---|
| `tenantId` | Tenant boundary for the operation |
| `providerConnectionId` | Connection boundary for provider-backed conflict protection |
| `activeRunId` | Existing queued or running run occupying the scope, when present |
| `activeOperationType` | Operation currently using the protected scope |

Rules:

- At most one provider-backed operation may be accepted at a time for one protected scope.
- If the same operation type is already active on the scope, the result is `deduped`.
- If a different covered operation is already active on the same scope, the result is `scope_busy`.

### 2. PreflightStartResult

This is the shared logical result of a covered start attempt.

| Field | Meaning | Source |
|---|---|---|
| `internalState` | Current service-owned state such as `started`, `deduped`, `scope_busy`, or `blocked` | `ProviderOperationStartResult` |
| `operatorState` | Operator-facing vocabulary: `accepted`, `deduped`, `scope_busy`, `blocked` | shared presenter |
| `operationType` | Covered operation being started | action host + registry |
| `runId` | Canonical run for accepted, deduped, or scope-busy results, and optionally for blocked truth where already created | `OperationRun` |
| `providerConnectionId` | Resolved connection identity when known | gate + resolver |
| `reasonCode` | Stable problem class for blocked or other directed outcomes | current reason system |
| `nextSteps` | Structured resolution or follow-up guidance | next-step registry / helper |

Validation rules:

- `blocked` must never dispatch a background job.
- `accepted`, `deduped`, and `scope_busy` must point to the canonical run the operator should inspect.
- `accepted` must carry the explicit `provider_connection_id` into accepted-work context.

### 3. AcceptedProviderBackedRunContext

Logical accepted-work context persisted inside `OperationRun.context`.

| Field | Meaning |
|---|---|
| `provider_connection_id` | Explicit connection identity used by the accepted run |
| `provider` | Provider family label for display and diagnostics |
| `target_scope` | Sanitized tenant/provider scope metadata |
| `source_surface` | Action-host family such as tenant detail, provider connection, onboarding, restore, or directory sync |
| `initiator_user_id` | Starting actor |
| `operation_specific_context` | Existing per-operation context already needed by downstream jobs |

Rules:

- Jobs must receive the same `provider_connection_id` that was accepted at click time.
- Monitoring and notifications explain accepted work using this context rather than a runtime default connection lookup.

### 4. ProviderStartPresentation

Logical derived presentation output returned by the shared start-result helper.

| Field | Meaning |
|---|---|
| `title` | Standardized accepted/deduped/scope-busy/blocked headline |
| `body` | Short reason or queue message aligned with the spec vocabulary |
| `statusStyle` | Existing toast/notification severity |
| `viewRunAction` | Canonical open-run action when a run exists |
| `nextStepActions[]` | Optional resolution actions or follow-up links |
| `domainVerb` | Local action verb preserved from the host surface |
| `domainTarget` | Local object noun preserved from the host surface |

Rules:

- Accepted and deduped outcomes continue to use the existing `OperationUxPresenter` toast style.
- Blocked and scope-busy outcomes must no longer rely on page-local copy branches.
- Domain verb and target remain local so the shared contract does not flatten the product vocabulary into generic verbs.

### 5. OnboardingBootstrapAdmission

Logical onboarding-only coordination model built from existing draft state.

| Field | Meaning |
|---|---|
| `selectedOperationTypes[]` | Bootstrap operations the operator selected |
| `acceptedOperationType` | The one operation type admitted for the current submission |
| `pendingOperationTypes[]` | Remaining selected types still waiting to run |
| `runIdsByOperationType` | Existing and newly accepted run references persisted in draft state |

Rules:

- A bootstrap submission may accept at most one provider-backed operation for the protected scope.
- Remaining bootstrap selections stay in existing draft state rather than spawning a new orchestration entity.
- The onboarding step continues to be the only primary context; operators should not need a new workflow page to understand the pending follow-up.

## State Transitions

### Covered Start Attempt

```text
requested
  -> blocked      (no queue admission, blocked truth retained where applicable)
  -> deduped      (existing same-operation active run reused)
  -> scope_busy   (existing different-operation active run reused)
  -> accepted     (run admitted, queued job dispatched with explicit provider connection)
```

### Onboarding Bootstrap Submission

```text
selected operations
  -> blocked / deduped / scope_busy  (no new run admitted)
  -> accepted operation + pending operations retained in draft state
```

## Non-Goals In The Data Model

- No new provider-start table or umbrella batch entity
- No new persisted summary or presentation artifact
- No platform-wide operation-type rename or taxonomy rewrite
- No new status family beyond the shared start-result vocabulary already required by the spec