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
73 lines
3.7 KiB
Markdown
73 lines
3.7 KiB
Markdown
# 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_runs` table and an `OperationRun` model.
|
||
- 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_counts` as the canonical “metrics” field for this rollout.
|
||
- **Rationale**: Matches existing schema; avoids adding a new `metrics` column during a UX migration.
|
||
- **Alternatives considered**:
|
||
- New `operation_runs.metrics` column: rejected (scope increase + migration risk).
|
||
|
||
### 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 `OperationRun` and 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).
|