## Summary - harden nested Filament and Livewire tenant-context handling across the backup schedule operation runs relation manager, managed-environment triage arrival continuity, the backup set policy picker table, and the Operate Hub shell - add architecture, feature, and browser coverage for nested Filament tenant-context continuity and restore-run resource behavior - add the Spec 334 artifacts (`spec.md`, `plan.md`, `tasks.md`, and the requirements checklist) ## Testing - Not run as part of this commit/push/PR workflow Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #395
151 lines
9.3 KiB
Markdown
151 lines
9.3 KiB
Markdown
# Implementation Plan: Spec 334 - Nested Filament / Livewire Context Contract Hardening
|
|
|
|
- Branch: `334-nested-filament-context-contract-hardening`
|
|
- Date: 2026-05-24
|
|
- Spec: `specs/334-nested-filament-context-contract-hardening/spec.md`
|
|
- Input: User-provided Spec 334 draft + repo inspection for path truth.
|
|
|
|
## Summary
|
|
|
|
Define and enforce a nested Filament/Livewire context contract so operator-critical nested surfaces do not depend on ambient `Filament::getTenant()` during modal, wizard, relation manager, widget, and Livewire update lifecycles.
|
|
|
|
Implement a narrow hardening slice across four confirmed surfaces, plus guard tests:
|
|
|
|
- `apps/platform/app/Livewire/BackupSetPolicyPickerTable.php`
|
|
- `apps/platform/app/Filament/Resources/RestoreRunResource.php` (+ `apps/platform/app/Filament/Concerns/ResolvesPanelTenantContext.php` seam)
|
|
- `apps/platform/app/Filament/Resources/BackupScheduleResource/RelationManagers/BackupScheduleOperationRunsRelationManager.php`
|
|
- `apps/platform/app/Filament/Widgets/ManagedEnvironment/ManagedEnvironmentTriageArrivalContinuity.php`
|
|
- new architecture guard: `apps/platform/tests/Architecture/FilamentTenantContextContractTest.php`
|
|
|
|
## Technical Context
|
|
|
|
- Language/Version: PHP 8.4.15, Laravel 12.52.x.
|
|
- Primary Dependencies: Filament 5.2.x, Livewire 4.1.x, Pest 4.x, Tailwind CSS 4.x.
|
|
- Storage: PostgreSQL; no schema change expected.
|
|
- Testing: Pest Feature + Livewire component tests + one architecture guard; browser smoke only for the two user-visible regression scenarios.
|
|
- Validation Lanes: confidence + browser (scoped).
|
|
- Target Platform: Laravel Sail locally; Dokploy/container deployment posture unchanged.
|
|
- Project Type: Laravel monolith under `apps/platform`.
|
|
- Performance Goals: DB-only context recovery; no Graph calls during UI render; no broad unscoped queries in nested surfaces.
|
|
- Constraints: No new persisted truth, migrations, packages, env vars, queue/scheduler changes, or routing architecture changes.
|
|
**Scale/Scope**: Four confirmed nested surfaces + shared seam hardening + guard tests.
|
|
|
|
## UI / Surface Guardrail Plan
|
|
|
|
- **Guardrail scope**: changed existing operator-facing nested surfaces (modal, wizard, relation manager, widget).
|
|
- **Affected routes/pages/actions/states/navigation/panel/provider surfaces**:
|
|
- Backup Set “Add policies” modal table (Livewire component).
|
|
- Restore Run Create wizard (resource create page).
|
|
- Backup Schedule Operation Runs relation manager table (nested resource detail).
|
|
- Environment dashboard triage widget (nested widget).
|
|
- **No-impact class**: N/A.
|
|
- **Native vs custom classification summary**: native Filament + Livewire surfaces; no custom UI framework.
|
|
- **Shared-family relevance**: environment context resolution, authorization/visibility gating, table selection semantics, wizard option closures, remembered context validation.
|
|
- **State layers in scope**: route-owned workspace/environment, Livewire component state (captured at mount), remembered environment context (validated only), ambient Filament tenant (fallback convenience only).
|
|
- **Audience modes in scope**: operator-MSP / platform operators. No customer/read-only surface changes expected.
|
|
- **Decision/diagnostic/raw hierarchy plan**: fail-closed states must be honest; do not show “no records” when context is invalid; no raw debug “framework state” troubleshooting exposed to operators.
|
|
- **Handling modes**: review-mandatory. This is a correctness hardening slice affecting authorization and scope.
|
|
- **Special surface test profiles**: `exception-coded-surface` (context recovery) + `shared-detail-family` (nested relation manager) + browser smoke for two user-visible regressions.
|
|
- **Required tests or manual smoke**:
|
|
- Feature/Livewire tests for each confirmed surface and its fail-closed behavior.
|
|
- Architecture guard preventing unsafe `Filament::setTenant(...)` usage in nested surfaces.
|
|
- Browser smoke for:
|
|
- Backup Set “Add policies” checkbox visibility + selection.
|
|
- Restore Run Create wizard no-crash on Livewire update transitions.
|
|
- **Exception path and spread control**: no broad fallback that sets tenant from arbitrary model IDs. Any referer-based recovery must validate workspace membership and environment entitlement.
|
|
- **UI/Productization coverage decision**: no new routes/pages; cover via tests + browser smoke + PR close-out note.
|
|
|
|
## Shared Pattern & System Fit
|
|
|
|
- **Cross-cutting feature marker**: yes (multiple nested surfaces).
|
|
- **Systems touched**:
|
|
- Filament tenant resolution seam: `apps/platform/app/Filament/Concerns/ResolvesPanelTenantContext.php`
|
|
- Route/shell context: `apps/platform/app/Support/OperateHub/OperateHubShell.php`
|
|
- Workspace/environment context + remembered context: `apps/platform/app/Support/Workspaces/WorkspaceContext.php`
|
|
- UI gating: `apps/platform/app/Support/Rbac/UiEnforcement.php`
|
|
- **Shared abstractions reused**: prefer existing helpers/policies over new framework layers.
|
|
- **New abstraction introduced?**: none by default. A small helper class may be introduced only if at least two confirmed surfaces would otherwise duplicate validated context recovery logic (ABSTR-001).
|
|
- **Bounded deviation / spread control**: any new helper must be feature-local in scope and must not become a generic “ambient context fixer” without explicit follow-up spec approval.
|
|
|
|
## OperationRun UX Impact
|
|
|
|
N/A. This feature does not introduce new queued operations. It must not create new OperationRun types or change OperationRun UX policy.
|
|
|
|
## Provider Boundary / Platform Core Check
|
|
|
|
Platform-core hardening only. No Graph contract, provider registry, or provider vocabulary changes.
|
|
|
|
## Implementation Approach
|
|
|
|
### Phase 1 — Repo truth + reproduce
|
|
|
|
- Inspect current behavior and confirm the concrete failure path(s) for:
|
|
- Add Policies modal selection checkbox hidden.
|
|
- Restore Run Create wizard crash during Livewire update.
|
|
- Document the exact call path(s) and which closures/methods access context.
|
|
|
|
### Phase 2 — Define nested context resolution order
|
|
|
|
Implement (or codify within existing seams) a deterministic resolution order for managed-environment context in nested surfaces:
|
|
|
|
1. **Owner/domain record** (owner record, component-bound record, backup set record, schedule record, widget record).
|
|
2. **Validated component state captured at mount** (e.g., environment ID saved in the Livewire component state).
|
|
3. **Route-owned workspace/environment** (when route params are available).
|
|
4. **Remembered environment** only if workspace membership and entitlement validate.
|
|
5. **Ambient Filament tenant** as fallback convenience only.
|
|
6. **Fail closed** with a clear, honest UI state.
|
|
|
|
Prohibited:
|
|
|
|
- blindly trusting referer as authority
|
|
- unguarded `Filament::setTenant($model->...)` derived from an arbitrary identifier
|
|
- broad “set tenant from model id” fallback in the shared seam
|
|
|
|
### Phase 3 — Apply the contract to confirmed surfaces
|
|
|
|
- **BackupSetPolicyPickerTable**:
|
|
- Resolve context from the BackupSet (validated) and scope policy query accordingly.
|
|
- Ensure mutation-time recheck before attaching policy IDs.
|
|
- Do not override a mismatched existing tenant; fail closed.
|
|
- **RestoreRunResource**:
|
|
- Ensure option closures used in wizard lifecycles can resolve environment context without route params.
|
|
- Implement validated Livewire update context recovery via the shared seam (`apps/platform/app/Support/OperateHub/OperateHubShell.php`) by treating the `Referer` path as a candidate (never authority) and re-validating workspace + membership + operability before using it.
|
|
- **BackupScheduleOperationRunsRelationManager**:
|
|
- Use owner schedule context (`$this->getOwnerRecord()`) as primary context.
|
|
- Avoid ambient `ManagedEnvironment::currentOrFail()`-style assumptions when owner exists.
|
|
- **ManagedEnvironmentTriageArrivalContinuity**:
|
|
- Prefer widget record context; ambient tenant only fallback.
|
|
- Use the same resolver for visibility and mutation-time checks.
|
|
|
|
### Phase 4 — Guardrails
|
|
|
|
- Add `apps/platform/tests/Architecture/FilamentTenantContextContractTest.php` to:
|
|
- detect unsafe `Filament::setTenant(...)` patterns in nested surfaces
|
|
- keep an explicit allowlist for infrastructure-only locations
|
|
- optionally classify (not fail) direct `Filament::getTenant()` usage in known high-risk directories first, to avoid noisy failures
|
|
|
|
### Phase 5 — Tests and validation
|
|
|
|
Add focused tests (Feature/Livewire) for:
|
|
|
|
- tenantless Add Policies picker: authorized user still sees checkboxes and can select items
|
|
- restore create wizard: does not throw when route params are missing in Livewire update lifecycle
|
|
- owner-scoped relation manager: query does not broaden when ambient tenant is null/wrong
|
|
- widget context: record context is preferred; missing context fails closed
|
|
|
|
Validation commands (narrow first):
|
|
|
|
- `cd apps/platform && ./vendor/bin/sail artisan test tests/Feature/Filament --filter='BackupSetPolicyPicker|RestoreRun|BackupScheduleOperationRuns|Triage' --compact`
|
|
- `cd apps/platform && ./vendor/bin/sail artisan test tests/Architecture --filter='FilamentTenantContextContract' --compact`
|
|
|
|
Browser smoke (only when feature tests pass):
|
|
|
|
- `cd apps/platform && php vendor/bin/pest tests/Browser/Spec334NestedFilamentContextContractSmokeTest.php --compact`
|
|
|
|
## Deployment / Ops Impact
|
|
|
|
- **Migrations**: none expected.
|
|
- **Env vars**: none expected.
|
|
- **Queues/scheduler**: none expected.
|
|
- **Filament assets**: no new registered assets expected; deployment posture unchanged.
|