TenantAtlas/specs/240-tenant-onboarding-readiness/data-model.md
ahmido ab6eccaf40
Some checks failed
Main Confidence / confidence (push) Failing after 48s
feat: add onboarding readiness workflow (#277)
## Summary
- add derived onboarding readiness to the managed tenant onboarding workflow and multi-draft picker
- keep provider-specific permission diagnostics secondary while preserving canonical `Open operation` and existing onboarding action semantics
- add spec-kit artifacts for `240-tenant-onboarding-readiness` and align roadmap/spec-candidate planning notes
- unify the required-permissions empty state copy to English

## Validation
- `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/RequiredPermissions/RequiredPermissionsEmptyStateTest.php`
- `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent`
- browser smoke exercised the onboarding picker, route-bound mismatch readiness state, canonical `Open operation` path, and local fixture cleanup

## Notes
- branch includes the generated spec artifacts under `specs/240-tenant-onboarding-readiness/`
- temporary browser smoke tenants/drafts/runs were cleaned from the local environment after validation

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #277
2026-04-25 21:17:31 +00:00

6.5 KiB
Raw Blame History

Data Model — Self-Service Tenant Onboarding & Connection Readiness

Spec: spec.md

No new persistent tables are required for this slice. Readiness is computed at render time from existing onboarding, provider connection, verification, and permission-posture truth.

Entities

TenantOnboardingSession (managed_tenant_onboarding_sessions)

Purpose: Workspace-scoped onboarding workflow record that owns resumability, checkpoint progression, and links to the managed tenant once identified.

Key fields (existing):

  • workspace_id (required FK)
  • tenant_id (nullable FK to tenants.id until the tenant is linked)
  • entra_tenant_id
  • current_step
  • version
  • lifecycle_state
  • current_checkpoint
  • last_completed_checkpoint
  • reason_code
  • blocking_reason_code
  • completed_at, cancelled_at
  • state JSON, constrained by TenantOnboardingSession::STATE_ALLOWED_KEYS

Relevant state keys (existing):

  • tenant_name
  • primary_domain
  • provider_connection_id
  • selected_provider_connection_id
  • verification_operation_run_id
  • bootstrap_operation_types
  • bootstrap_operation_runs
  • connection_recently_updated

Relationships (existing):

  • Belongs to Workspace
  • May belong to Tenant
  • Belongs to startedByUser
  • Belongs to updatedByUser

ProviderConnection (provider_connections)

Purpose: Tenant-owned provider access record whose consent, verification, and target-scope state inform onboarding readiness.

Key fields (existing, relevant):

  • workspace_id
  • tenant_id
  • provider
  • display_name
  • connection_type
  • is_default
  • is_enabled
  • consent_status
  • verification_status
  • target-scope identity fields consumed by ProviderConnectionTargetScopeNormalizer

Relationships / invariants (existing):

  • The selected provider connection must belong to the same workspace and tenant as the onboarding draft.
  • ProviderConnectionSurfaceSummary::forConnection() is the shared source for provider summary wording and contextual identity detail.

VerificationRunEvidence (operation_runs, existing subset)

Purpose: Existing supporting evidence for verification and bootstrap readiness, including canonical operation detail links.

Key fields (existing, relevant):

  • workspace_id
  • tenant_id
  • type
  • status
  • outcome
  • context.provider_connection_id
  • context.verification_report
  • summary_counts

Constraints / invariants (existing):

  • The verification run must belong to the same workspace and tenant as the onboarding draft.
  • Verification evidence is only trustworthy for readiness when context.provider_connection_id matches the drafts selected provider connection.
  • Canonical evidence links must continue to flow through OperationRunLinks / tenantless operation helpers.

PermissionPostureOverview (derived from existing permission posture data)

Purpose: Existing stored permission comparison summary used by onboarding verification assist and readiness freshness cues.

Source (existing):

  • TenantPermissionService::compare(...)
  • TenantRequiredPermissionsViewModelBuilder::build(...)

Relevant derived fields (existing):

  • overview.overall
  • overview.counts.missing_application
  • overview.counts.missing_delegated
  • overview.counts.error
  • overview.freshness.last_refreshed_at
  • overview.freshness.is_stale

Invariant (existing):

  • Permission freshness is stale when no refresh exists or last_refreshed_at is older than 30 days (TenantRequiredPermissionsViewModelBuilder::deriveFreshness).

OnboardingReadinessSummary (computed, not persisted)

Purpose: Operator-facing derived summary rendered on the onboarding landing picker and route-bound draft view.

Proposed runtime shape (presentation-only):

  • draft: id, tenant_name, stage_label, draft_status_label, started_by, updated_by, last_updated_human
  • checkpoint: current_checkpoint, last_completed_checkpoint, lifecycle_state
  • provider_summary: readiness_summary, consent_state, verification_state, target_scope_summary, contextual_identity_line
  • verification: status, overall, run_id, run_url, is_active, matches_selected_connection
  • freshness: connection_recently_updated, verification_mismatch, permission_last_refreshed_at, permission_data_is_stale
  • blocker: reason_code, blocking_reason_code, operator_summary
  • next_action: label, kind, url_or_action, required_capability
  • supporting_links: operation_url, tenant_url, consent_url when already available from existing routes/helpers

Important rule: This is a presentation shape only. It must map directly from existing onboarding lifecycle, provider connection, verification, and permission-posture truth. It is not a new domain model or persisted state family.

Derived Rules / Invariants

  • A draft without tenant identity cannot be ready; the primary action remains the identify-tenant step.
  • A draft without a selected provider connection cannot be ready; the primary action remains connect/select provider.
  • A verification run that does not match the selected provider connection is stale for readiness and must force a non-ready outcome.
  • connection_recently_updated=true invalidates previous verification trust until verification reruns.
  • Stale permission posture (overview.freshness.is_stale=true) must surface as a readiness attention cue or diagnostic freshness cue, not as ready.
  • Top-level readiness wording stays platform-neutral. Provider-specific permission names and consent instructions remain inside secondary diagnostics.
  • Supporting evidence uses canonical operation links only; no page-local run URLs are introduced.

Rendering Precedence (derived, not persisted)

No new persisted transitions are introduced. The readiness summary should follow this rendering precedence when choosing one primary next action:

  1. No identified tenant: Identify tenant
  2. No selected provider connection: Connect provider
  3. Consent missing or revoked: Grant consent
  4. Permission diagnostics blocked or incomplete: Review permissions / Grant consent as dictated by existing provider-owned diagnostics
  5. Verification missing, stale, or mismatched: Start verification or Rerun verification
  6. Verification active: Open operation or Refresh
  7. Bootstrap selected and still active/failed: Review bootstrap
  8. Lifecycle ready for activation: Complete onboarding

The multi-draft landing surface uses the same precedence, but only in compact form so the operator can choose the correct draft to open.