TenantAtlas/specs/276-support-access-governance/plan.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

319 lines
23 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Implementation Plan: Enterprise Access Boundary & Support Access Governance v1
**Branch**: `276-support-access-governance` | **Date**: 2026-05-05 | **Spec**: [spec.md](./spec.md)
**Input**: Feature specification from `specs/276-support-access-governance/spec.md`
## Summary
Prepare one bounded support-access governance slice on top of the repos current system support and recovery seams. The narrow implementation path is to introduce one workspace-owned support-access grant history with exactly two scopes, reuse the current system workspace detail page as the request and active-state surface, reuse workspace settings as the owner-approval surface, extend existing system and admin audit views for support-access history, and harden the existing owner-repair utility so it requires both active break-glass and an active recovery-scoped support grant.
This slice stays explicitly narrow. Filament remains v5 on Livewire v4, panel-provider registration stays in `apps/platform/bootstrap/providers.php`, no new globally searchable resource is introduced, and no asset registration change is expected. The plan does not create impersonation, a delegated admin browsing bridge, SCIM, or a second support console.
## Inherited Baseline / Explicit Delta
### Inherited baseline
- `BreakGlassSession`, the system dashboard break-glass actions, and the current system break-glass banner already provide a global emergency recovery control with TTL and audit.
- `RepairWorkspaceOwners` already exposes the current owner-repair utility and audit behavior, but today it only requires platform capability plus active break-glass.
- `ViewWorkspace` already acts as the system-plane workspace detail surface and already owns bounded workspace-scoped admin actions.
- `WorkspaceSettings` already acts as the admin-plane workspace singleton page and already supports workspace-owner-only actions.
- `AuditLog` already acts as the admin-plane customer-visible history surface.
- `AccessLogs` already acts as the system security history surface for platform auth and break-glass events.
### Explicit delta in this plan
- Add one workspace-owned support-access grant history with bounded lifecycle and expiry.
- Add one support-scope catalog with exactly `audit_view` and `workspace_recovery`.
- Add one shared `SupportAccessGrantResolver` or manager so current detail, settings, recovery, and history surfaces consume the same support-access truth.
- Add a request and end flow on `ViewWorkspace`.
- Add owner approval or denial for `workspace_recovery` on `WorkspaceSettings`.
- Extend `AuditLog` with a support-access filter and export path.
- Extend `AccessLogs` with support-access lifecycle events.
- Refactor `RepairWorkspaceOwners` so owner repair requires both active break-glass and an active recovery-scoped support grant for the chosen workspace.
## Technical Context
**Language/Version**: PHP 8.4, Laravel 12
**Primary Dependencies**: Filament v5, Livewire v4, Pest v4, existing `BreakGlassSession`, existing audit infrastructure, existing workspace settings and system workspace detail surfaces
**Storage**: PostgreSQL via a new workspace-owned `support_access_grants` table plus existing `audit_logs` and current session-backed break-glass state
**Testing**: Pest v4 `Unit` plus focused `Feature` coverage
**Validation Lanes**: fast-feedback, confidence
**Target Platform**: Laravel monolith in `apps/platform`, reusing existing admin and system Filament pages
**Project Type**: Web application (Laravel monolith with Filament panels)
**Performance Goals**: no new queue family, no Graph calls, and DB-only support-access resolution on current detail, settings, and history surfaces
**Constraints**: no impersonation, no delegated admin browsing bridge, no SCIM, no new support console, no new global-search resource, and no asset registration changes
**Scale/Scope**: 1 new workspace-owned entity, 1 bounded resolver or manager, 4 existing page families, and focused extensions to existing auth or audit tests
## Likely Affected Repo Surfaces
- `apps/platform/app/Models/SupportAccessGrant.php` as the new workspace-owned grant model.
- `apps/platform/database/migrations/*_create_support_access_grants_table.php` for new persistence.
- `apps/platform/database/factories/SupportAccessGrantFactory.php` for bounded test setup.
- `apps/platform/app/Services/Auth/SupportAccessGrantResolver.php` and `SupportAccessGrantManager.php` as the shared lifecycle and mutation layer.
- `apps/platform/app/Filament/System/Pages/Directory/ViewWorkspace.php` for request, end, and active-state summary.
- `apps/platform/app/Filament/System/Pages/RepairWorkspaceOwners.php` for the combined support-access plus break-glass recovery boundary.
- `apps/platform/app/Filament/System/Pages/Security/AccessLogs.php` for system-side support-access history.
- `apps/platform/app/Filament/Pages/Settings/WorkspaceSettings.php` for owner approval or denial and a current support-access summary.
- `apps/platform/app/Filament/Pages/Monitoring/AuditLog.php` for the support-access filter and export path.
- `apps/platform/app/Support/Auth/PlatformCapabilities.php` for new bounded platform-side support-access manage capability.
- `apps/platform/app/Support/Audit/AuditActionId.php`, `WorkspaceAuditLogger`, and `SystemConsoleAuditLogger` for stable support-access audit action IDs and structured metadata.
- `apps/platform/tests/Unit/System/SupportAccessGrantResolverTest.php` plus focused system, auth, settings, monitoring, and access-log feature tests.
## Support Access Fit
- Treat support access as a workspace-owned governance truth, not as an extension of `BreakGlassSession`.
- Keep exactly two scopes in v1 so the slice stays on current repo-real support work:
- `audit_view`
- `workspace_recovery`
- Keep support-access lifecycle distinct from break-glass lifecycle.
- Keep owner repair as the one high-risk mutation that requires both active break-glass and active recovery-scoped support access.
- Keep admin history export on the current audit surface rather than adding a second support-history page.
## UI / Filament & Livewire Fit
- Existing operator-facing surfaces remain native Filament surfaces under Livewire v4.
- No new Filament resource or globally searchable resource is required; current pages are sufficient.
- `ViewWorkspace` keeps one dominant support-access action family: request or end support access.
- `WorkspaceSettings` keeps approval scoped to pending `workspace_recovery` requests and must not become a second platform-control plane.
- `AuditLog` and `AccessLogs` stay read-only history surfaces and only expand their filter or event scope.
- Provider registration remains unchanged in `apps/platform/bootstrap/providers.php`, and no new asset strategy is planned. If a later shared asset becomes necessary, deployment remains the standard `cd apps/platform && php artisan filament:assets` path.
## RBAC / Policy Fit
- Workspace and tenant membership remain the primary admin-plane isolation boundaries. Wrong-plane or non-member requests stay `404`; in-scope actors missing capability stay `403`.
- Platform-side request and end actions should use one new bounded `PlatformCapabilities::SUPPORT_ACCESS_MANAGE` capability instead of reusing broad console visibility alone.
- Workspace-owner approval should remain on `WorkspaceSettings` and should reuse existing owner-level manage semantics rather than adding a separate customer support role.
- `AuditLog` export remains tied to the current admin-plane audit view capability.
- Business-state blocking on the recovery page must remain distinguishable from authorization failure.
## Audit / Logging Fit
- Every support-access request, approval, denial, activation, expiry, end, and ownerless waiver must write a stable audit action ID with structured metadata.
- `AuditLog` remains the customer-visible history substrate.
- `AccessLogs` remains the system-side security history substrate and expands to include support-access events.
- No second audit subsystem is needed.
## Data & Query Fit
- `support_access_grants.workspace_id` must be NOT NULL and indexed.
- Prevent overlapping `requested` or `active` grants for the same workspace, platform actor, and scope.
- Keep the v1 table bounded to the fields in `data-model.md`; do not add broad ticketing, provider, or impersonation fields.
- `SupportAccessGrantResolver` should expose a single current summary for the active workspace plus current page context.
- `RepairWorkspaceOwners` should query only the targeted workspaces active recovery grant, not scan across workspaces.
## UI / Surface Guardrail Plan
- **Guardrail scope**: changed surfaces
- **Native vs custom classification summary**: native Filament
- **Shared-family relevance**: system detail summaries, workspace settings approvals, audit-history filters, system security history, and recovery state messaging
- **State layers in scope**: page, detail
- **Audience modes in scope**: operator-MSP, support-platform
- **Decision/diagnostic/raw hierarchy plan**: decision-first, diagnostics-second, support-raw-third
- **Raw/support gating plan**: raw audit detail remains on existing history surfaces; default-visible content stays on current support posture and approval need
- **One-primary-action / duplicate-truth control**: `ViewWorkspace` remains the one place to start or end support access; `WorkspaceSettings` remains the one place to approve or deny risky recovery; history pages explain rather than re-decide
- **Handling modes by drift class or surface**: review-mandatory
- **Repository-signal treatment**: review-mandatory now; future hard-stop candidate if a second support console or impersonation bridge appears inside this slice
- **Special surface test profiles**: standard-native-filament, shared-detail-family, monitoring-state-page, exception-coded-surface
- **Required tests or manual smoke**: functional-core, state-contract, exception-fallback
- **Exception path and spread control**: the recovery page remains the named separately governed exception and must not spread its combined prerequisite logic to unrelated surfaces
- **Active feature PR close-out entry**: Guardrail
## Shared Pattern & System Fit
- **Cross-cutting feature marker**: yes
- **Systems touched**: `ViewWorkspace`, `WorkspaceSettings`, `AuditLog`, `AccessLogs`, `RepairWorkspaceOwners`, `BreakGlassSession`, audit action IDs, and current audit loggers
- **Shared abstractions reused**: current system detail pattern, current singleton settings pattern, current admin audit history, current system access logs, and current audit infrastructure
- **New abstraction introduced? why?**: one bounded `SupportAccessGrantResolver` or manager, because current repo truth has no support-access lifecycle abstraction and several surfaces need the same grant state and dedupe rules
- **Why the existing abstraction was sufficient or insufficient**: current break-glass and audit abstractions are sufficient for emergency recovery and history rendering, but insufficient for one workspace-scoped ordinary support-access lifecycle with approval and expiry
- **Bounded deviation / spread control**: no local page-specific support-access helper is allowed outside the shared resolver or manager path
## OperationRun UX Impact
- **Touches OperationRun start/completion/link UX?**: no
- **Central contract reused**: `N/A`
- **Delegated UX behaviors**: `N/A`
- **Surface-owned behavior kept local**: request or approval inputs only
- **Queued DB-notification policy**: `N/A`
- **Terminal notification path**: `N/A`
- **Exception path**: none
## Provider Boundary & Portability Fit
- **Shared provider/platform boundary touched?**: no
- **Provider-owned seams**: none in this slice
- **Platform-core seams**: support-access grant truth, approval flow, break-glass separation, and workspace-scoped history
- **Neutral platform terms / contracts preserved**: `support access`, `break-glass`, `workspace recovery`, `audit trail review`
- **Retained provider-specific semantics and why**: none
- **Bounded extraction or follow-up path**: future delegated support or impersonation only if promoted by a separate spec
## Constitution Check
*GATE: Must pass before implementation begins and again before merge.*
- Inventory-first / snapshot truth: PASS. This slice does not change tenant inventory or snapshot semantics.
- Read/write separation: PASS. Every mutation is bounded, confirmation-protected where high risk, and audit-backed.
- Graph contract path: PASS. No Graph or provider calls are introduced.
- Deterministic capabilities: PASS. Existing canonical capability registries remain authoritative.
- Workspace and tenant isolation: PASS. Workspace context and wrong-plane `404` remain unchanged.
- RBAC-UX plane separation: PASS. `/system` handles request or end; `/admin` handles approval or history.
- Destructive action discipline: PASS. High-risk approval and recovery remain confirmation-aware.
- Global search safety: PASS. No new searchable resource is added.
- OperationRun / Ops-UX: PASS. No new run family or `OperationRun` start surface is introduced.
- Data minimization: PASS. The new entity stores bounded support-access truth only.
- Test governance: PASS. Proof remains in one new unit family plus focused feature families.
- Proportionality / no premature abstraction: PASS. One new entity and one bounded resolver or manager are the narrowest viable path.
- Persisted truth: PASS. The new table represents independent product truth with its own lifecycle and audit need.
- Behavioral state: PASS. Grant status and approval mode change recovery behavior, expiry, and audit outcomes.
- Shared pattern first / UI semantics / Filament-native UI: PASS. Existing detail, settings, recovery, and history surfaces remain authoritative.
- Provider boundary: PASS. No provider-specific vocabulary or dependency is added.
- Filament / Laravel planning contract: PASS. Filament stays v5 on Livewire v4, provider registration remains in `apps/platform/bootstrap/providers.php`, no globally searchable resource is added, and no asset registration change is planned.
**Gate evaluation**: PASS.
**Post-design re-check**: PASS. `research.md`, `data-model.md`, `quickstart.md`, `contracts/workspace-support-access-governance.logical.openapi.yaml`, `checklists/requirements.md`, and `tasks.md` are present and aligned with the package.
## Test Governance Check
- **Test purpose / classification by changed surface**: `Unit` for grant lifecycle, expiry, and dedupe rules; `Feature` for system detail request flow, owner approval, recovery boundary, and history surfaces
- **Affected validation lanes**: fast-feedback, confidence
- **Why this lane mix is the narrowest sufficient proof**: the slice reuses native Filament and current audit surfaces, so focused unit and feature tests can prove the new truth without browser automation
- **Narrowest proving command(s)**:
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Unit/System/SupportAccessGrantResolverTest.php`
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/System/SupportAccessRequestFlowTest.php tests/Feature/System/SupportAccessRecoveryBoundaryTest.php tests/Feature/Auth/BreakGlassModeTest.php tests/Feature/Auth/BreakGlassWorkspaceOwnerRecoveryTest.php tests/Feature/System/Spec114/AccessLogsTest.php`
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Filament/Settings/WorkspaceSupportAccessApprovalTest.php tests/Feature/Monitoring/AuditLogSupportAccessHistoryTest.php`
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent`
- **Fixture / helper / factory / seed / context cost risks**: moderate but contained; one new factory is needed, but existing platform user, workspace, membership, and audit fixtures can be reused
- **Expensive defaults or shared helper growth introduced?**: no
- **Heavy-family additions, promotions, or visibility changes**: none planned
- **Surface-class relief / special coverage rule**: standard-native-filament relief for detail, settings, and history surfaces; exception-coded coverage for the recovery boundary
- **Closing validation and reviewer handoff**: reviewers should rely on the exact commands above, confirm that no impersonation bridge or second console appears, verify that recovery still needs active break-glass plus active recovery support access, and verify that support history export remains workspace-safe
- **Budget / baseline / trend follow-up**: none expected beyond a small feature-local increase
- **Review-stop questions**: did the slice add more than two support scopes, did it bypass break-glass on recovery, did it create a second history surface, and did it let admin history leak outside the workspace scope
- **Escalation path**: `document-in-feature` for contained naming drift; `reject-or-split` if the slice widens into impersonation, SCIM, or a second support console
- **Active feature PR close-out entry**: Guardrail
- **Why no dedicated follow-up spec is needed**: routine support-access upkeep should stay inside this feature unless future delegated support or impersonation is explicitly promoted as a separate slice
- **Test-governance outcome**: keep
## Review Checklist Status
- **Review checklist artifact**: `checklists/requirements.md`
- **Review outcome class**: `acceptable-special-case`
- **Workflow outcome**: `keep`
- **Test-governance outcome**: `keep`
- **Escalation rule**: if implementation adds admin-plane browsing, impersonation, SCIM, or a second support console, flip the workflow outcome to `split` before continuing
## Rollout Considerations
- Land persistence and shared resolver or manager first.
- Add workspace detail request or end flow next.
- Add workspace-owner approval next.
- Harden recovery enforcement only after support-access truth exists.
- Add history filter and export last so the customer-visible trail reflects the final lifecycle semantics.
- Keep Filament v5 on Livewire v4, provider registration in `apps/platform/bootstrap/providers.php`, global search unchanged, and assets unchanged.
## Risk Controls
- Reject any implementation that adds impersonation or delegated admin browsing.
- Reject any implementation that lets `workspace_recovery` proceed without active break-glass.
- Reject any implementation that adds more than the two scoped support capabilities in this slice.
- Reject any implementation that creates a second support history or approval surface outside the current detail, settings, and audit pages.
- Reject browser-heavy proof as the default validation lane.
## Research & Design Outputs
- `research.md` resolves the key design choices: workspace-scoped grants, two-scope catalog, recovery plus break-glass coupling, existing-surface reuse, and admin history export.
- `data-model.md` records the new grant entity, state and approval semantics, dedupe rule, and derived summary shape.
- `quickstart.md` provides the bounded reviewer flow, explicit approval and waiver expectations, and focused validation commands.
- `contracts/workspace-support-access-governance.logical.openapi.yaml` captures the logical route and action boundaries for request, approval, end, history, export, and recovery gating.
- `checklists/requirements.md` records the prep-time review outcome, workflow outcome, and test-governance outcome.
- `tasks.md` keeps implementation bounded to current support and recovery surfaces.
## Project Structure
### Documentation (this feature)
```text
specs/276-support-access-governance/
├── checklists/
│ └── requirements.md
├── contracts/
│ └── workspace-support-access-governance.logical.openapi.yaml
├── plan.md
├── research.md
├── data-model.md
├── quickstart.md
└── tasks.md
```
### Source Code (expected implementation surfaces)
```text
apps/platform/
├── app/
│ ├── Filament/
│ │ ├── Pages/
│ │ │ ├── Monitoring/
│ │ │ │ └── AuditLog.php
│ │ │ └── Settings/
│ │ │ └── WorkspaceSettings.php
│ │ └── System/Pages/
│ │ ├── Directory/
│ │ │ └── ViewWorkspace.php
│ │ ├── RepairWorkspaceOwners.php
│ │ └── Security/
│ │ └── AccessLogs.php
│ ├── Models/
│ │ └── SupportAccessGrant.php
│ ├── Services/
│ │ ├── Audit/
│ │ │ └── WorkspaceAuditLogger.php
│ │ ├── Auth/
│ │ │ ├── BreakGlassSession.php
│ │ │ ├── SupportAccessGrantManager.php
│ │ │ └── SupportAccessGrantResolver.php
│ │ └── SystemConsole/
│ │ └── SystemConsoleAuditLogger.php
│ └── Support/
│ ├── Audit/
│ │ └── AuditActionId.php
│ └── Auth/
│ └── PlatformCapabilities.php
├── database/
│ ├── factories/
│ │ └── SupportAccessGrantFactory.php
│ └── migrations/
│ └── *_create_support_access_grants_table.php
└── tests/
├── Feature/
│ ├── Auth/
│ │ ├── BreakGlassModeTest.php
│ │ └── BreakGlassWorkspaceOwnerRecoveryTest.php
│ ├── Filament/Settings/
│ │ └── WorkspaceSupportAccessApprovalTest.php
│ ├── Monitoring/
│ │ └── AuditLogSupportAccessHistoryTest.php
│ └── System/
│ ├── Spec114/AccessLogsTest.php
│ ├── SupportAccessRecoveryBoundaryTest.php
│ └── SupportAccessRequestFlowTest.php
└── Unit/
└── System/
└── SupportAccessGrantResolverTest.php
```
## Complexity Tracking
| Violation | Why Needed | Simpler Alternative Rejected Because |
|-----------|------------|-------------------------------------|
| New persisted support-access entity | Support access now needs its own lifecycle, expiry, and approval lineage | Session-only or audit-log-only approaches could not gate recovery and customer-visible approval safely |
## Proportionality Review
- **Current operator problem**: current support and recovery seams lack one bounded workspace-scoped support lifecycle that is both customer-visible and strong enough to gate recovery
- **Existing structure is insufficient because**: `BreakGlassSession` is global and current pages can only infer support state indirectly through scattered audit events
- **Narrowest correct implementation**: one grant history table plus one shared resolver or manager, added to the current system detail, settings, history, and recovery pages only
- **Ownership cost**: one new entity, one new resolver or manager, one new factory, one migration, and focused tests
- **Alternative intentionally rejected**: break-glass-only governance and broad impersonation bridge
- **Release truth**: current-release truth with bounded future preparation only