TenantAtlas/specs/061-provider-foundation/data-model.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

93 lines
3.5 KiB
Markdown

# Data Model: Provider Foundation v1
**Branch**: `061-provider-foundation`
**Date**: 2026-01-24
**Spec**: `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/061-provider-foundation/spec.md`
## Entities
### ProviderConnection
Represents a tenant-scoped connection to an external provider (v1: Microsoft).
**Identity**
- Scoped to a Suite Tenant (`tenant_id`).
- Canonical target scope identifier for Microsoft: `entra_tenant_id` (GUID).
- Uniqueness: `(tenant_id, provider, entra_tenant_id)` must be unique.
**Fields (suggested)**
- `id` (UUID)
- `tenant_id` (FK → tenants)
- `provider` (string; v1: `microsoft`)
- `entra_tenant_id` (string; GUID)
- `display_name` (string)
- `is_default` (boolean; exactly one default per `(tenant_id, provider)`)
- `status` (string enum): `connected | needs_consent | error | disabled`
- `health_status` (string enum): `ok | degraded | down`
- `scopes_granted` (json/jsonb; optional; stores observed granted scopes/permissions metadata)
- `last_health_check_at` (timestamp nullable)
- `last_error_reason_code` (string nullable; stable reason code)
- `last_error_message` (string nullable; sanitized short message)
- `metadata` (json/jsonb nullable; optional non-sensitive provider metadata)
- timestamps
**Indexes (suggested)**
- Unique index: `(tenant_id, provider, entra_tenant_id)`
- Partial unique index: `(tenant_id, provider)` where `is_default = true`
- Indexes for filtering: `(tenant_id, provider, status)`, `(tenant_id, provider, health_status)`
**State transitions (v1)**
- `status`: typically `needs_consent`/`error` → `connected` after successful health check; `disabled` is an explicit admin action.
- `health_status`: `ok` on successful check; `degraded/down` based on categorized failures (throttling vs outage vs auth).
---
### ProviderCredential
Represents securely stored credentials for exactly one provider connection.
**Identity**
- 1:1 with ProviderConnection (`provider_connection_id` unique).
**Fields (suggested)**
- `id` (UUID)
- `provider_connection_id` (FK → provider_connections, unique)
- `type` (string; v1: `client_secret`)
- `payload` (encrypted JSON/array)
- required keys (v1): `client_id`, `client_secret`
- optional key: `tenant_id` (should match ProviderConnection `entra_tenant_id` if stored)
- timestamps
**Constraints (suggested)**
- `payload` must be encrypted at rest.
- `payload` must never be exposed via UI/API serialization.
- If `payload.tenant_id` is stored, validate it matches `provider_connections.entra_tenant_id`.
---
### DefaultProviderConnection (concept)
Not a separate table by default; represented by `provider_connections.is_default = true`.
Rules:
- Multiple Microsoft connections per Suite Tenant are allowed.
- Exactly one default connection exists per `(tenant_id, provider)` and is used when starting operations without an explicit connection selection.
---
### OperationRun (existing)
Provider operations are tracked as `operation_runs` with provider context stored in the `context` JSON.
**Provider context fields (suggested)**
- `provider`: `microsoft`
- `provider_connection_id`: UUID
- `target_scope`: `{ "entra_tenant_id": "<guid>" }`
- `module`: `health_check | inventory | compliance`
- `selection`: optional selectors/filters for the operation (DB-only)
- `idempotency`: fingerprint/hash inputs used for dedupe
**Concurrency rules (from spec clarifications)**
- Same operation type + same scope: dedupe → return the active run.
- Different operation type while any run is active for the same scope: block as “scope busy” and link to the active run.