## Summary - standardize Microsoft provider connections around explicit platform vs dedicated identity modes - centralize admin-consent URL and runtime identity resolution so platform flows no longer fall back to tenant-local credentials - add migration classification, richer consent and verification state handling, dedicated override management, and focused regression coverage ## Validation - focused repo test coverage was added across provider identity, onboarding, audit, policy, guard, and migration flows - latest explicit passing run in the workspace: `vendor/bin/sail artisan test --compact tests/Feature/AdminConsentCallbackTest.php tests/Feature/Audit/ProviderConnectionConsentAuditTest.php` ## Notes - branch includes the full Spec 137 artifact set under `specs/137-platform-provider-identity/` - target base branch: `dev` Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #166
179 lines
13 KiB
Markdown
179 lines
13 KiB
Markdown
# 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.
|