## Summary
Implements Spec 145 for tenant action taxonomy and lifecycle-safe visibility.
This PR:
- adds a central tenant action policy surface and supporting value objects
- aligns tenant list, detail, edit, onboarding, and widget surfaces around lifecycle-safe actions
- standardizes operator-facing lifecycle wording around View, Resume onboarding, Archive, Restore, and Complete onboarding
- tightens onboarding and tenant lifecycle authorization semantics, including honest 404 vs 403 behavior
- updates related regression coverage and spec artifacts for Spec 145
- fixes follow-on full-suite regressions uncovered during validation, including onboarding browser flows, provider consent fixtures, workspace redirect DI expectations, and critical table/action/UI expectation drift
## Validation
Executed and passed:
- vendor/bin/sail bin pint --dirty --format agent
- vendor/bin/sail artisan test --compact
Result:
- 2581 passed
- 8 skipped
- 13534 assertions
## Notes
- Base branch: dev
- Feature branch commit: a33a41b
- Filament v5 / Livewire v4 compliance preserved
- No panel provider registration changes; Laravel 12 provider registration remains in bootstrap/providers.php
- No new globally searchable resource behavior added in this slice
- Destructive lifecycle actions remain confirmation-gated and authorization-protected
Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #174
150 lines
4.9 KiB
Markdown
150 lines
4.9 KiB
Markdown
# Data Model: Tenant Action Taxonomy and Lifecycle-Safe Visibility
|
|
|
|
## 1. Tenant
|
|
|
|
**Type**: Existing persisted model (`App\Models\Tenant`)
|
|
|
|
**Core fields**:
|
|
- `id`
|
|
- `workspace_id`
|
|
- `external_id`
|
|
- `tenant_id`
|
|
- `name`
|
|
- `status` (`draft`, `onboarding`, `active`, `archived`)
|
|
- `deleted_at`
|
|
- `is_current`
|
|
|
|
**Relationships**:
|
|
- belongs to `Workspace`
|
|
- has many `TenantOnboardingSession`
|
|
- has many provider/operational records already used elsewhere in the admin plane
|
|
|
|
**Validation / invariants**:
|
|
- `workspace_id` is required
|
|
- `status` must resolve to a canonical `TenantLifecycle`
|
|
- soft-delete implies archived semantics on lifecycle-sensitive surfaces
|
|
- only active tenants are selectable as remembered tenant context
|
|
|
|
**Lifecycle transitions relevant to this feature**:
|
|
- `draft -> onboarding`: onboarding workflow progresses after tenant identification
|
|
- `onboarding -> active`: onboarding completes through workflow activation semantics
|
|
- `onboarding -> draft`: last resumable onboarding draft is cancelled and linked tenant is normalized back to draft
|
|
- `active -> archived`: archive action soft-deletes tenant and sets archived semantics
|
|
- `archived -> active`: restore action reactivates archived tenant
|
|
|
|
## 2. TenantOnboardingSession
|
|
|
|
**Type**: Existing persisted model (`App\Models\TenantOnboardingSession`)
|
|
|
|
**Core fields**:
|
|
- `id`
|
|
- `workspace_id`
|
|
- `tenant_id` nullable until linked
|
|
- `entra_tenant_id`
|
|
- `current_step`
|
|
- `lifecycle_state`
|
|
- `current_checkpoint`
|
|
- `last_completed_checkpoint`
|
|
- `state` JSON
|
|
- `completed_at`
|
|
- `cancelled_at`
|
|
- `version`
|
|
|
|
**Relationships**:
|
|
- belongs to `Workspace`
|
|
- belongs to `Tenant` optionally
|
|
- belongs to `startedByUser`
|
|
- belongs to `updatedByUser`
|
|
|
|
**Validation / invariants**:
|
|
- workspace entitlement always required
|
|
- tenant entitlement required once a linked tenant exists
|
|
- resumability is workflow-derived, not inferred only from tenant lifecycle
|
|
- activation readiness is determined by `OnboardingLifecycleService`
|
|
|
|
**Lifecycle semantics relevant to this feature**:
|
|
- drives `Resume onboarding`
|
|
- drives `Complete onboarding` availability
|
|
- must remain distinct from archive/restore semantics
|
|
|
|
## 3. TenantActionContext
|
|
|
|
**Type**: New derived domain object or array DTO proposed by this plan
|
|
|
|
**Purpose**: Encapsulate the inputs needed to decide whether an action is visible, enabled, grouped, or executable on a specific surface.
|
|
|
|
**Fields**:
|
|
- `tenant_id`
|
|
- `workspace_id`
|
|
- `tenant_lifecycle`
|
|
- `surface` (`tenant_index_row`, `tenant_view_header`, `tenant_edit_header`, `onboarding_index_row`, `onboarding_detail_header`, `widget`, `context_menu`)
|
|
- `page_category`
|
|
- `has_related_onboarding_session`
|
|
- `related_onboarding_is_resumable`
|
|
- `is_member`
|
|
- `has_capability`
|
|
- `is_archived`
|
|
|
|
**Derivation sources**:
|
|
- `TenantOperabilityService`
|
|
- `OnboardingLifecycleService`
|
|
- `TenantOnboardingSessionPolicy`
|
|
- `UiEnforcement` / capability resolvers
|
|
|
|
## 4. TenantActionDescriptor
|
|
|
|
**Type**: New derived domain object or array DTO proposed by this plan
|
|
|
|
**Purpose**: Normalized description of one operator-facing action returned by the tenant-action policy surface.
|
|
|
|
**Fields**:
|
|
- `key` (`view`, `resume_onboarding`, `archive`, `restore`, `view_operations`, `verify`, `grant_admin_consent`)
|
|
- `family` (`neutral`, `onboarding_workflow`, `lifecycle_management`, `readiness`)
|
|
- `label`
|
|
- `visible`
|
|
- `enabled`
|
|
- `destructive`
|
|
- `requires_confirmation`
|
|
- `capability`
|
|
- `audit_action_id` nullable
|
|
- `reason_code` nullable when hidden or disabled
|
|
- `priority` or `group` to distinguish primary versus overflow actions
|
|
- `url` or `handler` metadata depending on surface
|
|
|
|
**Invariants**:
|
|
- label must match domain semantics
|
|
- archive and restore are mutually exclusive for one tenant on one surface
|
|
- onboarding-only actions and active-only actions are mutually exclusive except in explicit workflow context
|
|
- `requires_confirmation` must be true for destructive-like lifecycle mutations
|
|
|
|
## 5. TenantActionPolicySurface
|
|
|
|
**Type**: New service/resolver proposed by this plan
|
|
|
|
**Purpose**: Produce `TenantActionDescriptor` collections from `TenantActionContext` and central lifecycle/workflow/RBAC rules.
|
|
|
|
**Responsibilities**:
|
|
- resolve primary and overflow actions per surface
|
|
- enforce lifecycle-safe visibility before RBAC helper decoration
|
|
- keep onboarding workflow actions distinct from archive/restore
|
|
- provide reusable predicates for `canArchiveTenant`, `canRestoreTenant`, `canResumeOnboardingTenant`, `canShowActivationAction`, and `canShowReadinessActions`
|
|
|
|
**Non-responsibilities**:
|
|
- executing mutations
|
|
- replacing server-side authorization
|
|
- persisting lifecycle state
|
|
|
|
## 6. Audit Lifecycle Events
|
|
|
|
**Type**: Existing enum-backed audit vocabulary
|
|
|
|
**Relevant values**:
|
|
- `tenant.archived`
|
|
- `tenant.restored`
|
|
- `tenant.returned_to_draft`
|
|
- `managed_tenant_onboarding.resume`
|
|
- `managed_tenant_onboarding.cancelled`
|
|
- `managed_tenant_onboarding.activation`
|
|
|
|
**Requirement**:
|
|
- UI action taxonomy must stay aligned with these events so operator intent can be reconstructed from audit history. |