TenantAtlas/specs/276-support-access-governance/data-model.md
ahmido 1e0f21365b PR: 276-support-access-governance → platform-dev (#332)
Automated PR created via MCP by Copilot on user request: "pr gegen platform-dev".

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #332
2026-05-05 21:54:26 +00:00

132 lines
6.4 KiB
Markdown

# Data Model: Enterprise Access Boundary & Support Access Governance v1
**Date**: 2026-05-05
**Branch**: `276-support-access-governance`
## Overview
This slice adds one new workspace-owned truth: support-access grant history. Existing `audit_logs`, `BreakGlassSession`, and workspace settings remain in place. The new grant history drives support-access state, approval, expiry, and recovery gating.
## Persisted Truth
### 1. Support Access Grant
**Persistence**: New `support_access_grants` table
**Ownership**: Workspace-owned
**Scope**: Many historical rows per workspace, with dedupe preventing overlapping active or pending grants for the same workspace, platform actor, and scope.
| Field | Type | Nullable | Validation | Notes |
|-------|------|----------|------------|-------|
| `id` | bigint | no | primary key | Internal record id |
| `workspace_id` | bigint | no | foreign key | Primary customer scope anchor |
| `requested_by_platform_user_id` | bigint | no | foreign key | Platform actor who requested support access |
| `approved_by_user_id` | bigint | yes | foreign key | Workspace owner who approved the risky recovery path |
| `scope` | string | no | one of `audit_view`, `workspace_recovery` | Bounded v1 support scope catalog |
| `status` | string | no | one of `requested`, `active`, `denied`, `expired`, `ended` | Lifecycle state |
| `approval_mode` | string | no | one of `auto`, `owner_required`, `ownerless_waiver` | Explains why approval did or did not occur |
| `reason` | text | no | trimmed, min length 5 | Operator-supplied reason |
| `waiver_reason` | text | yes | required when `approval_mode=ownerless_waiver` | Explicit ownerless recovery waiver context |
| `ttl_minutes` | integer | no | positive integer, bounded max from config or policy | Requested active duration |
| `requested_at` | datetime | no | set on creation | Request timestamp |
| `approved_at` | datetime | yes | required when owner approval occurs | Approval timestamp |
| `starts_at` | datetime | yes | required when grant becomes active | Active timestamp |
| `expires_at` | datetime | yes | required when grant becomes active | Grant expiry |
| `ended_at` | datetime | yes | set when support access is ended manually | Manual end timestamp |
| `denied_at` | datetime | yes | set when owner denies a request | Denial timestamp |
| `created_at` | datetime | no | standard timestamp | Row creation |
| `updated_at` | datetime | no | standard timestamp | Row update |
**Write rules**:
- `workspace_id`, `requested_by_platform_user_id`, and `scope` are immutable once created.
- `requested` is the initial state for every new row.
- `audit_view` may move directly from `requested` to `active` with `approval_mode=auto`.
- `workspace_recovery` moves from `requested` to `active` only after owner approval or ownerless waiver.
- Active grants may transition to `expired` or `ended`. Requested grants may transition to `denied`.
**Dedupe rule**:
- At most one non-terminal row may exist for the same `workspace_id`, `requested_by_platform_user_id`, and `scope` while `status` is `requested` or `active`.
## Existing Persisted Truth Reused
### 2. Audit Log
**Persistence**: Existing `audit_logs` table
**Owner**: Existing audit infrastructure
This slice reuses `audit_logs` for customer-visible history and export. Support-access events become a first-class audit action family.
### 3. Break-Glass Session
**Persistence**: Existing session-backed `BreakGlassSession`
**Owner**: Existing system-plane emergency control
Break-glass remains session-backed and system-wide. It is not replaced by support-access grant history, but recovery gating now depends on both.
## Code-Owned Truth
### 4. Support Scope Catalog
**Persistence**: none, code-owned
| Scope | Label | Risk class | Requires owner approval? | Allows mutation? |
|-------|-------|------------|--------------------------|------------------|
| `audit_view` | Audit trail review | low | no | no |
| `workspace_recovery` | Workspace recovery | high | yes when owners exist | yes |
### 5. Approval Mode Catalog
**Persistence**: none, code-owned
| Mode | Meaning |
|------|---------|
| `auto` | Low-risk support access activated immediately |
| `owner_required` | Workspace owner must approve before activation |
| `ownerless_waiver` | No owner existed, so recovery required explicit break-glass-backed waiver |
## Derived Truth
### 6. Active Support Access Summary
**Persistence**: none, derived at runtime
**Owner**: `SupportAccessGrantResolver`
| Field | Type | Required | Notes |
|-------|------|----------|-------|
| `workspace_id` | int | yes | Current workspace |
| `active_grant_id` | int | no | Active grant when present |
| `pending_grant_id` | int | no | Pending risky grant when present |
| `scope` | string | no | Current or pending scope |
| `scope_label` | string | no | Operator-facing scope label |
| `status` | string | yes | Current support-access state summary |
| `reason` | string | no | Active or pending reason |
| `requester_label` | string | no | Platform requester display label |
| `approval_mode` | string | no | Explains activation path |
| `approver_label` | string | no | Owner approver display label |
| `expires_at` | datetime | no | Current expiry |
| `needs_break_glass` | bool | yes | True only for `workspace_recovery` |
### 7. Support Access Export Filter
**Persistence**: none, derived at runtime
**Owner**: existing admin audit-log page
The filter preset isolates audit actions that belong to the support-access family and remain in the active workspace scope only.
## State Transitions
| From | To | Trigger | Consequence |
|------|----|---------|-------------|
| none | `requested` | platform operator requests support access | grant becomes pending |
| `requested` | `active` | auto activation or explicit approval | support access becomes active until expiry or manual end |
| `requested` | `denied` | workspace owner denies recovery request | no active support access is granted |
| `active` | `expired` | current time passes `expires_at` | recovery and audit-view access end automatically |
| `active` | `ended` | platform operator ends support access | support access ends early |
## Boundaries Explicitly Preserved
- No tenant member impersonation, no direct customer session bridge, and no unrestricted admin browsing are introduced.
- `workspace_recovery` does not bypass break-glass and `audit_view` does not mutate customer state.
- Support-access history remains workspace-scoped even when audit rows include tenant references.