## 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
226 lines
25 KiB
Markdown
226 lines
25 KiB
Markdown
# Feature Specification: Tenant Action Taxonomy and Lifecycle-Safe Visibility
|
|
|
|
**Feature Branch**: `145-tenant-action-taxonomy-lifecycle-safe-visibility`
|
|
**Created**: 2026-03-15
|
|
**Status**: Draft
|
|
**Input**: User description: "Tenant actions currently blur lifecycle semantics, especially where labels, visibility, and actual persistence behavior do not match. The product needs an explicit and enterprise-grade action taxonomy so tenant actions are predictable, lifecycle-safe, and consistent across list views, detail pages, onboarding flows, and future governance surfaces."
|
|
|
|
## Spec Scope Fields *(mandatory)*
|
|
|
|
- **Scope**: workspace + tenant + onboarding-linked tenant actions
|
|
- **Primary Routes**:
|
|
- `/admin/tenants`
|
|
- `/admin/tenants/{tenant}`
|
|
- `/admin/onboarding`
|
|
- `/admin/onboarding/{onboardingDraft}`
|
|
- Any tenant-related action surface in tables, infolists, page headers, widgets, and contextual action groups within the admin plane
|
|
- **Data Ownership**:
|
|
- Tenants remain workspace-owned records.
|
|
- Tenant lifecycle semantics remain defined by Spec 143.
|
|
- Onboarding drafts and sessions remain separate workspace-scoped workflow records that may link to a tenant.
|
|
- This feature governs action semantics, labels, availability, and lifecycle-safe visibility only.
|
|
- This feature does not change workspace ownership, tenant ownership, or the hierarchy between tenant and onboarding records.
|
|
- **RBAC**:
|
|
- Authorization planes involved: admin `/admin` tenant-management and onboarding surfaces inside the admin plane.
|
|
- Workspace non-members or users lacking entitlement to the tenant in scope receive deny-as-not-found semantics.
|
|
- Workspace members who can see the tenant surface but lack the required lifecycle-action capability receive forbidden semantics.
|
|
- Action legitimacy must be determined from workspace membership, tenant entitlement, capability policy checks, tenant lifecycle, workflow state where relevant, and page context.
|
|
- Selected header tenant context must never be the primary determinant of whether a tenant lifecycle action is valid.
|
|
|
|
## User Scenarios & Testing *(mandatory)*
|
|
|
|
### User Story 1 - See The Right Next Action (Priority: P1)
|
|
|
|
As a workspace operator, I need each tenant surface to show the next valid action for that tenant's lifecycle instead of a misleading or impossible action, so that I can move work forward without interpreting hidden persistence rules.
|
|
|
|
**Why this priority**: This is the highest-risk operator failure. Misleading lifecycle actions directly cause incorrect administration and erode trust in the product.
|
|
|
|
**Independent Test**: Can be fully tested by preparing tenants in `draft`, `onboarding`, `active`, and `archived` states and verifying that each in-scope surface shows only lifecycle-valid actions with honest labels.
|
|
|
|
**Acceptance Scenarios**:
|
|
|
|
1. **Given** a tenant is in `draft` or `onboarding`, **When** the operator opens the tenants index or tenant detail page, **Then** the primary lifecycle-oriented action is `Resume onboarding` or another workflow-accurate onboarding action and `Archive` is not shown.
|
|
2. **Given** a tenant is `active`, **When** the operator opens a tenant management surface, **Then** the surface may show `Archive` and related non-lifecycle actions, but it does not show onboarding-only actions.
|
|
3. **Given** a tenant is `archived`, **When** the operator opens a tenant management surface, **Then** the surface may show `Restore` where authorized and does not show `Archive` or `Resume onboarding`.
|
|
|
|
---
|
|
|
|
### User Story 2 - Trust Action Labels (Priority: P2)
|
|
|
|
As a workspace operator, I need lifecycle actions to be named after the actual domain change they perform, so that I can understand what will happen before I click and later reconstruct the change from UI and audit history.
|
|
|
|
**Why this priority**: Honest naming is required for governance, auditability, and a stable operator mental model, but it depends on the lifecycle-safe availability rules established in User Story 1.
|
|
|
|
**Independent Test**: Can be fully tested by reviewing in-scope lifecycle-changing actions and confirming that archive-like behavior is labeled `Archive`, archive recovery is labeled `Restore`, and onboarding continuation is labeled `Resume onboarding` or equivalent workflow-accurate wording.
|
|
|
|
**Acceptance Scenarios**:
|
|
|
|
1. **Given** a tenant action moves a tenant into retained non-operational archived state, **When** the operator sees the action label, **Then** the action is labeled `Archive` and not `Deactivate`.
|
|
2. **Given** a tenant action reverses archival of an already established tenant record, **When** the operator sees the action label, **Then** the action is labeled `Restore` and not presented as generic activation or onboarding completion.
|
|
3. **Given** a tenant action continues onboarding workflow, **When** the operator sees the action label, **Then** the action is labeled `Resume onboarding` or equivalent workflow-accurate wording rather than a generic tenant-management verb.
|
|
|
|
---
|
|
|
|
### User Story 3 - Get Consistent Cross-Surface Behavior (Priority: P3)
|
|
|
|
As a workspace operator, I need tenant action availability to stay consistent across table rows, page headers, infolists, widgets, and contextual groups, so that the same tenant does not appear to support contradictory lifecycle operations depending on where I look.
|
|
|
|
**Why this priority**: Cross-surface consistency reduces future drift and prevents authorization or lifecycle bugs from hiding behind page-specific visibility logic.
|
|
|
|
**Independent Test**: Can be fully tested by comparing the action inventory for the same tenant lifecycle across the tenants index, tenant detail page, onboarding surfaces, and tenant-linked contextual surfaces and confirming that any differences are page-intent-specific rather than contradictory.
|
|
|
|
**Acceptance Scenarios**:
|
|
|
|
1. **Given** the same `active` tenant is shown on the index and detail page, **When** the operator compares visible lifecycle actions, **Then** both surfaces allow `Archive` where authorized and neither surface exposes onboarding-only lifecycle actions.
|
|
2. **Given** the same `archived` tenant appears in multiple in-scope surfaces, **When** the operator compares visible lifecycle actions, **Then** `Restore` is the only recovery action shown and any unavailable lifecycle actions remain hidden rather than failing after click.
|
|
3. **Given** the operator lacks the capability to perform a lifecycle mutation but can still inspect the tenant, **When** the operator visits different in-scope surfaces, **Then** the invalid lifecycle action remains unavailable everywhere and the tenant is still viewable where entitlement allows it.
|
|
|
|
### Edge Cases
|
|
|
|
- What happens when a tenant has onboarding workflow records but has already become `active`? The product must suppress onboarding-only actions and preserve normal active-tenant actions.
|
|
- What happens when an archived tenant remains viewable in a history or operations context? Read-only inspection may remain available where policy allows, but active-only or onboarding-only lifecycle actions must remain hidden.
|
|
- What happens when a user can view a tenant but lacks capability for archive or restore? The tenant remains inspectable, but lifecycle-changing actions stay hidden or resolve to forbidden if reached directly.
|
|
- What happens when list and detail pages intentionally differ in depth of action inventory? Differences are allowed only when they reflect page context, not contradictory lifecycle semantics.
|
|
- What happens when onboarding completion is workflow-ready but the operator is outside onboarding context? The product may link back into onboarding workflow, but it must not surface onboarding completion as a casual substitute for restore or archive reversal.
|
|
|
|
## Requirements *(mandatory)*
|
|
|
|
**Constitution alignment (required):** This feature changes operator-facing lifecycle action semantics and authorization-driven visibility but does not introduce new Microsoft Graph calls, new long-running work, or a new `OperationRun` type. Lifecycle-changing actions such as `Archive` and `Restore` remain auditable mutations. Any implementation slice that changes those actions must preserve confirmation, audit coverage, tenant isolation, and explicit operator feedback.
|
|
|
|
**Constitution alignment (OPS-UX):** This feature does not create or reuse an `OperationRun` for new workflows. It does establish vocabulary and lifecycle-safe linking rules that future operation or audit surfaces must reuse when they present tenant-related actions or cross-links.
|
|
|
|
**Constitution alignment (RBAC-UX):** This feature changes authorization behavior in the admin `/admin` plane and tenant-context behavior inside that plane. Cross-plane behavior is not in scope. Non-members or actors lacking tenant entitlement must receive deny-as-not-found behavior. Members who can inspect the tenant but lack the capability for lifecycle mutation must receive forbidden behavior for direct mutation attempts. Server-side enforcement must come from Gates, Policies, or a central tenant-action policy surface using the canonical capability registry rather than raw capability strings or role-name checks. Global search behavior for in-scope tenant records must remain non-member-safe and lifecycle-safe. Lifecycle-changing actions such as `Archive` and `Restore` must require confirmation. Regression coverage must include at least one positive authorization case and one negative authorization case for lifecycle actions.
|
|
|
|
**Constitution alignment (OPS-EX-AUTH-001):** Not applicable. This feature does not alter authentication handshake behavior.
|
|
|
|
**Constitution alignment (BADGE-001):** This feature does not define the full tenant-status presentation system, but any badge or status indicator touched in scope must continue to use centralized lifecycle semantics rather than page-local mappings. Full badge hardening remains a follow-up concern for Spec 146.
|
|
|
|
**Constitution alignment (UI-NAMING-001):** The target object is the tenant record and its linked onboarding workflow where applicable. Primary operator verbs are `View`, `Resume onboarding`, `Archive`, `Restore`, `View operations`, and onboarding/readiness support verbs such as `Start verification` where already present. Source disambiguation is used only when necessary to distinguish onboarding workflow from normal tenant management. The same lifecycle vocabulary must be preserved across buttons, confirmation modals, notifications, audit prose, and any future run titles or history records. Implementation-first terms such as `soft delete` or generic `deactivate` must not be primary operator-facing labels when the actual domain semantics are archival.
|
|
|
|
**Constitution alignment (Filament Action Surfaces):** This feature modifies Filament tenant-management and onboarding surfaces. The Action Surface Contract is satisfied if the implementation centralizes lifecycle-safe visibility, keeps no more than two visible row actions before overflow where practical, requires confirmation on destructive-like lifecycle mutations, and applies the same action taxonomy across the listed surfaces.
|
|
|
|
**Constitution alignment (UX-001 — Layout & Information Architecture):** This feature is not a layout redesign. Existing table, detail, and onboarding layouts remain intact. UX-001 compliance is preserved by keeping list pages as list pages, detail pages as inspection surfaces, and onboarding pages as workflow surfaces while correcting action grouping, empty-state CTAs, and lifecycle-safe action inventory where touched.
|
|
|
|
### Functional Requirements
|
|
|
|
- **FR-145-001**: The system MUST define a central tenant action taxonomy that distinguishes neutral inspection actions, onboarding workflow actions, lifecycle-management actions, and readiness or verification actions.
|
|
- **FR-145-002**: The system MUST label each tenant action according to the actual persisted domain behavior it triggers or the actual workflow it continues.
|
|
- **FR-145-003**: The system MUST NOT use `Deactivate` as the operator-facing label for an action whose real semantics are archive, retirement, or soft-deletion into retained non-operational state.
|
|
- **FR-145-004**: The system MUST keep onboarding workflow actions distinct from normal tenant-management lifecycle actions in naming, grouping, and availability rules.
|
|
- **FR-145-005**: `Resume onboarding` MUST be available only for tenants in `draft` or `onboarding` when workflow state and authorization make continuation meaningful.
|
|
- **FR-145-006**: `Archive` MUST be available only for `active` tenants that satisfy the required capability and page-context rules.
|
|
- **FR-145-007**: `Restore` MUST be available only for `archived` tenants that satisfy the required capability and page-context rules.
|
|
- **FR-145-008**: The system MUST treat onboarding completion or activation as conceptually distinct from archive recovery, and MUST NOT present `Restore` as a generic synonym for activation.
|
|
- **FR-145-009**: Draft and onboarding tenants MUST NOT expose active-only lifecycle actions such as `Archive` on in-scope generic tenant-management surfaces.
|
|
- **FR-145-010**: Active tenants MUST NOT expose onboarding-only actions such as `Resume onboarding` on in-scope generic tenant-management surfaces unless a page is explicitly onboarding-contextual.
|
|
- **FR-145-011**: Archived tenants MUST NOT expose onboarding-only or active-only lifecycle actions on in-scope surfaces.
|
|
- **FR-145-012**: Neutral inspection actions such as `View` and `View operations` MAY remain available across lifecycle states where the actor is entitled and the page context is valid, but they MUST NOT imply operability.
|
|
- **FR-145-013**: Readiness or verification actions MUST remain semantically distinct from lifecycle transitions and MUST NOT be used as implicit activation semantics.
|
|
- **FR-145-014**: Action visibility in scope MUST be determined by lifecycle validity, capability policy, workflow readiness where relevant, and page context rather than by raw shortcuts such as `!trashed()` or scattered one-off status checks.
|
|
- **FR-145-015**: The same lifecycle-action decision MUST be reusable across tables, page header actions, infolists, widgets, and contextual dropdowns so equivalent surfaces do not drift semantically.
|
|
- **FR-145-016**: When list and detail surfaces intentionally differ, the difference MUST reflect page depth or workflow context and MUST NOT create contradictory lifecycle meaning for the same tenant.
|
|
- **FR-145-017**: Lifecycle-changing actions in scope MUST remain server-side authorization protected even when they are hidden in the UI.
|
|
- **FR-145-018**: Tenant lifecycle-action legitimacy MUST NOT depend on the currently selected header tenant context.
|
|
- **FR-145-019**: Failure paths for invalid lifecycle actions MUST prefer non-visibility over click-then-refusal, and any direct refusal that still occurs MUST identify whether the cause is wrong lifecycle, wrong workflow state, missing capability, or missing entitlement.
|
|
- **FR-145-020**: Lifecycle-changing action naming and availability MUST remain audit-friendly so archive, restore, and onboarding completion intent can be distinguished later without inference.
|
|
- **FR-145-021**: In-scope implementations MUST move toward a central tenant-action policy surface or reusable lifecycle-aware predicates rather than expanding ad hoc visibility logic in resource-local code.
|
|
- **FR-145-022**: The product MUST adopt the conceptual lifecycle-by-action matrix below for in-scope actions, subject to capability and page-context rules.
|
|
|
|
## UI Action Matrix *(mandatory when Filament is changed)*
|
|
|
|
If this feature adds/modifies any Filament Resource / RelationManager / Page, fill out the matrix below.
|
|
|
|
For each surface, list the exact action labels, whether they are destructive (confirmation? typed confirmation?),
|
|
RBAC gating (capability + enforcement helper), and whether the mutation writes an audit log.
|
|
|
|
| Surface | Location | Header Actions | Inspect Affordance (List/Table) | Row Actions (max 2 visible) | Bulk Actions (grouped) | Empty-State CTA(s) | View Header Actions | Create/Edit Save+Cancel | Audit log? | Notes / Exemptions |
|
|
|---|---|---|---|---|---|---|---|---|---|---|
|
|
| Managed tenants index | `/admin/tenants` | Existing create/onboarding entry actions only where already valid | Row click or explicit `View` action | `View` plus one lifecycle-primary action: `Resume onboarding`, `Archive`, or `Restore` depending on lifecycle; any additional actions move into overflow | None in this scope unless already present and lifecycle-safe | Existing tenant creation or onboarding CTA remains singular per UX-001 | Not applicable | Existing save/cancel semantics unchanged | Yes for `Archive` and `Restore` | `Archive` and `Restore` are destructive-like lifecycle changes and require confirmation plus server-side capability enforcement. |
|
|
| Tenant detail page | `/admin/tenants/{tenant}` | None added in this spec | Route-record inspection | Not applicable | None | Not applicable | `Resume onboarding`, `Archive`, `Restore`, `View operations`, and lifecycle-safe readiness actions when valid | Existing save/cancel semantics unchanged where edit exists | Yes for lifecycle mutations | Detail pages may show richer action inventory than list rows, but lifecycle semantics must remain identical. |
|
|
| Onboarding index | `/admin/onboarding` | Existing onboarding-entry action only where already valid | Row click or explicit `View onboarding details` | `Resume onboarding` and `View` when linked tenant or draft is inspectable | None in this scope | Existing onboarding CTA remains singular per UX-001 | Not applicable | Existing save/cancel semantics unchanged | Workflow mutations remain audited under onboarding rules | Onboarding pages are workflow surfaces and must not expose `Archive` or `Restore` as peer actions. |
|
|
| Onboarding detail page | `/admin/onboarding/{onboardingDraft}` | None added in this spec | Route-record inspection | Not applicable | None | Not applicable | `Resume onboarding`, `Complete onboarding` where workflow-ready, `View tenant`, readiness actions, and related support actions where already valid | Existing save/cancel semantics unchanged | Yes for workflow mutations and any lifecycle completion event | `Complete onboarding` belongs to workflow context, not generic tenant-management surfaces. |
|
|
| Tenant-linked widgets and contextual groups | In-scope admin widgets, infolists, and context menus | None added in this spec | Existing linked tenant affordance | Match the same lifecycle-valid primary action as the parent surface or show no lifecycle mutation | None in this scope | Not applicable | Not applicable | Not applicable | Yes when a lifecycle mutation is exposed | Exemption: widget-specific secondary actions may vary by surface, but lifecycle action meaning and availability must not contradict the core matrix. |
|
|
|
|
### Key Entities *(include if feature involves data)*
|
|
|
|
- **Tenant**: A durable workspace-owned record with lifecycle state and lifecycle-governed management semantics.
|
|
- **Tenant Lifecycle State**: The canonical state set inherited from Spec 143: `draft`, `onboarding`, `active`, and `archived`.
|
|
- **Onboarding Workflow Record**: A workspace-scoped draft or session that governs onboarding progression and may link to a tenant.
|
|
- **Tenant Action Taxonomy**: The product-level classification of tenant actions into neutral inspection, onboarding workflow, lifecycle management, and readiness or verification actions.
|
|
- **Tenant Action Policy Surface**: The central decision layer that resolves whether a given action is semantically valid, visible, and executable for a tenant in a given lifecycle and page context.
|
|
|
|
## Success Criteria *(mandatory)*
|
|
|
|
### Measurable Outcomes
|
|
|
|
- **SC-145-001**: In focused regression coverage across in-scope tenant surfaces, 100% of archive-like actions are labeled `Archive` and 0 are labeled `Deactivate`.
|
|
- **SC-145-002**: In focused regression coverage across in-scope tenant surfaces, 100% of `Restore` actions appear only for `archived` tenants and 0 appear for `draft`, `onboarding`, or `active` tenants.
|
|
- **SC-145-003**: In focused regression coverage across in-scope tenant surfaces, 100% of `Resume onboarding` actions appear only for `draft` or `onboarding` tenants and 0 appear for `active` or `archived` tenants outside explicit onboarding workflow context.
|
|
- **SC-145-004**: In focused regression coverage, the same tenant lifecycle does not expose contradictory lifecycle-changing actions across the tenants index and tenant detail page for any covered tenant state.
|
|
- **SC-145-005**: In focused authorization coverage, 100% of non-member or non-entitled lifecycle-action access attempts resolve as deny-as-not-found, and 100% of in-scope capability denials resolve as forbidden.
|
|
- **SC-145-006**: In focused UX validation, 100% of covered lifecycle-changing actions use operator-facing names that match the underlying lifecycle outcome and can be distinguished in later audit review without inference.
|
|
|
|
## Lifecycle-By-Action Matrix
|
|
|
|
| Lifecycle | View | Resume onboarding | Complete onboarding / Activate | Archive | Restore | View operations | Verification / readiness actions |
|
|
|---|---|---|---|---|---|---|---|
|
|
| Draft | Yes | Yes | Workflow-dependent | No | No | Usually yes when records exist | Yes when meaningful |
|
|
| Onboarding | Yes | Yes | Workflow-dependent | No | No | Yes | Yes |
|
|
| Active | Yes | No | No | Yes | No | Yes | Yes |
|
|
| Archived | Yes where policy allows | No | No | No | Yes | Yes where policy allows | Usually no unless explicitly read-only support exists |
|
|
|
|
## Summary
|
|
|
|
Tenant-related actions currently blur lifecycle semantics by mixing archive behavior, onboarding continuation, neutral viewing, and readiness support under labels and visibility rules that do not consistently match actual product behavior. This creates operator confusion, weakens audit clarity, and makes future governance features harder to implement safely.
|
|
|
|
This feature defines a formal tenant action taxonomy and lifecycle-safe visibility model so that action meaning, action availability, and persisted domain behavior align across list views, detail pages, onboarding flows, and future governance surfaces.
|
|
|
|
## Goals
|
|
|
|
- Define a clear central taxonomy for tenant actions.
|
|
- Align action labels with actual domain behavior.
|
|
- Make lifecycle-changing actions available only when semantically valid for the current tenant lifecycle.
|
|
- Keep onboarding workflow actions distinct from normal active-tenant management actions.
|
|
- Reduce duplicated visibility logic across list views, detail pages, widgets, and contextual groups.
|
|
- Create an enterprise-grade action model that future audit, governance, and read-only surfaces can inherit.
|
|
|
|
## Non-Goals
|
|
|
|
- This feature does not redesign the onboarding workflow end to end.
|
|
- This feature does not introduce a generalized lifecycle state-machine engine.
|
|
- This feature does not create new tenant lifecycle states beyond those accepted in Spec 143.
|
|
- This feature does not define the full visual design system for buttons, badges, or menus.
|
|
- This feature does not introduce permanent deletion as a required surface, though it reserves taxonomy space for a separate destructive tier.
|
|
- This feature does not change workspace or tenant ownership boundaries.
|
|
|
|
## Assumptions
|
|
|
|
- Spec 143 remains the source of truth for canonical tenant lifecycle semantics.
|
|
- Spec 144 remains the source of truth for canonical operation-viewer legitimacy when tenant-linked records cross lifecycle or header-context boundaries.
|
|
- In-scope tenant actions already exist across multiple surfaces and need semantic hardening rather than a parallel action system.
|
|
- Existing capability registry and authorization primitives can support central lifecycle-aware predicates without redefining the product's ownership model.
|
|
|
|
## Migration Strategy
|
|
|
|
1. Immediate semantic correction: replace misleading lifecycle labels, remove obviously invalid lifecycle actions from the wrong states, and ensure onboarding tenants expose workflow-appropriate next actions.
|
|
2. Predicate centralization: move scattered lifecycle-action visibility checks into central lifecycle-aware rules reused by list, detail, onboarding, and contextual surfaces.
|
|
3. Lifecycle hardening: keep archive, restore, and onboarding completion technically and conceptually distinct, and align downstream audit or event naming with the corrected taxonomy.
|
|
|
|
## Risks
|
|
|
|
- Renaming labels without fixing visibility logic would leave the underlying semantics inconsistent.
|
|
- Over-centralizing without page-context nuance could suppress legitimate detail-page actions that do not belong on list pages.
|
|
- Hiding onboarding actions without clear workflow continuation paths would make onboarding tenants feel blocked or lost.
|
|
- Failing to keep restore distinct from onboarding completion would preserve ambiguity in both UX and audit interpretation.
|
|
|
|
## Follow-Up Dependencies
|
|
|
|
- Spec 146 — Central Tenant Status Presentation
|
|
- Spec 147 — Tenant Selector and Remembered Context Enforcement
|
|
- Spec 148 — Central Tenant Operability Policy
|
|
- Future audit hardening work to align lifecycle event naming and operator-visible history with the corrected action taxonomy
|
|
|
|
## Final Direction
|
|
|
|
Tenant actions must behave like explicit domain operations rather than loosely named UI affordances. Onboarding actions remain onboarding actions, archive means archive, restore means restore, active-tenant management remains distinct from onboarding workflow, and lifecycle-changing actions appear only when they are semantically valid for the current tenant.
|