TenantAtlas/specs/061-provider-foundation/research.md
ahmido a0ed9e24c5 feat: unify provider connection actions and notifications (#73)
## 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
2026-01-25 01:01:37 +00:00

4.6 KiB
Raw Blame History

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 repos 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 OperationRuns 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.