190 lines
7.2 KiB
PL/PgSQL
190 lines
7.2 KiB
PL/PgSQL
-- Origin Graph — Initial Schema
|
|
-- Migration: 001
|
|
-- All tables use UUIDs as primary keys and include created_at / updated_at.
|
|
-- Enable pgcrypto for gen_random_uuid() if not already enabled.
|
|
CREATE EXTENSION IF NOT EXISTS "pgcrypto";
|
|
|
|
-- ── Enum types ────────────────────────────────────────────────────────────────
|
|
|
|
CREATE TYPE origin_type AS ENUM (
|
|
'GIT_COMMIT',
|
|
'LINEAR_ISSUE',
|
|
'SLACK_MESSAGE',
|
|
'URL',
|
|
'FORK'
|
|
);
|
|
|
|
CREATE TYPE diff_status AS ENUM (
|
|
'DRAFT',
|
|
'EXPORTED',
|
|
'IMPLEMENTED',
|
|
'BLOCKED'
|
|
);
|
|
|
|
CREATE TYPE team_role AS ENUM (
|
|
'OWNER',
|
|
'DESIGNER',
|
|
'ENGINEER',
|
|
'PM',
|
|
'VIEWER'
|
|
);
|
|
|
|
CREATE TYPE agent_type AS ENUM (
|
|
'CURSOR',
|
|
'CLAUDE_CODE',
|
|
'GENERIC'
|
|
);
|
|
|
|
CREATE TYPE workspace_plan AS ENUM (
|
|
'FREE',
|
|
'TEAM',
|
|
'ENTERPRISE'
|
|
);
|
|
|
|
CREATE TYPE agent_session_status AS ENUM (
|
|
'ACTIVE',
|
|
'COMPLETED',
|
|
'FAILED'
|
|
);
|
|
|
|
-- ── workspaces ────────────────────────────────────────────────────────────────
|
|
|
|
CREATE TABLE workspaces (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
name TEXT NOT NULL,
|
|
owner_id TEXT NOT NULL, -- Clerk user ID
|
|
plan workspace_plan NOT NULL DEFAULT 'FREE',
|
|
settings_jsonb JSONB NOT NULL DEFAULT '{}',
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
);
|
|
|
|
-- ── origins ───────────────────────────────────────────────────────────────────
|
|
|
|
CREATE TABLE origins (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
type origin_type NOT NULL,
|
|
source_ref TEXT NOT NULL,
|
|
source_metadata_jsonb JSONB NOT NULL DEFAULT '{}',
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
);
|
|
|
|
-- ── artboards ─────────────────────────────────────────────────────────────────
|
|
|
|
CREATE TABLE artboards (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
workspace_id UUID NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
|
|
name TEXT NOT NULL,
|
|
origin_id UUID REFERENCES origins(id) ON DELETE SET NULL,
|
|
parent_artboard_id UUID REFERENCES artboards(id) ON DELETE SET NULL,
|
|
metadata_jsonb JSONB NOT NULL DEFAULT '{}',
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
);
|
|
|
|
CREATE INDEX artboards_workspace_idx ON artboards(workspace_id);
|
|
CREATE INDEX artboards_parent_idx ON artboards(parent_artboard_id);
|
|
|
|
-- ── intent_diffs ──────────────────────────────────────────────────────────────
|
|
|
|
CREATE TABLE intent_diffs (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
artboard_id UUID NOT NULL REFERENCES artboards(id) ON DELETE CASCADE,
|
|
author_id TEXT NOT NULL, -- Clerk user ID
|
|
changes_jsonb JSONB NOT NULL DEFAULT '{}',
|
|
summary TEXT NOT NULL DEFAULT '',
|
|
status diff_status NOT NULL DEFAULT 'DRAFT',
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
);
|
|
|
|
CREATE INDEX intent_diffs_artboard_idx ON intent_diffs(artboard_id);
|
|
CREATE INDEX intent_diffs_status_idx ON intent_diffs(status);
|
|
|
|
-- ── agent_sessions ────────────────────────────────────────────────────────────
|
|
|
|
CREATE TABLE agent_sessions (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
artboard_id UUID NOT NULL REFERENCES artboards(id) ON DELETE CASCADE,
|
|
diff_id UUID REFERENCES intent_diffs(id) ON DELETE SET NULL,
|
|
agent_type agent_type NOT NULL,
|
|
messages_jsonb JSONB NOT NULL DEFAULT '[]',
|
|
status agent_session_status NOT NULL DEFAULT 'ACTIVE',
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
);
|
|
|
|
CREATE INDEX agent_sessions_artboard_idx ON agent_sessions(artboard_id);
|
|
CREATE INDEX agent_sessions_diff_idx ON agent_sessions(diff_id);
|
|
|
|
-- ── design_language_files ─────────────────────────────────────────────────────
|
|
|
|
CREATE TABLE design_language_files (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
workspace_id UUID NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
|
|
name TEXT NOT NULL,
|
|
schema_jsonb JSONB NOT NULL,
|
|
version INTEGER NOT NULL DEFAULT 1,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
);
|
|
|
|
CREATE INDEX dlf_workspace_idx ON design_language_files(workspace_id);
|
|
|
|
-- ── team_members ──────────────────────────────────────────────────────────────
|
|
|
|
CREATE TABLE team_members (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
workspace_id UUID NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
|
|
user_id TEXT NOT NULL, -- Clerk user ID
|
|
role team_role NOT NULL DEFAULT 'VIEWER',
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
UNIQUE (workspace_id, user_id)
|
|
);
|
|
|
|
CREATE INDEX team_members_workspace_idx ON team_members(workspace_id);
|
|
CREATE INDEX team_members_user_idx ON team_members(user_id);
|
|
|
|
-- ── updated_at trigger ────────────────────────────────────────────────────────
|
|
|
|
CREATE OR REPLACE FUNCTION set_updated_at()
|
|
RETURNS TRIGGER LANGUAGE plpgsql AS $$
|
|
BEGIN
|
|
NEW.updated_at = now();
|
|
RETURN NEW;
|
|
END;
|
|
$$;
|
|
|
|
DO $$
|
|
DECLARE t TEXT;
|
|
BEGIN
|
|
FOREACH t IN ARRAY ARRAY['workspaces','origins','artboards','intent_diffs',
|
|
'agent_sessions','design_language_files','team_members']
|
|
LOOP
|
|
EXECUTE format(
|
|
'CREATE TRIGGER trg_%I_updated_at
|
|
BEFORE UPDATE ON %I
|
|
FOR EACH ROW EXECUTE FUNCTION set_updated_at()',
|
|
t, t
|
|
);
|
|
END LOOP;
|
|
END;
|
|
$$;
|
|
|
|
-- ── RPC: get_diffs_by_status ──────────────────────────────────────────────────
|
|
-- Used by getDiffsByStatus() in queries.ts.
|
|
-- Joins intent_diffs → artboards to scope results by workspace_id.
|
|
|
|
create or replace function get_diffs_by_status(p_workspace_id uuid, p_status text)
|
|
returns setof intent_diffs
|
|
language sql stable as $$
|
|
select d.*
|
|
from intent_diffs d
|
|
join artboards a on a.id = d.artboard_id
|
|
where a.workspace_id = p_workspace_id
|
|
and d.status = p_status
|
|
order by d.created_at desc;
|
|
$$;
|