Summary Kurz: Implementiert Feature 054 — canonical OperationRun-flow, Monitoring UI, dispatch-safety, notifications, dedupe, plus small UX safety clarifications (RBAC group search delegated; Restore group mapping DB-only). What Changed Core service: OperationRun lifecycle, dedupe and dispatch helpers — OperationRunService.php. Model + migration: OperationRun model and migration — OperationRun.php, 2026_01_16_180642_create_operation_runs_table.php. Notifications: queued + terminal DB notifications (initiator-only) — OperationRunQueued.php, OperationRunCompleted.php. Monitoring UI: Filament list/detail + Livewire pieces (DB-only render) — OperationRunResource.php and related pages/views. Start surfaces / Jobs: instrumented start surfaces, job middleware, and job updates to use canonical runs — multiple app/Jobs/* and app/Filament/* updates (see tests for full coverage). RBAC + Restore UX clarifications: RBAC group search is delegated-Graph-based and disabled without delegated token; Restore group mapping remains DB-only (directory cache) and helper text always visible — TenantResource.php, RestoreRunResource.php. Specs / Constitution: updated spec & quickstart and added one-line constitution guideline about Graph usage: spec.md quickstart.md constitution.md Tests & Verification Unit / Feature tests added/updated for run lifecycle, notifications, idempotency, and UI guards: see tests/Feature/* (notably OperationRunServiceTest, MonitoringOperationsTest, OperationRunNotificationTest, and various Filament feature tests). Full test run locally: ./vendor/bin/sail artisan test → 587 passed, 5 skipped. Migrations Adds create_operation_runs_table migration; run php artisan migrate in staging after review. Notes / Rationale Monitoring pages are explicitly DB-only at render time (no Graph calls). Start surfaces enqueue work only and return a “View run” link. Delegated Graph access is used only for explicit user actions (RBAC group search); restore mapping intentionally uses cached DB data only to avoid render-time Graph calls. Dispatch wrapper marks runs failed immediately if background dispatch throws synchronously to avoid misleading “queued” states. Upgrade / Deploy Considerations Run migrations: ./vendor/bin/sail artisan migrate. Background workers should be running to process queued jobs (recommended to monitor queue health during rollout). No secret or token persistence changes. PR checklist Tests updated/added for changed behavior Specs updated: 054-unify-runs-suitewide docs + quickstart Constitution note added (.specify) Pint formatting applied Co-authored-by: Ahmed Darrazi <ahmeddarrazi@adsmac.local> Reviewed-on: #63
64 lines
3.6 KiB
Markdown
64 lines
3.6 KiB
Markdown
# Phase 0 Research: Inventory Sync Button (046)
|
|
|
|
**Date**: 2026-01-09
|
|
|
|
## Findings
|
|
|
|
### Existing patterns to reuse
|
|
|
|
#### DB-backed notifications
|
|
- Filament DB notifications are already used in multiple places.
|
|
- Example: Policy Sync action calls `Filament\Notifications\Notification::make()->sendToDatabase(auth()->user())->send()`.
|
|
|
|
#### Bottom-right progress widget
|
|
- The bottom-right progress widget is implemented by `App\Livewire\BulkOperationProgress` and renders `resources/views/livewire/bulk-operation-progress.blade.php`.
|
|
- It polls `BulkOperationRun` filtered by `tenant_id = Tenant::current()->id` and `user_id = auth()->id()`.
|
|
- It is injected globally into Filament via a render hook in `App\Providers\Filament\AdminPanelProvider`.
|
|
|
|
#### Inventory Sync run records
|
|
- Inventory sync runs are already persisted in `inventory_sync_runs` with counts and status.
|
|
- Current `InventorySyncService::syncNow(...)` runs inline and uses locks/concurrency to create/update `InventorySyncRun`.
|
|
|
|
#### Authorization
|
|
- The app already uses tenant-role based authorization for sync operations (e.g. `User::canSyncTenant($tenant)` in `TenantResource`).
|
|
|
|
#### Inventory selection payload
|
|
- Inventory Sync requires a selection payload with shape: `{policy_types: list<string>, categories: list<string>, include_foundations: bool, include_dependencies: bool}`.
|
|
- There is no existing UI picker for inventory selection.
|
|
|
|
## Decisions
|
|
|
|
### Decision: Start Inventory Sync as a queued job
|
|
- **Chosen**: Dispatch an Inventory Sync job from the UI action.
|
|
- **Rationale**: Aligns with existing background operation UX and avoids blocking Livewire requests.
|
|
- **Alternatives considered**:
|
|
- Run inline (current `syncNow`) — rejected due to UX (slow request) and mismatch with existing “progress widget” expectations.
|
|
|
|
### Decision: Use DB notifications + progress widget UX consistent with Policy/Bulk operations
|
|
- **Chosen**: Create a `BulkOperationRun` (resource `inventory`, action `sync`) so the existing bottom-right widget shows progress; also send DB notifications at start and completion/failure.
|
|
- **Rationale**: Matches established UX language and avoids inventing new UI surfaces.
|
|
- **Alternatives considered**:
|
|
- Only show toast notifications — rejected; user explicitly requires DB notification panel + progress widget.
|
|
|
|
### Decision: Authorize via tenant role sync permission
|
|
- **Chosen**: Gate the UI action using `auth()->user()->canSyncTenant(Tenant::current())`.
|
|
- **Rationale**: Aligns with existing “sync” authorization patterns already used for tenant/policy operations.
|
|
- **Alternatives considered**:
|
|
- Introduce new permission strings/roles — rejected for MVP; adds RBAC surface area.
|
|
|
|
### Decision: Default selection = “full inventory”
|
|
- **Chosen**: Dispatch inventory sync with policy types set to `PolicyTypeResolver::supportedPolicyTypes()`, empty categories, and `include_foundations=true`, `include_dependencies=true`.
|
|
- **Rationale**: Simplest interpretation of “Run Inventory Sync” without inventing a new picker UX.
|
|
- **Alternatives considered**:
|
|
- Reuse backup policy picker UI — rejected; different domain (backup selection), more UX than requested.
|
|
|
|
### Decision: Attribute initiator on run record and audit trail
|
|
- **Chosen**: Store initiator identity on `InventorySyncRun` and also emit an audit record.
|
|
- **Rationale**: Improves traceability and aligns with constitution principle “Operations / Run Observability Standard”.
|
|
- **Alternatives considered**:
|
|
- Audit log only — rejected (you chose C).
|
|
|
|
## Open Questions (for Phase 1 design)
|
|
|
|
- None remaining for planning; implementation will add a dedicated queued job.
|