# Scheduler Graph Jobs: PostgreSQL Migration Plan (2025-12-06) ## Goals - Replace Mongo-based GraphJobStore/PolicyRunService with PostgreSQL equivalents. - Keep graph job determinism (status transitions, ordering) and tenant isolation. - Provide schema, repository surface, and migration steps to unblock PG-T7.1.2a (Cleanup Wave A). ## Proposed Schema (schema: `scheduler`) - `graph_jobs` - `id UUID PK` - `tenant_id TEXT NOT NULL` - `type SMALLINT NOT NULL` (0=build,1=overlay) - `status SMALLINT NOT NULL` (queued, running, completed, failed, canceled) - `payload JSONB NOT NULL` (serialized GraphBuildJob/GraphOverlayJob) - `created_at TIMESTAMPTZ NOT NULL DEFAULT now()` - `updated_at TIMESTAMPTZ NOT NULL DEFAULT now()` - `correlation_id TEXT NULL` - Indexes: `idx_graph_jobs_tenant_status` (tenant_id, status, created_at DESC), `idx_graph_jobs_tenant_type_status` (tenant_id, type, status, created_at DESC) - `graph_job_events` - `id BIGSERIAL PK` - `job_id UUID NOT NULL REFERENCES graph_jobs(id) ON DELETE CASCADE` - `tenant_id TEXT NOT NULL` - `status SMALLINT NOT NULL` - `payload JSONB NOT NULL` - `created_at TIMESTAMPTZ NOT NULL DEFAULT now()` - Index: `idx_graph_job_events_job` (job_id, created_at DESC) ## Repository Contracts - `IGraphJobRepository` (Postgres) - `ValueTask InsertAsync(GraphBuildJob job, CancellationToken ct)` - `ValueTask InsertAsync(GraphOverlayJob job, CancellationToken ct)` - `ValueTask TryReplaceAsync(GraphBuildJob job, GraphJobStatus expected, CancellationToken ct)` - `ValueTask TryReplaceOverlayAsync(GraphOverlayJob job, GraphJobStatus expected, CancellationToken ct)` - `ValueTask GetBuildJobAsync(string tenantId, string id, CancellationToken ct)` - `ValueTask GetOverlayJobAsync(string tenantId, string id, CancellationToken ct)` - `ValueTask> ListBuildJobsAsync(string tenantId, GraphJobStatus? status, int limit, CancellationToken ct)` - `ValueTask> ListOverlayJobsAsync(string tenantId, GraphJobStatus? status, int limit, CancellationToken ct)` - `ValueTask AppendEventAsync(GraphJobEvent evt, CancellationToken ct)` ## Migration - New migration file: `014_graph_jobs.sql` under `src/Scheduler/__Libraries/StellaOps.Scheduler.Storage.Postgres/Migrations` with the tables above. ## DI Changes - Replace `AddSchedulerMongoStorage` and `MongoGraphJobStore` in WebService with `AddSchedulerPostgresStorage` and new `PostgresGraphJobStore` implementing `IGraphJobStore`. - Worker.Backfill: swap Mongo options to Postgres options; use Postgres repos from `StellaOps.Scheduler.Storage.Postgres`. ## Tests - Add Postgres integration tests for `PostgresGraphJobRepository` covering insert/list/update/expected-status checks and event log. - Update WebService/Worker tests to use Postgres fixtures; remove Mongo fixtures. ## Rollback - If regressions occur, revert migration + DI switch; Mongo storage remains in history. ## Owners - Schema/repo: Scheduler Guild - DI/tests: Scheduler Guild