## Summary - introduce the Provider Connection Filament resource (list/create/edit) with DB-only controls, grouped action dropdowns, and badge-driven status/health rendering - wire up the provider foundation stack (migrations, models, policies, providers, operations, badges, and audits) plus the required spec docs/checklists - standardize Inventory Sync notifications so the job no longer writes its own DB rows; terminal notifications now flow exclusively through OperationRunCompleted while the start surface still shows the queued toast ## Testing - ./vendor/bin/sail php ./vendor/bin/pint --dirty - ./vendor/bin/sail artisan test tests/Unit/Badges/ProviderConnectionBadgesTest.php - ./vendor/bin/sail artisan test tests/Feature/ProviderConnections tests/Feature/Filament/ProviderConnectionsDbOnlyTest.php - ./vendor/bin/sail artisan test tests/Feature/Inventory/RunInventorySyncJobTest.php tests/Feature/Inventory/InventorySyncStartSurfaceTest.php Co-authored-by: Ahmed Darrazi <ahmeddarrazi@MacBookPro.fritz.box> Reviewed-on: #73
92 lines
4.6 KiB
Markdown
92 lines
4.6 KiB
Markdown
y# Research: Provider Foundation v1 (Microsoft-first, Security-first)
|
||
|
||
**Branch**: `061-provider-foundation`
|
||
**Date**: 2026-01-24
|
||
**Spec**: `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/061-provider-foundation/spec.md`
|
||
**Plan**: `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/061-provider-foundation/plan.md`
|
||
|
||
## Decisions
|
||
|
||
### D-001 — Keep the Graph contract path as the only Microsoft Graph entry
|
||
|
||
**Decision**: All Microsoft Graph calls remain behind `GraphClientInterface` and are modeled in `config/graph_contracts.php`; provider modules/services must not introduce ad-hoc HTTP clients or hardcoded Graph paths.
|
||
|
||
**Rationale**: This preserves the repo’s constitution (“Single Contract Path to Graph”) and prevents endpoint sprawl. It also reuses the existing retry/backoff/logging behavior already centralized in the Graph client.
|
||
|
||
**Alternatives considered**:
|
||
- Build a new provider-specific HTTP gateway: rejected because it risks bypassing the existing Graph contract + logging path and reintroduces “two Graph clients”.
|
||
- Allow `GraphClientInterface::request()` with hardcoded paths in feature code: rejected because it undermines contract registry governance.
|
||
|
||
---
|
||
|
||
### D-002 — Canonical Microsoft target scope identifier
|
||
|
||
**Decision**: The canonical target scope identifier for Microsoft provider connections is the Entra tenant ID (GUID). Domains may be stored as display labels only.
|
||
|
||
**Rationale**: Tenant IDs are stable and unambiguous; domains can change and multiple domains can exist.
|
||
|
||
**Alternatives considered**:
|
||
- Domain as canonical identifier: rejected due to ambiguity and change risk.
|
||
- Allow either: rejected for v1 to avoid inconsistent locking/routing keys.
|
||
|
||
---
|
||
|
||
### D-003 — Multiple Microsoft connections per Suite Tenant with a required default
|
||
|
||
**Decision**: A Suite Tenant may have multiple Microsoft provider connections (distinct Entra tenant IDs). Exactly one connection is marked as the default; operations use the default unless a connection is explicitly selected.
|
||
|
||
**Rationale**: Supports real-world multi-tenant management while keeping day-to-day usage predictable.
|
||
|
||
**Alternatives considered**:
|
||
- Exactly one Microsoft connection per Suite Tenant: rejected as too restrictive for long-term roadmap (M365/security suite expansion).
|
||
|
||
---
|
||
|
||
### D-004 — OperationRun identity, dedupe, and “scope busy” behavior
|
||
|
||
**Decision**: Provider operations are tracked as `OperationRun`s with two concurrency rules:
|
||
1) Re-starting the same operation type for the same scope returns the active run (dedupe; no new run).
|
||
2) Starting a different operation type while any run is active for that scope is blocked (“scope busy”) and links to the active run.
|
||
|
||
**Rationale**: Prevents accidental overlap, avoids run spam, and keeps user expectations simple and consistent.
|
||
|
||
**Alternatives considered**:
|
||
- Queue the second operation to run later: rejected for v1 because it creates “silent delays” and unexpected ordering.
|
||
- Always reuse an active run even for a different operation: rejected because it would attach unrelated work to the wrong run.
|
||
|
||
---
|
||
|
||
### D-005 — Authorization aligns with existing tenant roles
|
||
|
||
**Decision**:
|
||
- Owner/Manager can manage provider connections and credentials.
|
||
- Owner/Manager/Operator can start provider operations (health check, inventory, compliance).
|
||
- Readonly is view-only.
|
||
|
||
**Rationale**: Credential/connection management is security-sensitive; operations are operational work that Operators need for daily workflow.
|
||
|
||
**Alternatives considered**:
|
||
- Restrict operations to Owner/Manager only: rejected because it blocks day-to-day operations.
|
||
|
||
---
|
||
|
||
### D-006 — Failure reason codes and redaction reuse existing run sanitization
|
||
|
||
**Decision**: Provider operation failures use stable reason codes and short sanitized messages via the existing run failure sanitization utilities; extend reason codes only when needed for clear operator feedback (e.g., authentication misconfiguration).
|
||
|
||
**Rationale**: Keeps error handling consistent suite-wide and prevents token/secret/PII leakage.
|
||
|
||
**Alternatives considered**:
|
||
- Persist raw Graph error payloads for debugging: rejected due to secret/PII leak risk and constitution requirements.
|
||
|
||
---
|
||
|
||
### D-007 — DB-only render is enforced by design and tests
|
||
|
||
**Decision**: Provider Connections and Monitoring/Operations surfaces must be DB-only at render/poll time; outbound provider calls occur only in queued jobs started via explicit user actions.
|
||
|
||
**Rationale**: Prevents accidental “poll storms” against Graph and preserves predictable UI performance.
|
||
|
||
**Alternatives considered**:
|
||
- Inline health checks during page load: rejected as a render-side effect and operationally unsafe.
|