124 lines
4.7 KiB
SQL
124 lines
4.7 KiB
SQL
-- Grow event backbone: raw event inbox, service session links, artifacts, and QScore projections.
|
|
-- Postgres stores every raw GrowEvent first. Actors/projectors can rebuild from this stream.
|
|
|
|
CREATE TABLE IF NOT EXISTS grow_events (
|
|
id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
|
|
user_id TEXT REFERENCES users(id) ON DELETE CASCADE,
|
|
org_id TEXT,
|
|
source TEXT NOT NULL,
|
|
type TEXT NOT NULL,
|
|
category TEXT NOT NULL DEFAULT 'service' CHECK (category IN ('mission', 'service', 'artifact', 'usage', 'qscore', 'entitlement', 'system')),
|
|
occurred_at TIMESTAMPTZ NOT NULL,
|
|
received_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
mission JSONB,
|
|
subject JSONB,
|
|
correlation JSONB,
|
|
payload JSONB NOT NULL DEFAULT '{}'::jsonb,
|
|
raw JSONB,
|
|
dedupe_key TEXT,
|
|
processing_status TEXT NOT NULL DEFAULT 'pending' CHECK (processing_status IN ('pending', 'processing', 'processed', 'failed', 'unresolved')),
|
|
processing_error TEXT,
|
|
processed_at TIMESTAMPTZ
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS grow_events_user_idx
|
|
ON grow_events(user_id, occurred_at DESC);
|
|
CREATE INDEX IF NOT EXISTS grow_events_status_idx
|
|
ON grow_events(processing_status, received_at ASC);
|
|
CREATE INDEX IF NOT EXISTS grow_events_source_idx
|
|
ON grow_events(source, type, occurred_at DESC);
|
|
CREATE UNIQUE INDEX IF NOT EXISTS grow_events_dedupe_idx
|
|
ON grow_events(dedupe_key);
|
|
|
|
CREATE TABLE IF NOT EXISTS mission_service_sessions (
|
|
id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
|
|
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
mission_instance_id TEXT REFERENCES grow_active_missions(instance_id) ON DELETE SET NULL,
|
|
mission_id TEXT,
|
|
stage_id TEXT,
|
|
service_id TEXT NOT NULL,
|
|
external_id TEXT NOT NULL,
|
|
status TEXT NOT NULL DEFAULT 'active',
|
|
metadata JSONB,
|
|
last_event_id TEXT REFERENCES grow_events(id) ON DELETE SET NULL,
|
|
last_checked_at TIMESTAMPTZ,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS mission_service_sessions_user_idx
|
|
ON mission_service_sessions(user_id, updated_at DESC);
|
|
CREATE UNIQUE INDEX IF NOT EXISTS mission_service_sessions_external_idx
|
|
ON mission_service_sessions(service_id, external_id);
|
|
CREATE INDEX IF NOT EXISTS mission_service_sessions_mission_idx
|
|
ON mission_service_sessions(mission_instance_id, stage_id);
|
|
|
|
CREATE TABLE IF NOT EXISTS mission_artifacts (
|
|
id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
|
|
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
mission_instance_id TEXT REFERENCES grow_active_missions(instance_id) ON DELETE CASCADE,
|
|
mission_id TEXT,
|
|
stage_id TEXT,
|
|
source_event_id TEXT REFERENCES grow_events(id) ON DELETE SET NULL,
|
|
service_id TEXT,
|
|
external_id TEXT,
|
|
type TEXT NOT NULL,
|
|
title TEXT NOT NULL,
|
|
status TEXT NOT NULL DEFAULT 'ready',
|
|
summary TEXT,
|
|
content_md TEXT,
|
|
metadata JSONB,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS mission_artifacts_user_idx
|
|
ON mission_artifacts(user_id, created_at DESC);
|
|
CREATE INDEX IF NOT EXISTS mission_artifacts_mission_idx
|
|
ON mission_artifacts(mission_instance_id, created_at DESC);
|
|
CREATE INDEX IF NOT EXISTS mission_artifacts_external_idx
|
|
ON mission_artifacts(service_id, external_id);
|
|
|
|
CREATE TABLE IF NOT EXISTS grow_qscore_signals (
|
|
id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
|
|
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
source_event_id TEXT REFERENCES grow_events(id) ON DELETE SET NULL,
|
|
signal_id TEXT NOT NULL,
|
|
score DOUBLE PRECISION NOT NULL,
|
|
present BOOLEAN NOT NULL DEFAULT TRUE,
|
|
source TEXT,
|
|
raw JSONB,
|
|
occurred_at TIMESTAMPTZ NOT NULL,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS grow_qscore_signals_user_idx
|
|
ON grow_qscore_signals(user_id, occurred_at DESC);
|
|
CREATE INDEX IF NOT EXISTS grow_qscore_signals_signal_idx
|
|
ON grow_qscore_signals(signal_id, occurred_at DESC);
|
|
|
|
CREATE TABLE IF NOT EXISTS grow_qscore_latest (
|
|
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
signal_id TEXT NOT NULL,
|
|
score DOUBLE PRECISION NOT NULL,
|
|
present BOOLEAN NOT NULL DEFAULT TRUE,
|
|
source TEXT,
|
|
source_event_id TEXT REFERENCES grow_events(id) ON DELETE SET NULL,
|
|
raw JSONB,
|
|
occurred_at TIMESTAMPTZ NOT NULL,
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
PRIMARY KEY (user_id, signal_id)
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS grow_qscore_latest_user_idx
|
|
ON grow_qscore_latest(user_id, updated_at DESC);
|
|
|
|
CREATE TABLE IF NOT EXISTS grow_qscore_projection_state (
|
|
user_id TEXT PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE,
|
|
score INTEGER NOT NULL DEFAULT 0,
|
|
signal_count INTEGER NOT NULL DEFAULT 0,
|
|
dimensions JSONB,
|
|
summary TEXT,
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
);
|