Implements explicit UiActionContext contract as requested. Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #434
253 lines
17 KiB
Markdown
253 lines
17 KiB
Markdown
# Implementation Plan: Spec 363 - Explicit UiActionContext Contract for Scoped No-Record Actions
|
|
|
|
**Branch**: `feat/363-explicit-uiactioncontext-contract` | **Preparation Branch**: `363-explicit-uiactioncontext-contract` | **Date**: 2026-06-07 | **Spec**: `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/363-explicit-uiactioncontext-contract/spec.md`
|
|
**Input**: Feature specification from `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/363-explicit-uiactioncontext-contract/spec.md`
|
|
|
|
**Note**: This plan is repo-aware and preparation-only. No application implementation is performed in this step.
|
|
|
|
## Summary
|
|
|
|
Add an explicit action-context contract for workspace- and environment-scoped no-record Filament actions.
|
|
|
|
The implementation should:
|
|
|
|
- introduce a narrow request-time `UiActionContext` contract
|
|
- harden `UiEnforcement` so scoped no-record actions cannot silently use implicit `Filament::getTenant()` as product scope truth
|
|
- preserve record-backed action behavior where scope comes from the record
|
|
- retrofit representative latent-risk no-record actions
|
|
- add first-click modal/no-run test helpers and action lifecycle tests
|
|
- add a static guard that fails future risky scoped no-record actions without explicit context
|
|
|
|
No migrations, panel/provider changes, global-search changes, asset strategy changes, or new product workflows are planned.
|
|
|
|
## Technical Context
|
|
|
|
**Language/Version**: PHP 8.4.15
|
|
**Primary Dependencies**: Laravel 12.52, Filament 5.2.1, Livewire 4.1.4, Pest 4.3.1
|
|
**Storage**: PostgreSQL via Sail, but no schema changes are planned
|
|
**Testing**: Pest Unit + Feature/Filament-Livewire + Architecture/guard; Browser optional only if visible UI hierarchy/copy changes materially
|
|
**Validation Lanes**: fast-feedback, confidence, browser optional
|
|
**Target Platform**: Laravel monolith in Sail / Dokploy container workflow
|
|
**Project Type**: single web application (`apps/platform`)
|
|
**Performance Goals**: no Graph calls during render/action-state/modal mount; static scan remains bounded and deterministic
|
|
**Constraints**: no new persistence, no operation type, no capability string, no panel/provider, no asset registration, no global-search change, no compatibility shim, no broad record-backed action rewrite
|
|
**Scale/Scope**: no-record scoped actions first, plus representative action retrofits and static recurrence guard
|
|
|
|
## UI / Surface Guardrail Plan
|
|
|
|
- **Guardrail scope**: changed existing actions on existing pages
|
|
- **Affected routes/pages/actions/states/navigation/panel/provider surfaces**:
|
|
- Inventory list `run_inventory_sync`
|
|
- Policy list/header sync and related Policy Sync start surface
|
|
- Entra Groups `sync_groups`
|
|
- Evidence Snapshot `create_snapshot` and `create_first_snapshot`
|
|
- Review Pack `generate_pack` and `generate_first`
|
|
- Environment Review `create_review`
|
|
- Environment Diagnostics `bootstrapOwner` and `mergeDuplicateMemberships`
|
|
- Restore Run create entrypoint and create wizard
|
|
- Environment Dashboard support request / support diagnostics actions
|
|
- **No-impact class, if applicable**: N/A, because existing high-impact actions change context behavior
|
|
- **Native vs custom classification summary**: native Filament pages/resources/actions with shared RBAC enforcement
|
|
- **Shared-family relevance**: header/page/empty-state action family, RBAC UI enforcement family, OperationRun start family
|
|
- **State layers in scope**: page render, action visibility, action disabled state, first-click modal mount, submit/execute handler
|
|
- **Audience modes in scope**: operator-MSP and support-platform
|
|
- **Decision/diagnostic/raw hierarchy plan**: show safe action state and missing-context copy only; keep low-level Livewire/Filament request details out of UI
|
|
- **Raw/support gating plan**: no raw request, referer, token, Graph, credential, or payload data in visible UI
|
|
- **One-primary-action / duplicate-truth control**: do not duplicate run outcome truth in action modals; after submit reuse existing OperationRun links/toasts
|
|
- **Handling modes by drift class or surface**: review-mandatory for any scoped no-record action that opens a modal, dispatches work, creates an `OperationRun`, or mutates state
|
|
- **Repository-signal treatment**: record-backed actions are context only unless the static guard proves they behave like no-record scoped actions
|
|
- **Special surface test profiles**: standard-native-filament plus action-lifecycle-contract
|
|
- **Required tests or manual smoke**: Unit + Feature/Filament-Livewire + static guard; Browser only if implementation changes visible copy/hierarchy materially
|
|
- **Exception path and spread control**: bounded static-guard exceptions must name the file/action and why record/page scope is safe
|
|
- **Active feature PR close-out entry**: Guardrail / Smoke Coverage
|
|
- **UI/Productization coverage decision**: no new UI coverage registry update is expected because no new route/page family is introduced
|
|
- **Coverage artifacts to update**: none by default
|
|
- **No-impact rationale**: N/A
|
|
- **Navigation / Filament provider-panel handling**: no panel provider, panel path, navigation, or cluster change
|
|
- **Screenshot or page-report need**: no by default
|
|
|
|
## Shared Pattern & System Fit
|
|
|
|
- **Cross-cutting feature marker**: yes
|
|
- **Systems touched**:
|
|
- `apps/platform/app/Support/Rbac/UiEnforcement.php`
|
|
- `apps/platform/app/Support/Rbac/WorkspaceUiEnforcement.php` as reference/comparison only unless small shared context support is justified
|
|
- new `apps/platform/app/Support/Rbac/Actions/` contract classes if implementation confirms this namespace is still best
|
|
- `apps/platform/app/Filament/Concerns/ResolvesPanelTenantContext.php`
|
|
- selected existing Filament resources/pages/actions
|
|
- selected existing action tests and new guard/test helper
|
|
- **Shared abstractions reused**: existing RBAC helpers, capability resolvers, policies/gates, page context resolvers, OperationRun start helpers, Filament action testing helpers
|
|
- **New abstraction introduced? why?**: yes, a narrow `UiActionContext` request-time contract is allowed because the problem is RBAC/isolation/queue legitimacy-critical and already repo-verified across multiple surfaces
|
|
- **Why the existing abstraction was sufficient or insufficient**: `UiEnforcement` is the right shared path, but it currently allows ambiguous nullable no-record context and implicit Filament tenant fallback
|
|
- **Bounded deviation / spread control**: keep new classes under an RBAC/action namespace; do not create a generic UI framework, presenter, workflow engine, or action catalog rewrite
|
|
|
|
## OperationRun UX Impact
|
|
|
|
- **Touches OperationRun start/completion/link UX?**: yes, start/mount/submit lifecycle only
|
|
- **Central contract reused**: existing `OperationRunService`, run dispatch handlers, `OperationRunLinks`, `OperationUxPresenter`, and `OpsUxBrowserEvents`
|
|
- **Delegated UX behaviors**: queued toasts, run links, run-enqueued browser events, and terminal lifecycle notifications remain unchanged
|
|
- **Surface-owned behavior kept local**: action form values and confirmation/missing-context copy
|
|
- **Queued DB-notification policy**: unchanged
|
|
- **Terminal notification path**: unchanged
|
|
- **Exception path**: if broader execution reauthorization is weaker than UI gating, stop and propose `OperationRun Start Authorization Contract Hardening`
|
|
|
|
## Provider Boundary & Portability Fit
|
|
|
|
- **Shared provider/platform boundary touched?**: no new provider seam
|
|
- **Provider-owned seams**: existing Graph/provider jobs and services remain provider-owned and are not modified beyond receiving explicit, reauthorized scope
|
|
- **Platform-core seams**: workspace/environment action context and RBAC UI enforcement
|
|
- **Neutral platform terms / contracts preserved**: workspace, environment, record, system, product scope, action context
|
|
- **Retained provider-specific semantics and why**: only current Microsoft/Graph semantics inside existing actions/jobs remain
|
|
- **Bounded extraction or follow-up path**: none unless broader OperationRun execution authorization weakness is discovered
|
|
|
|
## Constitution Check
|
|
|
|
*GATE: Must pass before implementation starts. Re-check if scope changes.*
|
|
|
|
- Inventory-first: PASS. No inventory truth changes; Inventory Sync action context becomes explicit only.
|
|
- Read/write separation: PASS. Modal open remains non-mutating; submit/execute must reauthorize before writes/jobs.
|
|
- Graph contract path: PASS. No new Graph calls; render/mount must remain no-Graph.
|
|
- Deterministic capabilities: PASS. Existing capabilities remain authoritative.
|
|
- Workspace and tenant isolation: PASS. Explicit context improves workspace/environment scope safety.
|
|
- RBAC-UX: PASS. UI state remains affordance only; server-side policies/gates remain execution truth.
|
|
- TEST-GOV-001: PASS. Unit + Feature/action + static guard are the narrowest honest proof.
|
|
- PROP-001 / ABSTR-001: PASS only because the new abstraction is security/isolation/action-lifecycle critical and already justified by repeated repo evidence.
|
|
- PERSIST-001 / STATE-001: PASS. No new persisted truth or persisted status family is introduced.
|
|
- XCUT-001 / LAYER-001: PASS. Extend the existing shared `UiEnforcement` path instead of adding local one-off action rules.
|
|
- UI-COV-001: PASS. Existing reachable surfaces are classified; no new page family is expected.
|
|
- LEAN-001: PASS. No compatibility shim for old no-record fallback behavior.
|
|
|
|
## Test Governance Check
|
|
|
|
- **Test purpose / classification by changed surface**:
|
|
- Unit: `UiActionContext`, scope/source enums, resolver helpers, missing-context behavior, `UiEnforcement` context resolution
|
|
- Feature/Filament-Livewire: selected page/resource actions, first-click modal mount, no-run/no-job on modal open, submit reauthorization, wrong-context/readonly behavior
|
|
- Architecture/Feature guard: static source scan for risky scoped no-record actions without explicit context
|
|
- Browser: optional smoke only if visible hierarchy/copy changes materially
|
|
- **Affected validation lanes**: fast-feedback, confidence, browser optional
|
|
- **Why this lane mix is the narrowest sufficient proof**: the behavior is request-time action lifecycle and static source guard behavior, not DB schema or provider API behavior
|
|
- **Narrowest proving command(s)**:
|
|
- `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Unit/Support/Rbac/Actions tests/Unit/Support/Rbac/UiEnforcementScopedActionContextTest.php`
|
|
- `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Architecture/ScopedUiActionContextContractTest.php tests/Feature/Filament/InventoryItemResourceTest.php tests/Feature/PolicySyncStartSurfaceTest.php tests/Feature/RunStartAuthorizationTest.php`
|
|
- `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Filament/EntraGroupAdminScopeTest.php tests/Feature/Evidence/EvidenceSnapshotResourceTest.php tests/Feature/ReviewPack/ReviewPackResourceTest.php tests/Feature/Filament/RestoreRunUiEnforcementTest.php`
|
|
- **Fixture / helper / factory / seed / context cost risks**: keep workspace/environment/member/capability setup explicit; do not introduce full-context defaults in shared helpers
|
|
- **Expensive defaults or shared helper growth introduced?**: no
|
|
- **Heavy-family additions, promotions, or visibility changes**: none by default
|
|
- **Surface-class relief / special coverage rule**: standard-native-filament plus action-lifecycle-contract
|
|
- **Closing validation and reviewer handoff**: reviewers should verify no hidden `Filament::getTenant()` product-scope fallback for scoped no-record actions, no modal-open side effects, and no compatibility path
|
|
- **Budget / baseline / trend follow-up**: none expected
|
|
- **Review-stop questions**: did implementation broaden into record-backed action migration, OperationRun redesign, UI redesign, or product features?
|
|
- **Escalation path**: document-in-feature for contained static-guard false positives; follow-up-spec for broader execution authorization weakness; reject-or-split for scope creep
|
|
- **Active feature PR close-out entry**: Guardrail / Smoke Coverage
|
|
- **Why no dedicated follow-up spec is needed now**: the root issue is explicit enough to solve as one bounded action-context contract
|
|
|
|
## Repo-Verified Runtime Surfaces Likely Affected
|
|
|
|
### Core RBAC / Context
|
|
|
|
- `apps/platform/app/Support/Rbac/UiEnforcement.php`
|
|
- `apps/platform/app/Support/Rbac/WorkspaceUiEnforcement.php` (context/reference only unless sharing is justified)
|
|
- `apps/platform/app/Filament/Concerns/ResolvesPanelTenantContext.php`
|
|
- new `apps/platform/app/Support/Rbac/Actions/UiActionContext.php`
|
|
- new `apps/platform/app/Support/Rbac/Actions/UiActionScope.php`
|
|
- new `apps/platform/app/Support/Rbac/Actions/UiActionContextSource.php`
|
|
- new `apps/platform/app/Support/Rbac/Actions/ResolvesUiActionContext.php`
|
|
|
|
### Representative Action Surfaces
|
|
|
|
- `apps/platform/app/Filament/Resources/InventoryItemResource/Pages/ListInventoryItems.php`
|
|
- `apps/platform/app/Filament/Resources/PolicyResource.php`
|
|
- `apps/platform/app/Filament/Resources/PolicyResource/Pages/ListPolicies.php`
|
|
- `apps/platform/app/Filament/Resources/EntraGroupResource/Pages/ListEntraGroups.php`
|
|
- `apps/platform/app/Filament/Resources/EvidenceSnapshotResource.php`
|
|
- `apps/platform/app/Filament/Resources/EvidenceSnapshotResource/Pages/ListEvidenceSnapshots.php`
|
|
- `apps/platform/app/Filament/Resources/ReviewPackResource.php`
|
|
- `apps/platform/app/Filament/Resources/EnvironmentReviewResource.php`
|
|
- `apps/platform/app/Filament/Pages/EnvironmentDiagnostics.php`
|
|
- `apps/platform/app/Filament/Resources/RestoreRunResource.php`
|
|
- `apps/platform/app/Filament/Resources/RestoreRunResource/Pages/CreateRestoreRun.php`
|
|
- `apps/platform/app/Filament/Pages/EnvironmentDashboard.php`
|
|
|
|
### Tests / Guards
|
|
|
|
- `apps/platform/tests/Unit/Support/Rbac/Actions/*`
|
|
- `apps/platform/tests/Unit/Support/Rbac/UiEnforcementScopedActionContextTest.php`
|
|
- `apps/platform/tests/Feature/Architecture/ScopedUiActionContextContractTest.php`
|
|
- `apps/platform/tests/Support/Filament/ScopedActionAssertions.php`
|
|
- existing action tests under `apps/platform/tests/Feature/Filament`, `apps/platform/tests/Feature/Evidence`, `apps/platform/tests/Feature/ReviewPack`, and `apps/platform/tests/Feature/RunStartAuthorizationTest.php`
|
|
- existing support action tests under `apps/platform/tests/Feature/SupportDiagnostics` and `apps/platform/tests/Feature/SupportRequests`
|
|
|
|
## Technical Approach
|
|
|
|
1. Re-read this spec, plan, tasks, checklist, the constitution, and relevant guidelines before runtime edits.
|
|
2. Re-verify the current action callsites and exact action names.
|
|
3. Add failing Unit coverage for context value objects and `UiEnforcement` scoped behavior.
|
|
4. Add failing Feature/Filament coverage for the known latent-risk actions.
|
|
5. Add the narrow `UiActionContext` contract and helper/trait.
|
|
6. Harden `UiEnforcement` to require explicit context for scoped no-record actions while preserving record-backed paths.
|
|
7. Retrofit representative actions to pass explicit context and reauthorize on submit.
|
|
8. Add reusable first-click modal/no-run helper only where it reduces duplication.
|
|
9. Add the static guard with actionable failures.
|
|
10. Run focused tests, Pint dirty, and diff checks.
|
|
|
|
## Risk Controls
|
|
|
|
- Keep the first implementation scoped to no-record workspace/environment actions.
|
|
- Do not remove valid record-backed context resolution.
|
|
- Do not allow `Filament::getTenant()` as fallback product-scope truth for scoped no-record actions.
|
|
- Keep modal open non-mutating.
|
|
- Keep server-side authorization in handlers/services/policies.
|
|
- Keep missing-context copy enterprise-safe and localizable later.
|
|
- No new migrations, assets, global search, panel provider, navigation, capability, operation type, or route.
|
|
- Stop if implementation needs persistence, broad OperationRun redesign, or many static-guard false positives across record-backed actions.
|
|
|
|
## Implementation Phases
|
|
|
|
### Phase 1: Baseline and Repo-Truth Inventory
|
|
|
|
Confirm current branch/worktree, re-read dependencies, and inventory exact callsites/action names before edits.
|
|
|
|
### Phase 2: Contract and Unit Tests
|
|
|
|
Add the action-context value object/enums/trait or equivalent and Unit coverage for workspace, environment, record, system, and missing context behavior.
|
|
|
|
### Phase 3: UiEnforcement Contract
|
|
|
|
Add explicit scoped-action API or compatible signature changes, remove implicit scoped no-record fallback, preserve record-backed behavior, and cover missing-context classification.
|
|
|
|
### Phase 4: Representative Action Retrofits
|
|
|
|
Retrofit Inventory Sync, Policy Sync, Entra Group Sync, Evidence Snapshot, Review Pack, Environment Review, Environment Diagnostics, Restore create, and Environment Dashboard support actions.
|
|
|
|
### Phase 5: Test Helper and Static Guard
|
|
|
|
Add the reusable first-click modal/no-run helper and static architecture guard.
|
|
|
|
### Phase 6: Validation and Close-Out
|
|
|
|
Run focused tests, optional browser smoke only if needed, Pint dirty, `git diff --check`, and record no-migration/no-asset/no-provider/global-search status.
|
|
|
|
## Project Structure
|
|
|
|
### Documentation (this feature)
|
|
|
|
```text
|
|
specs/363-explicit-uiactioncontext-contract/
|
|
├── spec.md
|
|
├── plan.md
|
|
├── tasks.md
|
|
└── checklists/
|
|
└── requirements.md
|
|
```
|
|
|
|
### Application (later implementation only)
|
|
|
|
```text
|
|
apps/platform/app/Support/Rbac/Actions/
|
|
apps/platform/app/Support/Rbac/UiEnforcement.php
|
|
apps/platform/app/Filament/...
|
|
apps/platform/tests/...
|
|
```
|
|
|
|
No application files are changed during this preparation step.
|