Fix build and code structure improvements. New but essential UI functionality. CI improvements. Documentation improvements. AI module improvements.

This commit is contained in:
StellaOps Bot
2025-12-26 21:54:17 +02:00
parent 335ff7da16
commit c2b9cd8d1f
3717 changed files with 264714 additions and 48202 deletions

View File

@@ -13,8 +13,8 @@
Link="Fixtures\%(RecursiveDir)%(Filename)%(Extension)" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.0" />
<PackageReference Include="RoaringBitmap" Version="0.0.9" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" />
<PackageReference Include="RoaringBitmap" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,32 @@
using Microsoft.EntityFrameworkCore;
using StellaOps.Infrastructure.EfCore.Context;
namespace StellaOps.Scheduler.Persistence.EfCore.Context;
/// <summary>
/// EF Core DbContext for the Scheduler module.
/// Placeholder for future EF Core scaffolding from PostgreSQL schema.
/// </summary>
public class SchedulerDbContext : StellaOpsDbContextBase
{
/// <summary>
/// Creates a new Scheduler DbContext.
/// </summary>
public SchedulerDbContext(DbContextOptions<SchedulerDbContext> options)
: base(options)
{
}
/// <inheritdoc />
protected override string SchemaName => "scheduler";
/// <inheritdoc />
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// Entity configurations will be added after scaffolding
// from the PostgreSQL database using:
// dotnet ef dbcontext scaffold
}
}

View File

@@ -1,25 +1,25 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using StellaOps.Infrastructure.Postgres;
using StellaOps.Infrastructure.Postgres.Options;
using StellaOps.Scheduler.Models;
using StellaOps.Scheduler.Storage.Postgres.Repositories;
using StellaOps.Scheduler.Persistence.Postgres;
using StellaOps.Scheduler.Persistence.Postgres.Repositories;
namespace StellaOps.Scheduler.Storage.Postgres;
namespace StellaOps.Scheduler.Persistence.Extensions;
/// <summary>
/// Extension methods for configuring Scheduler PostgreSQL storage services.
/// Extension methods for configuring Scheduler persistence services.
/// </summary>
public static class ServiceCollectionExtensions
public static class SchedulerPersistenceExtensions
{
/// <summary>
/// Adds Scheduler PostgreSQL storage services.
/// Adds Scheduler PostgreSQL persistence services using configuration section.
/// </summary>
/// <param name="services">Service collection.</param>
/// <param name="configuration">Configuration root.</param>
/// <param name="sectionName">Configuration section name for PostgreSQL options.</param>
/// <returns>Service collection for chaining.</returns>
public static IServiceCollection AddSchedulerPostgresStorage(
public static IServiceCollection AddSchedulerPersistence(
this IServiceCollection services,
IConfiguration configuration,
string sectionName = "Postgres:Scheduler")
@@ -46,12 +46,12 @@ public static class ServiceCollectionExtensions
}
/// <summary>
/// Adds Scheduler PostgreSQL storage services with explicit options.
/// Adds Scheduler PostgreSQL persistence services with explicit options.
/// </summary>
/// <param name="services">Service collection.</param>
/// <param name="configureOptions">Options configuration action.</param>
/// <returns>Service collection for chaining.</returns>
public static IServiceCollection AddSchedulerPostgresStorage(
public static IServiceCollection AddSchedulerPersistence(
this IServiceCollection services,
Action<PostgresOptions> configureOptions)
{

View File

@@ -0,0 +1,596 @@
-- Scheduler Schema: Consolidated Initial Schema
-- Consolidated from migrations 001-012b (pre_1.0 archived)
-- Creates the complete scheduler schema for jobs, triggers, workers, runs, and policies
BEGIN;
-- ============================================================================
-- SECTION 1: Schema Creation
-- ============================================================================
CREATE SCHEMA IF NOT EXISTS scheduler;
CREATE SCHEMA IF NOT EXISTS scheduler_app;
-- ============================================================================
-- SECTION 2: Enum Types
-- ============================================================================
DO $$ BEGIN
CREATE TYPE scheduler.job_status AS ENUM (
'pending', 'scheduled', 'leased', 'running',
'succeeded', 'failed', 'canceled', 'timed_out'
);
EXCEPTION WHEN duplicate_object THEN null; END $$;
DO $$ BEGIN
CREATE TYPE scheduler.graph_job_type AS ENUM ('build', 'overlay');
EXCEPTION WHEN duplicate_object THEN NULL; END $$;
DO $$ BEGIN
CREATE TYPE scheduler.graph_job_status AS ENUM ('pending', 'running', 'completed', 'failed', 'canceled');
EXCEPTION WHEN duplicate_object THEN NULL; END $$;
DO $$ BEGIN
CREATE TYPE scheduler.run_state AS ENUM ('planning','queued','running','completed','error','cancelled');
EXCEPTION WHEN duplicate_object THEN NULL; END $$;
DO $$ BEGIN
CREATE TYPE scheduler.policy_run_status AS ENUM ('pending','submitted','retrying','failed','completed','cancelled');
EXCEPTION WHEN duplicate_object THEN NULL; END $$;
-- ============================================================================
-- SECTION 3: Helper Functions
-- ============================================================================
CREATE OR REPLACE FUNCTION scheduler.update_updated_at()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION scheduler_app.require_current_tenant()
RETURNS TEXT
LANGUAGE plpgsql STABLE SECURITY DEFINER
AS $$
DECLARE
v_tenant TEXT;
BEGIN
v_tenant := current_setting('app.tenant_id', true);
IF v_tenant IS NULL OR v_tenant = '' THEN
RAISE EXCEPTION 'app.tenant_id session variable not set'
USING HINT = 'Set via: SELECT set_config(''app.tenant_id'', ''<tenant>'', false)',
ERRCODE = 'P0001';
END IF;
RETURN v_tenant;
END;
$$;
REVOKE ALL ON FUNCTION scheduler_app.require_current_tenant() FROM PUBLIC;
-- ============================================================================
-- SECTION 4: Core Tables
-- ============================================================================
-- Jobs table
CREATE TABLE IF NOT EXISTS scheduler.jobs (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id TEXT NOT NULL,
project_id TEXT,
job_type TEXT NOT NULL,
status scheduler.job_status NOT NULL DEFAULT 'pending',
priority INT NOT NULL DEFAULT 0,
payload JSONB NOT NULL DEFAULT '{}',
payload_digest TEXT NOT NULL,
idempotency_key TEXT NOT NULL,
correlation_id TEXT,
attempt INT NOT NULL DEFAULT 0,
max_attempts INT NOT NULL DEFAULT 3,
lease_id UUID,
worker_id TEXT,
lease_until TIMESTAMPTZ,
not_before TIMESTAMPTZ,
reason TEXT,
result JSONB,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
scheduled_at TIMESTAMPTZ,
leased_at TIMESTAMPTZ,
started_at TIMESTAMPTZ,
completed_at TIMESTAMPTZ,
created_by TEXT,
UNIQUE(tenant_id, idempotency_key)
);
CREATE INDEX idx_jobs_tenant_status ON scheduler.jobs(tenant_id, status);
CREATE INDEX idx_jobs_tenant_type ON scheduler.jobs(tenant_id, job_type);
CREATE INDEX idx_jobs_scheduled ON scheduler.jobs(tenant_id, status, not_before, priority DESC, created_at)
WHERE status = 'scheduled';
CREATE INDEX idx_jobs_leased ON scheduler.jobs(tenant_id, status, lease_until)
WHERE status = 'leased';
CREATE INDEX idx_jobs_project ON scheduler.jobs(tenant_id, project_id);
CREATE INDEX idx_jobs_correlation ON scheduler.jobs(correlation_id);
-- Triggers table (cron-based job triggers)
CREATE TABLE IF NOT EXISTS scheduler.triggers (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id TEXT NOT NULL,
name TEXT NOT NULL,
description TEXT,
job_type TEXT NOT NULL,
job_payload JSONB NOT NULL DEFAULT '{}',
cron_expression TEXT NOT NULL,
timezone TEXT NOT NULL DEFAULT 'UTC',
enabled BOOLEAN NOT NULL DEFAULT TRUE,
next_fire_at TIMESTAMPTZ,
last_fire_at TIMESTAMPTZ,
last_job_id UUID REFERENCES scheduler.jobs(id),
fire_count BIGINT NOT NULL DEFAULT 0,
misfire_count INT NOT NULL DEFAULT 0,
metadata JSONB NOT NULL DEFAULT '{}',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
created_by TEXT,
UNIQUE(tenant_id, name)
);
CREATE INDEX idx_triggers_tenant_id ON scheduler.triggers(tenant_id);
CREATE INDEX idx_triggers_next_fire ON scheduler.triggers(enabled, next_fire_at) WHERE enabled = TRUE;
CREATE INDEX idx_triggers_job_type ON scheduler.triggers(tenant_id, job_type);
CREATE TRIGGER trg_triggers_updated_at
BEFORE UPDATE ON scheduler.triggers
FOR EACH ROW EXECUTE FUNCTION scheduler.update_updated_at();
-- Workers table (global, NOT RLS-protected)
CREATE TABLE IF NOT EXISTS scheduler.workers (
id TEXT PRIMARY KEY,
tenant_id TEXT,
hostname TEXT NOT NULL,
process_id INT,
job_types TEXT[] NOT NULL DEFAULT '{}',
max_concurrent_jobs INT NOT NULL DEFAULT 1,
current_jobs INT NOT NULL DEFAULT 0,
status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'draining', 'stopped')),
last_heartbeat_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
registered_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
metadata JSONB NOT NULL DEFAULT '{}'
);
CREATE INDEX idx_workers_status ON scheduler.workers(status);
CREATE INDEX idx_workers_heartbeat ON scheduler.workers(last_heartbeat_at);
CREATE INDEX idx_workers_tenant ON scheduler.workers(tenant_id);
COMMENT ON TABLE scheduler.workers IS 'Global worker registry. Not RLS-protected - workers serve all tenants.';
-- Distributed locks
CREATE TABLE IF NOT EXISTS scheduler.locks (
lock_key TEXT PRIMARY KEY,
tenant_id TEXT NOT NULL,
holder_id TEXT NOT NULL,
acquired_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
expires_at TIMESTAMPTZ NOT NULL,
metadata JSONB NOT NULL DEFAULT '{}'
);
CREATE INDEX idx_locks_tenant ON scheduler.locks(tenant_id);
CREATE INDEX idx_locks_expires ON scheduler.locks(expires_at);
-- Job history
CREATE TABLE IF NOT EXISTS scheduler.job_history (
id BIGSERIAL PRIMARY KEY,
job_id UUID NOT NULL,
tenant_id TEXT NOT NULL,
project_id TEXT,
job_type TEXT NOT NULL,
status scheduler.job_status NOT NULL,
attempt INT NOT NULL,
payload_digest TEXT NOT NULL,
result JSONB,
reason TEXT,
worker_id TEXT,
duration_ms BIGINT,
created_at TIMESTAMPTZ NOT NULL,
completed_at TIMESTAMPTZ NOT NULL,
archived_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_job_history_tenant ON scheduler.job_history(tenant_id);
CREATE INDEX idx_job_history_job_id ON scheduler.job_history(job_id);
CREATE INDEX idx_job_history_type ON scheduler.job_history(tenant_id, job_type);
CREATE INDEX idx_job_history_completed ON scheduler.job_history(tenant_id, completed_at);
-- Metrics table
CREATE TABLE IF NOT EXISTS scheduler.metrics (
id BIGSERIAL PRIMARY KEY,
tenant_id TEXT NOT NULL,
job_type TEXT NOT NULL,
period_start TIMESTAMPTZ NOT NULL,
period_end TIMESTAMPTZ NOT NULL,
jobs_created BIGINT NOT NULL DEFAULT 0,
jobs_completed BIGINT NOT NULL DEFAULT 0,
jobs_failed BIGINT NOT NULL DEFAULT 0,
jobs_timed_out BIGINT NOT NULL DEFAULT 0,
avg_duration_ms BIGINT,
p50_duration_ms BIGINT,
p95_duration_ms BIGINT,
p99_duration_ms BIGINT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE(tenant_id, job_type, period_start)
);
CREATE INDEX idx_metrics_tenant_period ON scheduler.metrics(tenant_id, period_start);
-- ============================================================================
-- SECTION 5: Schedules and Runs
-- ============================================================================
CREATE TABLE IF NOT EXISTS scheduler.schedules (
id TEXT PRIMARY KEY,
tenant_id TEXT NOT NULL,
name TEXT NOT NULL,
description TEXT,
enabled BOOLEAN NOT NULL DEFAULT TRUE,
cron_expression TEXT,
timezone TEXT NOT NULL DEFAULT 'UTC',
mode TEXT NOT NULL CHECK (mode IN ('analysisonly', 'contentrefresh')),
selection JSONB NOT NULL DEFAULT '{}',
only_if JSONB NOT NULL DEFAULT '{}',
notify JSONB NOT NULL DEFAULT '{}',
limits JSONB NOT NULL DEFAULT '{}',
subscribers TEXT[] NOT NULL DEFAULT '{}',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
created_by TEXT NOT NULL,
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_by TEXT NOT NULL,
deleted_at TIMESTAMPTZ,
deleted_by TEXT
);
CREATE INDEX IF NOT EXISTS idx_schedules_tenant ON scheduler.schedules(tenant_id) WHERE deleted_at IS NULL;
CREATE INDEX IF NOT EXISTS idx_schedules_enabled ON scheduler.schedules(tenant_id, enabled) WHERE deleted_at IS NULL;
CREATE UNIQUE INDEX IF NOT EXISTS uq_schedules_tenant_name_active ON scheduler.schedules(tenant_id, name) WHERE deleted_at IS NULL;
-- Runs table with generated columns for stats
CREATE TABLE IF NOT EXISTS scheduler.runs (
id TEXT NOT NULL,
tenant_id TEXT NOT NULL,
schedule_id TEXT,
trigger JSONB NOT NULL,
state scheduler.run_state NOT NULL,
stats JSONB NOT NULL,
reason JSONB NOT NULL,
created_at TIMESTAMPTZ NOT NULL,
started_at TIMESTAMPTZ,
finished_at TIMESTAMPTZ,
error TEXT,
deltas JSONB NOT NULL,
retry_of TEXT,
schema_version TEXT,
finding_count INT GENERATED ALWAYS AS (NULLIF((stats->>'findingCount'), '')::int) STORED,
critical_count INT GENERATED ALWAYS AS (NULLIF((stats->>'criticalCount'), '')::int) STORED,
high_count INT GENERATED ALWAYS AS (NULLIF((stats->>'highCount'), '')::int) STORED,
new_finding_count INT GENERATED ALWAYS AS (NULLIF((stats->>'newFindingCount'), '')::int) STORED,
component_count INT GENERATED ALWAYS AS (NULLIF((stats->>'componentCount'), '')::int) STORED,
PRIMARY KEY (tenant_id, id)
);
CREATE INDEX IF NOT EXISTS idx_runs_state ON scheduler.runs(state);
CREATE INDEX IF NOT EXISTS idx_runs_schedule ON scheduler.runs(tenant_id, schedule_id);
CREATE INDEX IF NOT EXISTS idx_runs_created ON scheduler.runs(created_at);
CREATE INDEX IF NOT EXISTS ix_runs_with_findings ON scheduler.runs(tenant_id, created_at DESC) WHERE finding_count > 0;
CREATE INDEX IF NOT EXISTS ix_runs_critical ON scheduler.runs(tenant_id, created_at DESC, critical_count) WHERE critical_count > 0;
CREATE INDEX IF NOT EXISTS ix_runs_summary_cover ON scheduler.runs(tenant_id, state, created_at DESC) INCLUDE (finding_count, critical_count, high_count, new_finding_count);
CREATE INDEX IF NOT EXISTS ix_runs_tenant_findings ON scheduler.runs(tenant_id, finding_count DESC, created_at DESC) WHERE state = 'completed';
-- Impact snapshots
CREATE TABLE IF NOT EXISTS scheduler.impact_snapshots (
snapshot_id TEXT PRIMARY KEY,
tenant_id TEXT NOT NULL,
run_id TEXT,
impact JSONB NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_impact_snapshots_run ON scheduler.impact_snapshots(run_id);
-- Run summaries
CREATE TABLE IF NOT EXISTS scheduler.run_summaries (
id TEXT PRIMARY KEY,
tenant_id TEXT NOT NULL,
schedule_id TEXT REFERENCES scheduler.schedules(id),
period_start TIMESTAMPTZ NOT NULL,
period_end TIMESTAMPTZ NOT NULL,
total_runs INT NOT NULL DEFAULT 0,
successful_runs INT NOT NULL DEFAULT 0,
failed_runs INT NOT NULL DEFAULT 0,
cancelled_runs INT NOT NULL DEFAULT 0,
avg_duration_seconds NUMERIC(10,2),
max_duration_seconds INT,
min_duration_seconds INT,
total_findings_detected INT NOT NULL DEFAULT 0,
new_criticals INT NOT NULL DEFAULT 0,
computed_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE (tenant_id, schedule_id, period_start)
);
CREATE INDEX IF NOT EXISTS idx_run_summaries_tenant ON scheduler.run_summaries(tenant_id, period_start DESC);
-- Execution logs
CREATE TABLE IF NOT EXISTS scheduler.execution_logs (
id BIGSERIAL PRIMARY KEY,
run_id TEXT NOT NULL,
logged_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
level TEXT NOT NULL,
message TEXT NOT NULL,
logger TEXT,
data JSONB NOT NULL DEFAULT '{}'
);
CREATE INDEX IF NOT EXISTS idx_execution_logs_run ON scheduler.execution_logs(run_id);
-- ============================================================================
-- SECTION 6: Graph Jobs (v2 schema)
-- ============================================================================
CREATE TABLE IF NOT EXISTS scheduler.graph_jobs (
id UUID PRIMARY KEY,
tenant_id TEXT NOT NULL,
type scheduler.graph_job_type NOT NULL,
status scheduler.graph_job_status NOT NULL,
payload JSONB NOT NULL,
correlation_id TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_graph_jobs_tenant_status ON scheduler.graph_jobs(tenant_id, status, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_graph_jobs_tenant_type_status ON scheduler.graph_jobs(tenant_id, type, status, created_at DESC);
CREATE TABLE IF NOT EXISTS scheduler.graph_job_events (
id BIGSERIAL PRIMARY KEY,
job_id UUID NOT NULL REFERENCES scheduler.graph_jobs(id) ON DELETE CASCADE,
tenant_id TEXT NOT NULL,
status scheduler.graph_job_status NOT NULL,
payload JSONB NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_graph_job_events_job ON scheduler.graph_job_events(job_id, created_at DESC);
-- ============================================================================
-- SECTION 7: Policy Run Jobs
-- ============================================================================
CREATE TABLE IF NOT EXISTS scheduler.policy_jobs (
id TEXT PRIMARY KEY,
tenant_id TEXT NOT NULL,
policy_pack_id TEXT NOT NULL,
policy_version INT,
target_type TEXT NOT NULL,
target_id TEXT NOT NULL,
status TEXT NOT NULL CHECK (status IN ('pending','queued','running','completed','failed','cancelled')),
priority INT NOT NULL DEFAULT 100,
run_id TEXT,
requested_by TEXT,
mode TEXT,
metadata JSONB NOT NULL DEFAULT '{}',
inputs JSONB NOT NULL DEFAULT '{}',
attempt_count INT NOT NULL DEFAULT 0,
max_attempts INT NOT NULL DEFAULT 3,
queued_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
available_at TIMESTAMPTZ,
submitted_at TIMESTAMPTZ,
started_at TIMESTAMPTZ,
completed_at TIMESTAMPTZ,
cancellation_requested BOOLEAN NOT NULL DEFAULT FALSE,
cancellation_reason TEXT,
cancelled_at TIMESTAMPTZ,
last_attempt_at TIMESTAMPTZ,
last_error TEXT,
lease_owner TEXT,
lease_expires_at TIMESTAMPTZ,
correlation_id TEXT
);
CREATE INDEX IF NOT EXISTS idx_policy_jobs_tenant_status ON scheduler.policy_jobs(tenant_id, status);
CREATE INDEX IF NOT EXISTS idx_policy_jobs_run ON scheduler.policy_jobs(run_id);
CREATE TABLE IF NOT EXISTS scheduler.policy_run_jobs (
id TEXT PRIMARY KEY,
tenant_id TEXT NOT NULL,
policy_id TEXT NOT NULL,
policy_version INT,
mode TEXT NOT NULL,
priority INT NOT NULL,
priority_rank INT NOT NULL,
run_id TEXT,
requested_by TEXT,
correlation_id TEXT,
metadata JSONB,
inputs JSONB NOT NULL,
queued_at TIMESTAMPTZ,
status scheduler.policy_run_status NOT NULL,
attempt_count INT NOT NULL,
last_attempt_at TIMESTAMPTZ,
last_error TEXT,
created_at TIMESTAMPTZ NOT NULL,
updated_at TIMESTAMPTZ NOT NULL,
available_at TIMESTAMPTZ NOT NULL,
submitted_at TIMESTAMPTZ,
completed_at TIMESTAMPTZ,
lease_owner TEXT,
lease_expires_at TIMESTAMPTZ,
cancellation_requested BOOLEAN NOT NULL DEFAULT FALSE,
cancellation_requested_at TIMESTAMPTZ,
cancellation_reason TEXT,
cancelled_at TIMESTAMPTZ,
schema_version TEXT
);
CREATE INDEX IF NOT EXISTS idx_policy_run_jobs_tenant ON scheduler.policy_run_jobs(tenant_id);
CREATE INDEX IF NOT EXISTS idx_policy_run_jobs_status ON scheduler.policy_run_jobs(status);
CREATE INDEX IF NOT EXISTS idx_policy_run_jobs_run ON scheduler.policy_run_jobs(run_id);
CREATE INDEX IF NOT EXISTS idx_policy_run_jobs_policy ON scheduler.policy_run_jobs(tenant_id, policy_id);
-- ============================================================================
-- SECTION 8: Partitioned Audit Table
-- ============================================================================
CREATE TABLE IF NOT EXISTS scheduler.audit (
id BIGSERIAL,
tenant_id TEXT NOT NULL,
user_id UUID,
action TEXT NOT NULL,
resource_type TEXT NOT NULL,
resource_id TEXT,
old_value JSONB,
new_value JSONB,
correlation_id TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
PRIMARY KEY (id, created_at)
) PARTITION BY RANGE (created_at);
-- Create partitions dynamically
DO $$
DECLARE
v_start DATE;
v_end DATE;
v_partition_name TEXT;
BEGIN
v_start := date_trunc('month', NOW() - INTERVAL '6 months')::DATE;
WHILE v_start <= date_trunc('month', NOW() + INTERVAL '3 months')::DATE LOOP
v_end := (v_start + INTERVAL '1 month')::DATE;
v_partition_name := 'audit_' || to_char(v_start, 'YYYY_MM');
IF NOT EXISTS (
SELECT 1 FROM pg_class c
JOIN pg_namespace n ON c.relnamespace = n.oid
WHERE n.nspname = 'scheduler' AND c.relname = v_partition_name
) THEN
EXECUTE format(
'CREATE TABLE scheduler.%I PARTITION OF scheduler.audit FOR VALUES FROM (%L) TO (%L)',
v_partition_name, v_start, v_end
);
END IF;
v_start := v_end;
END LOOP;
END $$;
CREATE TABLE IF NOT EXISTS scheduler.audit_default PARTITION OF scheduler.audit DEFAULT;
CREATE INDEX IF NOT EXISTS ix_audit_tenant ON scheduler.audit(tenant_id);
CREATE INDEX IF NOT EXISTS ix_audit_resource ON scheduler.audit(resource_type, resource_id);
CREATE INDEX IF NOT EXISTS ix_audit_correlation ON scheduler.audit(correlation_id) WHERE correlation_id IS NOT NULL;
CREATE INDEX IF NOT EXISTS brin_audit_created ON scheduler.audit USING BRIN(created_at) WITH (pages_per_range = 128);
COMMENT ON TABLE scheduler.audit IS 'Audit log for scheduler operations. Partitioned monthly by created_at for retention management.';
-- ============================================================================
-- SECTION 9: Row-Level Security
-- ============================================================================
-- scheduler.schedules
ALTER TABLE scheduler.schedules ENABLE ROW LEVEL SECURITY;
ALTER TABLE scheduler.schedules FORCE ROW LEVEL SECURITY;
CREATE POLICY schedules_tenant_isolation ON scheduler.schedules FOR ALL
USING (tenant_id = scheduler_app.require_current_tenant())
WITH CHECK (tenant_id = scheduler_app.require_current_tenant());
-- scheduler.runs
ALTER TABLE scheduler.runs ENABLE ROW LEVEL SECURITY;
ALTER TABLE scheduler.runs FORCE ROW LEVEL SECURITY;
CREATE POLICY runs_tenant_isolation ON scheduler.runs FOR ALL
USING (tenant_id = scheduler_app.require_current_tenant())
WITH CHECK (tenant_id = scheduler_app.require_current_tenant());
-- scheduler.jobs
ALTER TABLE scheduler.jobs ENABLE ROW LEVEL SECURITY;
ALTER TABLE scheduler.jobs FORCE ROW LEVEL SECURITY;
CREATE POLICY jobs_tenant_isolation ON scheduler.jobs FOR ALL
USING (tenant_id = scheduler_app.require_current_tenant())
WITH CHECK (tenant_id = scheduler_app.require_current_tenant());
-- scheduler.triggers
ALTER TABLE scheduler.triggers ENABLE ROW LEVEL SECURITY;
ALTER TABLE scheduler.triggers FORCE ROW LEVEL SECURITY;
CREATE POLICY triggers_tenant_isolation ON scheduler.triggers FOR ALL
USING (tenant_id = scheduler_app.require_current_tenant())
WITH CHECK (tenant_id = scheduler_app.require_current_tenant());
-- scheduler.graph_jobs
ALTER TABLE scheduler.graph_jobs ENABLE ROW LEVEL SECURITY;
ALTER TABLE scheduler.graph_jobs FORCE ROW LEVEL SECURITY;
CREATE POLICY graph_jobs_tenant_isolation ON scheduler.graph_jobs FOR ALL
USING (tenant_id = scheduler_app.require_current_tenant())
WITH CHECK (tenant_id = scheduler_app.require_current_tenant());
-- scheduler.policy_jobs
ALTER TABLE scheduler.policy_jobs ENABLE ROW LEVEL SECURITY;
ALTER TABLE scheduler.policy_jobs FORCE ROW LEVEL SECURITY;
CREATE POLICY policy_jobs_tenant_isolation ON scheduler.policy_jobs FOR ALL
USING (tenant_id = scheduler_app.require_current_tenant())
WITH CHECK (tenant_id = scheduler_app.require_current_tenant());
-- scheduler.locks
ALTER TABLE scheduler.locks ENABLE ROW LEVEL SECURITY;
ALTER TABLE scheduler.locks FORCE ROW LEVEL SECURITY;
CREATE POLICY locks_tenant_isolation ON scheduler.locks FOR ALL
USING (tenant_id = scheduler_app.require_current_tenant())
WITH CHECK (tenant_id = scheduler_app.require_current_tenant());
-- scheduler.impact_snapshots
ALTER TABLE scheduler.impact_snapshots ENABLE ROW LEVEL SECURITY;
ALTER TABLE scheduler.impact_snapshots FORCE ROW LEVEL SECURITY;
CREATE POLICY impact_snapshots_tenant_isolation ON scheduler.impact_snapshots FOR ALL
USING (tenant_id = scheduler_app.require_current_tenant())
WITH CHECK (tenant_id = scheduler_app.require_current_tenant());
-- scheduler.run_summaries
ALTER TABLE scheduler.run_summaries ENABLE ROW LEVEL SECURITY;
ALTER TABLE scheduler.run_summaries FORCE ROW LEVEL SECURITY;
CREATE POLICY run_summaries_tenant_isolation ON scheduler.run_summaries FOR ALL
USING (tenant_id = scheduler_app.require_current_tenant())
WITH CHECK (tenant_id = scheduler_app.require_current_tenant());
-- scheduler.audit
ALTER TABLE scheduler.audit ENABLE ROW LEVEL SECURITY;
ALTER TABLE scheduler.audit FORCE ROW LEVEL SECURITY;
CREATE POLICY audit_tenant_isolation ON scheduler.audit FOR ALL
USING (tenant_id = scheduler_app.require_current_tenant())
WITH CHECK (tenant_id = scheduler_app.require_current_tenant());
-- scheduler.job_history
ALTER TABLE scheduler.job_history ENABLE ROW LEVEL SECURITY;
ALTER TABLE scheduler.job_history FORCE ROW LEVEL SECURITY;
CREATE POLICY job_history_tenant_isolation ON scheduler.job_history FOR ALL
USING (tenant_id = scheduler_app.require_current_tenant())
WITH CHECK (tenant_id = scheduler_app.require_current_tenant());
-- scheduler.metrics
ALTER TABLE scheduler.metrics ENABLE ROW LEVEL SECURITY;
ALTER TABLE scheduler.metrics FORCE ROW LEVEL SECURITY;
CREATE POLICY metrics_tenant_isolation ON scheduler.metrics FOR ALL
USING (tenant_id = scheduler_app.require_current_tenant())
WITH CHECK (tenant_id = scheduler_app.require_current_tenant());
-- scheduler.execution_logs inherits from runs
ALTER TABLE scheduler.execution_logs ENABLE ROW LEVEL SECURITY;
ALTER TABLE scheduler.execution_logs FORCE ROW LEVEL SECURITY;
CREATE POLICY execution_logs_tenant_isolation ON scheduler.execution_logs FOR ALL
USING (
run_id IN (SELECT id FROM scheduler.runs WHERE tenant_id = scheduler_app.require_current_tenant())
);
-- ============================================================================
-- SECTION 10: Admin Bypass Role
-- ============================================================================
DO $$
BEGIN
IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'scheduler_admin') THEN
CREATE ROLE scheduler_admin WITH NOLOGIN BYPASSRLS;
END IF;
END
$$;
COMMIT;

View File

@@ -1,6 +1,6 @@
using System.Text.Json;
namespace StellaOps.Scheduler.Storage.Postgres;
namespace StellaOps.Scheduler.Persistence.Postgres;
internal static class CanonicalJsonSerializer
{

View File

@@ -1,4 +1,4 @@
namespace StellaOps.Scheduler.Storage.Postgres.Models;
namespace StellaOps.Scheduler.Persistence.Postgres.Models;
/// <summary>
/// Scope type for failure signatures.

View File

@@ -1,4 +1,4 @@
namespace StellaOps.Scheduler.Storage.Postgres.Models;
namespace StellaOps.Scheduler.Persistence.Postgres.Models;
/// <summary>
/// Job status values matching the PostgreSQL enum.

View File

@@ -1,4 +1,4 @@
namespace StellaOps.Scheduler.Storage.Postgres.Models;
namespace StellaOps.Scheduler.Persistence.Postgres.Models;
/// <summary>
/// Represents a job history entity in the scheduler schema.

View File

@@ -1,4 +1,4 @@
namespace StellaOps.Scheduler.Storage.Postgres.Models;
namespace StellaOps.Scheduler.Persistence.Postgres.Models;
/// <summary>
/// Represents a distributed lock entity in the scheduler schema.

View File

@@ -1,4 +1,4 @@
namespace StellaOps.Scheduler.Storage.Postgres.Models;
namespace StellaOps.Scheduler.Persistence.Postgres.Models;
/// <summary>
/// Represents a metrics entity in the scheduler schema.

View File

@@ -1,4 +1,4 @@
namespace StellaOps.Scheduler.Storage.Postgres.Models;
namespace StellaOps.Scheduler.Persistence.Postgres.Models;
/// <summary>
/// Represents a trigger entity in the scheduler schema.

View File

@@ -1,4 +1,4 @@
namespace StellaOps.Scheduler.Storage.Postgres.Models;
namespace StellaOps.Scheduler.Persistence.Postgres.Models;
/// <summary>
/// Worker status values.

View File

@@ -1,9 +1,9 @@
using Microsoft.Extensions.Logging;
using Npgsql;
using StellaOps.Infrastructure.Postgres.Repositories;
using StellaOps.Scheduler.Storage.Postgres.Models;
using StellaOps.Scheduler.Persistence.Postgres.Models;
namespace StellaOps.Scheduler.Storage.Postgres.Repositories;
namespace StellaOps.Scheduler.Persistence.Postgres.Repositories;
/// <summary>
/// PostgreSQL repository for distributed lock operations.

View File

@@ -1,9 +1,9 @@
using Microsoft.Extensions.Logging;
using Npgsql;
using StellaOps.Infrastructure.Postgres.Repositories;
using StellaOps.Scheduler.Storage.Postgres.Models;
using StellaOps.Scheduler.Persistence.Postgres.Models;
namespace StellaOps.Scheduler.Storage.Postgres.Repositories;
namespace StellaOps.Scheduler.Persistence.Postgres.Repositories;
/// <summary>
/// PostgreSQL repository for failure signature operations.

View File

@@ -4,7 +4,7 @@ using Npgsql;
using StellaOps.Infrastructure.Postgres;
using StellaOps.Scheduler.Models;
namespace StellaOps.Scheduler.Storage.Postgres.Repositories;
namespace StellaOps.Scheduler.Persistence.Postgres.Repositories;
public sealed class GraphJobRepository : IGraphJobRepository
{

View File

@@ -1,6 +1,6 @@
using StellaOps.Scheduler.Storage.Postgres.Models;
using StellaOps.Scheduler.Persistence.Postgres.Models;
namespace StellaOps.Scheduler.Storage.Postgres.Repositories;
namespace StellaOps.Scheduler.Persistence.Postgres.Repositories;
/// <summary>
/// Repository interface for distributed lock operations.

View File

@@ -1,6 +1,6 @@
using StellaOps.Scheduler.Storage.Postgres.Models;
using StellaOps.Scheduler.Persistence.Postgres.Models;
namespace StellaOps.Scheduler.Storage.Postgres.Repositories;
namespace StellaOps.Scheduler.Persistence.Postgres.Repositories;
/// <summary>
/// Repository interface for failure signature operations.

View File

@@ -3,7 +3,7 @@ using System.Threading;
using System.Threading.Tasks;
using StellaOps.Scheduler.Models;
namespace StellaOps.Scheduler.Storage.Postgres.Repositories;
namespace StellaOps.Scheduler.Persistence.Postgres.Repositories;
public interface IGraphJobRepository
{

View File

@@ -1,6 +1,6 @@
using StellaOps.Scheduler.Models;
namespace StellaOps.Scheduler.Storage.Postgres.Repositories;
namespace StellaOps.Scheduler.Persistence.Postgres.Repositories;
public interface IImpactSnapshotRepository
{

View File

@@ -1,6 +1,6 @@
using StellaOps.Scheduler.Storage.Postgres.Models;
using StellaOps.Scheduler.Persistence.Postgres.Models;
namespace StellaOps.Scheduler.Storage.Postgres.Repositories;
namespace StellaOps.Scheduler.Persistence.Postgres.Repositories;
/// <summary>
/// Repository interface for job history operations.

View File

@@ -1,6 +1,6 @@
using StellaOps.Scheduler.Storage.Postgres.Models;
using StellaOps.Scheduler.Persistence.Postgres.Models;
namespace StellaOps.Scheduler.Storage.Postgres.Repositories;
namespace StellaOps.Scheduler.Persistence.Postgres.Repositories;
/// <summary>
/// Repository interface for job operations.

View File

@@ -1,6 +1,6 @@
using StellaOps.Scheduler.Storage.Postgres.Models;
using StellaOps.Scheduler.Persistence.Postgres.Models;
namespace StellaOps.Scheduler.Storage.Postgres.Repositories;
namespace StellaOps.Scheduler.Persistence.Postgres.Repositories;
/// <summary>
/// Repository interface for metrics operations.

View File

@@ -1,6 +1,6 @@
using StellaOps.Scheduler.Models;
namespace StellaOps.Scheduler.Storage.Postgres.Repositories;
namespace StellaOps.Scheduler.Persistence.Postgres.Repositories;
public interface IPolicyRunJobRepository
{

View File

@@ -1,6 +1,6 @@
using StellaOps.Scheduler.Models;
namespace StellaOps.Scheduler.Storage.Postgres.Repositories;
namespace StellaOps.Scheduler.Persistence.Postgres.Repositories;
public interface IRunRepository
{

View File

@@ -1,6 +1,6 @@
using StellaOps.Scheduler.Models;
namespace StellaOps.Scheduler.Storage.Postgres.Repositories;
namespace StellaOps.Scheduler.Persistence.Postgres.Repositories;
public interface IScheduleRepository
{

View File

@@ -1,6 +1,6 @@
using StellaOps.Scheduler.Storage.Postgres.Models;
using StellaOps.Scheduler.Persistence.Postgres.Models;
namespace StellaOps.Scheduler.Storage.Postgres.Repositories;
namespace StellaOps.Scheduler.Persistence.Postgres.Repositories;
/// <summary>
/// Repository interface for trigger operations.

View File

@@ -1,6 +1,6 @@
using StellaOps.Scheduler.Storage.Postgres.Models;
using StellaOps.Scheduler.Persistence.Postgres.Models;
namespace StellaOps.Scheduler.Storage.Postgres.Repositories;
namespace StellaOps.Scheduler.Persistence.Postgres.Repositories;
/// <summary>
/// Repository interface for worker operations.

View File

@@ -3,7 +3,7 @@ using Dapper;
using StellaOps.Scheduler.Models;
using StellaOps.Infrastructure.Postgres.Connections;
namespace StellaOps.Scheduler.Storage.Postgres.Repositories;
namespace StellaOps.Scheduler.Persistence.Postgres.Repositories;
public sealed class ImpactSnapshotRepository : IImpactSnapshotRepository
{

View File

@@ -1,9 +1,9 @@
using Microsoft.Extensions.Logging;
using Npgsql;
using StellaOps.Infrastructure.Postgres.Repositories;
using StellaOps.Scheduler.Storage.Postgres.Models;
using StellaOps.Scheduler.Persistence.Postgres.Models;
namespace StellaOps.Scheduler.Storage.Postgres.Repositories;
namespace StellaOps.Scheduler.Persistence.Postgres.Repositories;
/// <summary>
/// PostgreSQL repository for job history operations.

View File

@@ -1,9 +1,9 @@
using Microsoft.Extensions.Logging;
using Npgsql;
using StellaOps.Infrastructure.Postgres.Repositories;
using StellaOps.Scheduler.Storage.Postgres.Models;
using StellaOps.Scheduler.Persistence.Postgres.Models;
namespace StellaOps.Scheduler.Storage.Postgres.Repositories;
namespace StellaOps.Scheduler.Persistence.Postgres.Repositories;
/// <summary>
/// PostgreSQL repository for job operations.

View File

@@ -1,9 +1,9 @@
using Microsoft.Extensions.Logging;
using Npgsql;
using StellaOps.Infrastructure.Postgres.Repositories;
using StellaOps.Scheduler.Storage.Postgres.Models;
using StellaOps.Scheduler.Persistence.Postgres.Models;
namespace StellaOps.Scheduler.Storage.Postgres.Repositories;
namespace StellaOps.Scheduler.Persistence.Postgres.Repositories;
/// <summary>
/// PostgreSQL repository for metrics operations.

View File

@@ -4,7 +4,7 @@ using Dapper;
using StellaOps.Scheduler.Models;
using StellaOps.Infrastructure.Postgres.Connections;
namespace StellaOps.Scheduler.Storage.Postgres.Repositories;
namespace StellaOps.Scheduler.Persistence.Postgres.Repositories;
public sealed class PolicyRunJobRepository : IPolicyRunJobRepository
{

View File

@@ -1,7 +1,7 @@
using System.Collections.Immutable;
using StellaOps.Scheduler.Models;
namespace StellaOps.Scheduler.Storage.Postgres.Repositories;
namespace StellaOps.Scheduler.Persistence.Postgres.Repositories;
public sealed class RunQueryOptions
{

View File

@@ -5,7 +5,7 @@ using StellaOps.Infrastructure.Postgres.Options;
using StellaOps.Scheduler.Models;
using StellaOps.Infrastructure.Postgres.Connections;
namespace StellaOps.Scheduler.Storage.Postgres.Repositories;
namespace StellaOps.Scheduler.Persistence.Postgres.Repositories;
public sealed class RunRepository : IRunRepository
{

View File

@@ -2,7 +2,7 @@ using System.Collections.Concurrent;
using System.Collections.Immutable;
using StellaOps.Scheduler.Models;
namespace StellaOps.Scheduler.Storage.Postgres.Repositories;
namespace StellaOps.Scheduler.Persistence.Postgres.Repositories;
public sealed class RunSummaryService : IRunSummaryService
{

View File

@@ -1,4 +1,4 @@
namespace StellaOps.Scheduler.Storage.Postgres.Repositories;
namespace StellaOps.Scheduler.Persistence.Postgres.Repositories;
public sealed class ScheduleQueryOptions
{

View File

@@ -3,7 +3,7 @@ using Dapper;
using StellaOps.Scheduler.Models;
using StellaOps.Infrastructure.Postgres.Connections;
namespace StellaOps.Scheduler.Storage.Postgres.Repositories;
namespace StellaOps.Scheduler.Persistence.Postgres.Repositories;
public sealed class ScheduleRepository : IScheduleRepository
{

View File

@@ -1,9 +1,9 @@
using Microsoft.Extensions.Logging;
using Npgsql;
using StellaOps.Infrastructure.Postgres.Repositories;
using StellaOps.Scheduler.Storage.Postgres.Models;
using StellaOps.Scheduler.Persistence.Postgres.Models;
namespace StellaOps.Scheduler.Storage.Postgres.Repositories;
namespace StellaOps.Scheduler.Persistence.Postgres.Repositories;
/// <summary>
/// PostgreSQL repository for trigger operations.

View File

@@ -1,9 +1,9 @@
using Microsoft.Extensions.Logging;
using Npgsql;
using StellaOps.Infrastructure.Postgres.Repositories;
using StellaOps.Scheduler.Storage.Postgres.Models;
using StellaOps.Scheduler.Persistence.Postgres.Models;
namespace StellaOps.Scheduler.Storage.Postgres.Repositories;
namespace StellaOps.Scheduler.Persistence.Postgres.Repositories;
/// <summary>
/// PostgreSQL repository for worker operations.

View File

@@ -3,7 +3,7 @@ using Microsoft.Extensions.Options;
using StellaOps.Infrastructure.Postgres.Connections;
using StellaOps.Infrastructure.Postgres.Options;
namespace StellaOps.Scheduler.Storage.Postgres;
namespace StellaOps.Scheduler.Persistence.Postgres;
/// <summary>
/// PostgreSQL data source for the Scheduler module.

View File

@@ -0,0 +1,36 @@
<?xml version="1.0" ?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<LangVersion>preview</LangVersion>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<RootNamespace>StellaOps.Scheduler.Persistence</RootNamespace>
<AssemblyName>StellaOps.Scheduler.Persistence</AssemblyName>
<Description>Consolidated persistence layer for StellaOps Scheduler module (EF Core + Raw SQL)</Description>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Dapper" />
<PackageReference Include="Microsoft.EntityFrameworkCore" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" PrivateAssets="all" />
<PackageReference Include="Npgsql" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\StellaOps.Scheduler.Models\StellaOps.Scheduler.Models.csproj" />
<ProjectReference Include="..\..\..\__Libraries\StellaOps.Infrastructure.Postgres\StellaOps.Infrastructure.Postgres.csproj" />
<ProjectReference Include="..\..\..\__Libraries\StellaOps.Infrastructure.EfCore\StellaOps.Infrastructure.EfCore.csproj" />
</ItemGroup>
<!-- Embed SQL migrations as resources -->
<ItemGroup>
<EmbeddedResource Include="Migrations\**\*.sql" />
</ItemGroup>
</Project>

View File

@@ -5,15 +5,15 @@
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="StackExchange.Redis" Version="2.8.37" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="10.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="10.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.0" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="10.0.0" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions" Version="10.0.0" />
<PackageReference Include="NATS.Client.Core" Version="2.0.0" />
<PackageReference Include="NATS.Client.JetStream" Version="2.0.0" />
<PackageReference Include="StackExchange.Redis" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions" />
<PackageReference Include="NATS.Client.Core" />
<PackageReference Include="NATS.Client.JetStream" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\StellaOps.Scheduler.Models\StellaOps.Scheduler.Models.csproj" />

View File

@@ -1,26 +0,0 @@
<?xml version="1.0" ?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<LangVersion>preview</LangVersion>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<RootNamespace>StellaOps.Scheduler.Storage.Postgres</RootNamespace>
</PropertyGroup>
<ItemGroup>
<EmbeddedResource Include="Migrations\**\*.sql" LogicalName="%(RecursiveDir)%(Filename)%(Extension)" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\__Libraries\StellaOps.Infrastructure.Postgres\StellaOps.Infrastructure.Postgres.csproj" />
<ProjectReference Include="..\StellaOps.Scheduler.Models\StellaOps.Scheduler.Models.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Dapper" Version="2.1.24" />
</ItemGroup>
</Project>

View File

@@ -12,7 +12,7 @@ using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Npgsql;
using StellaOps.Scheduler.Storage.Postgres;
using StellaOps.Scheduler.Persistence.Postgres;
using StellaOps.Scheduler.Worker.Options;
namespace StellaOps.Scheduler.Worker.Execution;

View File

@@ -6,7 +6,7 @@ using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using StellaOps.Scheduler.Models;
using StellaOps.Scheduler.Queue;
using StellaOps.Scheduler.Storage.Postgres.Repositories;
using StellaOps.Scheduler.Persistence.Postgres.Repositories;
using StellaOps.Scheduler.Worker.Events;
using StellaOps.Scheduler.Worker.Observability;

View File

@@ -5,7 +5,7 @@ using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using StellaOps.Scheduler.Models;
using StellaOps.Scheduler.Storage.Postgres.Repositories;
using StellaOps.Scheduler.Persistence.Postgres.Repositories;
using StellaOps.Scheduler.Worker.Options;
namespace StellaOps.Scheduler.Worker.Graph;

View File

@@ -4,7 +4,7 @@ using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using StellaOps.Scheduler.Models;
using StellaOps.Scheduler.Storage.Postgres.Repositories;
using StellaOps.Scheduler.Persistence.Postgres.Repositories;
using StellaOps.Scheduler.Worker.Graph.Cartographer;
using StellaOps.Scheduler.Worker.Graph.Scheduler;
using StellaOps.Scheduler.Worker.Options;

View File

@@ -5,7 +5,7 @@ using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using StellaOps.Scheduler.Models;
using StellaOps.Scheduler.Storage.Postgres.Repositories;
using StellaOps.Scheduler.Persistence.Postgres.Repositories;
using StellaOps.Scheduler.Worker.Options;
namespace StellaOps.Scheduler.Worker.Graph;

View File

@@ -4,7 +4,7 @@ using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using StellaOps.Scheduler.Models;
using StellaOps.Scheduler.Storage.Postgres.Repositories;
using StellaOps.Scheduler.Persistence.Postgres.Repositories;
using StellaOps.Scheduler.Worker.Graph.Cartographer;
using StellaOps.Scheduler.Worker.Graph.Scheduler;
using StellaOps.Scheduler.Worker.Options;

View File

@@ -2,8 +2,8 @@ using System.Text.Json;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using StellaOps.Scheduler.Storage.Postgres.Models;
using StellaOps.Scheduler.Storage.Postgres.Repositories;
using StellaOps.Scheduler.Persistence.Postgres.Models;
using StellaOps.Scheduler.Persistence.Postgres.Repositories;
namespace StellaOps.Scheduler.Worker.Indexing;

View File

@@ -1,7 +1,7 @@
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using StellaOps.Scheduler.Models;
using StellaOps.Scheduler.Storage.Postgres.Repositories;
using StellaOps.Scheduler.Persistence.Postgres.Repositories;
using StellaOps.Scheduler.Worker.Options;
namespace StellaOps.Scheduler.Worker.Planning;

View File

@@ -2,7 +2,7 @@ using System.Collections.Immutable;
using Microsoft.Extensions.Logging;
using StellaOps.Scheduler.Models;
using StellaOps.Scheduler.Queue;
using StellaOps.Scheduler.Storage.Postgres.Repositories;
using StellaOps.Scheduler.Persistence.Postgres.Repositories;
using StellaOps.Scheduler.Worker.Options;
using StellaOps.Scheduler.Worker.Observability;

View File

@@ -6,7 +6,7 @@ using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using StellaOps.Scheduler.Models;
using StellaOps.Scheduler.Storage.Postgres.Repositories;
using StellaOps.Scheduler.Persistence.Postgres.Repositories;
using StellaOps.Scheduler.Worker.Options;
namespace StellaOps.Scheduler.Worker.Policy;

View File

@@ -4,7 +4,7 @@ using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using StellaOps.Scheduler.Models;
using StellaOps.Scheduler.Storage.Postgres.Repositories;
using StellaOps.Scheduler.Persistence.Postgres.Repositories;
using StellaOps.Scheduler.Worker.Observability;
using StellaOps.Scheduler.Worker.Options;

View File

@@ -8,14 +8,14 @@
<ItemGroup>
<ProjectReference Include="../StellaOps.Scheduler.ImpactIndex/StellaOps.Scheduler.ImpactIndex.csproj" />
<ProjectReference Include="../StellaOps.Scheduler.Models/StellaOps.Scheduler.Models.csproj" />
<ProjectReference Include="../StellaOps.Scheduler.Storage.Postgres/StellaOps.Scheduler.Storage.Postgres.csproj" />
<ProjectReference Include="../StellaOps.Scheduler.Persistence/StellaOps.Scheduler.Persistence.csproj" />
<ProjectReference Include="../StellaOps.Scheduler.Queue/StellaOps.Scheduler.Queue.csproj" />
<ProjectReference Include="../../../Notify/__Libraries/StellaOps.Notify.Models/StellaOps.Notify.Models.csproj" />
<ProjectReference Include="../../../Notify/__Libraries/StellaOps.Notify.Queue/StellaOps.Notify.Queue.csproj" />
<ProjectReference Include="../../../Scanner/__Libraries/StellaOps.Scanner.Surface.Env/StellaOps.Scanner.Surface.Env.csproj" />
<ProjectReference Include="../../../Scanner/__Libraries/StellaOps.Scanner.Surface.FS/StellaOps.Scanner.Surface.FS.csproj" />
<PackageReference Include="Cronos" Version="0.9.0" />
<PackageReference Include="System.Threading.RateLimiting" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="10.0.0" />
<PackageReference Include="Cronos" />
<PackageReference Include="System.Threading.RateLimiting" />
<PackageReference Include="Microsoft.Extensions.Http" />
</ItemGroup>
</Project>