From e3a4a3c5c7c98ed280ffdc91175c274f1aadb3f2 Mon Sep 17 00:00:00 2001 From: Hein Puth Date: Wed, 15 Jul 2026 05:14:09 +0200 Subject: [PATCH] fix: build UI assets in CI --- .gitea/workflows/ci.yml | 16 + migrations/020_generated_schema.sql | 543 +++++++++++++++++++++++++++- migrations/110_per_user_tenancy.sql | 2 + schema/files.dbml | 2 + schema/meta.dbml | 4 + schema/plans.dbml | 2 + 6 files changed, 552 insertions(+), 17 deletions(-) diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 0ce86d1..6560315 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -18,6 +18,14 @@ jobs: with: go-version: '1.26' + - name: Set up Node + uses: actions/setup-node@v4 + with: + node-version: '24' + + - name: Enable pnpm + run: corepack enable + - name: Cache Go modules uses: actions/cache@v4 with: @@ -34,6 +42,14 @@ jobs: - name: Tidy modules run: go mod tidy + - name: Install UI dependencies + run: pnpm install --frozen-lockfile + working-directory: ui + + - name: Build UI assets + run: pnpm run build + working-directory: ui + - name: Run tests run: go test ./... diff --git a/migrations/020_generated_schema.sql b/migrations/020_generated_schema.sql index f922f2e..4ced9d5 100644 --- a/migrations/020_generated_schema.sql +++ b/migrations/020_generated_schema.sql @@ -110,6 +110,13 @@ CREATE SEQUENCE IF NOT EXISTS public.identity_thought_links_id START 1 CACHE 1; +CREATE SEQUENCE IF NOT EXISTS public.identity_thought_learning_links_id + INCREMENT 1 + MINVALUE 1 + MAXVALUE 9223372036854775807 + START 1 + CACHE 1; + CREATE SEQUENCE IF NOT EXISTS public.identity_embeddings_id INCREMENT 1 MINVALUE 1 @@ -332,6 +339,7 @@ CREATE TABLE IF NOT EXISTS public.thoughts ( id bigserial NOT NULL, metadata jsonb DEFAULT '{}'::jsonb, project_id bigint, + tenant_key text, updated_at timestamptz DEFAULT now() ); @@ -341,7 +349,8 @@ CREATE TABLE IF NOT EXISTS public.projects ( guid uuid NOT NULL DEFAULT gen_random_uuid(), id bigserial NOT NULL, last_active_at timestamptz DEFAULT now(), - name text NOT NULL + name text NOT NULL, + tenant_key text ); CREATE TABLE IF NOT EXISTS public.thought_links ( @@ -352,6 +361,14 @@ CREATE TABLE IF NOT EXISTS public.thought_links ( to_id bigint NOT NULL ); +CREATE TABLE IF NOT EXISTS public.thought_learning_links ( + created_at timestamptz NOT NULL DEFAULT now(), + id bigserial NOT NULL, + learning_id bigint NOT NULL, + relation text NOT NULL DEFAULT 'source', + thought_id bigint NOT NULL +); + CREATE TABLE IF NOT EXISTS public.embeddings ( created_at timestamptz DEFAULT now(), dim integer NOT NULL, @@ -375,6 +392,7 @@ CREATE TABLE IF NOT EXISTS public.stored_files ( project_id bigint, sha256 text NOT NULL, size_bytes bigint NOT NULL, + tenant_key text, thought_id bigint, updated_at timestamptz NOT NULL DEFAULT now() ); @@ -390,6 +408,7 @@ CREATE TABLE IF NOT EXISTS public.chat_histories ( project_id bigint, session_id text NOT NULL, summary text, + tenant_key text, title text, updated_at timestamptz NOT NULL DEFAULT now() ); @@ -424,6 +443,7 @@ CREATE TABLE IF NOT EXISTS public.learnings ( summary text NOT NULL, supersedes_learning_id bigint, tags text[] NOT NULL DEFAULT '{}', + tenant_key text, updated_at timestamptz NOT NULL DEFAULT now() ); @@ -450,6 +470,7 @@ CREATE TABLE IF NOT EXISTS public.plans ( status text NOT NULL DEFAULT 'draft', supersedes_plan_id bigint, tags text[] NOT NULL DEFAULT '{}', + tenant_key text, title text NOT NULL, updated_at timestamptz NOT NULL DEFAULT now() ); @@ -1552,6 +1573,19 @@ BEGIN END; $$; +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_schema = 'public' + AND table_name = 'thoughts' + AND column_name = 'tenant_key' + ) THEN + ALTER TABLE public.thoughts ADD COLUMN tenant_key text; + END IF; +END; +$$; + DO $$ BEGIN IF NOT EXISTS ( @@ -1643,6 +1677,19 @@ BEGIN END; $$; +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_schema = 'public' + AND table_name = 'projects' + AND column_name = 'tenant_key' + ) THEN + ALTER TABLE public.projects ADD COLUMN tenant_key text; + END IF; +END; +$$; + DO $$ BEGIN IF NOT EXISTS ( @@ -1708,6 +1755,71 @@ BEGIN END; $$; +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_schema = 'public' + AND table_name = 'thought_learning_links' + AND column_name = 'created_at' + ) THEN + ALTER TABLE public.thought_learning_links ADD COLUMN created_at timestamptz NOT NULL DEFAULT now(); + END IF; +END; +$$; + +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_schema = 'public' + AND table_name = 'thought_learning_links' + AND column_name = 'id' + ) THEN + ALTER TABLE public.thought_learning_links ADD COLUMN id bigserial NOT NULL; + END IF; +END; +$$; + +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_schema = 'public' + AND table_name = 'thought_learning_links' + AND column_name = 'learning_id' + ) THEN + ALTER TABLE public.thought_learning_links ADD COLUMN learning_id bigint NOT NULL; + END IF; +END; +$$; + +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_schema = 'public' + AND table_name = 'thought_learning_links' + AND column_name = 'relation' + ) THEN + ALTER TABLE public.thought_learning_links ADD COLUMN relation text NOT NULL DEFAULT 'source'; + END IF; +END; +$$; + +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_schema = 'public' + AND table_name = 'thought_learning_links' + AND column_name = 'thought_id' + ) THEN + ALTER TABLE public.thought_learning_links ADD COLUMN thought_id bigint NOT NULL; + END IF; +END; +$$; + DO $$ BEGIN IF NOT EXISTS ( @@ -1955,6 +2067,19 @@ BEGIN END; $$; +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_schema = 'public' + AND table_name = 'stored_files' + AND column_name = 'tenant_key' + ) THEN + ALTER TABLE public.stored_files ADD COLUMN tenant_key text; + END IF; +END; +$$; + DO $$ BEGIN IF NOT EXISTS ( @@ -2111,6 +2236,19 @@ BEGIN END; $$; +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_schema = 'public' + AND table_name = 'chat_histories' + AND column_name = 'tenant_key' + ) THEN + ALTER TABLE public.chat_histories ADD COLUMN tenant_key text; + END IF; +END; +$$; + DO $$ BEGIN IF NOT EXISTS ( @@ -2475,6 +2613,19 @@ BEGIN END; $$; +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_schema = 'public' + AND table_name = 'learnings' + AND column_name = 'tenant_key' + ) THEN + ALTER TABLE public.learnings ADD COLUMN tenant_key text; + END IF; +END; +$$; + DO $$ BEGIN IF NOT EXISTS ( @@ -2735,6 +2886,19 @@ BEGIN END; $$; +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_schema = 'public' + AND table_name = 'plans' + AND column_name = 'tenant_key' + ) THEN + ALTER TABLE public.plans ADD COLUMN tenant_key text; + END IF; +END; +$$; + DO $$ BEGIN IF NOT EXISTS ( @@ -5177,6 +5341,29 @@ BEGIN END; $$; +DO $$ +DECLARE + current_type text; +BEGIN + SELECT pg_catalog.format_type(a.atttypid, a.atttypmod) + INTO current_type + FROM pg_attribute a + JOIN pg_class t ON t.oid = a.attrelid + JOIN pg_namespace n ON n.oid = t.relnamespace + WHERE n.nspname = 'public' + AND t.relname = 'thoughts' + AND a.attname = 'tenant_key' + AND a.attnum > 0 + AND NOT a.attisdropped; + + IF current_type IS NOT NULL + AND current_type <> ALL(ARRAY['text']) THEN + ALTER TABLE public.thoughts + ALTER COLUMN tenant_key TYPE text USING tenant_key::text; + END IF; +END; +$$; + DO $$ DECLARE current_type text; @@ -5338,6 +5525,29 @@ BEGIN END; $$; +DO $$ +DECLARE + current_type text; +BEGIN + SELECT pg_catalog.format_type(a.atttypid, a.atttypmod) + INTO current_type + FROM pg_attribute a + JOIN pg_class t ON t.oid = a.attrelid + JOIN pg_namespace n ON n.oid = t.relnamespace + WHERE n.nspname = 'public' + AND t.relname = 'projects' + AND a.attname = 'tenant_key' + AND a.attnum > 0 + AND NOT a.attisdropped; + + IF current_type IS NOT NULL + AND current_type <> ALL(ARRAY['text']) THEN + ALTER TABLE public.projects + ALTER COLUMN tenant_key TYPE text USING tenant_key::text; + END IF; +END; +$$; + DO $$ DECLARE current_type text; @@ -5453,6 +5663,121 @@ BEGIN END; $$; +DO $$ +DECLARE + current_type text; +BEGIN + SELECT pg_catalog.format_type(a.atttypid, a.atttypmod) + INTO current_type + FROM pg_attribute a + JOIN pg_class t ON t.oid = a.attrelid + JOIN pg_namespace n ON n.oid = t.relnamespace + WHERE n.nspname = 'public' + AND t.relname = 'thought_learning_links' + AND a.attname = 'created_at' + AND a.attnum > 0 + AND NOT a.attisdropped; + + IF current_type IS NOT NULL + AND current_type <> ALL(ARRAY['timestamptz', 'timestamp with time zone']) THEN + ALTER TABLE public.thought_learning_links + ALTER COLUMN created_at TYPE timestamptz USING created_at::timestamptz; + END IF; +END; +$$; + +DO $$ +DECLARE + current_type text; +BEGIN + SELECT pg_catalog.format_type(a.atttypid, a.atttypmod) + INTO current_type + FROM pg_attribute a + JOIN pg_class t ON t.oid = a.attrelid + JOIN pg_namespace n ON n.oid = t.relnamespace + WHERE n.nspname = 'public' + AND t.relname = 'thought_learning_links' + AND a.attname = 'id' + AND a.attnum > 0 + AND NOT a.attisdropped; + + IF current_type IS NOT NULL + AND current_type <> ALL(ARRAY['bigint']) THEN + ALTER TABLE public.thought_learning_links + ALTER COLUMN id TYPE bigint USING id::bigint; + END IF; +END; +$$; + +DO $$ +DECLARE + current_type text; +BEGIN + SELECT pg_catalog.format_type(a.atttypid, a.atttypmod) + INTO current_type + FROM pg_attribute a + JOIN pg_class t ON t.oid = a.attrelid + JOIN pg_namespace n ON n.oid = t.relnamespace + WHERE n.nspname = 'public' + AND t.relname = 'thought_learning_links' + AND a.attname = 'learning_id' + AND a.attnum > 0 + AND NOT a.attisdropped; + + IF current_type IS NOT NULL + AND current_type <> ALL(ARRAY['bigint']) THEN + ALTER TABLE public.thought_learning_links + ALTER COLUMN learning_id TYPE bigint USING learning_id::bigint; + END IF; +END; +$$; + +DO $$ +DECLARE + current_type text; +BEGIN + SELECT pg_catalog.format_type(a.atttypid, a.atttypmod) + INTO current_type + FROM pg_attribute a + JOIN pg_class t ON t.oid = a.attrelid + JOIN pg_namespace n ON n.oid = t.relnamespace + WHERE n.nspname = 'public' + AND t.relname = 'thought_learning_links' + AND a.attname = 'relation' + AND a.attnum > 0 + AND NOT a.attisdropped; + + IF current_type IS NOT NULL + AND current_type <> ALL(ARRAY['text']) THEN + ALTER TABLE public.thought_learning_links + ALTER COLUMN relation TYPE text USING relation::text; + END IF; +END; +$$; + +DO $$ +DECLARE + current_type text; +BEGIN + SELECT pg_catalog.format_type(a.atttypid, a.atttypmod) + INTO current_type + FROM pg_attribute a + JOIN pg_class t ON t.oid = a.attrelid + JOIN pg_namespace n ON n.oid = t.relnamespace + WHERE n.nspname = 'public' + AND t.relname = 'thought_learning_links' + AND a.attname = 'thought_id' + AND a.attnum > 0 + AND NOT a.attisdropped; + + IF current_type IS NOT NULL + AND current_type <> ALL(ARRAY['bigint']) THEN + ALTER TABLE public.thought_learning_links + ALTER COLUMN thought_id TYPE bigint USING thought_id::bigint; + END IF; +END; +$$; + DO $$ DECLARE current_type text; @@ -5890,6 +6215,29 @@ BEGIN END; $$; +DO $$ +DECLARE + current_type text; +BEGIN + SELECT pg_catalog.format_type(a.atttypid, a.atttypmod) + INTO current_type + FROM pg_attribute a + JOIN pg_class t ON t.oid = a.attrelid + JOIN pg_namespace n ON n.oid = t.relnamespace + WHERE n.nspname = 'public' + AND t.relname = 'stored_files' + AND a.attname = 'tenant_key' + AND a.attnum > 0 + AND NOT a.attisdropped; + + IF current_type IS NOT NULL + AND current_type <> ALL(ARRAY['text']) THEN + ALTER TABLE public.stored_files + ALTER COLUMN tenant_key TYPE text USING tenant_key::text; + END IF; +END; +$$; + DO $$ DECLARE current_type text; @@ -6166,6 +6514,29 @@ BEGIN END; $$; +DO $$ +DECLARE + current_type text; +BEGIN + SELECT pg_catalog.format_type(a.atttypid, a.atttypmod) + INTO current_type + FROM pg_attribute a + JOIN pg_class t ON t.oid = a.attrelid + JOIN pg_namespace n ON n.oid = t.relnamespace + WHERE n.nspname = 'public' + AND t.relname = 'chat_histories' + AND a.attname = 'tenant_key' + AND a.attnum > 0 + AND NOT a.attisdropped; + + IF current_type IS NOT NULL + AND current_type <> ALL(ARRAY['text']) THEN + ALTER TABLE public.chat_histories + ALTER COLUMN tenant_key TYPE text USING tenant_key::text; + END IF; +END; +$$; + DO $$ DECLARE current_type text; @@ -6810,6 +7181,29 @@ BEGIN END; $$; +DO $$ +DECLARE + current_type text; +BEGIN + SELECT pg_catalog.format_type(a.atttypid, a.atttypmod) + INTO current_type + FROM pg_attribute a + JOIN pg_class t ON t.oid = a.attrelid + JOIN pg_namespace n ON n.oid = t.relnamespace + WHERE n.nspname = 'public' + AND t.relname = 'learnings' + AND a.attname = 'tenant_key' + AND a.attnum > 0 + AND NOT a.attisdropped; + + IF current_type IS NOT NULL + AND current_type <> ALL(ARRAY['text']) THEN + ALTER TABLE public.learnings + ALTER COLUMN tenant_key TYPE text USING tenant_key::text; + END IF; +END; +$$; + DO $$ DECLARE current_type text; @@ -7270,6 +7664,29 @@ BEGIN END; $$; +DO $$ +DECLARE + current_type text; +BEGIN + SELECT pg_catalog.format_type(a.atttypid, a.atttypmod) + INTO current_type + FROM pg_attribute a + JOIN pg_class t ON t.oid = a.attrelid + JOIN pg_namespace n ON n.oid = t.relnamespace + WHERE n.nspname = 'public' + AND t.relname = 'plans' + AND a.attname = 'tenant_key' + AND a.attnum > 0 + AND NOT a.attisdropped; + + IF current_type IS NOT NULL + AND current_type <> ALL(ARRAY['text']) THEN + ALTER TABLE public.plans + ALTER COLUMN tenant_key TYPE text USING tenant_key::text; + END IF; +END; +$$; + DO $$ DECLARE current_type text; @@ -9035,6 +9452,50 @@ BEGIN END; $$; +DO $$ +DECLARE + current_pk_name text; + current_pk_matches boolean := false; +BEGIN + SELECT tc.constraint_name, + COALESCE( + ARRAY( + SELECT a.attname::text + FROM pg_constraint c + JOIN pg_class t ON t.oid = c.conrelid + JOIN pg_namespace n ON n.oid = t.relnamespace + JOIN unnest(c.conkey) WITH ORDINALITY AS cols(attnum, ord) + ON TRUE + JOIN pg_attribute a + ON a.attrelid = t.oid + AND a.attnum = cols.attnum + WHERE c.contype = 'p' + AND n.nspname = 'public' + AND t.relname = 'thought_learning_links' + ORDER BY cols.ord + ), + ARRAY[]::text[] + ) = ARRAY['id'] + INTO current_pk_name, current_pk_matches + FROM information_schema.table_constraints tc + WHERE tc.table_schema = 'public' + AND tc.table_name = 'thought_learning_links' + AND tc.constraint_type = 'PRIMARY KEY'; + + IF current_pk_name IS NOT NULL + AND NOT current_pk_matches + AND current_pk_name IN ('thought_learning_links_pkey', 'public_thought_learning_links_pkey') THEN + EXECUTE 'ALTER TABLE public.thought_learning_links DROP CONSTRAINT ' || quote_ident(current_pk_name) || ' CASCADE'; + END IF; + + -- Add the desired primary key only when no matching primary key already exists. + IF current_pk_name IS NULL + OR (NOT current_pk_matches AND current_pk_name IN ('thought_learning_links_pkey', 'public_thought_learning_links_pkey')) THEN + ALTER TABLE public.thought_learning_links ADD CONSTRAINT pk_public_thought_learning_links PRIMARY KEY (id); + END IF; +END; +$$; + DO $$ DECLARE current_pk_name text; @@ -9708,9 +10169,18 @@ CREATE INDEX IF NOT EXISTS idx_project_personas_project_id_persona_id CREATE INDEX IF NOT EXISTS idx_arc_stage_parts_stage_id_part_id ON public.arc_stage_parts USING btree (stage_id, part_id); +CREATE INDEX IF NOT EXISTS idx_thoughts_tenant_key_project_id + ON public.thoughts USING btree (tenant_key, project_id); + +CREATE UNIQUE INDEX IF NOT EXISTS uidx_projects_tenant_key_name + ON public.projects USING btree (tenant_key, name); + CREATE INDEX IF NOT EXISTS idx_thought_links_from_id_to_id_relation ON public.thought_links USING btree (from_id, to_id, relation); +CREATE UNIQUE INDEX IF NOT EXISTS uidx_thought_learning_links_thought_id_learning_id + ON public.thought_learning_links USING btree (thought_id, learning_id); + CREATE UNIQUE INDEX IF NOT EXISTS uidx_embeddings_thought_id_model ON public.embeddings USING btree (thought_id, model); @@ -9865,19 +10335,6 @@ BEGIN END; $$; -DO $$ -BEGIN - IF NOT EXISTS ( - SELECT 1 FROM information_schema.table_constraints - WHERE table_schema = 'public' - AND table_name = 'projects' - AND constraint_name = 'ukey_projects_name' - ) THEN - ALTER TABLE public.projects ADD CONSTRAINT ukey_projects_name UNIQUE (name); - END IF; -END; -$$; - DO $$ BEGIN IF NOT EXISTS ( @@ -10328,6 +10785,38 @@ BEGIN END IF; END; $$;DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.table_constraints + WHERE table_schema = 'public' + AND table_name = 'thought_learning_links' + AND constraint_name = 'fk_thought_learning_links_learning_id' + ) THEN + ALTER TABLE public.thought_learning_links + ADD CONSTRAINT fk_thought_learning_links_learning_id + FOREIGN KEY (learning_id) + REFERENCES public.learnings (id) + ON DELETE NO ACTION + ON UPDATE NO ACTION; + END IF; +END; +$$;DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.table_constraints + WHERE table_schema = 'public' + AND table_name = 'thought_learning_links' + AND constraint_name = 'fk_thought_learning_links_thought_id' + ) THEN + ALTER TABLE public.thought_learning_links + ADD CONSTRAINT fk_thought_learning_links_thought_id + FOREIGN KEY (thought_id) + REFERENCES public.thoughts (id) + ON DELETE NO ACTION + ON UPDATE NO ACTION; + END IF; +END; +$$;DO $$ BEGIN IF NOT EXISTS ( SELECT 1 FROM information_schema.table_constraints @@ -10912,15 +11401,15 @@ BEGIN IF EXISTS ( SELECT 1 FROM pg_class c INNER JOIN pg_namespace n ON n.oid = c.relnamespace - WHERE c.relname = 'identity_persona_arc_id' + WHERE c.relname = 'identity_persona_arc_persona_id' AND n.nspname = 'public' AND c.relkind = 'S' ) THEN - SELECT COALESCE(MAX(id), 0) + 1 + SELECT COALESCE(MAX(persona_id), 0) + 1 FROM public.persona_arc INTO m_cnt; - PERFORM setval('public.identity_persona_arc_id'::regclass, m_cnt); + PERFORM setval('public.identity_persona_arc_persona_id'::regclass, m_cnt); END IF; END; $$; @@ -10982,6 +11471,25 @@ BEGIN END; $$; DO $$ +DECLARE + m_cnt bigint; +BEGIN + IF EXISTS ( + SELECT 1 FROM pg_class c + INNER JOIN pg_namespace n ON n.oid = c.relnamespace + WHERE c.relname = 'identity_thought_learning_links_id' + AND n.nspname = 'public' + AND c.relkind = 'S' + ) THEN + SELECT COALESCE(MAX(id), 0) + 1 + FROM public.thought_learning_links + INTO m_cnt; + + PERFORM setval('public.identity_thought_learning_links_id'::regclass, m_cnt); + END IF; +END; +$$; +DO $$ DECLARE m_cnt bigint; BEGIN @@ -11295,5 +11803,6 @@ $$; + diff --git a/migrations/110_per_user_tenancy.sql b/migrations/110_per_user_tenancy.sql index 16455fd..7c39990 100644 --- a/migrations/110_per_user_tenancy.sql +++ b/migrations/110_per_user_tenancy.sql @@ -9,6 +9,8 @@ alter table plans add column if not exists tenant_key text; alter table chat_histories add column if not exists tenant_key text; -- Project names are now unique inside a tenant rather than globally. +alter table projects drop constraint if exists ukey_projects_name; +alter table projects drop constraint if exists projects_name_key; drop index if exists projects_name_key; create unique index if not exists projects_tenant_key_name_idx on projects (coalesce(tenant_key, ''), name); diff --git a/schema/files.dbml b/schema/files.dbml index 8df0d13..a4a8f8f 100644 --- a/schema/files.dbml +++ b/schema/files.dbml @@ -3,6 +3,7 @@ Table stored_files { guid uuid [unique, not null, default: `gen_random_uuid()`] thought_id bigint [ref: > thoughts.id] project_id bigint [ref: > projects.id] + tenant_key text name text [not null] media_type text [not null] kind text [not null, default: 'file'] @@ -16,6 +17,7 @@ Table stored_files { indexes { thought_id project_id + tenant_key sha256 } } diff --git a/schema/meta.dbml b/schema/meta.dbml index 5945e10..0c48b8e 100644 --- a/schema/meta.dbml +++ b/schema/meta.dbml @@ -6,6 +6,7 @@ Table chat_histories { channel text agent_id text project_id bigint [ref: > projects.id] + tenant_key text messages jsonb [not null, default: `'[]'`] summary text metadata jsonb [not null, default: `'{}'`] @@ -15,6 +16,7 @@ Table chat_histories { indexes { session_id project_id + tenant_key channel agent_id created_at @@ -46,6 +48,7 @@ Table learnings { source_type text source_ref text project_id bigint [ref: > projects.id] + tenant_key text related_thought_id bigint [ref: > thoughts.id] related_skill_id bigint [ref: > agent_skills.id] reviewed_by text @@ -58,6 +61,7 @@ Table learnings { indexes { project_id + tenant_key category area status diff --git a/schema/plans.dbml b/schema/plans.dbml index 3e658f9..03e5f06 100644 --- a/schema/plans.dbml +++ b/schema/plans.dbml @@ -6,6 +6,7 @@ Table plans { status text [not null, default: 'draft'] // draft, active, blocked, completed, cancelled, superseded priority text [not null, default: 'medium'] // low, medium, high, critical project_id bigint [ref: > projects.id] + tenant_key text owner text due_date timestamptz completed_at timestamptz @@ -18,6 +19,7 @@ Table plans { indexes { project_id + tenant_key status priority owner