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
12 KiB
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)
- T001 Confirm spec artifacts present in specs/089-provider-connections-tenantless-ui/{spec,plan,research,data-model,quickstart,tasks}.md
- T002 [P] Validate existing provider capabilities exist in app/Support/Auth/Capabilities.php (PROVIDER_VIEW/PROVIDER_MANAGE/PROVIDER_RUN)
- 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)
- T004 Define tenant-context default filter precedence contract for Provider Connections (query
tenant_idoverrides session TenantContext) in app/Filament/Resources/ProviderConnectionResource.php - 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)
- 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)
- 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)
- T008 [P] [US1] Add feature test for canonical list route 404 for non-workspace member in tests/Feature/ProviderConnections/TenantlessListRouteTest.php
- 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
- T010 [P] [US1] Add feature test for
tenant_idquery override (authorized tenant shows rows; unauthorized tenant shows 0 rows) in tests/Feature/ProviderConnections/TenantFilterOverrideTest.php
Implementation
- T011 [US1] Change canonical Filament resource slug to tenantless in app/Filament/Resources/ProviderConnectionResource.php (from
tenants/{tenant}/provider-connectionstoprovider-connections) - T012 [US1] Update Provider Connections navigation placement in app/Filament/Resources/ProviderConnectionResource.php (group:
Settings, subgroup:Integrations, label:Provider Connections) - 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 - 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
- T015 [US1] Update list query scoping in app/Filament/Resources/ProviderConnectionResource.php to: workspace-scope + membership join + optional tenant filter (
tenant_idquery > TenantContext default) - T016 [US1] Add required tenant transparency columns + filters in app/Filament/Resources/ProviderConnectionResource.php (Tenant column with deep link to Tenant view + Tenant filter)
- T017 [US1] Add required list columns for last error reason/message in app/Filament/Resources/ProviderConnectionResource.php (reason code + truncated message, sanitized)
- 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) - T019 [US1] Add meaningful empty state + CTA behavior to app/Filament/Resources/ProviderConnectionResource/Pages/ListProviderConnections.php
Legacy redirect
- 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} - 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-connectionsremains 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)
- T022 [P] [US2] Add feature test: non-tenant member direct record access is 404 in tests/Feature/ProviderConnections/RecordAccessNotFoundTest.php
- 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)
- 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
- 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()
- 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} - 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
- T028 [US2] Update Edit page tenant resolution to prefer record’s tenant (not route tenant) in app/Filament/Resources/ProviderConnectionResource/Pages/EditProviderConnection.php
- T029 [US2] Update Create page to require explicit tenant selection (query
tenant_idor context default) in app/Filament/Resources/ProviderConnectionResource/Pages/CreateProviderConnection.php (abort 404 if no entitled tenant can be resolved) - 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)
- 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)
- 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)
- 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)
- 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
- 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) - 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)
- 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
-
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) -
T039 [P] Run formatting and fix any findings in app/** and tests/** using
vendor/bin/sail bin pint --dirty -
T040 Review navigation grouping consistency for Settings → Integrations in app/Providers/Filament/AdminPanelProvider.php (ensure Provider Connections appears where spec requires)
-
T041 Validate that Provider Connections remains excluded from global search in app/Filament/Resources/ProviderConnectionResource.php
-
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)
-
T043 [P] Add regression test asserting required list filters exist and behave (Provider, Status, Health, Default-only) in tests/Feature/ProviderConnections/RequiredFiltersTest.php
-
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 (T001–T003) → Foundational (T004–T007) → US1 (T008–T021) → US2 (T022–T033) → US3 (T034–T037) → Polish (T038–T044)
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 T011–T019 once slug decision is finalized
US2
- Run in parallel:
- T022–T024 (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).