TenantAtlas/specs/081-provider-connection-cutover/plan.md
ahmido 4db8030f2a Spec 081: Provider connection cutover (#98)
Implements Spec 081 provider-connection cutover.

Highlights:
- Adds provider connection resolution + gating for operations/verification.
- Adds provider credential observer wiring.
- Updates Filament tenant verify flow to block with next-steps when provider connection isn’t ready.
- Adds spec docs under specs/081-provider-connection-cutover/ and extensive Spec081 test coverage.

Tests:
- vendor/bin/sail artisan test --compact tests/Feature/Filament/TenantSetupTest.php
- Focused suites for ProviderConnections/Verification ran during implementation (see local logs).

Co-authored-by: Ahmed Darrazi <ahmeddarrazi@MacBookPro.fritz.box>
Reviewed-on: #98
2026-02-08 11:28:51 +00:00

140 lines
6.9 KiB
Markdown

# Implementation Plan: Provider Connection Full Cutover
**Branch**: `081-provider-connection-cutover` | **Date**: 2026-02-07 | **Spec**: [specs/081-provider-connection-cutover/spec.md](spec.md)
**Input**: Feature specification from `specs/081-provider-connection-cutover/spec.md`
**Note**: This template is filled in by the `/speckit.plan` command. See `.specify/scripts/` for helper scripts.
## Summary
Cut over all provider-facing runtime flows from legacy tenant-stored app credentials (`tenants.app_*`) to a single, deterministic credential source: `ProviderConnection` + `ProviderCredential`.
Key behaviors:
- Runtime provider calls resolve a `ProviderConnection` (default per tenant/provider) and build Graph options via `ProviderGateway`.
- Missing/invalid configuration blocks provider-backed starts but still creates an `OperationRun` with stable `reason_code` + link-only next steps.
- A one-time, idempotent backfill ensures Microsoft default connections exist/are repaired using the decision tree in the spec.
## Technical Context
<!--
ACTION REQUIRED: Replace the content in this section with the technical details
for the project. The structure here is presented in advisory capacity to guide
the iteration process.
-->
**Language/Version**: PHP 8.4.15
**Primary Dependencies**: Laravel 12, Filament v5, Livewire v4, Socialite v5
**Storage**: PostgreSQL (via Laravel Sail)
**Testing**: Pest v4 + PHPUnit v12 (run via `vendor/bin/sail artisan test --compact`)
**Target Platform**: Laravel web application (Sail-first local dev; Dokploy container deploy)
**Project Type**: Web application (Filament admin + queued jobs)
**Performance Goals**: Deterministic provider operations; no remote calls during page render; avoid N+1 patterns in tables/global search
**Constraints**: Secrets must never appear in logs/audits/reports; Graph calls only via `GraphClientInterface` and contract registry; blocked starts must still create observable runs
**Scale/Scope**: Enterprise multi-tenant workspace; provider operations are queued and deduped via `OperationRun`
## Constitution Check
*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
- Inventory-first: PASS (no changes to inventory/snapshot semantics; cutover affects provider auth only)
- Read/write separation: PASS (credential mutations remain confirmed + audited; provider operations remain `OperationRun`-tracked)
- Graph contract path: PASS (provider calls continue via `GraphClientInterface`; no new Graph endpoints introduced by this spec)
- Deterministic capabilities: PASS (no capability derivation changes required; enforce central resolver usage where needed)
- RBAC-UX planes + 404/403 semantics: PASS (provider connection management remains tenant-scoped; non-members 404, members missing capability 403)
- Destructive confirmation standard: PASS (credential rotation/mutations require confirmation; enforced server-side)
- Global search tenant safety: PASS (no new global search surfaces introduced in this spec)
- Tenant isolation: PASS (provider connections are workspace-owned + tenant-scoped; no cross-tenant shortcuts)
- Run observability: PASS (blocked starts still create runs; Monitoring remains DB-only)
- Automation: PASS (jobs remain queued + idempotent; throttling/backoff policies unchanged)
- Data minimization & safe logging: PASS (explicitly prohibit secrets in logs/audits/reports)
- Badge semantics (BADGE-001): PASS WITH WORK (if `OperationRunOutcome` gains `blocked`, update badge domain + tests)
## Project Structure
### Documentation (this feature)
```text
specs/081-provider-connection-cutover/
├── plan.md # This file (/speckit.plan command output)
├── research.md # Phase 0 output (/speckit.plan command)
├── data-model.md # Phase 1 output (/speckit.plan command)
├── quickstart.md # Phase 1 output (/speckit.plan command)
├── contracts/ # Phase 1 output (/speckit.plan command)
└── tasks.md # Phase 2 output (/speckit.tasks command - NOT created by /speckit.plan)
```
### Source Code (repository root)
<!--
ACTION REQUIRED: Replace the placeholder tree below with the concrete layout
for this feature. Delete unused options and expand the chosen structure with
real paths (e.g., apps/admin, packages/something). The delivered plan must
not include Option labels.
-->
```text
app/
├── Console/Commands/
├── Filament/
│ ├── Pages/
│ └── Resources/
├── Jobs/
├── Models/
├── Policies/
├── Services/
│ ├── Graph/
│ ├── Intune/
│ ├── Inventory/
│ └── Providers/
└── Support/
config/
└── graph_contracts.php
database/
├── factories/
└── migrations/
tests/
├── Feature/
└── Unit/
```
**Structure Decision**: Laravel monolith with Filament admin and queued operations; provider integrations live under `app/Services/Providers/*` with Graph calls routed via `GraphClientInterface` + `config/graph_contracts.php`.
## Complexity Tracking
> **Fill ONLY if Constitution Check has violations that must be justified**
| Violation | Why Needed | Simpler Alternative Rejected Because |
|-----------|------------|-------------------------------------|
| N/A | N/A | N/A |
## Phase 0 — Outline & Research (complete)
- Output: [specs/081-provider-connection-cutover/research.md](research.md)
- Key repo facts captured: existing `ProviderConnection`/`ProviderCredential`, partial unique index for defaults, and identified legacy tenant-credential read hotspots.
## Phase 1 — Design & Contracts (complete)
- Output: [specs/081-provider-connection-cutover/data-model.md](data-model.md)
- Output: `specs/081-provider-connection-cutover/contracts/*`
- Output: `specs/081-provider-connection-cutover/quickstart.md`
### Post-design Constitution Re-check
- PASS: No render-time provider calls are introduced.
- PASS: Provider calls remain behind the Graph contract registry and gateway.
- PASS WITH WORK: Any new `OperationRunOutcome` value requires centralized badge mapping + tests.
## Phase 2 — Implementation Planning (next)
`tasks.md` will be produced by `/speckit.tasks` and should cover, at minimum:
- Runtime cutover: remove/replace all uses of `Tenant::graphOptions()` and `tenants.app_*` in provider-facing services/jobs.
- Resolution rules: default `ProviderConnection` lookup per (tenant, provider), with deterministic error/blocked semantics.
- Backfill command: `tenantpilot:provider-connections:backfill-microsoft-defaults` (idempotent, safe, no duplicates).
- Operations: represent blocked starts as `outcome=blocked` (status remains `completed`), with stable reason codes and link-only next steps.
- Filament UI: remove tenant credential fields and consolidate credential management under provider connections with confirmed actions.
- Regression guards: tests that fail on runtime legacy reads + tests for backfill, blocked runs, and badge mapping.