140 lines
6.9 KiB
Markdown
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.
|