4.7 KiB
4.7 KiB
Research — Managed Tenant Onboarding Wizard v1
This research consolidates repo-specific patterns and decisions needed to implement Spec 069 safely.
Decision 1 — “Managed tenant” maps to existing Tenant model
- Decision: Implement the onboarding wizard around the existing
App\Models\Tenantentity. - Rationale: The current
/adminpanel is already multi-tenant withTenant::classtenancy (AdminPanelProvider), tenant membership rules, and tenant-scopedOperationRunand provider operations. - Alternatives considered:
- Introduce a new
ManagedTenantmodel: rejected for v1 because it would duplicate existing tenancy/membership and require broad refactors.
- Introduce a new
Decision 2 — Wizard UI implemented as a Filament page using Step
- Decision: Implement the onboarding flow as a Filament page (tenant-plane) that composes steps using
Filament\Schemas\Components\Wizard\Step. - Rationale: Repo already uses step-based wizards (
RestoreRunResource) and Filament v5 + Livewire v4 are the established UI stack. - Alternatives considered:
- Keep
TenantResourcesimple create/edit forms and add helper text: rejected because Spec 069 requires a guided, resumable multi-step flow. - Build a non-Filament controller + Blade wizard: rejected; would bypass consistent Filament RBAC/UX patterns.
- Keep
Decision 3 — RBAC-UX enforcement uses existing middleware + UiEnforcement
- Decision: Enforce “non-member → 404, member missing capability → 403” via existing infrastructure:
App\Support\Middleware\DenyNonMemberTenantAccessfor tenant-scoped routes (404 for non-members).App\Support\Rbac\UiEnforcementfor Filament actions (disabled + tooltip + 404/403 server-side guards).App\Services\Auth\CapabilityResolver+App\Support\Auth\Capabilitiesregistry (no raw strings).
- Rationale: This matches the repo constitution and existing patterns in resources/pages.
- Alternatives considered:
- Ad-hoc
abort(403)/abort(404)scattered in actions: rejected (regression risk; violates RBAC-UX-008 intent).
- Ad-hoc
Decision 4 — DB-only render is guaranteed by strict separation
- Decision: Wizard pages render only from:
Tenantfields (including encrypted credential fields that never rehydrate secrets)- onboarding-session persisted payload (JSON)
- last completed
OperationRunrecords / stored summaries
- Rationale: Constitution requires DB-only render for monitoring and operational pages; Livewire requests should not trigger Graph.
- Alternatives considered:
- “Check on mount”: rejected; would violate DB-only render.
Decision 5 — All checks are enqueue-only, observable via OperationRun
- Decision: All verification / connectivity / inventory operations triggered from the wizard create/reuse an
OperationRunand dispatch a job. - Rationale:
OperationRunServiceprovides run-identity dedupe with a DB constraint; provider scoped checks already follow this pattern viaProviderOperationStartGate. - Alternatives considered:
- Synchronous checks in UI actions: rejected; violates run-observability and DB-only render intent.
Decision 6 — Session persistence uses a dedicated onboarding session table
- Decision: Introduce a persisted onboarding session record that stores:
- actor + timestamps
- current step
- non-secret payload JSON
- status (active/completed/abandoned)
- foreign keys to tenant (once known)
- Rationale: Spec requires resumability and dedupe (“auto-resume existing active session”).
- Alternatives considered:
- Store progress in Laravel session only: rejected (not resilient across devices, logouts, and multi-user concurrency).
Decision 7 — Capability naming aligns with existing registry
- Decision: Use existing canonical capability registry (
App\Support\Auth\Capabilities) and map Spec 069 semantics to:- start onboarding / create tenant →
Capabilities::TENANT_MANAGE(or introduce a dedicatedtenant.createif needed, but still via registry) - manage credentials/config →
Capabilities::TENANT_MANAGE - run checks (provider operations / inventory) →
Capabilities::PROVIDER_RUNand/orCapabilities::TENANT_INVENTORY_SYNC_RUN
- start onboarding / create tenant →
- Rationale: Current app already enforces these capabilities widely; adding new strings is possible but must remain centralized.
- Alternatives considered:
- Introduce
managed_tenants.*capabilities in parallel: deferred unless Spec 068 v2 requires that rename.
- Introduce
Open Questions (deferred but not blocking plan)
- Whether Spec 068 v2 introduces a separate “Workspace” model and renames
Tenantto “ManagedTenant”. If yes, the wizard should be adapted in that refactor; the v1 implementation should keep seams (service layer + session model) to migrate cleanly.