## Summary - normalize provider-neutral target-scope and identity contracts across provider connection resolution, operation-start gating, verification reporting, and boundary configuration - align provider connection resource, onboarding, tenant summaries, and operation follow-up on the same shared scope contract while keeping Microsoft-specific profile details in provider-owned metadata - add Spec 281 artifacts and focused feature/browser coverage for the new provider-scope contract - move the tenant dashboard context-chip rail into Filament header widgets so the metadata row renders directly under the page subtitle ## Validation - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Providers/ProviderConnectionTargetScopeNeutralityTest.php tests/Feature/Providers/ProviderIdentityResolutionNeutralityTest.php tests/Feature/Providers/ProviderOperationStartGateTargetScopeContextTest.php tests/Feature/Filament/ProviderConnectionResourceScopeSummaryTest.php tests/Feature/Onboarding/ManagedTenantOnboardingProviderConnectionScopeTest.php tests/Feature/Guards/ProviderConnectionMicrosoftScopeLeakGuardTest.php` - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Browser/Spec281ProviderConnectionScopeSmokeTest.php` - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Dashboard/TenantDashboardProductizationSummaryTest.php` - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Browser/Dashboard/TenantDashboardProductizationSmokeTest.php` - `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent` ## Notes - Filament remains on v5 with Livewire v4-compatible surfaces only. - Provider registration location is unchanged; Laravel 11+ providers stay in `apps/platform/bootstrap/providers.php`. - `ProviderConnectionResource` remains non-globally-searchable and still exposes View/Edit pages. - No new asset registration was added; deploy-time `filament:assets` expectations are unchanged. - No new destructive action path was introduced; existing server authorization and confirmation handling remain in place where applicable. Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #339
232 lines
13 KiB
Markdown
232 lines
13 KiB
Markdown
# Data Model: Provider Connection Scope & Microsoft Profile Extraction
|
|
|
|
**Date**: 2026-05-07
|
|
**Branch**: `281-provider-connection-scope`
|
|
|
|
## Overview
|
|
|
|
This slice introduces no new persistence. It keeps the existing provider-connection, credential, and run records intact and instead standardizes the derived runtime contracts that platform-core seams expose to UI, audit, and provider-operation flows.
|
|
|
|
## Persisted Truth Unchanged
|
|
|
|
- `ProviderConnection` remains the workspace-owned, managed-environment-scoped binding record.
|
|
- `ProviderCredential` remains the optional credential record attached to one `ProviderConnection`.
|
|
- `OperationRun` remains execution truth and keeps its current identity and lifecycle ownership.
|
|
- `config/provider_boundaries.php` remains the single source for provider-owned versus platform-core seam classification.
|
|
- No new table, registry, provider-profile entity, enum family, or taxonomy is introduced.
|
|
|
|
## Derived Runtime Contracts
|
|
|
|
### 1. Provider Connection Record
|
|
|
|
**Persistence**: existing database row
|
|
**Owner**: `ProviderConnection`
|
|
|
|
| Field | Type | Required | Notes |
|
|
|---|---|---|---|
|
|
| `id` | int | yes | Existing record key |
|
|
| `workspace_id` | int | yes | Existing workspace boundary |
|
|
| `managed_environment_id` | int | yes | Existing managed-environment boundary; already the canonical scope anchor |
|
|
| `provider` | string | yes | Current provider key (`microsoft` today) |
|
|
| `display_name` | string | yes | Operator-visible connection label |
|
|
| `connection_type` | enum | yes | Existing `platform` or `dedicated` connection type |
|
|
| `is_default` | bool | yes | Existing default-binding flag |
|
|
| `is_enabled` | bool | yes | Existing enablement flag |
|
|
| `consent_status` | enum | yes | Existing consent state |
|
|
| `verification_status` | enum | yes | Existing verification state |
|
|
| `entra_tenant_id` | string | yes | Existing provider-owned persisted identifier; not the shared contract key after this slice |
|
|
| `metadata` | array | no | Existing legacy-identity and provider-owned metadata |
|
|
|
|
**Rules**:
|
|
|
|
- `managed_environment_id` remains the persisted scope anchor; the stale candidate move is not reopened.
|
|
- `entra_tenant_id` may remain a provider-owned stored value, but platform-core consumers must read the normalized `target_scope` contract instead of exposing this column name as shared truth.
|
|
- `metadata` remains derived/provider-owned detail and must not become a second canonical shared scope contract.
|
|
|
|
### 2. Shared Target Scope Descriptor
|
|
|
|
**Persistence**: derived
|
|
**Owner**: `ProviderConnectionTargetScopeDescriptor`
|
|
|
|
| Field | Type | Required | Notes |
|
|
|---|---|---|---|
|
|
| `provider` | string | yes | Shared provider key |
|
|
| `scope_kind` | string | yes | Current release supports `tenant` only |
|
|
| `scope_identifier` | string | yes | Neutral scope identifier used across platform-core seams |
|
|
| `scope_display_name` | string | yes | Operator-facing name for the scope |
|
|
| `shared_label` | string | yes | Current shared label, `Target scope` |
|
|
| `shared_help_text` | string | yes | Current shared help text |
|
|
|
|
**Rules**:
|
|
|
|
- This is the canonical shared `target_scope` object for connection resolution, identity resolution, audit metadata, surface summaries, onboarding readiness, and provider-operation start context.
|
|
- Shared `target_scope` payloads must not require `entra_tenant_id` as a top-level key.
|
|
- `scope_kind` remains the current `tenant` constant; this slice does not add new scope-state machinery.
|
|
|
|
### 3. Provider Context
|
|
|
|
**Persistence**: derived
|
|
**Owner**: `ProviderIdentityContextMetadata`
|
|
|
|
| Field | Type | Required | Notes |
|
|
|---|---|---|---|
|
|
| `provider` | string | yes | Provider key for the disclosed context |
|
|
| `details` | list<object> | yes | Ordered provider-owned detail items for profile, consent, audit, or troubleshooting disclosure |
|
|
|
|
**Nested `provider_context.details` item**
|
|
|
|
| Field | Type | Required | Notes |
|
|
|---|---|---|---|
|
|
| `detail_key` | string | yes | Stable provider-owned detail key such as `microsoft_tenant_id`, `admin_consent_url`, `required_permissions_url`, or `portal_domain` |
|
|
| `detail_label` | string | yes | Operator/support label |
|
|
| `detail_value` | string | yes | Current provider-owned value |
|
|
| `visibility` | string | yes | `contextual_only`, `audit_only`, or `troubleshooting_only` |
|
|
|
|
**Rules**:
|
|
|
|
- `provider_context` is the canonical nested provider-owned wrapper carried by shared identity, summary, onboarding, audit, and run-context contracts.
|
|
- Current Microsoft details include `microsoft_tenant_id`, `authority_tenant`, `redirect_uri`, consent links, required-permissions guidance, domains, and portal/profile links.
|
|
- The detail set is intentionally provider-owned and extensible; this slice does not freeze provider context to a three-key catalog.
|
|
- These values may appear in nested provider profile/context blocks or audit metadata, but they do not replace the shared `target_scope` descriptor.
|
|
|
|
### 4. Provider Identity Resolution Contract
|
|
|
|
**Persistence**: derived
|
|
**Owner**: `ProviderIdentityResolution`
|
|
|
|
| Field | Type | Required | Notes |
|
|
|---|---|---|---|
|
|
| `resolved` | bool | yes | Shared resolved/blocked status |
|
|
| `connection_type` | string | yes | Existing connection-type truth |
|
|
| `target_scope` | object | no | Canonical shared `target_scope` descriptor |
|
|
| `effective_client_identity.client_id` | string | no | Neutral shared client identity when resolved |
|
|
| `effective_client_identity.credential_source` | string | yes | Shared credential source (`platform_config`, dedicated source, legacy source) |
|
|
| `blocked_reason.reason_code` | string | no | Existing provider reason code when blocked |
|
|
| `blocked_reason.message` | string | no | Operator-facing blocked reason message |
|
|
| `provider_context` | object | yes | Nested provider-owned context wrapper with `provider` and ordered `details` |
|
|
|
|
**Rules**:
|
|
|
|
- The shared contract center is `target_scope`, effective client identity, credential source, and blocked reason.
|
|
- Legacy `tenantContext` is an implementation concern that should be absorbed into nested provider context or authority handling, not left as the primary shared contract field name.
|
|
- `clientSecret` remains runtime-only and is excluded from surface and audit contracts.
|
|
- Blocked results still return `target_scope` when it can be normalized, so surfaces keep one consistent summary even on failure.
|
|
|
|
### 5. Provider Connection Surface Summary
|
|
|
|
**Persistence**: derived
|
|
**Owner**: `ProviderConnectionSurfaceSummary`
|
|
|
|
| Field | Type | Required | Notes |
|
|
|---|---|---|---|
|
|
| `provider` | string | yes | Shared provider key |
|
|
| `target_scope` | object | yes | Canonical shared descriptor |
|
|
| `consent_state` | string | yes | Existing consent status value |
|
|
| `verification_state` | string | yes | Existing verification status value |
|
|
| `readiness_summary` | string | yes | Existing operator summary |
|
|
| `target_scope_summary` | string | yes | Shared rendered summary for UI surfaces |
|
|
| `provider_context` | object | yes | Nested provider-owned context wrapper with `provider` and ordered `details` |
|
|
| `contextual_identity_line` | string | no | Optional condensed display line derived from nested provider context |
|
|
| `is_enabled` | bool | yes | Existing enablement state for display logic |
|
|
|
|
**Rules**:
|
|
|
|
- `ProviderConnectionResource`, `ManagedTenantOnboardingWizard`, and managed-environment related-context summaries must all reuse this contract.
|
|
- Default-visible content remains summary-first: target scope, readiness, consent, and verification.
|
|
- Provider-specific detail is secondary and derived from nested provider context detail only.
|
|
- Invalid target scope falls back to an explicit review-needed summary instead of leaking raw provider fields back into shared UI.
|
|
|
|
### 6. Onboarding Provider-Connection Readiness View
|
|
|
|
**Persistence**: derived
|
|
**Owner**: `ManagedTenantOnboardingWizard`
|
|
|
|
| Field | Type | Required | Notes |
|
|
|---|---|---|---|
|
|
| `provider_connection_id` | int | yes | Selected or referenced connection |
|
|
| `provider_summary` | object | yes | Reused `ProviderConnectionSurfaceSummary` payload |
|
|
| `permission_overview` | object | yes | Existing required-permissions overview including nested provider-owned `required_permissions_url` guidance |
|
|
|
|
**Rules**:
|
|
|
|
- Onboarding must reuse the same `provider_summary.target_scope` and `target_scope_summary` contract as the provider-connections resource.
|
|
- Supporting verification and permission links remain secondary and stay nested under `permission_overview.required_permissions_url` or equivalent provider-owned guidance fields.
|
|
- No onboarding-only target-scope wording or fallback structure is introduced.
|
|
|
|
### 7. Provider Operation Run Context
|
|
|
|
**Persistence**: derived run context in existing `OperationRun` rows
|
|
**Owner**: `ProviderOperationStartGate`
|
|
|
|
| Field | Type | Required | Notes |
|
|
|---|---|---|---|
|
|
| `execution_authority_mode` | string | yes | Existing execution-authority contract |
|
|
| `required_capability` | string | no | Existing capability contract |
|
|
| `provider` | string | yes | Shared provider key |
|
|
| `module` | string | yes | Existing provider-operation module |
|
|
| `provider_binding` | object | yes | Existing registry binding metadata |
|
|
| `provider_connection_id` | int | no | Existing binding identity when present |
|
|
| `target_scope` | object | yes | Canonical shared descriptor |
|
|
| `provider_context` | object | no | Nested provider-owned details when required for follow-up |
|
|
|
|
**Rules**:
|
|
|
|
- Started and blocked runs must use the same neutral shared `target_scope` schema.
|
|
- Shared run context must stop writing `target_scope.entra_tenant_id` as the primary contract.
|
|
- Provider-specific fields needed for follow-up or troubleshooting move to nested `provider_context` or equivalent provider-owned metadata.
|
|
- Current dedupe identity remains `provider_connection_id` plus existing identity inputs; this slice does not redefine run identity semantics.
|
|
|
|
### 8. Credential Scope Validation Invariant
|
|
|
|
**Persistence**: derived runtime validation only
|
|
**Owner**: `CredentialManager`
|
|
|
|
| Field | Type | Required | Notes |
|
|
|---|---|---|---|
|
|
| `provider_connection_id` | int | yes | Existing credential owner |
|
|
| `payload.client_id` | string | yes | Existing credential field |
|
|
| `payload.client_secret` | string | yes | Existing credential field |
|
|
| `payload.scope_assertion` | mixed | no | Existing payload assertion if present today |
|
|
| `normalized_target_scope_identifier` | string | yes | Derived from canonical shared descriptor |
|
|
|
|
**Rules**:
|
|
|
|
- No provider-credential schema change is introduced.
|
|
- If a payload carries a scope assertion, validation should compare it to the normalized target-scope identifier rather than leaking raw provider-column names into the platform-core error contract.
|
|
- Neutral mismatch wording belongs in the shared seam; provider-specific values remain nested metadata only.
|
|
|
|
### 9. Provider Boundary Review Record
|
|
|
|
**Persistence**: config-driven
|
|
**Owner**: `config/provider_boundaries.php`
|
|
|
|
| Field | Type | Required | Notes |
|
|
|---|---|---|---|
|
|
| `seam_key` | string | yes | Boundary seam identifier |
|
|
| `owner` | string | yes | `platform_core` or `provider_owned` |
|
|
| `neutral_terms` | list<string> | yes | Shared vocabulary allowed at the seam |
|
|
| `retained_provider_semantics` | list<string> | yes | Documented provider-specific exceptions |
|
|
| `follow_up_action` | string | yes | Existing review follow-up rule |
|
|
|
|
**Rules**:
|
|
|
|
- `provider.connection_resolution`, `provider.identity_resolution`, and `provider.operation_start_gate` remain platform-core seams and must carry only the documented provider-specific exceptions.
|
|
- `provider.gateway_runtime` remains provider-owned.
|
|
- `config/provider_boundaries.php` stays the single review record for this classification; the slice does not create a new taxonomy.
|
|
|
|
## Contract Flow
|
|
|
|
1. `ProviderConnection` is loaded inside its current workspace plus managed-environment scope.
|
|
2. `ProviderConnectionTargetScopeNormalizer` derives the canonical shared `target_scope` descriptor and the nested `provider_context` wrapper.
|
|
3. `ProviderConnectionResolver` validates enablement, consent, and supported binding using the normalized `target_scope` contract.
|
|
4. `ProviderIdentityResolver` emits one `ProviderIdentityResolution` result centered on target scope, effective client identity, and nested provider context.
|
|
5. `ProviderConnectionSurfaceSummary` renders the same summary contract for the provider-connections resource, onboarding, and related-context surfaces.
|
|
6. `ProviderOperationStartGate` records the same neutral `target_scope` contract into `OperationRun` context while nesting any provider-only detail under provider context.
|
|
7. Provider-owned consumers such as admin-consent URL shaping and Graph runtime mapping read the nested provider context they need without re-promoting those values into shared platform-core vocabulary.
|
|
|
|
## Deferred Boundaries
|
|
|
|
- No new provider implementation is introduced.
|
|
- No provider-profile table, registry, package engine, or artifact taxonomy is introduced.
|
|
- No routing work from Spec `280` is absorbed.
|
|
- No RBAC redesign, copy-neutralization, or cutover quality-gate work from Specs `282` through `287` is introduced. |