Some checks failed
Main Confidence / confidence (push) Failing after 49s
## Summary - unify provider-backed action starts behind the shared provider dispatch gate and shared start-result presenter - align tenant, onboarding, provider-connection, restore, directory, and monitoring surfaces with the same blocked, deduped, scope-busy, and accepted semantics - include the spec kit artifacts for spec 216 and the regression fixes that brought the full suite back to green ## Validation - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/RestoreRunIdempotencyTest.php tests/Feature/ExecuteRestoreRunJobTest.php tests/Feature/Restore/RestoreRunProviderStartTest.php tests/Feature/Hardening/ExecuteRestoreRunJobGateTest.php tests/Feature/Hardening/BlockedWriteAuditLogTest.php tests/Feature/Onboarding/OnboardingDraftLifecycleTest.php` - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Browser/Spec177InventoryCoverageTruthSmokeTest.php` - `cd apps/platform && ./vendor/bin/sail artisan test --compact` ## Notes - branch: `216-provider-dispatch-gate` - commit: `34230be7` Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #255
236 lines
9.8 KiB
Markdown
236 lines
9.8 KiB
Markdown
# 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 |