23 KiB
Implementation Plan: Enterprise Access Boundary & Support Access Governance v1
Branch: 276-support-access-governance | Date: 2026-05-05 | Spec: 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 repo’s 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.RepairWorkspaceOwnersalready exposes the current owner-repair utility and audit behavior, but today it only requires platform capability plus active break-glass.ViewWorkspacealready acts as the system-plane workspace detail surface and already owns bounded workspace-scoped admin actions.WorkspaceSettingsalready acts as the admin-plane workspace singleton page and already supports workspace-owner-only actions.AuditLogalready acts as the admin-plane customer-visible history surface.AccessLogsalready 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_viewandworkspace_recovery. - Add one shared
SupportAccessGrantResolveror 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_recoveryonWorkspaceSettings. - Extend
AuditLogwith a support-access filter and export path. - Extend
AccessLogswith support-access lifecycle events. - Refactor
RepairWorkspaceOwnersso 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.phpas the new workspace-owned grant model.apps/platform/database/migrations/*_create_support_access_grants_table.phpfor new persistence.apps/platform/database/factories/SupportAccessGrantFactory.phpfor bounded test setup.apps/platform/app/Services/Auth/SupportAccessGrantResolver.phpandSupportAccessGrantManager.phpas the shared lifecycle and mutation layer.apps/platform/app/Filament/System/Pages/Directory/ViewWorkspace.phpfor request, end, and active-state summary.apps/platform/app/Filament/System/Pages/RepairWorkspaceOwners.phpfor the combined support-access plus break-glass recovery boundary.apps/platform/app/Filament/System/Pages/Security/AccessLogs.phpfor system-side support-access history.apps/platform/app/Filament/Pages/Settings/WorkspaceSettings.phpfor owner approval or denial and a current support-access summary.apps/platform/app/Filament/Pages/Monitoring/AuditLog.phpfor the support-access filter and export path.apps/platform/app/Support/Auth/PlatformCapabilities.phpfor new bounded platform-side support-access manage capability.apps/platform/app/Support/Audit/AuditActionId.php,WorkspaceAuditLogger, andSystemConsoleAuditLoggerfor stable support-access audit action IDs and structured metadata.apps/platform/tests/Unit/System/SupportAccessGrantResolverTest.phpplus 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_viewworkspace_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.
ViewWorkspacekeeps one dominant support-access action family: request or end support access.WorkspaceSettingskeeps approval scoped to pendingworkspace_recoveryrequests and must not become a second platform-control plane.AuditLogandAccessLogsstay 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 standardcd apps/platform && php artisan filament:assetspath.
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 stay403. - Platform-side request and end actions should use one new bounded
PlatformCapabilities::SUPPORT_ACCESS_MANAGEcapability instead of reusing broad console visibility alone. - Workspace-owner approval should remain on
WorkspaceSettingsand should reuse existing owner-level manage semantics rather than adding a separate customer support role. AuditLogexport 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.
AuditLogremains the customer-visible history substrate.AccessLogsremains 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_idmust be NOT NULL and indexed.- Prevent overlapping
requestedoractivegrants 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. SupportAccessGrantResolvershould expose a single current summary for the active workspace plus current page context.RepairWorkspaceOwnersshould query only the targeted workspace’s 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:
ViewWorkspaceremains the one place to start or end support access;WorkspaceSettingsremains 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
SupportAccessGrantResolveror 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
404remain unchanged. - RBAC-UX plane separation: PASS.
/systemhandles request or end;/adminhandles 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
OperationRunstart 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:
Unitfor grant lifecycle, expiry, and dedupe rules;Featurefor 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.phpexport 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.phpexport 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.phpexport 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-featurefor contained naming drift;reject-or-splitif 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
splitbefore 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_recoveryproceed 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.mdresolves the key design choices: workspace-scoped grants, two-scope catalog, recovery plus break-glass coupling, existing-surface reuse, and admin history export.data-model.mdrecords the new grant entity, state and approval semantics, dedupe rule, and derived summary shape.quickstart.mdprovides the bounded reviewer flow, explicit approval and waiver expectations, and focused validation commands.contracts/workspace-support-access-governance.logical.openapi.yamlcaptures the logical route and action boundaries for request, approval, end, history, export, and recovery gating.checklists/requirements.mdrecords the prep-time review outcome, workflow outcome, and test-governance outcome.tasks.mdkeeps implementation bounded to current support and recovery surfaces.
Project Structure
Documentation (this feature)
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)
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:
BreakGlassSessionis 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