# 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.