Kurzbeschreibung Implementiert Feature 055 — Ops‑UX Constitution Rollout v1.3.0. Behebt: globales BulkOperationProgress-Widget benötigt keinen manuellen Refresh mehr; ETA/Elapsed aktualisieren korrekt; Widget verschwindet automatisch. Verbesserungen: zuverlässiges polling (Alpine factory + Livewire fallback), sofortiger Enqueue‑Signal-Dispatch, Failure‑Message‑Sanitization, neue Guard‑ und Regressionstests, Specs/Tasks aktualisiert. Was geändert wurde (Auszug) InventoryLanding.php bulk-operation-progress.blade.php OperationUxPresenter.php SyncRestoreRunToOperationRun.php PolicyResource.php PolicyVersionResource.php RestoreRunResource.php tests/Feature/OpsUx/* (PollerRegistration, TerminalNotificationFailureMessageTest, CanonicalViewRunLinksTest, OperationCatalogCoverageTest, UnknownOperationTypeLabelTest) InventorySyncButtonTest.php tasks.md Tests Neue Tests hinzugefügt; php artisan test --group=ops-ux lokal grün (alle relevanten Tests laufen). How to verify manually Auf Branch wechseln: 055-ops-ux-rollout In Filament: Inventory → Sync (oder relevante Bulk‑Aktion) auslösen. Beobachten: Progress‑Widget erscheint sofort, ETA/Elapsed aktualisiert, Widget verschwindet nach Fertigstellung ohne Browser‑Refresh. Optional: ./vendor/bin/sail exec app php artisan test --filter=OpsUx oder php artisan test --group=ops-ux Besonderheiten / Hinweise Einzelne, synchrone Policy‑Actions (ignore/restore/PolicyVersion single archive/restore/forceDelete) sind absichtlich inline und erzeugen kein OperationRun. Bulk‑Aktionen und restore.execute werden als Runs modelliert. Wenn gewünscht, kann ich die inline‑Actions auf OperationRunService umstellen, damit sie in Monitoring → Operations sichtbar werden. Remote: Branch ist bereits gepusht (origin/055-ops-ux-rollout). PR kann in Gitea erstellt werden. Links Specs & tasks: tasks.md Monitoring page: Operations.php Co-authored-by: Ahmed Darrazi <ahmeddarrazi@adsmac.local> Reviewed-on: #64
3.7 KiB
3.7 KiB
Phase 0 Research: Ops-UX Constitution Rollout (v1.3.0 Alignment) (055)
Date: 2026-01-18
Findings
Current operation-run storage and UX primitives
- The repo has a tenant-scoped
operation_runstable and anOperationRunmodel. - Structured “metrics” for this rollout are stored as
operation_runs.summary_counts(JSONB). - Canonical Monitoring entrypoint exists via the Filament resource
OperationRunResource. - Canonical route building already exists in
App\Support\OperationRunLinks.
Existing progress widget patterns
- A bottom-right Livewire widget exists today for bulk operations:
App\Livewire\BulkOperationProgress. - It is injected globally via a Filament render hook in
App\Providers\Filament\AdminPanelProvider. - Current behavior is not constitution-compliant:
- It shows terminal states and renders terminal wording.
- It renders percentages and per-run counts unconditionally.
- It is user-scoped today (filters by
user_id = auth()->id()).
Notifications
- Filament database notifications are already used and are persistent by default.
- Current code has OperationRun DB notifications (queued + completed), but this rollout requires:
- no queued DB notifications
- exactly one terminal notification per run
- initiator-only audience
Decisions
Decision 1: Tenant-wide progress widget scope
- Chosen: The progress widget shows all active runs for the current tenant (not only runs started by the current user), for users with access to Monitoring → Operations.
- Rationale: Aligns with the constitution’s tenant-scoped operations model and avoids “why don’t I see what’s running?” support loops.
- Alternatives considered:
- User-only widget: rejected (hides tenant work and defeats the monitoring intent).
Decision 2: Canonical metrics source
- Chosen: Treat
operation_runs.summary_countsas the canonical “metrics” field for this rollout. - Rationale: Matches existing schema; avoids adding a new
metricscolumn during a UX migration. - Alternatives considered:
- New
operation_runs.metricscolumn: rejected (scope increase + migration risk).
- New
Decision 3: Unknown operation types in UI
- Chosen: Soft-fail at runtime with label
Unknown operation, and fail-fast in CI for code-produced operation types. - Rationale: Keeps Monitoring usable for legacy/dirty data while enforcing discipline for new work.
- Alternatives considered:
- Throw exception at runtime: rejected (breaks Monitoring for historical data).
- Render raw type string: rejected (leaks internal naming and encourages drift).
Decision 4: DB notification audience
- Chosen: Initiator-only for terminal DB notifications.
- Rationale: Prevents tenant-wide notification spam; Monitoring remains the tenant-wide audit surface.
- Alternatives considered:
- Tenant-wide fan-out: rejected (noisy; not necessary for monitoring).
Decision 5: No queued DB notifications
- Chosen: Ban queued DB notifications repo-wide for OperationRuns.
- Rationale: Simplifies dedupe; queued intent belongs to the toast surface.
- Alternatives considered:
- Allow queued DB notifications with dedupe: rejected (still noisy; adds edge cases).
Decision 6: Migration approach for progress widget
- Chosen: Reuse the existing “global Livewire progress widget via render hook” pattern, but migrate it to query
OperationRunand apply constitution rules. - Rationale: Low-risk way to ship a single widget surface across the app.
- Alternatives considered:
- Per-feature widgets/pages: rejected (violates the “three surfaces only” rule).
Open Questions
None (all clarifications captured in the feature spec).