TenantAtlas/specs/073-unified-managed-tenant-onboarding-wizard/research.md
ahmido b6343d5c3a feat: unified managed tenant onboarding wizard (#88)
Implements workspace-scoped managed tenant onboarding wizard (Filament v5 / Livewire v4) with strict RBAC (404/403 semantics), resumable sessions, provider connection selection/creation, verification OperationRun, and optional bootstrap. Removes legacy onboarding entrypoints and adds Pest coverage + spec artifacts (073).

## Summary
<!-- Kurz: Was ändert sich und warum? -->

## Spec-Driven Development (SDD)
- [ ] Es gibt eine Spec unter `specs/<NNN>-<feature>/`
- [ ] Enthaltene Dateien: `plan.md`, `tasks.md`, `spec.md`
- [ ] Spec beschreibt Verhalten/Acceptance Criteria (nicht nur Implementation)
- [ ] Wenn sich Anforderungen während der Umsetzung geändert haben: Spec/Plan/Tasks wurden aktualisiert

## Implementation
- [ ] Implementierung entspricht der Spec
- [ ] Edge cases / Fehlerfälle berücksichtigt
- [ ] Keine unbeabsichtigten Änderungen außerhalb des Scopes

## Tests
- [ ] Tests ergänzt/aktualisiert (Pest/PHPUnit)
- [ ] Relevante Tests lokal ausgeführt (`./vendor/bin/sail artisan test` oder `php artisan test`)

## Migration / Config / Ops (falls relevant)
- [ ] Migration(en) enthalten und getestet
- [ ] Rollback bedacht (rückwärts kompatibel, sichere Migration)
- [ ] Neue Env Vars dokumentiert (`.env.example` / Doku)
- [ ] Queue/cron/storage Auswirkungen geprüft

## UI (Filament/Livewire) (falls relevant)
- [ ] UI-Flows geprüft
- [ ] Screenshots/Notizen hinzugefügt

## Notes
<!-- Links, Screenshots, Follow-ups, offene Punkte -->

Co-authored-by: Ahmed Darrazi <ahmeddarrazi@adsmac.fritz.box>
Reviewed-on: #88
2026-02-03 17:30:15 +00:00

3.9 KiB
Raw Blame History

Research — Unified Managed Tenant Onboarding Wizard (073)

This document resolves planning unknowns and records key implementation decisions.

Decisions

1) Managed Tenant model = existing Tenant

  • Decision: Treat the existing App\Models\Tenant as the “Managed Tenant” concept.
  • Rationale: The admin panel tenancy, membership model, and most operational flows already key off Tenant.
  • Alternatives considered:
    • Introduce a new ManagedTenant model/table.
    • Keep Tenant as-is and build onboarding as “just another page”.
  • Why rejected: A second tenant-like model would duplicate authorization, routing, and operational conventions.

2) Workspace-scoped uniqueness + stable route key

  • Decision: Enforce uniqueness by (workspace_id, tenant_id) (where tenant_id is the Entra tenant ID), and ensure Filaments route tenant key stays globally unique.
  • Rationale: The feature spec explicitly defines the uniqueness key, and cross-workspace safety requires first-class scoping.
  • Implementation note: Today tenants.external_id is unique and is force-set to tenant_id in Tenant::saving(). If we allow the same tenant_id across workspaces, external_id must NOT be set to tenant_id anymore. Prefer a generated opaque stable external_id (UUID) and keep tenant_id strictly as the business identifier.
  • Alternatives considered:
    • Keep global uniqueness on tenant_id and keep using external_id = tenant_id.
  • Why rejected: Conflicts with the clarified uniqueness key and complicates “deny-as-not-found” behavior via DB constraint errors.

3) Wizard route location = workspace-scoped (/admin/w/{workspace}/...)

  • Decision: Mount onboarding at a workspace-scoped route: /admin/w/{workspace}/managed-tenants/onboarding.
  • Rationale: This path is explicitly exempted from forced tenant selection in EnsureFilamentTenantSelected, allowing onboarding before a tenant exists.
  • Alternatives considered:
    • Tenant-scoped Filament routes (/admin/t/{tenant}/...).
    • Reusing Filaments built-in tenant registration page (tenantRegistration).
  • Why rejected: Tenant-scoped routes require a tenant to exist/selected; built-in registration is a legacy entry point we must remove.

4) Verification implementation = existing provider operation (provider.connection.check)

  • Decision: Use provider.connection.check (module health_check) executed via ProviderConnectionHealthCheckJob as the onboarding verification run.
  • Rationale: It already uses OperationRun, writes sanitized outcomes, and performs Graph calls off-request.
  • Alternatives considered:
    • New onboarding-specific operation type.
  • Why rejected: Adds duplication without a clear benefit for v1.

5) Authorization surface = workspace capability (Owner+Manager)

  • Decision: Add a dedicated workspace capability for onboarding (e.g., workspace_managed_tenant.onboard) and grant it to workspace Owner and Manager in WorkspaceRoleCapabilityMap.
  • Rationale: The spec requires Owner+Manager; existing workspace capabilities dont exactly match this (e.g., WORKSPACE_MANAGE is Owner-only).
  • Alternatives considered:
    • Check workspace role strings (owner/manager) directly.
    • Reuse an unrelated capability like WORKSPACE_MEMBERSHIP_MANAGE.
  • Why rejected: Constitution forbids role-string checks in feature code; reusing unrelated capability broadens authorization implicitly.

6) Legacy entry points = removed/404 (no redirects)

  • Decision: Remove/disable these entry points and ensure 404 behavior:
    • /admin/register-tenant (Filament registration page)
    • /admin/managed-tenants* legacy redirects
    • /admin/new redirect
    • /admin/w/{workspace}/managed-tenants/onboarding redirect stub
  • Rationale: FR-001 requires wizard-only entry and “not found” behavior.

Open Questions

  • None. All technical unknowns required for planning are resolved.