# 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.