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
2.6 KiB
2.6 KiB
Data Model — Unified Managed Tenant Onboarding Wizard (073)
Entities
Workspace
Existing entity. Onboarding is always initiated within a selected workspace.
Tenant (Managed Tenant)
Existing model: App\Models\Tenant
Key fields (existing or to be confirmed/extended):
id(PK)workspace_id(FK to workspaces)tenant_id(string; Entra tenant ID) — spec’sentra_tenant_idexternal_id(string; globally unique route key used by Filament tenancy)name(string)domain(string|null)status(string) — v1 lifecycle:pending(created / onboarding)active(ready)archived(no longer managed)
Indexes / constraints (design intent):
- Unique:
(workspace_id, tenant_id) - Keep
external_idglobally unique (for/admin/t/{tenant}routing) and do not force it to equaltenant_id.
State transitions:
pending→activeafter successful verificationactive→archivedon soft-delete (existing behavior)archived→activeon restore (existing behavior)
ProviderConnection
Existing model: App\Models\ProviderConnection
- Belongs to
Tenant - Contains
entra_tenant_id(string) and default/active flags.
TenantOnboardingSession (new)
New model/table to persist resumable onboarding state. Must never persist or return secrets.
Proposed fields:
id(PK)workspace_id(FK)tenant_id(FK to tenants.id) — nullable until tenant is created, depending on wizard flowentra_tenant_id(string) — denormalized for upsert/idempotency before tenant existscurrent_step(string; e.g.,identify,connection,verify,bootstrap,complete)state(jsonb/json) — safe fields only (no secrets)tenant_nametenant_domainselected_provider_connection_idverification_run_id(OperationRun id)bootstrap_run_ids(array)
started_by_user_id(FK users)updated_by_user_id(FK users)completed_at(timestamp|null)- timestamps
Constraints:
- Unique:
(workspace_id, entra_tenant_id)
State transitions:
in_progress(implied bycompleted_at = null) →completed(completed_at != null)
Validation rules (high level)
entra_tenant_id(tenant_id) must be a non-empty string; validate as GUID format if enforced elsewhere.- Tenant name required to create tenant.
- ProviderConnection selection must belong to the same tenant/workspace.
Authorization boundaries
- Workspace scope: non-members denied as 404.
- Workspace member but missing onboarding capability: 403.
- Tenant scope: once tenant exists/selected, tenant membership rules apply as currently implemented.