# Implementation Plan: Self-Service Tenant Onboarding & Connection Readiness **Branch**: `240-tenant-onboarding-readiness` | **Date**: 2026-04-25 | **Spec**: `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/240-tenant-onboarding-readiness/spec.md` **Input**: Feature specification from `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/240-tenant-onboarding-readiness/spec.md` **Note**: This template is filled in by the `/speckit.plan` command. See `.specify/scripts/` for helper scripts. ## Summary - Add one operator-facing, derived readiness summary to the existing managed-tenant onboarding workflow: the route-bound draft at `/admin/onboarding/{onboardingDraft}` always shows full readiness, while the `/admin/onboarding` landing surface adds compact readiness only when multiple resumable drafts exist and preserves the existing single-draft redirect behavior. - Reuse current onboarding draft lifecycle, provider connection summary, verification diagnostics, the existing 30-day permission freshness rule, and canonical OperationRun links instead of adding new persistence, readiness enums, or provider-generic onboarding frameworks. - Keep the workflow DB-only at render time, workspace- and tenant-safe, and centered on one operator decision: what blocks this tenant now and what the next action is. - Defer numeric completion scoring and any cross-surface readiness abstraction; later consumers must reuse the same derived onboarding truth instead of broadening this slice. ## Technical Context **Language/Version**: PHP 8.4 (Laravel 12) **Primary Dependencies**: Laravel 12 + Filament v5 + Livewire v4 + Pest; existing onboarding services (`OnboardingLifecycleService`, `OnboardingDraftStageResolver`), provider connection summary, verification assist, and Ops-UX helpers **Storage**: PostgreSQL via existing `managed_tenant_onboarding_sessions`, `provider_connections`, `operation_runs`, and stored permission-posture data; no new persistence planned **Testing**: Pest feature + unit tests (Filament/Livewire feature coverage plus policy/unit coverage) **Validation Lanes**: fast-feedback **Target Platform**: Sail-backed Laravel admin panel under `/admin` **Project Type**: web **Performance Goals**: onboarding landing and draft routes remain DB-only at render/hydration, compose readiness in-request from existing records, and avoid outbound HTTP or new queue starts during page render **Constraints**: preserve workspace isolation, linked-tenant entitlement checks, existing RBAC capability boundaries, provider-boundary neutrality in top-level wording, current destructive confirmation patterns, current OperationRun start UX, and no new tables/enums/frameworks for readiness **Scale/Scope**: one workspace-scoped onboarding workflow surface, one derived readiness composition, and focused onboarding/policy coverage only ## UI / Surface Guardrail Plan - **Guardrail scope**: changed surfaces - **Native vs custom classification summary**: native Filament + shared primitives - **Shared-family relevance**: status messaging, action links, badges, embedded diagnostics, navigation - **State layers in scope**: page + workflow-step + derived summary - **Handling modes by drift class or surface**: review-mandatory - **Repository-signal treatment**: review-mandatory - **Special surface test profiles**: standard-native-filament - **Required tests or manual smoke**: functional-core - **Exception path and spread control**: existing guided-workflow exception for `ManagedTenantOnboardingWizard`; no new surface exemption - **Active feature PR close-out entry**: Guardrail ## Shared Pattern & System Fit - **Cross-cutting feature marker**: yes - **Systems touched**: `ManagedTenantOnboardingWizard`, onboarding landing/draft picker, `OnboardingLifecycleService`, `OnboardingDraftStageResolver`, `ProviderConnectionSurfaceSummary`, `VerificationAssistViewModelBuilder`, `TenantRequiredPermissionsViewModelBuilder`, `OperationRunLinks` - **Shared abstractions reused**: `OnboardingLifecycleService`, `OnboardingDraftStageResolver`, `ProviderConnectionSurfaceSummary`, `VerificationAssistViewModelBuilder`, `TenantRequiredPermissionsViewModelBuilder`, `OperationRunLinks`, `OperationUxPresenter`, `ProviderOperationStartResultPresenter` - **New abstraction introduced? why?**: none; readiness stays a thin derived composition on the existing workflow surface - **Why the existing abstraction was sufficient or insufficient**: existing services already own checkpoint progression, provider connection wording, permission freshness, verification diagnostics, and canonical run links; the missing piece is a single operator-facing composition and action prioritization - **Bounded deviation / spread control**: provider-specific consent and permission names remain inside existing diagnostic detail and provider-owned next steps; top-level readiness copy stays platform-neutral, and any shared builder extension must stay additive and behavior-preserving for non-onboarding consumers while onboarding-specific prioritization remains page-local ## OperationRun UX Impact - **Touches OperationRun start/completion/link UX?**: yes - **Central contract reused**: shared OperationRun UX layer via `OperationRunLinks`, `OperationUxPresenter`, and the existing onboarding `tenantlessOperationRunUrl(...)` helper - **Delegated UX behaviors**: queued toast, dedupe-or-blocked messaging, canonical `Open operation` link labeling, tenant/workspace-safe run URL resolution, and terminal lifecycle notifications remain delegated to shared Ops-UX paths - **Surface-owned behavior kept local**: readiness wording, freshness explanation, and next-action prioritization inside the onboarding workflow - **Queued DB-notification policy**: unchanged explicit opt-in; this slice does not add queued or running DB notifications - **Terminal notification path**: central lifecycle mechanism already used by reused verification/bootstrap actions - **Exception path**: none ## Provider Boundary & Portability Fit - **Shared provider/platform boundary touched?**: yes - **Provider-owned seams**: consent diagnostics, missing-permission detail, provider-specific remediation next steps, target-scope identity detail - **Platform-core seams**: readiness summary, checkpoint progress, next-action labels, freshness messaging, workflow routing - **Neutral platform terms / contracts preserved**: `provider connection`, `readiness`, `diagnostics`, `next action`, `freshness`, `onboarding step` - **Retained provider-specific semantics and why**: Microsoft permission names and consent language stay inside existing verification assist and provider summary detail because the operator needs exact remediation instructions for the supported provider - **Bounded extraction or follow-up path**: none; if a second provider appears later, revisit only the provider-owned detail seam rather than the workflow shell ## Constitution Check *GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.* - Persisted truth / proportionality: PASS — readiness remains derived from existing onboarding, provider connection, operation-run, and permission-posture truth; no new table, enum, or state family is planned. - Read/write separation / destructive actions: PASS — this slice changes operator understanding on an existing wizard; existing cancel/delete/complete actions retain current confirmation, audit, and authorization rules. - Graph contract path / DB-only render: PASS — render and Livewire hydration stay DB-only, reusing stored provider connection, verification, and permission-posture data with no new Graph calls. - RBAC / isolation: PASS — existing workspace membership, linked-tenant entitlement, and `Capabilities::*` gates remain authoritative; non-members and wrong-scope actors stay 404, capability-denied members stay 403. - Ops-UX / OperationRun link semantics: PASS — existing verification/bootstrap starts and run links continue to use shared OperationRun UX and canonical tenantless route helpers; no new run-start path is introduced. - Provider boundary / shared pattern reuse: PASS — provider-neutral readiness remains top-level, Microsoft-specific details stay contextual, and existing shared builders/helpers are reused before any local deviation. - Test governance: PASS — proof stays in fast-feedback feature/unit coverage using existing onboarding fixtures; no new browser or heavy-governance family is required. - Global search / panel registration: N/A — this slice changes a Filament page, not a global-searchable resource or panel provider. ## Test Governance Check - **Test purpose / classification by changed surface**: Feature (wizard + landing/picker rendering and behavior) plus targeted Unit/Policy coverage for isolation semantics and existing freshness helper behavior where directly reused - **Affected validation lanes**: fast-feedback - **Why this lane mix is the narrowest sufficient proof**: the workflow is server-driven Filament/Livewire UI backed by existing models and policies, so feature tests can prove readiness composition, next-action precedence, and deny semantics without browser automation - **Narrowest proving command(s)**: `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/ManagedTenantOnboardingWizardTest.php`; `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Onboarding/OnboardingDraftPickerTest.php tests/Feature/Onboarding/OnboardingDraftAuthorizationTest.php`; `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Unit/Policies/TenantOnboardingSessionPolicyTest.php tests/Unit/TenantRequiredPermissionsFreshnessTest.php` - **Fixture / helper / factory / seed / context cost risks**: reuse existing onboarding draft, workspace membership, tenant membership, provider connection, and operation-run fixtures; avoid adding browser fixtures or new provider mocks - **Expensive defaults or shared helper growth introduced?**: no; any new test helpers should stay onboarding-local - **Heavy-family additions, promotions, or visibility changes**: none - **Surface-class relief / special coverage rule**: standard-native-filament guided-workflow exception already exists; add feature assertions to cover the readiness summary on both landing and draft routes - **Closing validation and reviewer handoff**: rerun the targeted onboarding wizard, draft-picker/authorization, and policy/freshness tests after implementation; reviewers should verify one primary next action, correct 404 vs 403 semantics, and no render-time outbound HTTP - **Budget / baseline / trend follow-up**: none expected beyond ordinary feature-local upkeep - **Review-stop questions**: Does the slice stay in fast-feedback? Did any new fixture force browser/heavy coverage? Did the implementation introduce a second readiness taxonomy or persisted truth? - **Escalation path**: document-in-feature if a shared helper needs a tiny extension; reject-or-split if implementation tries to add new persistence/frameworks or browser-lane proof - **Active feature PR close-out entry**: Guardrail - **Why no dedicated follow-up spec is needed**: the planned proof extends already-existing onboarding suites and does not add a new recurring test cost center ### Implementation Close-Out — 2026-04-25 - **Guardrail result**: keep. The implementation stayed inside the existing guided onboarding page, reused current lifecycle/stage, provider summary, verification assist, permission freshness, and OperationRun link paths, and did not add persistence, enums, a readiness taxonomy, or a cross-surface framework. - **Fast-feedback proof**: `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/ManagedTenantOnboardingWizardTest.php tests/Feature/Onboarding/OnboardingDraftPickerTest.php tests/Feature/Onboarding/OnboardingDraftAuthorizationTest.php tests/Unit/Policies/TenantOnboardingSessionPolicyTest.php tests/Unit/TenantRequiredPermissionsFreshnessTest.php` passed with 55 tests and 212 assertions. - **Provider-boundary / lane-cost decision**: keep. Provider-specific permission and consent detail remains secondary and provider-owned; top-level readiness wording stays platform-neutral. No browser, heavy-governance, new fixture family, or follow-up spec is required. - **Explicit defers retained**: numeric completion score and cross-surface readiness reuse remain deferred; future consumers should reuse this derived onboarding truth rather than broaden this slice. ## Project Structure ### Documentation (this feature) ```text specs/240-tenant-onboarding-readiness/ ├── plan.md ├── research.md ├── data-model.md ├── quickstart.md ├── checklists/ │ └── requirements.md ├── contracts/ │ └── onboarding-readiness.openapi.yaml └── tasks.md ``` ### Source Code (repository root) ```text apps/platform/ ├── app/ │ ├── Filament/Pages/Workspaces/ManagedTenantOnboardingWizard.php │ ├── Models/TenantOnboardingSession.php │ ├── Services/Intune/TenantRequiredPermissionsViewModelBuilder.php │ ├── Services/Onboarding/ │ │ ├── OnboardingDraftStageResolver.php │ │ └── OnboardingLifecycleService.php │ ├── Support/OperationRunLinks.php │ ├── Support/Providers/TargetScope/ProviderConnectionSurfaceSummary.php │ └── Support/Verification/VerificationAssistViewModelBuilder.php └── tests/ ├── Feature/ManagedTenantOnboardingWizardTest.php ├── Feature/Onboarding/OnboardingDraftAuthorizationTest.php ├── Feature/Onboarding/OnboardingDraftPickerTest.php ├── Unit/Policies/TenantOnboardingSessionPolicyTest.php └── Unit/TenantRequiredPermissionsFreshnessTest.php ``` **Structure Decision**: Single Laravel web application. This feature remains confined to the existing onboarding wizard/landing workflow, existing onboarding + provider support services, and focused onboarding/policy tests. ## Complexity Tracking No constitution violations are required for this feature. The plan explicitly avoids new persistence, abstractions, readiness enums, or cross-surface frameworks. ## Proportionality Review N/A — the plan intentionally keeps readiness derived and local to the existing onboarding workflow. No new persisted entity, abstraction layer, enum/status family, or taxonomy is proposed. ## Phase 0 — Research (output: `research.md`) See: `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/240-tenant-onboarding-readiness/research.md` Goals: - Confirm the narrowest existing sources of truth for onboarding readiness, draft landing metadata, provider summary, permission freshness, and canonical operation links. - Resolve the freshness question by reusing the existing 30-day permission freshness rule plus current connection-change and selected-connection-mismatch signals rather than introducing a new onboarding-specific threshold or persisted freshness model. - Confirm that landing-route behavior remains the same surface (single-draft redirect or multi-draft picker) so readiness context is added without creating a second onboarding register. ## Phase 1 — Design & Contracts (outputs: `data-model.md`, `contracts/`, `quickstart.md`) See: - `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/240-tenant-onboarding-readiness/data-model.md` - `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/240-tenant-onboarding-readiness/contracts/onboarding-readiness.openapi.yaml` - `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/240-tenant-onboarding-readiness/quickstart.md` Design focus: - Add one derived readiness composition on `ManagedTenantOnboardingWizard` and the existing draft picker using current draft lifecycle, provider connection summary, verification assist, the existing 30-day permission freshness rule, and explicit "check has not run yet" guidance where no evidence exists. - Keep landing-route behavior intact: a single resumable draft still redirects to the route-bound draft; a multi-draft landing view gains compact readiness snippets next to existing metadata. - Define next-action precedence from existing truth only: identify tenant → connect provider → grant consent/fix permissions → run or rerun verification → review bootstrap → complete onboarding. - Keep permission and consent detail secondary and provider-owned; keep `Open operation` and consent links canonical and shared. - Keep onboarding-specific readiness wording and action prioritization local to the onboarding workflow; if a shared provider or verification builder needs extension, keep the change additive and regression-safe for existing non-onboarding consumers. - Defer numeric completion score and any support-diagnostic or trial/demo-specific projection to later specs that reuse the same derived onboarding truth. - Do not add new tables, readiness enums, global resources, or provider-generic onboarding abstractions. ## Phase 1 — Agent Context Update After Phase 1 artifacts are generated, update Copilot context from the plan: - `/Users/ahmeddarrazi/Documents/projects/wt-plattform/.specify/scripts/bash/update-agent-context.sh copilot` ## Phase 2 — Implementation Outline (tasks created in `/speckit.tasks`) - Extend onboarding landing and draft rendering to surface a derived readiness summary, freshness, and one primary next action from existing services/helpers. - Reuse `OnboardingLifecycleService` snapshot truth, `OnboardingDraftStageResolver`, `ProviderConnectionSurfaceSummary`, `VerificationAssistViewModelBuilder`, and `TenantRequiredPermissionsViewModelBuilder` to map existing records into operator-facing copy. - Add compact readiness metadata to the multi-draft picker and route-bound resume context without creating a new onboarding index resource. - Preserve existing consent, verification, bootstrap, operation-link, and destructive header actions; only change prioritization, grouping emphasis, and explanatory copy. - Expand targeted feature and policy tests for readiness states, freshness/mismatch handling, landing summary behavior, and 404 vs 403 regressions. ## Constitution Check (Post-Design) Re-check result: PASS. Design artifacts keep readiness derived, DB-only at render time, workspace/tenant safe, Ops-UX compliant, and constrained to existing onboarding + provider foundations.