TenantAtlas/specs/054-unify-runs-suitewide/contracts/service_interface.md
ahmido 3030dd9af2 054-unify-runs-suitewide (#63)
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
2026-01-17 22:25:00 +00:00

1.6 KiB

Service Interface: Operation Runs

App\Services\OperationRunService

ensureRun

Idempotently creates or retrieves an active run.

public function ensureRun(
    Tenant $tenant,
    string $type,
    array $inputs,
    ?User $initiator = null
): OperationRun
  • Logic:

    1. Compute hash = sha256(tenant_id + type + sorted_json(inputs)).
    2. Try finding active run (queued or running) with this hash.
    3. If found, return it.
    4. If not found, create new queued run.
    5. Return run.
    6. If an existing active run is returned (dedupe), the initiator (user_id, initiator_name) MUST NOT be replaced.
  • Dispatch failure:

    • If queue dispatch fails after a run was created, the system MUST NOT leave misleading queued runs; instead complete the run immediately as failed (e.g., failure code queue.dispatch_failed) and show a clear UI message.

updateRun

Updates the status/outcome of a run.

public function updateRun(
    OperationRun $run,
    string $status,
    ?string $outcome = null,
    array $summaryCounts = [],
    array $failures = []
): OperationRun

failRun

Helper to fail a run immediately.

public function failRun(OperationRun $run, Throwable $e): OperationRun

App\Jobs\Middleware\TrackOperationRun

Middleware for Jobs to automatically handle running -> completed/failed transitions if bound to a run.

App\Listeners\SyncRestoreRunToOperationRun

Listener for RestoreRun events to update the shadow OperationRun. The adapter row is created/visible only once a restore run reaches previewed (or later).