TenantAtlas/specs/148-central-tenant-operability-policy/quickstart.md
ahmido 417df4f9aa feat: central tenant operability policy (#177)
## Summary
- centralize tenant operability into a lane-aware, actor-aware policy boundary
- align selector eligibility, administrative discoverability, remembered context, tenant-bound routes, and canonical run viewers
- add focused Pest coverage plus Spec 148 artifacts and final polish task completion

## Validation
- `vendor/bin/sail artisan test --compact tests/Unit/Tenants/TenantOperabilityServiceTest.php tests/Unit/Tenants/TenantOperabilityOutcomeTest.php tests/Feature/Workspaces/ChooseTenantPageTest.php tests/Feature/Workspaces/SelectTenantControllerTest.php tests/Feature/TenantRBAC/ArchivedTenantRouteAccessTest.php tests/Feature/TenantRBAC/TenantRouteDenyAsNotFoundTest.php tests/Feature/Operations/TenantlessOperationRunViewerTest.php tests/Feature/OpsUx/OperateHubShellTest.php tests/Feature/Rbac/TenantLifecycleActionVisibilityTest.php tests/Feature/TenantRBAC/TenantSwitcherScopeTest.php tests/Feature/Rbac/TenantResourceAuthorizationTest.php tests/Feature/Filament/ManagedTenantsLandingLifecycleTest.php tests/Feature/Filament/TenantGlobalSearchLifecycleScopeTest.php tests/Feature/Onboarding/OnboardingDraftLifecycleTest.php tests/Feature/Onboarding/OnboardingDraftAuthorizationTest.php`
- `vendor/bin/sail bin pint --dirty --format agent`
- manual browser smoke checks on `/admin/choose-tenant`, `/admin/tenants`, `/admin/onboarding`, `/admin/onboarding/{draft}`, and `/admin/operations/{run}`

## Filament / platform notes
- Livewire v4 compliance preserved
- panel provider registration unchanged in `bootstrap/providers.php`
- Tenant resource global search remains backed by existing view/edit pages and is now separated from active-only selector eligibility
- destructive actions remain action closures with confirmation and authorization enforcement
- no asset pipeline changes and no new `filament:assets` deployment requirement

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #177
2026-03-17 11:48:55 +00:00

4.3 KiB

Quickstart: Central Tenant Operability Policy

Goal

Validate that one central operability authority now drives selector membership, remembered-context validity, tenant-bound page legitimacy, canonical viewer behavior, and lifecycle-safe action availability.

Prerequisites

  1. Start Sail.
  2. Ensure a test workspace exists with tenants covering draft, onboarding, active, and archived lifecycle states.
  3. Ensure at least one onboarding session is linked to a draft or onboarding tenant.
  4. Ensure at least one OperationRun references a tenant that is not standard-selector eligible.

Implementation Validation Order

1. Run focused unit coverage for the policy core

vendor/bin/sail artisan test --compact tests/Unit/Tenants

Expected outcome:

  • Operability outcomes are stable across all lifecycle and lane combinations.
  • Reason codes distinguish lifecycle denial, lane denial, and capability denial.

2. Run focused selector and remembered-context tests

vendor/bin/sail artisan test --compact --filter=ChooseTenant
vendor/bin/sail artisan test --compact --filter=SelectTenant
vendor/bin/sail artisan test --compact --filter=remembered

Expected outcome:

  • Only active tenants are selectable in the standard selector.
  • Stale remembered context is cleared when the tenant becomes missing, out of workspace, or selector-ineligible.

3. Run focused tenant-bound and canonical-view tests

vendor/bin/sail artisan test --compact tests/Feature/Operations
vendor/bin/sail artisan test --compact --filter=TenantlessOperationRunViewer
vendor/bin/sail artisan test --compact --filter=OperateHubShell
vendor/bin/sail artisan test --compact --filter=ViewTenant

Expected outcome:

  • /admin/operations/{run} remains valid under mismatched or empty selected tenant context.
  • /admin/tenants/{tenant} remains valid for authorized onboarding or archived tenants even when they are not selector-eligible.
  • Shell-level context resolution keeps canonical and tenant-bound routes valid without falling back to selector-lane assumptions.

4. Run focused lifecycle-action tests

vendor/bin/sail artisan test --compact --filter=archive
vendor/bin/sail artisan test --compact --filter=restore
vendor/bin/sail artisan test --compact --filter="resume onboarding"
vendor/bin/sail artisan test --compact tests/Feature/Onboarding/OnboardingDraftAuthorizationTest.php
vendor/bin/sail artisan test --compact --filter="onboarding completion"
vendor/bin/sail artisan test --compact --filter=readiness

Expected outcome:

  • Archive, Restore, and Resume onboarding resolve from the central operability layer.
  • Onboarding-completion plus readiness or verification affordances resolve from the same policy boundary with lifecycle-aware and capability-aware reasons.
  • Non-members remain 404.
  • In-scope users without capability remain 403.

5. Run focused discoverability and global-search tests

vendor/bin/sail artisan test --compact --filter=TenantResourceGlobalSearch
vendor/bin/sail artisan test --compact --filter=discoverability

Expected outcome:

  • Administrative discoverability and tenant global search do not collapse back to standard selector eligibility.
  • Non-active tenants can remain administratively discoverable when policy allows, even though they are not selectable in the active-lane chooser.

6. Manual smoke-check in the browser

  1. Open /admin/choose-tenant and confirm only active tenants are selectable.
  2. Open /admin/tenants with no selected tenant and confirm the list remains usable.
  3. Open /admin/onboarding and /admin/onboarding/{onboardingDraft} and confirm onboarding-lane actions remain available only when operability allows them.
  4. Open an archived tenant detail route directly and confirm the page renders when authorized.
  5. Open /admin/operations/{run} for a run linked to an onboarding or archived tenant while a different tenant is selected and confirm the mismatch is informational only.
  6. Verify lifecycle action buttons plus onboarding-completion and readiness or verification affordances remain honest and confirmation-backed where applicable.

Non-Goals For This Slice

  • No schema migration.
  • No new Graph calls.
  • No new assets or Filament panel registration changes.
  • No new OperationRun type.