TenantAtlas/specs/069-tenant-onboarding-wizard-v2/research.md
2026-02-01 01:20:10 +01:00

99 lines
4.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Research: Managed Tenant Onboarding Wizard UI (v2) (069)
This document resolves Phase 0 unknowns and captures the design decisions used by [plan.md](./plan.md).
## Decision 1 — Scope mapping ("Workspace" vs current app tenant)
**Decision:** For v2, interpret **Workspace scope** and **Managed Tenant** from the spec as the existing Filament tenant model: `App\Models\Tenant`.
**Rationale:**
- The current apps authorization plane, routing, and multi-tenancy are already built around `Tenant`.
- Provider connections are already tenant-scoped (`provider_connections.tenant_id`).
- Introducing a new Workspace/ManagedTenant hierarchy would expand the change surface (routing, policies, membership model, UI) beyond what is needed to ship the wizard + task board.
**Alternatives considered:**
- Add a new `workspaces` model/table with `managed_tenants` underneath it.
- Rejected for Phase 1: would require reworking tenancy, membership, policies, and navigation.
## Decision 2 — Evidence as the status source-of-truth
**Decision:** Step/task badges are derived from stored evidence rows; any "status" fields elsewhere are treated as derived cache.
**Rationale:**
- Matches FR-006 and prevents UI from being dependent on ephemeral job output.
- Enables stable audit/troubleshooting and deterministic rendering (Monitoring pages remain DB-only).
**Alternatives considered:**
- Cache the current status directly on `Tenant`.
- Rejected: easy to drift from reality and makes history/audit harder.
## Decision 3 — Task catalog representation
**Decision:** Implement onboarding tasks as a small, explicit catalog (PHP enum or config-backed list) that defines:
- `task_type` (stable key)
- prerequisites
- which OperationRun type/job implements the task
- which evidence type(s) it writes
**Rationale:**
- Keeps task definitions centralized and testable.
- Supports the task board UX (show prerequisites, last status, rerun).
**Alternatives considered:**
- Store task definitions in the database.
- Rejected for Phase 1: adds complexity/migrations and makes review harder.
## Decision 4 — Concurrency + idempotency for task starts
**Decision:** Enforce "one active run per (managed_tenant_id, task_type)" by:
- Using `OperationRunService::ensureRunWithIdentity(...)` with an identity payload that includes at least `{ tenant_id, task_type }`.
- Maintaining/using an active-run unique constraint for the computed identity hash.
**Rationale:**
- Aligns with the constitution (DB-level active run dedupe) and existing provider start-gate patterns.
- Prevents double-click duplicates and conflicting task runs.
**Alternatives considered:**
- Application-only mutexes/locks.
- Rejected: insufficient without DB-level protection.
## Decision 5 — Collaboration locking model
**Decision:** Add session-level locking fields to onboarding sessions:
- `locked_by_user_id`
- `locked_until`
**Rationale:**
- Simple, explainable behavior.
- Supports takeover/handoff and prevents silent overwrites.
**Alternatives considered:**
- Per-step/per-task fine-grained locks.
- Rejected for Phase 1: higher complexity with limited user value.
## Decision 6 — Legacy (v1) onboarding migration path
**Decision:** Provide a migration bridge that can:
- Create a Provider Connection for a tenant if the legacy `Tenant` credential fields exist.
- Move credentials into `provider_credentials` (encrypted) and stop rendering the legacy credential fields in the onboarding UI.
**Rationale:**
- Satisfies FR-021 without requiring a full backfill of historical run output.
- Aligns with the repos existing secure credential patterns (`ProviderCredential` + `CredentialManager`).
**Alternatives considered:**
- Keep using `Tenant.app_client_secret` for v2.
- Rejected: conflicts with ProviderConnection-first direction and increases leak risk.
## Decision 7 — Filament implementation shape
**Decision:** Implement wizard + task board as Filament Pages/Actions.
**Rationale:**
- Matches current admin UI architecture.
- Allows capability-gated actions with consistent RBAC UX patterns.
**Alternatives considered:**
- Standalone Blade controllers for v2 onboarding.
- Rejected: splits patterns and complicates authorization/testing conventions.