# 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 **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) ```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.