## 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
13 KiB
Implementation Plan: Platform Provider Identity Standardization
Branch: 137-platform-provider-identity | Date: 2026-03-13 | Spec: specs/137-platform-provider-identity/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:
ProviderConnectionResourcealready has Edit/View pages but global search is disabled, so no new global-search obligation is introduced.TenantResourceremains 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
GraphClientInterfaceand 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.
ProviderConnectionResourceremains 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
OperationRunwhere 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
OperationRunstate transitions are added outsideOperationRunService. - 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)
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)
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
- 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
- Output: specs/137-platform-provider-identity/quickstart.md
- Output: specs/137-platform-provider-identity/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
OperationRunobservability 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 toprovider_connections, and add dedicated credential lifecycle metadata toprovider_credentials, while preserving backward-compatiblestatusandhealth_statussemantics. - Central services: add
PlatformProviderIdentityResolver,ProviderIdentityResolver,AdminConsentUrlFactory,ProviderConnectionClassifier, andProviderConnectionStateProjector. - Runtime cutover: refactor
CredentialManager,ProviderGateway,ProviderConnectionResolver,MicrosoftGraphOptionsResolver, and downstream provider consumers so platform connections use the central identity and dedicated connections useProviderCredentialonly. - 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
OperationRunpattern. - 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.yamlis 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.