diff --git a/specs/068-workspace-foundation-v1/checklists/requirements.md b/specs/068-workspace-foundation-v1/checklists/requirements.md new file mode 100644 index 0000000..fa8b610 --- /dev/null +++ b/specs/068-workspace-foundation-v1/checklists/requirements.md @@ -0,0 +1,35 @@ +# Specification Quality Checklist: Workspace Foundation & Managed Tenant Onboarding Unification (v1) + +**Purpose**: Validate specification completeness and quality before proceeding to planning +**Created**: 2026-01-31 +**Feature**: [specs/068-workspace-foundation-v1/spec.md](../spec.md) + +## Content Quality + +- [x] No implementation details (languages, frameworks, APIs) +- [x] Focused on user value and business needs +- [x] Written for non-technical stakeholders +- [x] All mandatory sections completed + +## Requirement Completeness + +- [x] No [NEEDS CLARIFICATION] markers remain +- [x] Requirements are testable and unambiguous +- [x] Success criteria are measurable +- [x] Success criteria are technology-agnostic (no implementation details) +- [x] All acceptance scenarios are defined +- [x] Edge cases are identified +- [x] Scope is clearly bounded +- [x] Dependencies and assumptions identified + +## Feature Readiness + +- [x] All functional requirements have clear acceptance criteria +- [x] User scenarios cover primary flows +- [x] Feature meets measurable outcomes defined in Success Criteria +- [x] No implementation details leak into specification + +## Notes + +- All items pass as of 2026-01-31. +- Items marked incomplete require spec updates before `/speckit.clarify` or `/speckit.plan` diff --git a/specs/068-workspace-foundation-v1/plan.md b/specs/068-workspace-foundation-v1/plan.md new file mode 100644 index 0000000..5848d74 --- /dev/null +++ b/specs/068-workspace-foundation-v1/plan.md @@ -0,0 +1,82 @@ +# Implementation Plan: Workspace Foundation & Managed Tenant Onboarding Unification (v1) + +**Branch**: `068-workspace-foundation-v1` | **Date**: 2026-02-01 | **Spec**: ./spec.md +**Input**: Feature specification from `specs/068-workspace-foundation-v1/spec.md` + +**Note**: This template is filled in by the `/speckit.plan` command. See `.specify/scripts/` for helper scripts. + +## Summary + +Unify managed tenant onboarding behind a single canonical admin “front door” and ensure managed-tenant management stays tenantless (no tenant-in-tenant URLs). + +Repo alignment note: in this codebase, “Managed tenants” are represented by the existing `App\\Models\\Tenant` model and are managed via `App\\Filament\\Resources\\TenantResource` (which already opts out of tenancy scoping via `protected static bool $isScopedToTenant = false`). + +## Technical Context + +specs/068-workspace-foundation-v1/ +├── plan.md # This file +├── research.md # Phase 0 output +├── data-model.md # Phase 1 output +├── quickstart.md # Phase 1 output +├── contracts/ # Phase 1 output +└── tasks.md # Phase 2 output (generated by /speckit.tasks) +**Project Type**: Laravel web application +**Performance Goals**: N/A (routing + RBAC UX change) +**Constraints**: +```text +app/ +├── Filament/ +│ ├── Pages/ +│ │ ├── ChooseTenant.php +│ │ ├── NoAccess.php +│ │ └── (new) ManagedTenants/* +│ └── Resources/ +│ └── TenantResource.php +├── Models/ +│ └── Tenant.php +├── Providers/ +│ ├── AuthServiceProvider.php +│ └── Filament/AdminPanelProvider.php +├── Services/ +│ └── Auth/RoleCapabilityMap.php +└── Support/ + ├── Auth/Capabilities.php + └── Middleware/DenyNonMemberTenantAccess.php + +routes/web.php + +tests/ +├── Feature/ +└── Unit/ +``` + +**Structure Decision**: Laravel web application, implemented primarily in `app/Filament/*` and `app/Support/Auth/*`. + +## Phase 0 — Outline & Research + +Output: `research.md` + +- Filament tenancy: confirm best-practice approach for tenantless pages and redirects inside a tenancy-enabled panel. +- Routing: confirm how to implement `/admin/new` redirect in a way that respects authentication and avoids route conflicts. +- RBAC-UX: confirm patterns to preserve 404 vs 403 semantics for managed-tenant actions and pages. + +## Phase 1 — Design & Contracts + +Outputs: `data-model.md`, `contracts/*`, `quickstart.md` + +- Data model: reuse the existing `Tenant` model to represent a “managed tenant”. +- Session state: “Open” stores the selected tenant in session only (no DB persistence). +- Contracts: no new external API or OpenAPI contracts expected for v1. + +## Phase 2 — Planning (Implementation Steps) + +This plan is executed via `tasks.md` (generated by `/speckit.tasks`). Implementation sequence: + +1. Add canonical onboarding entry: `/admin/managed-tenants/onboarding`. +2. Add legacy redirect: `/admin/new` → canonical onboarding. +3. Ensure managed-tenant CRUD remains tenantless (no `/admin/t/{tenant}` required). +4. Implement “Open” behavior: + - If active: select tenant in session and redirect to a stable tenantless destination (e.g. `/admin/managed-tenants/current`). + - If archived: show status screen instead of selecting/redirecting. +5. Add/align capability registry entries and role mapping. +6. Add/extend Pest tests for redirects and 404/403 semantics. diff --git a/specs/068-workspace-foundation-v1/spec.md b/specs/068-workspace-foundation-v1/spec.md new file mode 100644 index 0000000..5a7e400 --- /dev/null +++ b/specs/068-workspace-foundation-v1/spec.md @@ -0,0 +1,218 @@ +# Feature Specification: Workspace Foundation & Managed Tenant Onboarding Unification (v1) + +**Feature Branch**: `068-workspace-foundation-v1` +**Created**: 2026-01-31 +**Status**: Draft +**Input**: Consolidate Managed Tenant onboarding and routing into a single admin “front door”, remove tenant-in-tenant patterns, and standardize RBAC UX semantics for Managed Tenant flows. + +## Clarifications + +### Session 2026-01-31 + +- Q: Should `tenant_managed_tenants.open` be a separate capability? → A: No. “Open” is allowed whenever `tenant_managed_tenants.view` is allowed. +- Q: What is the canonical destination for “Open” (for an active managed tenant) in v1? → A: A stable tenantless landing page in the admin area (e.g. `/admin/managed-tenants/current`) that shows the selected managed tenant, with the selection stored in session. +- Q: Where should the “current managed tenant” selection be stored in v1? → A: Session-only. +- Q: What should be the canonical onboarding URL/path in v1? → A: `/admin/managed-tenants/onboarding`. +- Q: For archived/deactivated tenants, should “View” always be allowed for viewers? → A: Yes. Archived tenants remain viewable for users with `tenant_managed_tenants.view`. + +## User Scenarios & Testing *(mandatory)* + + + +### User Story 1 - Add managed tenant via single front door (Priority: P1) + +As an admin user, I can add a new managed tenant through one clearly labeled entry point (“Add managed tenant”), so there is no ambiguity about where onboarding begins. + +**Why this priority**: This removes the current confusion and is the prerequisite for a future wizard-based onboarding experience. + +**Independent Test**: Can be fully tested by verifying only one visible “Add managed tenant” entry exists, and legacy direct URLs redirect to the canonical onboarding screen. + +**Acceptance Scenarios**: + +1. **Given** I can access the admin panel, **When** I look for a way to add a managed tenant, **Then** there is exactly one visible entry point labeled “Add managed tenant”. +2. **Given** I open a legacy onboarding URL directly (e.g., the previously used “/admin/new”), **When** the page loads, **Then** I am redirected to the canonical onboarding screen. + +--- + +### User Story 2 - Manage tenants without tenant-in-tenant navigation (Priority: P2) + +As an admin user, I can list, view, and manage managed tenants in a tenantless admin area, so the system does not require an already-selected tenant context to manage tenants. + +**Why this priority**: Eliminates tenant-in-tenant logic and removes a large source of inconsistent access/404 semantics. + +**Independent Test**: Can be fully tested by verifying there is a tenantless managed-tenant listing and that links/routes do not require any “current tenant” parameter. + +**Acceptance Scenarios**: + +1. **Given** I have access to the admin panel, **When** I navigate to the managed tenants list, **Then** the list loads without requiring a pre-selected tenant context. +2. **Given** I open any managed-tenant detail screen via URL, **When** the page loads, **Then** the URL does not include a “current tenant” path prefix. + +--- + +### User Story 3 - Open an active tenant context and handle archived tenants safely (Priority: P3) + +As an admin user, I can “Open” a managed tenant to work within its context, and if a managed tenant is archived/deactivated I get a clear status screen instead of a broken experience. + +**Why this priority**: Prevents confusing 404s and ensures consistent, safe operations as tenants change lifecycle state. + +**Independent Test**: Can be fully tested by verifying “Open” is deterministic for active tenants, and for archived tenants it shows a status screen with only allowed actions. + +**Acceptance Scenarios**: + +1. **Given** a managed tenant is active and I am allowed to open it, **When** I click “Open”, **Then** I land on a stable tenantless screen that clearly indicates which managed tenant is selected. +2. **Given** a managed tenant is archived/deactivated, **When** I click “Open”, **Then** I see a status screen explaining the tenant is archived (not a 404). +3. **Given** a managed tenant is archived/deactivated and I do not have permission to restore or force delete it, **When** I view the status screen, **Then** those actions are not executable. + +--- + +### Edge Cases + +- Attempting to access managed-tenant screens as a non-member of the tenant-plane scope. +- Attempting to execute a mutation (create/edit/archive/restore/delete) without the necessary capability. +- A managed tenant transitions to archived/deactivated while a user has an open browser tab. +- Legacy deep links to the old tenant-scoped managed-tenant routes. +- A user opens the admin panel with no “current managed tenant” selected yet. + +## Requirements *(mandatory)* + +**Constitution alignment (required):** If this feature introduces any Microsoft Graph calls, any write/change behavior, +or any long-running/queued/scheduled work, the spec MUST describe contract registry updates, safety gates +(preview/confirmation/audit), tenant isolation, run observability (`OperationRun` type/identity/visibility), and tests. +If security-relevant DB-only actions intentionally skip `OperationRun`, the spec MUST describe `AuditLog` entries. + +**Constitution alignment (RBAC-UX):** If this feature introduces or changes authorization behavior, the spec MUST: +- state which authorization plane(s) are involved (tenant `/admin/t/{tenant}` vs platform `/system`), +- ensure any cross-plane access is deny-as-not-found (404), +- explicitly define 404 vs 403 semantics: + - non-member / not entitled to tenant scope → 404 (deny-as-not-found) + - member but missing capability → 403 +- describe how authorization is enforced server-side (Gates/Policies) for every mutation/operation-start/credential change, +- reference the canonical capability registry (no raw capability strings; no role-string checks in feature code), +- ensure global search is tenant-scoped and non-member-safe (no hints; inaccessible results treated as 404 semantics), +- ensure destructive-like actions require confirmation (`->requiresConfirmation()`), +- include at least one positive and one negative authorization test, and note any RBAC regression tests added/updated. + +**Constitution alignment (OPS-EX-AUTH-001):** OIDC/SAML login handshakes may perform synchronous outbound HTTP (e.g., token exchange) +on `/auth/*` endpoints without an `OperationRun`. This MUST NOT be used for Monitoring/Operations pages. + +**Constitution alignment (BADGE-001):** If this feature changes status-like badges (status/outcome/severity/risk/availability/boolean), +the spec MUST describe how badge semantics stay centralized (no ad-hoc mappings) and which tests cover any new/changed values. + + + +### Functional Requirements + +#### Scope, Definitions, Non-goals + +- **FR-001 (Scope / Plane)**: The feature MUST apply only to the admin tenant-plane area and MUST NOT change platform/system-plane behavior. +- **FR-002 (Terminology)**: The UI MUST use the term “Managed tenant” (or an equivalent unambiguous label) in places where “Tenant” could be confused with a workspace or platform tenant concept. +- **FR-003 (Non-goals enforced)**: This version MUST NOT introduce a wizard/stepper onboarding UI, a new workspace membership model, or a provider/credentials architecture refactor. + +#### Single Front Door + +- **FR-004 (Canonical onboarding entry)**: The system MUST provide exactly one visible UI entry point to start managed-tenant onboarding (“Add managed tenant”), leading to a canonical onboarding screen. +- **FR-004a (Canonical onboarding path)**: The canonical onboarding screen MUST be reachable at `/admin/managed-tenants/onboarding`. +- **FR-005 (Legacy entry points)**: Legacy onboarding entry points MUST be removed from navigation/buttons, or MUST redirect to the canonical onboarding screen. +- **FR-006 (Direct URL behavior)**: Direct requests to the legacy onboarding URL (previously used “/admin/new”) MUST redirect to the canonical onboarding screen. + +#### Tenantless Managed Tenants Area (No tenant-in-tenant) + +- **FR-007 (Tenantless routes)**: Listing, viewing, and editing managed tenants MUST be available without requiring a “current tenant” context in the URL. +- **FR-008 (No tenant-in-tenant)**: Managed-tenant management MUST NOT appear under a tenant-scoped URL structure (e.g., MUST NOT require “/t/{currentTenant}/…” style path segments). + +#### “Open” vs “Switch” semantics + +- **FR-009 (Open semantics)**: “Open” on a managed tenant MUST mean “enter this managed tenant’s context within the admin area”, not “switch workspaces”. +- **FR-010 (Deterministic destination)**: “Open” MUST take the user to a stable, deterministic destination that clearly indicates the selected managed tenant. +- **FR-011 (No tenant-in-tenant link generation)**: Links used for “Open” MUST NOT rely on a tenant-scoped routing prefix. +- **FR-011a (Open authorization)**: “Open” MUST be authorized by `tenant_managed_tenants.view` in v1 (no separate “open” capability). +- **FR-011b (Open destination)**: In v1, “Open” MUST navigate to a stable tenantless destination in the admin area (e.g. `/admin/managed-tenants/current`), using a session-based “current managed tenant” selection. +- **FR-011c (Selection storage)**: In v1, the “current managed tenant” selection MUST be stored in server-side session (no required DB persistence). + +#### Archived / Deactivated Managed Tenants UX + +- **FR-012 (Archived view access)**: Archived/deactivated managed tenants MUST remain viewable (read-only) for users authorized by `tenant_managed_tenants.view`. +- **FR-012a (No 404 for viewers)**: Archived/deactivated managed tenants MUST NOT present a “not found” experience solely due to being archived/deactivated when the user is authorized to view managed tenants. +- **FR-013 (Archived open behavior)**: “Open” on an archived/deactivated managed tenant MUST NOT result in a “not found” experience; it MUST show a dedicated status screen explaining the tenant is archived/deactivated. +- **FR-014 (Archived actions)**: The archived/deactivated status screen MUST present only actions that are allowed for the current user (e.g., restore, force delete), and MUST prevent execution when not allowed. + +#### RBAC UX and Enforcement + +- **FR-015 (404 vs 403 semantics)**: Authorization behavior MUST follow these rules: + - Non-member / not entitled to tenant-plane scope → treated as “not found” in user experience. + - Member but missing capability → forbidden (action visible but disabled where appropriate; execution prevented). +- **FR-016 (Consistent UI affordances)**: In managed-tenant flows, actions MUST consistently follow these UX rules: + - Non-member: action not shown and not executable. + - Member without capability: action visible but disabled with an explanatory tooltip; not executable. + - Member with capability: action enabled. +- **FR-017 (Server-side defense-in-depth)**: All mutations and operation-start actions in the managed-tenant area MUST be rejected server-side when the user lacks authorization. + +#### Capabilities (Canonical) + +- **FR-018 (Capability registry)**: Managed-tenant functionality MUST be controlled via canonical capabilities (no ad-hoc permission checks). +- **FR-019 (Minimal capabilities set)**: The system MUST define, at minimum, the following capabilities (names are canonical): + - `tenant_managed_tenants.view` + - `tenant_managed_tenants.create` + - `tenant_managed_tenants.manage` + - `tenant_managed_tenants.archive` + - `tenant_managed_tenants.restore` + - `tenant_managed_tenants.force_delete` +- **FR-020 (Default role mapping)**: Default role-to-capability mapping MUST align with: + - Owner/Manager: all managed-tenant capabilities. + - Operator: view (includes “Open”) and tenant-context operations where permitted; not create/manage/archive/force delete. + - Readonly: view only. + +#### Backwards Compatibility + +- **FR-021 (Redirect compatibility)**: Legacy managed-tenant entry points and legacy deep links MUST redirect to the new tenantless managed-tenant area when reachable. +- **FR-022 (No data loss)**: The feature MUST NOT delete or irreversibly modify existing managed-tenant data. + +#### Acceptance Criteria Summary + +- Exactly one visible “Add managed tenant” entry exists in the admin UI. +- Direct requests to the legacy onboarding URL redirect to the canonical onboarding screen. +- Managed-tenant management is available without any “current tenant” path prefix. +- “Open” leads to a stable tenant-context destination for active managed tenants. +- “Open” for archived/deactivated managed tenants shows a dedicated status screen (not “not found”). +- Authorization outcomes match the defined 404-vs-403 semantics and actions are never executable without the required capability. +- The canonical managed-tenant capabilities exist and role mapping matches the default expectations. +- No managed-tenant data is deleted or irreversibly changed by this feature. + +#### Assumptions & Dependencies + +- A managed tenant entity already exists with a lifecycle indicator (active vs archived/deactivated) that can be used to drive UX decisions. +- The admin interface can represent a “current managed tenant” selection (even if it is not persisted long-term in v1). +- In v1, the selection is session-only (not stored in the database). +- A canonical capability registry exists (or can be extended) to hold the managed-tenant capabilities. +- Legacy deep links may exist in bookmarks and documentation and therefore must remain reachable via redirects. + +### Key Entities *(include if feature involves data)* + +- **Workspace (v1 minimal)**: An organizational container in the admin interface used to structure managed-tenant management. In v1 it is a routing/UI concept and does not introduce a new membership model. +- **Managed Tenant**: A Microsoft Entra/Intune tenant managed by the product, including identity, consent/connection state, and lifecycle state (active vs archived/deactivated). +- **Tenant Context (admin)**: The “current selection” of a managed tenant that determines what data/actions the admin interface displays. +- **Capability**: A permission unit used to allow/deny actions and UI affordances for managed-tenant flows. + +## Success Criteria *(mandatory)* + +### Measurable Outcomes + +- **SC-001 (Single entry point)**: 100% of visible “add managed tenant” journeys originate from the single canonical entry point (no second visible onboarding CTA in the admin UI). +- **SC-002 (No tenant-in-tenant)**: 0 managed-tenant CRUD routes require a “current tenant” path prefix. +- **SC-003 (Archived UX)**: 100% of attempts to “Open” an archived/deactivated managed tenant result in a defined status screen (never a “not found” experience for authorized viewers). +- **SC-004 (RBAC semantics)**: For managed-tenant flows, authorization outcomes are consistent and testable: non-members receive “not found” experience, members without capability are blocked from execution. +- **SC-005 (Task completion)**: A user with the appropriate capability can start managed-tenant onboarding and reach the onboarding screen successfully on the first attempt in under 30 seconds. diff --git a/specs/068-workspace-foundation-v1/tasks.md b/specs/068-workspace-foundation-v1/tasks.md new file mode 100644 index 0000000..2c3f97c --- /dev/null +++ b/specs/068-workspace-foundation-v1/tasks.md @@ -0,0 +1,174 @@ +--- + +description: "Task list for Workspace Foundation & Managed Tenant Onboarding Unification (v1)" +--- + +# Tasks: Workspace Foundation & Managed Tenant Onboarding Unification (v1) + +**Input**: Design documents from `/specs/068-workspace-foundation-v1/` +**Prerequisites**: plan.md (required), spec.md (required) + +**Tests**: REQUIRED (Pest) — this feature changes runtime routing + authorization UX. +**Operations**: No new long-running/remote/queued/scheduled work expected. +**RBAC**: MUST preserve semantics: +- non-member / not entitled to tenant scope → 404 (deny-as-not-found) +- member but missing capability → 403 + +## Format: `[ID] [P?] [Story] Description with file path` + +- **[P]**: Can run in parallel (different files, no dependencies) +- **[US#]**: Which user story this task belongs to + +--- + +## Phase 1: Setup (Shared Infrastructure) + +**Purpose**: Confirm local tooling and repo structure for safe iteration. + +- [ ] T001 Verify Sail app boots and admin routes resolve using docker-compose.yml and routes/web.php +- [ ] T002 [P] Identify existing managed-tenant CRUD entry points to de-duplicate using app/Filament/Resources/TenantResource.php and app/Filament/Resources/TenantResource/Pages/ListTenants.php + +--- + +## Phase 2: Foundational (Blocking Prerequisites) + +**Purpose**: RBAC capability primitives and shared context helpers needed by all user stories. + +- [ ] T003 Add managed-tenant capability constants to app/Support/Auth/Capabilities.php +- [ ] T004 Update default role-to-capability mapping for managed-tenant capabilities in app/Services/Auth/RoleCapabilityMap.php +- [ ] T005 [P] Ensure Gate registration picks up new capabilities (and add regression assertions if needed) in app/Providers/AuthServiceProvider.php +- [ ] T006 [P] Add/extend capability registry tests for managed-tenant capabilities in tests/Unit/Auth/CapabilitiesRegistryTest.php +- [ ] T007 [P] Add/extend “unknown capability” guard coverage for managed-tenant capabilities usage in tests/Unit/Auth/UnknownCapabilityGuardTest.php +- [ ] T008 [P] Add/extend UI enforcement unit coverage for managed-tenant actions (disabled vs hidden vs executable) in tests/Unit/Support/Rbac/UiEnforcementTest.php + +**Checkpoint**: Capability strings exist, role mapping covers them, and unit tests enforce the registry. + +--- + +## Phase 3: User Story 1 — Add managed tenant via single front door (Priority: P1) 🎯 MVP + +**Goal**: Exactly one visible “Add managed tenant” entry exists, and legacy `/admin/new` redirects to the canonical onboarding page. + +**Independent Test**: +- Visiting `/admin/new` redirects to `/admin/managed-tenants/onboarding`. +- The managed-tenant list shows a single “Add managed tenant” entry point. + +### Tests for User Story 1 + +- [ ] T009 [P] [US1] Add feature test for legacy redirect `/admin/new` → `/admin/managed-tenants/onboarding` in tests/Feature/ManagedTenants/OnboardingRedirectTest.php +- [ ] T010 [P] [US1] Add feature test that onboarding page is reachable for authorized users in tests/Feature/ManagedTenants/OnboardingPageTest.php +- [ ] T011 [P] [US1] Add feature test ensuring the tenants list exposes only one onboarding CTA in tests/Feature/ManagedTenants/SingleEntryPointTest.php + +### Implementation for User Story 1 + +- [ ] T012 [US1] Create tenantless onboarding Filament page class in app/Filament/Pages/ManagedTenants/Onboarding.php +- [ ] T013 [P] [US1] Create onboarding page Blade view in resources/views/filament/pages/managed-tenants/onboarding.blade.php +- [ ] T014 [US1] Register canonical onboarding route `/admin/managed-tenants/onboarding` via panel authenticated routes in app/Providers/Filament/AdminPanelProvider.php +- [ ] T015 [US1] Register legacy redirect `/admin/new` → canonical onboarding in app/Providers/Filament/AdminPanelProvider.php +- [ ] T016 [US1] Update tenants list header action to a single labeled CTA (“Add managed tenant”) and ensure it links to canonical onboarding in app/Filament/Resources/TenantResource/Pages/ListTenants.php +- [ ] T017 [US1] Redirect the resource create route (if still reachable) to canonical onboarding to avoid a second onboarding entry point in app/Filament/Resources/TenantResource/Pages/CreateTenant.php + +**Checkpoint**: US1 complete — one front door, legacy redirect works, tests pass. + +--- + +## Phase 4: User Story 2 — Manage tenants without tenant-in-tenant navigation (Priority: P2) + +**Goal**: Managed-tenant list/view/edit screens are tenantless (no `/admin/t/{tenant}/...` required). + +**Independent Test**: +- Managed-tenant list loads without a tenant route prefix. +- Managed-tenant view/edit URLs are tenantless. + +### Tests for User Story 2 + +- [ ] T018 [P] [US2] Add feature test that managed-tenant list route is tenantless (no `/t/` prefix) in tests/Feature/ManagedTenants/TenantlessRoutesTest.php +- [ ] T019 [P] [US2] Add feature test that managed-tenant view route is tenantless (no `/t/` prefix) in tests/Feature/ManagedTenants/TenantlessRoutesTest.php +- [ ] T020 [P] [US2] Add feature test that managed-tenant edit route is tenantless (no `/t/` prefix) in tests/Feature/ManagedTenants/TenantlessRoutesTest.php + +### Implementation for User Story 2 + +- [ ] T021 [US2] Confirm resource is tenantless-scoped and keep it that way (`$isScopedToTenant = false`) in app/Filament/Resources/TenantResource.php +- [ ] T022 [US2] Ensure navigation label/grouping uses “Managed tenants” terminology in app/Filament/Resources/TenantResource.php +- [ ] T023 [US2] Ensure direct URL access to view/edit enforces RBAC-UX (non-member → 404, member missing capability → 403) in app/Filament/Resources/TenantResource.php +- [ ] T023a [P] [US2] Add feature test: member without `tenant_managed_tenants.manage` receives 403 when attempting to access the managed-tenant edit page in tests/Feature/ManagedTenants/AuthorizationSemanticsTest.php + +**Checkpoint**: US2 complete — tenantless management routes and consistent auth semantics. + +--- + +## Phase 5: User Story 3 — Open an active tenant context and handle archived tenants safely (Priority: P3) + +**Goal**: “Open” works for active tenants via session-only selection, and archived tenants show a status screen. + +**Independent Test**: +- Active tenant “Open” stores selection in session and lands on a deterministic page that shows the selected tenant. +- Archived tenant “Open” shows a status page (not 404) for viewers. +- Restore/force delete actions require confirmation and are authorization-guarded. + +### Tests for User Story 3 + +- [ ] T024 [P] [US3] Add feature test: “Open” on active tenant sets session selection and redirects deterministically in tests/Feature/ManagedTenants/OpenActiveTenantTest.php +- [ ] T025 [P] [US3] Add feature test: “Open” on archived tenant shows status page (not 404) in tests/Feature/ManagedTenants/OpenArchivedTenantTest.php +- [ ] T026 [P] [US3] Add feature test: archived status page hides or disables restore/force-delete when unauthorized in tests/Feature/ManagedTenants/ArchivedActionsAuthorizationTest.php +- [ ] T027 [P] [US3] Add feature test: restore/force-delete require confirmation and are server-side blocked when unauthorized in tests/Feature/ManagedTenants/ArchivedActionsAuthorizationTest.php + +### Implementation for User Story 3 + +- [ ] T028 [P] [US3] Implement session-backed managed-tenant context helper (get/set/clear) in app/Support/ManagedTenants/ManagedTenantContext.php +- [ ] T029 [US3] Create deterministic tenantless “current managed tenant” landing page in app/Filament/Pages/ManagedTenants/Current.php +- [ ] T030 [P] [US3] Create landing page Blade view showing selected tenant identity in resources/views/filament/pages/managed-tenants/current.blade.php +- [ ] T031 [US3] Create archived status Filament page in app/Filament/Pages/ManagedTenants/ArchivedStatus.php +- [ ] T032 [P] [US3] Create archived status Blade view in resources/views/filament/pages/managed-tenants/archived-status.blade.php +- [ ] T032a [US3] Register tenantless page routes for “current” and “archived status” in app/Providers/Filament/AdminPanelProvider.php (ensure paths match spec: `/admin/managed-tenants/current` and `/admin/managed-tenants/archived`) +- [ ] T033 [US3] Add “Open” table action on managed-tenant list, authorized by `tenant_managed_tenants.view`, with archived handling in app/Filament/Resources/TenantResource.php +- [ ] T034 [US3] Add “Open” action on the managed-tenant view page (if present) with same behavior in app/Filament/Resources/TenantResource/Pages/ViewTenant.php +- [ ] T035 [US3] Add restore + force-delete actions on archived status page with `->action(...)` + `->requiresConfirmation()` + server-side auth checks in app/Filament/Pages/ManagedTenants/ArchivedStatus.php + +**Checkpoint**: US3 complete — “Open” is deterministic for active tenants and safe/clear for archived tenants. + +--- + +## Phase 6: Polish & Cross-Cutting Concerns + +**Purpose**: Hardening, consistency, and developer ergonomics. + +- [ ] T036 [P] Ensure all destructive-like actions use `->action(...)` + `->requiresConfirmation()` consistently in app/Filament/Resources/TenantResource.php +- [ ] T037 [P] Run Pint on changed files to match repo style in composer.json (via `vendor/bin/sail bin pint --dirty`) +- [ ] T038 Run targeted Pest suite for this feature in tests/Feature/ManagedTenants/ + +--- + +## Dependencies & Execution Order + +- Phase 1 (Setup) → Phase 2 (Foundational) → US1 (MVP) → US2 → US3 → Polish + +### User Story Dependencies + +- US1 depends on Phase 2 (capabilities available for authorization checks). +- US2 depends on Phase 2; can be started after US1, but is logically independent. +- US3 depends on Phase 2 and benefits from US2 being in place (tenantless navigation). + +--- + +## Parallel Execution Examples + +### After Foundational Phase + +- [P] tasks in Phase 2 can be split across registry/mapping/tests. +- US1 tests (T009–T011) can be written in parallel. +- US3 page/view creation tasks (T029–T032) can be done in parallel with the context helper (T028). + +--- + +## Implementation Strategy + +### MVP Scope (recommended) + +- Complete Phase 1 + Phase 2 + US1. +- Validate only US1 acceptance scenarios and ship. + +### Incremental Delivery + +- Add US2 next (tenantless route guarantees). +- Add US3 last (session context + archived safe UX).