feat(vibe): persist durable session plans and events

This commit is contained in:
kami
2026-08-01 22:32:42 +04:00
parent 3641ec9e8e
commit 515cab2f89
6 changed files with 639 additions and 0 deletions
+64
View File
@@ -644,4 +644,68 @@ export const MIGRATIONS: Migration[] = [
EXECUTE FUNCTION propagate_album_release_date_to_tracks();
`,
},
{
// Vibe v2 needs an immutable event ledger and revisioned plans. The
// legacy session_state table remains in place as a derived-state cache so
// existing v2 endpoints can migrate independently.
id: '20260801_vibe_session_persistence',
sql: `
CREATE TABLE IF NOT EXISTS vibe_sessions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL,
status TEXT NOT NULL CHECK (status IN ('active', 'paused', 'ended', 'expired', 'replaced')),
seed_track_id UUID REFERENCES tracks(id) ON DELETE SET NULL,
context JSONB NOT NULL DEFAULT '{}'::jsonb,
policy_version TEXT NOT NULL,
started_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
last_event_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
ended_at TIMESTAMPTZ
);
CREATE INDEX IF NOT EXISTS idx_vibe_sessions_user_last_event
ON vibe_sessions (user_id, last_event_at DESC);
CREATE TABLE IF NOT EXISTS vibe_events (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
client_event_id UUID,
session_id UUID NOT NULL REFERENCES vibe_sessions(id) ON DELETE CASCADE,
user_id UUID NOT NULL,
track_id UUID REFERENCES tracks(id) ON DELETE SET NULL,
type TEXT NOT NULL,
occurred_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
position_ms INTEGER,
duration_ms INTEGER,
payload JSONB NOT NULL DEFAULT '{}'::jsonb,
UNIQUE (session_id, client_event_id)
);
CREATE INDEX IF NOT EXISTS idx_vibe_events_session_occurred
ON vibe_events (session_id, occurred_at);
CREATE INDEX IF NOT EXISTS idx_vibe_events_user_occurred
ON vibe_events (user_id, occurred_at DESC);
CREATE TABLE IF NOT EXISTS vibe_plan_versions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
session_id UUID NOT NULL REFERENCES vibe_sessions(id) ON DELETE CASCADE,
version INTEGER NOT NULL CHECK (version > 0),
reason TEXT NOT NULL,
state_snapshot JSONB NOT NULL,
objective_snapshot JSONB NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE (session_id, version)
);
CREATE TABLE IF NOT EXISTS vibe_plan_items (
plan_version_id UUID NOT NULL REFERENCES vibe_plan_versions(id) ON DELETE CASCADE,
ordinal INTEGER NOT NULL CHECK (ordinal >= 0),
track_id UUID NOT NULL REFERENCES tracks(id) ON DELETE CASCADE,
slot_role TEXT,
candidate_source TEXT NOT NULL,
score REAL NOT NULL,
score_breakdown JSONB NOT NULL,
explanation JSONB NOT NULL,
committed BOOLEAN NOT NULL DEFAULT false,
PRIMARY KEY (plan_version_id, ordinal),
UNIQUE (plan_version_id, track_id)
);
`,
},
];