TenantAtlas/specs/073-unified-managed-tenant-onboarding-wizard/research.md
ahmido 8e34b6084f 073-unified-managed-tenant-onboarding-wizard (#90)
Kontext / Ziel
Diese PR liefert den einzigen kanonischen Onboarding-Entry unter /admin/onboarding (workspace-first, tenantless bis zur Aktivierung) und ergänzt einen tenantless OperationRun-Viewer unter /admin/operations/{run} mit membership→404 Semantik.

Was ist enthalten?
Single entry point: /admin/onboarding ist der einzige Einstieg; Legacy Entry Points liefern echte 404 (keine Redirects).
Wizard v1 (Enterprise): idempotentes Identifizieren eines Managed Tenants (per Entra Tenant ID), resumable Session-Flow.
Provider Connection Step: Auswahl oder Erstellung, Secrets werden nie erneut gerendert / nicht in Session-State persistiert.
Verification als OperationRun: async/queued, DB-only Rendering im Wizard (keine Graph-Calls beim Rendern).
Tenantless Run Viewing: /admin/operations/{run} funktioniert ohne ausgewählten Workspace/Tenant, aber bleibt über Workspace-Mitgliedschaft autorisiert (non-member → 404).
RBAC-UX Semantik: non-member → 404, member ohne Capability → UI disabled + tooltip, server-side Action → 403.
Auditability: Aktivierung/Overrides sind auditierbar, stable action IDs, keine Secrets.
Tech / Version-Safety
Filament v5 / Livewire v4.0+ kompatibel.
Laravel 11+: Panel Provider Registrierung in providers.php (unverändert).
Tests / Format
vendor/bin/sail bin pint --dirty
Full suite: vendor/bin/sail artisan test --no-ansi → 984 passed, 5 skipped (exit 0)
Ops / Deployment Notes
Keine zusätzlichen Services vorausgesetzt.
Falls Assets registriert wurden: Deployment weiterhin mit php artisan filament:assets (wie üblich im Projekt).

Co-authored-by: Ahmed Darrazi <ahmeddarrazi@adsmac.fritz.box>
Co-authored-by: Ahmed Darrazi <ahmeddarrazi@MacBookPro.fritz.box>
Reviewed-on: #90
2026-02-04 23:30:55 +00:00

4.6 KiB
Raw Blame History

Research — Managed Tenant Onboarding Wizard V1 (Enterprise) (073)

This document resolves planning unknowns and records key implementation decisions aligned with the clarified spec.

Decisions

1) Managed Tenant model = existing Tenant

  • Decision: Treat App\Models\Tenant as the “Managed Tenant” record.
  • Rationale: Filament tenancy, membership model, and tenant-scoped flows already depend on Tenant; duplicating a second tenant-like table would multiply authorization and routing complexity.
  • Alternatives considered: Introduce a new ManagedTenant model/table.
  • Why rejected: Duplicates tenancy and membership boundaries; increases cross-plane leak risk.

2) Entra Tenant ID uniqueness = global, bound to one workspace

  • Decision: Enforce global uniqueness for tenants.tenant_id (Entra Tenant ID) and bind it to exactly one workspace (the workspace_id on the tenant).
  • Rationale: Matches FR-011 and the clarification decision (“global uniqueness bound to one workspace”).
  • Alternatives considered: Allow the same Entra Tenant ID in multiple workspaces.
  • Why rejected: Violates the clarified requirement and complicates deny-as-not-found behavior.

3) Canonical onboarding entry point = /admin/onboarding (only)

  • Decision: Provide /admin/onboarding as the sole onboarding entry point.
  • Rationale: Keeps a single user-facing URL for enterprise workflows; avoids fragmented legacy entry points.
  • Alternatives considered: Workspace-scoped onboarding route (/admin/w/{workspace}/...).
  • Why rejected: Conflicts with clarified spec (canonical /admin/onboarding only).

4) Tenantless operations viewer = existing OperationRunResource route /admin/operations/{run}

  • Decision: Keep the route shape /admin/operations/{run} (already provided by OperationRunResource slug operations) and make it compliant by changing authorization + middleware behavior.
  • Rationale: Minimizes routing surface area and leverages existing Monitoring → Operations UI.
  • Alternatives considered: Create a separate “run viewer” page outside the resource.
  • Why rejected: Duplicates infolist rendering and complicates observability conventions.

5) /admin/operations/{run} must not require selected workspace or auto-switch

  • Decision: Exempt /admin/operations/{run} from forced workspace selection and from any “auto selection” side effects that would prevent tenantless viewing.
  • Rationale: Spec requires (a) no workspace in the URL, (b) no pre-selected workspace required, (c) no auto-switching.
  • Alternatives considered: Keep current EnsureWorkspaceSelected behavior (redirect to choose workspace).
  • Why rejected: Violates FR-017a and can leak resource existence via redirects.

6) OperationRun authorization = workspace membership (non-member → 404)

  • Decision: Authorize viewing a run by checking membership in the runs workspace; non-member gets deny-as-not-found (404).
  • Rationale: FR-017a defines access semantics; runs must be viewable tenantlessly before activation.
  • Alternatives considered: Authorize by Tenant::current() + matching run.tenant_id.
  • Why rejected: Requires tenant routing/selection and breaks tenantless viewing.

7) OperationRun schema = add workspace_id, allow tenantless runs, preserve idempotency

  • Decision: Add operation_runs.workspace_id (FK) and allow tenant_id to be nullable for pre-activation operations. Preserve DB-level dedupe using two partial unique indexes:
    • Tenant-bound runs: UNIQUE (tenant_id, run_identity_hash) WHERE tenant_id IS NOT NULL AND status IN ('queued', 'running')
    • Tenantless runs: UNIQUE (workspace_id, run_identity_hash) WHERE tenant_id IS NULL AND status IN ('queued', 'running')
  • Rationale: Enables tenantless operations while preserving race-safe idempotency guarantees.
  • Alternatives considered: Keep tenant_id required and always derive workspace via join.
  • Why rejected: Blocks tenantless flows and makes authorization join-dependent.

8) Provider connection ownership = workspace-owned, default 1:1 binding

  • Decision: Align Provider Connections to be workspace-owned and (by default) bound to exactly one managed tenant; reuse is disabled by default and policy-gated.
  • Rationale: Matches FR-022/022a/022b and reduces blast radius of credential reuse.
  • Alternatives considered: Keep provider connections tenant-owned.
  • Why rejected: Conflicts with clarified spec ownership model.

Open Questions

  • None for planning; implementation will need to reconcile existing DB schema and policies with the decisions above.