TenantAtlas/specs/089-provider-connections-tenantless-ui/tasks.md
ahmido fb4de17c63 feat(spec-089): provider connections tenantless UI (#107)
Implements Spec 089: moves Provider Connections to canonical tenantless route under `/admin/provider-connections`, enforces 404/403 semantics (workspace/tenant membership vs capability), adds tenant transparency (tenant column + filter + deep links), adds legacy redirects for old tenant-scoped URLs without leaking Location for 404 cases, and adds regression test coverage (RBAC semantics, filters, UI enforcement tooltips, Microsoft-only MVP scope, navigation placement).

Notes:
- Filament v5 / Livewire v4 compatible.
- Global search remains disabled for Provider Connections.
- Destructive/manage actions require confirmation and are policy-gated.

Tests:
- `vendor/bin/sail artisan test --compact tests/Feature/ProviderConnections`

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #107
2026-02-12 16:35:13 +00:00

162 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Tasks: Provider Connections (Tenantless UI + Tenant Transparency)
**Input**: Design documents from `specs/089-provider-connections-tenantless-ui/`
**Prerequisites**: plan.md (required), spec.md (required), research.md, data-model.md, contracts/
**Tests**: Required (Pest) — this feature changes runtime auth + routing.
---
## Phase 1: Setup (Shared Infrastructure)
- [X] T001 Confirm spec artifacts present in specs/089-provider-connections-tenantless-ui/{spec,plan,research,data-model,quickstart,tasks}.md
- [X] T002 [P] Validate existing provider capabilities exist in app/Support/Auth/Capabilities.php (PROVIDER_VIEW/PROVIDER_MANAGE/PROVIDER_RUN)
- [X] T003 [P] Inventory existing Provider Connections routes/actions and update the UI Action Matrix in specs/089-provider-connections-tenantless-ui/spec.md (anchor to app/Filament/Resources/ProviderConnectionResource.php)
---
## Phase 2: Foundational (Blocking Prerequisites)
- [X] T004 Define tenant-context default filter precedence contract for Provider Connections (query `tenant_id` overrides session TenantContext) in app/Filament/Resources/ProviderConnectionResource.php
- [X] T005 Implement JOIN-based tenant-membership scoping query helper for Provider Connections in app/Filament/Resources/ProviderConnectionResource.php (no large in-memory tenant-id lists)
- [X] T006 Ensure non-workspace member access is deny-as-not-found (404) for Provider Connections surfaces via existing middleware/policy wiring (verify and adjust in app/Policies/ProviderConnectionPolicy.php and panel middleware if needed)
- [X] T007 Create baseline authorization regression tests for 404 vs 403 semantics in tests/Feature/ProviderConnections/AuthorizationSemanticsTest.php
**Checkpoint**: Foundation ready (tenant resolution, scoping approach, baseline auth tests).
---
## Phase 3: User Story 1 — Workspace-weite Übersicht (Priority: P1) 🎯 MVP
**Goal**: Canonical tenantless route + central navigation placement + tenant transparency on list with safe scoping and default filtering.
**Independent Test**: Workspace member sees only entitled tenant rows at `/admin/provider-connections`, default filter respects TenantContext, `?tenant_id=` overrides, non-workspace member gets 404.
### Tests (write first)
- [X] T008 [P] [US1] Add feature test for canonical list route 404 for non-workspace member in tests/Feature/ProviderConnections/TenantlessListRouteTest.php
- [X] T009 [P] [US1] Add feature test for scoping: member of Tenant A not Tenant B sees only A rows in tests/Feature/ProviderConnections/TenantlessListScopingTest.php
- [X] T010 [P] [US1] Add feature test for `tenant_id` query override (authorized tenant shows rows; unauthorized tenant shows 0 rows) in tests/Feature/ProviderConnections/TenantFilterOverrideTest.php
### Implementation
- [X] T011 [US1] Change canonical Filament resource slug to tenantless in app/Filament/Resources/ProviderConnectionResource.php (from `tenants/{tenant}/provider-connections` to `provider-connections`)
- [X] T012 [US1] Update Provider Connections navigation placement in app/Filament/Resources/ProviderConnectionResource.php (group: `Settings`, subgroup: `Integrations`, label: `Provider Connections`)
- [X] T013 [US1] Update ProviderConnectionResource::getUrl behavior in app/Filament/Resources/ProviderConnectionResource.php to stop inferring `{tenant}` path params and instead support tenant filter via query string
- [X] T014 [US1] Update ProviderConnectionResource::getEloquentQuery() in app/Filament/Resources/ProviderConnectionResource.php to allow tenantless list + record access while enforcing workspace + tenant membership scoping at query time
- [X] T015 [US1] Update list query scoping in app/Filament/Resources/ProviderConnectionResource.php to: workspace-scope + membership join + optional tenant filter (`tenant_id` query > TenantContext default)
- [X] T016 [US1] Add required tenant transparency columns + filters in app/Filament/Resources/ProviderConnectionResource.php (Tenant column with deep link to Tenant view + Tenant filter)
- [X] T017 [US1] Add required list columns for last error reason/message in app/Filament/Resources/ProviderConnectionResource.php (reason code + truncated message, sanitized)
- [X] T018 [US1] Ensure list has a clear inspection affordance and action-surface contract compliance in app/Filament/Resources/ProviderConnectionResource.php (prefer `recordUrl()` clickable rows; keep max 2 visible row actions)
- [X] T019 [US1] Add meaningful empty state + CTA behavior to app/Filament/Resources/ProviderConnectionResource/Pages/ListProviderConnections.php
### Legacy redirect
- [X] T020 [US1] Add legacy redirects for workspace-managed tenant routes in routes/web.php (302 only for entitled members; otherwise 404; no Location leaks): `/admin/tenants/{tenant:external_id}/provider-connections``/admin/provider-connections?tenant_id={tenant_external_id}`, `/admin/tenants/{tenant:external_id}/provider-connections/create``/admin/provider-connections/create?tenant_id={tenant_external_id}`, `/admin/tenants/{tenant:external_id}/provider-connections/{record}/edit``/admin/provider-connections/{record}/edit?tenant_id={tenant_external_id}`
- [X] T021 [P] [US1] Add legacy redirect tests in tests/Feature/ProviderConnections/LegacyRedirectTest.php (302 for entitled; 404 for non-workspace/non-tenant members; assert no Location header for 404 cases; assert `/admin/t/{tenant_external_id}/provider-connections` remains 404 and does not redirect)
**Checkpoint**: US1 delivers canonical tenantless list + safe scoping + redirect.
---
## Phase 4: User Story 2 — Sicherer Detail-/Edit-Zugriff ohne Secrets (Priority: P2)
**Goal**: Secure view/edit + actions gated by capability; non-member 404; member missing capability 403; no plaintext secrets.
**Independent Test**: Direct record access behaves as spec (404/403), manage actions are confirmed + audited, run actions create OperationRun, secrets never displayed.
### Tests (write first)
- [X] T022 [P] [US2] Add feature test: non-tenant member direct record access is 404 in tests/Feature/ProviderConnections/RecordAccessNotFoundTest.php
- [X] T023 [P] [US2] Add feature test: tenant member missing Capabilities::PROVIDER_VIEW gets 403 for list/detail in tests/Feature/ProviderConnections/CapabilityForbiddenTest.php (no raw capability strings)
- [X] T024 [P] [US2] Add feature test: tenant member missing Capabilities::PROVIDER_MANAGE cannot mutate (403) in tests/Feature/ProviderConnections/ManageCapabilityEnforcementTest.php (no raw capability strings)
### Implementation
- [X] T025 [US2] Add a Provider Connection View page (required for “detail” semantics) in app/Filament/Resources/ProviderConnectionResource/Pages/ViewProviderConnection.php and register it in app/Filament/Resources/ProviderConnectionResource.php getPages()
- [X] T026 [US2] Update record routes to tenantless paths in app/Filament/Resources/ProviderConnectionResource.php and related Pages/* so record URLs no longer depend on `{tenant}`
- [X] T027 [US2] Update authorization semantics (404 for non-members; 403 for missing capability; viewAny/view=Capabilities::PROVIDER_VIEW; create/update/delete=Capabilities::PROVIDER_MANAGE) in app/Policies/ProviderConnectionPolicy.php
- [X] T028 [US2] Update Edit page tenant resolution to prefer records tenant (not route tenant) in app/Filament/Resources/ProviderConnectionResource/Pages/EditProviderConnection.php
- [X] T029 [US2] Update Create page to require explicit tenant selection (query `tenant_id` or context default) in app/Filament/Resources/ProviderConnectionResource/Pages/CreateProviderConnection.php (abort 404 if no entitled tenant can be resolved)
- [X] T030 [US2] Ensure all destructive-like/manage actions require confirmation in app/Filament/Resources/ProviderConnectionResource.php and app/Filament/Resources/ProviderConnectionResource/Pages/EditProviderConnection.php (enable/disable, set default, credential updates)
- [X] T031 [US2] Ensure manage actions write AuditLog using the correct logger (tenant/workspace as appropriate) and do not include secrets in context (review and adjust in app/Filament/Resources/ProviderConnectionResource.php and Pages/EditProviderConnection.php)
- [X] T032 [US2] Ensure run/health actions create/reuse OperationRun and link to canonical viewer (verify OperationRunLinks tenantless path usage in app/Filament/Resources/ProviderConnectionResource.php and Pages/EditProviderConnection.php)
- [X] T033 [US2] Ensure UI never renders plaintext secrets and provides no secret copy affordances (confirm forms/columns in app/Filament/Resources/ProviderConnectionResource.php)
**Checkpoint**: US2 secures detail/edit surfaces + action gating + confirmations.
---
## Phase 5: User Story 3 — Tenant-Detailseite zeigt effektiven Provider-State + Deep Link (Priority: P3)
**Goal**: Tenant view shows effective default provider connection state and links to tenant-filtered canonical list.
**Independent Test**: Tenant view displays default connection summary and CTA to `/admin/provider-connections?tenant_id=<tenant>`.
### Tests (write first)
- [X] T034 [P] [US3] Add feature test asserting tenant view contains CTA URL to canonical provider connections with tenant_id in tests/Feature/Tenants/TenantProviderConnectionsCtaTest.php
### Implementation
- [X] T035 [US3] Update tenant header action URL to tenantless canonical list in app/Filament/Resources/TenantResource/Pages/ViewTenant.php (use `/admin/provider-connections?tenant_id={external_id}` semantics)
- [X] T036 [US3] Add “Provider connection” effective state section to the tenant infolist in app/Filament/Resources/TenantResource.php (display name, status/health, last check; show needs-action state if missing)
- [X] T037 [US3] Add a dedicated infolist entry view for the provider connection state in resources/views/filament/infolists/entries/provider-connection-state.blade.php
**Checkpoint**: US3 completes tenant transparency from tenant detail.
---
## Phase 6: Polish & Cross-Cutting Concerns
- [X] T038 [P] Run targeted test suite for Provider Connections changes: `vendor/bin/sail artisan test --compact tests/Feature/ProviderConnections` (add notes to specs/089-provider-connections-tenantless-ui/quickstart.md if paths differ)
- [X] T039 [P] Run formatting and fix any findings in app/** and tests/** using `vendor/bin/sail bin pint --dirty`
- [X] T040 Review navigation grouping consistency for Settings → Integrations in app/Providers/Filament/AdminPanelProvider.php (ensure Provider Connections appears where spec requires)
- [X] T041 Validate that Provider Connections remains excluded from global search in app/Filament/Resources/ProviderConnectionResource.php
- [X] T042 [P] Add regression test asserting disabled actions render with helper text/tooltip for tenant members missing capability (UI enforcement) in tests/Feature/ProviderConnections/DisabledActionsTooltipTest.php (or add an explicit exemption in specs/089-provider-connections-tenantless-ui/spec.md if not feasible)
- [X] T043 [P] Add regression test asserting required list filters exist and behave (Provider, Status, Health, Default-only) in tests/Feature/ProviderConnections/RequiredFiltersTest.php
- [X] T044 [P] Add regression test asserting MVP provider scope remains Microsoft-only (no non-Microsoft provider options exposed) in tests/Feature/ProviderConnections/MvpProviderScopeTest.php
---
## Dependencies & Execution Order
- Setup (T001T003) → Foundational (T004T007) → US1 (T008T021) → US2 (T022T033) → US3 (T034T037) → Polish (T038T044)
```mermaid
graph TD
P1[Phase 1: Setup] --> P2[Phase 2: Foundational]
P2 --> US1[US1: Tenantless List]
P2 --> US2[US2: Secure View/Edit]
P2 --> US3[US3: Tenant View State]
US1 --> Polish[Phase 6: Polish]
US2 --> Polish
US3 --> Polish
```
## Parallel Execution Examples
### US1
- Run in parallel:
- T008, T009, T010 (tests)
- T020 + T021 (redirect + test) can be done alongside T011T019 once slug decision is finalized
### US2
- Run in parallel:
- T022T024 (tests)
- T025 (View page scaffolding) and T027 (policy fixes) can be developed independently
### US3
- Run in parallel:
- T034 (test) and T037 (Blade entry view) while T036 changes TenantResource infolist
## Implementation Strategy
- MVP = US1 only (canonical tenantless list + safe scoping + legacy redirect).
- Add US2 next (secure detail/edit + action confirmations + audit/run correctness).
- Add US3 last (tenant view effective-state + CTA).