# Implementation Plan: Platform Provider Identity Standardization

**Branch**: `137-platform-provider-identity` | **Date**: 2026-03-13 | **Spec**: [specs/137-platform-provider-identity/spec.md](spec.md)
**Input**: Feature specification from `specs/137-platform-provider-identity/spec.md`

**Note**: This template is filled in by the `/speckit.plan` command. See `.specify/scripts/` for helper scripts.

## Summary

Standardize Microsoft provider connections around one centrally managed platform app identity while keeping dedicated customer-specific app registrations as an explicitly authorized exception.

The implementation adds an explicit `connection_type` model, splits consent state from verification state, centralizes platform identity resolution and admin-consent URL generation, and updates runtime provider resolution so platform connections no longer depend on per-connection credentials. Existing onboarding, callback, verification, and downstream provider consumers will be refactored to consume the same identity-selection path, while a migration classifier marks legacy connections as platform, dedicated, or review-required without introducing a third runtime mode.

## Technical Context

**Language/Version**: PHP 8.4.15  
**Primary Dependencies**: Laravel 12, Filament v5, Livewire v4, Laravel Sail, Pest v4, PHPUnit v12  
**Storage**: PostgreSQL via Laravel migrations and encrypted model casts  
**Testing**: Pest feature and unit tests, including Livewire component tests run via `vendor/bin/sail artisan test --compact`  
**Target Platform**: Laravel web application with Filament admin panels and queued jobs, deployed in containers  
**Project Type**: Web application  
**Performance Goals**: Consent URL generation and provider connection page rendering remain DB-only and deterministic; remote verification and provider operations remain queued or explicit action-triggered; platform identity resolution is constant-time from config or secret abstraction  
**Constraints**: Platform secrets must never be persisted into tenant-owned rows; Graph calls must continue through `GraphClientInterface` and `config/graph_contracts.php`; platform connections must not silently fall back to tenant-local or dedicated credentials; tenant/workspace non-members must get 404 and members lacking capability must get 403; destructive credential or type mutations require confirmation  
**Scale/Scope**: Cross-cutting provider foundation change touching onboarding, callback, verification, provider operations, audit events, migrations, and regression guards for all Microsoft provider consumers

### Filament v5 Implementation Notes

- **Livewire v4.0+ compliance**: Maintained. All in-scope Filament and onboarding surfaces remain Livewire v4 compatible.
- **Provider registration location**: No new panel is introduced. Existing panel providers remain registered in `bootstrap/providers.php`.
- **Global search rule**: `ProviderConnectionResource` already has Edit/View pages but global search is disabled, so no new global-search obligation is introduced. `TenantResource` remains outside this feature’s global-search scope.
- **Destructive actions**: Dedicated credential delete, credential rotate, and connection-type changes away from dedicated remain destructive-like and must execute through confirmed actions with server-side authorization.
- **Asset strategy**: No new Filament assets are planned. Existing deployment practice still includes `php artisan filament:assets`; this feature does not add global assets or on-demand asset registrations.
- **Testing plan**: Add unit tests for resolver and consent factory behavior, feature or Livewire tests for onboarding and provider connection management, migration-classification tests, authorization tests, and regression guards against legacy credential fallback.

## Constitution Check

*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*

- Inventory-first: PASS. This feature changes provider identity selection, not inventory or snapshot ownership.
- Read/write separation: PASS. Connection creation, connection-type changes, consent initiation, dedicated credential mutations, and migration overrides remain explicit writes with audit coverage and focused tests.
- Graph contract path: PASS. Runtime Graph calls remain behind `GraphClientInterface` and the existing contract registry; no direct endpoint shortcuts are introduced.
- Deterministic capabilities: PASS. Authorization remains tied to the canonical capability registry; no new ad-hoc capability strings are needed.
- RBAC-UX planes + 404/403 semantics: PASS. In-scope routes stay in the tenant/admin plane, cross-plane access remains 404, tenant/workspace non-members remain 404, and members lacking capability remain 403.
- Workspace isolation: PASS. Provider connection management remains workspace-bound and tenant-scoped.
- Destructive confirmation standard: PASS WITH WORK. Dedicated credential deletion, dedicated credential rotation, and explicit connection-type changes must all use `->requiresConfirmation()` and server-side checks.
- Global search tenant safety: PASS. `ProviderConnectionResource` remains non-globally-searchable, so no new tenant-leak surface is introduced.
- Tenant isolation: PASS. All provider reads and writes continue to require the resolved tenant scope.
- Run observability: PASS. The admin consent handshake stays synchronous under the auth exception; verification and provider operations continue using `OperationRun` where they already do.
- Ops-UX 3-surface feedback: PASS. Existing verification runs keep the current queued toast, progress surfaces, and terminal notification pattern.
- Ops-UX lifecycle: PASS. No direct `OperationRun` state transitions are added outside `OperationRunService`.
- Ops-UX summary counts: PASS. No new non-numeric summary payload is planned.
- Ops-UX guards: PASS. Existing operation guards remain, and this feature adds fallback guards for provider identity resolution.
- Ops-UX system runs: PASS. No new system-wide notification fan-out is introduced.
- Automation: PASS. Existing queued verification and provider jobs remain deduped and idempotent.
- Data minimization: PASS. Platform secrets stay centralized; audit, verification, and UI outputs remain redacted.
- Badge semantics (BADGE-001): PASS WITH WORK. New or newly surfaced consent and verification states must use centralized badge rendering and receive regression coverage.
- UI naming (UI-NAMING-001): PASS WITH WORK. Platform connection, Dedicated connection, Grant admin consent, and Run verification again must be consistent across wizard, detail, next-step, and audit surfaces.
- Filament UI Action Surface Contract: PASS WITH WORK. Existing ProviderConnectionResource and onboarding wizard surfaces need form and action updates but remain within the contract.
- Filament UI UX-001: PASS WITH WORK. Create and edit flows must present platform-default onboarding in structured sections and remove naked credential inputs from the standard path.

## Project Structure

### Documentation (this feature)

```text
specs/137-platform-provider-identity/
├── plan.md
├── research.md
├── data-model.md
├── quickstart.md
├── contracts/
│   └── provider-identity.openapi.yaml
└── tasks.md
```

### Source Code (repository root)

```text
app/
├── Filament/
│   ├── Pages/Workspaces/ManagedTenantOnboardingWizard.php
│   └── Resources/
│       ├── ProviderConnectionResource.php
│       ├── ProviderConnectionResource/Pages/
│       └── TenantResource.php
├── Http/Controllers/
│   ├── AdminConsentCallbackController.php
│   └── TenantOnboardingController.php
├── Models/
│   ├── ProviderConnection.php
│   ├── ProviderCredential.php
│   └── Tenant.php
├── Observers/ProviderCredentialObserver.php
├── Services/
│   ├── Intune/
│   ├── Providers/
│   └── Verification/
├── Support/
│   ├── Links/RequiredPermissionsLinks.php
│   ├── Providers/
│   └── Verification/
└── Jobs/ProviderConnectionHealthCheckJob.php

config/
├── graph.php
└── graph_contracts.php

database/
├── factories/
└── migrations/

resources/views/
└── admin-consent-callback.blade.php

tests/
├── Feature/
│   ├── Audit/
│   ├── Guards/
│   ├── Onboarding/
│   └── ProviderConnections/
└── Unit/
    ├── Policies/
    └── Providers/
```

**Structure Decision**: Keep the Laravel monolith structure. Provider identity logic will be centralized under `app/Services/Providers/*`, with Filament and controller surfaces consuming those services instead of reading credential sources directly.

## 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/137-platform-provider-identity/research.md](research.md)
- Resolved the main design choices: string-backed `connection_type`, centralized platform identity resolver, canonical admin-consent builder, binary runtime mode with explicit migration-review metadata, and separate consent versus verification state.
- Confirmed current code hotspots: runtime provider gateway and resolver assume every connection has dedicated credentials, onboarding still collects client ID and secret, and consent URL generation still falls back to legacy tenant fields.

## Phase 1 — Design & Contracts (complete)

- Output: [specs/137-platform-provider-identity/data-model.md](data-model.md)
- Output: [specs/137-platform-provider-identity/quickstart.md](quickstart.md)
- Output: [specs/137-platform-provider-identity/contracts/provider-identity.openapi.yaml](contracts/provider-identity.openapi.yaml)

### Post-design Constitution Re-check

- PASS: Platform identity remains centralized; no tenant-owned secret duplication is introduced.
- PASS: Verification and downstream provider operations continue to use the Graph contract path and existing `OperationRun` observability model.
- PASS WITH WORK: Filament create/edit and onboarding surfaces must be updated to remove standard credential entry while preserving confirmation and stronger authorization for dedicated override flows.
- PASS WITH WORK: New consent and verification statuses require centralized badge rendering and test coverage.

## Phase 2 — Implementation Planning (next)

`tasks.md` will be produced by `/speckit.tasks` and should cover, at minimum:

- Schema migration: add `connection_type`, `consent_status`, consent metadata, `verification_status`, and migration-review metadata to `provider_connections`, and add dedicated credential lifecycle metadata to `provider_credentials`, while preserving backward-compatible `status` and `health_status` semantics.
- Central services: add `PlatformProviderIdentityResolver`, `ProviderIdentityResolver`, `AdminConsentUrlFactory`, `ProviderConnectionClassifier`, and `ProviderConnectionStateProjector`.
- Runtime cutover: refactor `CredentialManager`, `ProviderGateway`, `ProviderConnectionResolver`, `MicrosoftGraphOptionsResolver`, and downstream provider consumers so platform connections use the central identity and dedicated connections use `ProviderCredential` only.
- Consent cutover: remove consent URL generation from tenant-field fallback logic and route all consent surfaces through the canonical factory.
- Onboarding UX: make platform the default connection path, show platform app identity read-only, remove standard credential entry, and gate dedicated override behind stronger authorization.
- Callback and verification: persist explicit connection type, keep consent and verification states separate, and preserve the existing verification `OperationRun` pattern.
- Migration and safeguards: classify existing connections into platform, dedicated, or review-required through an explicit post-migration command or queued backfill, block new standard reads from legacy tenant app fields, and add guard tests against fallback regressions.
- Audit and RBAC: extend auditable events for connection-type changes, consent start and result, consent revocation detection, verification results, dedicated credential lifecycle changes, and migration classification outcomes; enforce stronger dedicated-management authorization; and add positive and negative authorization coverage plus payload-shape assertions.

### Contract Implementation Note

- `contracts/provider-identity.openapi.yaml` is an internal action contract, not a promise of brand-new standalone HTTP controllers for every operation.
- Existing Filament or Livewire action handlers may satisfy the contract as long as they preserve the documented authorization, confirmation, request-shape, audit, and response semantics.
- Implementation should prefer adapting existing authorized surfaces over adding new standalone routes. New transport endpoints should be introduced only if an existing surface cannot faithfully satisfy the contract semantics.

### Deployment Sequencing Note

- Schema migrations for this feature must remain schema-only and must not execute classification or data backfill logic inline.
- Legacy classification and audited backfill must run only after deploy via the explicit classification command or an equivalent queued operational path.
- Release validation must confirm that T042 and T043 execute as post-deploy operational work, not as migration side effects.
