diff --git a/migrations/020_generated_schema.sql b/migrations/020_generated_schema.sql index 34a1e4f..981611d 100644 --- a/migrations/020_generated_schema.sql +++ b/migrations/020_generated_schema.sql @@ -275,6 +275,30 @@ CREATE TABLE IF NOT EXISTS public.tool_annotations ( updated_at timestamptz NOT NULL DEFAULT now() ); +CREATE TABLE IF NOT EXISTS public.learnings ( + action_required boolean NOT NULL DEFAULT false, + area text NOT NULL DEFAULT 'other', + category text NOT NULL DEFAULT 'insight', + confidence text NOT NULL DEFAULT 'hypothesis', + created_at timestamptz NOT NULL DEFAULT now(), + details text NOT NULL DEFAULT '', + duplicate_of_learning_id uuid, + id uuid NOT NULL DEFAULT gen_random_uuid(), + priority text NOT NULL DEFAULT 'medium', + project_id uuid, + related_skill_id uuid, + related_thought_id uuid, + reviewed_at timestamptz, + reviewed_by text, + source_ref text, + source_type text, + status text NOT NULL DEFAULT 'pending', + summary text NOT NULL, + supersedes_learning_id uuid, + tags text, + updated_at timestamptz NOT NULL DEFAULT now() +); + CREATE TABLE IF NOT EXISTS public.agent_skills ( content text NOT NULL, created_at timestamptz NOT NULL DEFAULT now(), @@ -2597,6 +2621,279 @@ BEGIN END; $$; +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_schema = 'public' + AND table_name = 'learnings' + AND column_name = 'action_required' + ) THEN + ALTER TABLE public.learnings ADD COLUMN action_required boolean NOT NULL DEFAULT false; + END IF; +END; +$$; + +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_schema = 'public' + AND table_name = 'learnings' + AND column_name = 'area' + ) THEN + ALTER TABLE public.learnings ADD COLUMN area text NOT NULL DEFAULT 'other'; + END IF; +END; +$$; + +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_schema = 'public' + AND table_name = 'learnings' + AND column_name = 'category' + ) THEN + ALTER TABLE public.learnings ADD COLUMN category text NOT NULL DEFAULT 'insight'; + END IF; +END; +$$; + +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_schema = 'public' + AND table_name = 'learnings' + AND column_name = 'confidence' + ) THEN + ALTER TABLE public.learnings ADD COLUMN confidence text NOT NULL DEFAULT 'hypothesis'; + END IF; +END; +$$; + +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_schema = 'public' + AND table_name = 'learnings' + AND column_name = 'created_at' + ) THEN + ALTER TABLE public.learnings 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 = 'learnings' + AND column_name = 'details' + ) THEN + ALTER TABLE public.learnings ADD COLUMN details text NOT NULL DEFAULT ''; + END IF; +END; +$$; + +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_schema = 'public' + AND table_name = 'learnings' + AND column_name = 'duplicate_of_learning_id' + ) THEN + ALTER TABLE public.learnings ADD COLUMN duplicate_of_learning_id uuid; + END IF; +END; +$$; + +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_schema = 'public' + AND table_name = 'learnings' + AND column_name = 'id' + ) THEN + ALTER TABLE public.learnings ADD COLUMN id uuid NOT NULL DEFAULT gen_random_uuid(); + END IF; +END; +$$; + +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_schema = 'public' + AND table_name = 'learnings' + AND column_name = 'priority' + ) THEN + ALTER TABLE public.learnings ADD COLUMN priority text NOT NULL DEFAULT 'medium'; + END IF; +END; +$$; + +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_schema = 'public' + AND table_name = 'learnings' + AND column_name = 'project_id' + ) THEN + ALTER TABLE public.learnings ADD COLUMN project_id uuid; + END IF; +END; +$$; + +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_schema = 'public' + AND table_name = 'learnings' + AND column_name = 'related_skill_id' + ) THEN + ALTER TABLE public.learnings ADD COLUMN related_skill_id uuid; + END IF; +END; +$$; + +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_schema = 'public' + AND table_name = 'learnings' + AND column_name = 'related_thought_id' + ) THEN + ALTER TABLE public.learnings ADD COLUMN related_thought_id uuid; + END IF; +END; +$$; + +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_schema = 'public' + AND table_name = 'learnings' + AND column_name = 'reviewed_at' + ) THEN + ALTER TABLE public.learnings ADD COLUMN reviewed_at timestamptz; + END IF; +END; +$$; + +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_schema = 'public' + AND table_name = 'learnings' + AND column_name = 'reviewed_by' + ) THEN + ALTER TABLE public.learnings ADD COLUMN reviewed_by text; + END IF; +END; +$$; + +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_schema = 'public' + AND table_name = 'learnings' + AND column_name = 'source_ref' + ) THEN + ALTER TABLE public.learnings ADD COLUMN source_ref text; + END IF; +END; +$$; + +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_schema = 'public' + AND table_name = 'learnings' + AND column_name = 'source_type' + ) THEN + ALTER TABLE public.learnings ADD COLUMN source_type text; + END IF; +END; +$$; + +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_schema = 'public' + AND table_name = 'learnings' + AND column_name = 'status' + ) THEN + ALTER TABLE public.learnings ADD COLUMN status text NOT NULL DEFAULT 'pending'; + END IF; +END; +$$; + +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_schema = 'public' + AND table_name = 'learnings' + AND column_name = 'summary' + ) THEN + ALTER TABLE public.learnings ADD COLUMN summary text NOT NULL; + END IF; +END; +$$; + +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_schema = 'public' + AND table_name = 'learnings' + AND column_name = 'supersedes_learning_id' + ) THEN + ALTER TABLE public.learnings ADD COLUMN supersedes_learning_id uuid; + END IF; +END; +$$; + +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_schema = 'public' + AND table_name = 'learnings' + AND column_name = 'tags' + ) THEN + ALTER TABLE public.learnings ADD COLUMN tags text; + END IF; +END; +$$; + +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_schema = 'public' + AND table_name = 'learnings' + AND column_name = 'updated_at' + ) THEN + ALTER TABLE public.learnings ADD COLUMN updated_at timestamptz NOT NULL DEFAULT now(); + END IF; +END; +$$; + DO $$ BEGIN IF NOT EXISTS ( @@ -3403,6 +3700,34 @@ BEGIN END; $$; +DO $$ +DECLARE + auto_pk_name text; +BEGIN + -- Drop auto-generated primary key if it exists + SELECT constraint_name INTO auto_pk_name + FROM information_schema.table_constraints + WHERE table_schema = 'public' + AND table_name = 'learnings' + AND constraint_type = 'PRIMARY KEY' + AND constraint_name IN ('learnings_pkey', 'public_learnings_pkey'); + + IF auto_pk_name IS NOT NULL THEN + EXECUTE 'ALTER TABLE public.learnings DROP CONSTRAINT ' || quote_ident(auto_pk_name); + END IF; + + -- Add named primary key if it doesn't exist + IF NOT EXISTS ( + SELECT 1 FROM information_schema.table_constraints + WHERE table_schema = 'public' + AND table_name = 'learnings' + AND constraint_name = 'pk_public_learnings' + ) THEN + ALTER TABLE public.learnings ADD CONSTRAINT pk_public_learnings PRIMARY KEY (id); + END IF; +END; +$$; + DO $$ DECLARE auto_pk_name text; @@ -3475,6 +3800,15 @@ CREATE INDEX IF NOT EXISTS idx_contact_interactions_contact_id_occurred_at CREATE INDEX IF NOT EXISTS idx_maintenance_logs_task_id_completed_at ON public.maintenance_logs USING btree (task_id, completed_at); +CREATE INDEX IF NOT EXISTS idx_learnings_details + ON public.learnings USING gin (details gin_trgm_ops); + +CREATE INDEX IF NOT EXISTS idx_learnings_summary + ON public.learnings USING gin (summary gin_trgm_ops); + +CREATE INDEX IF NOT EXISTS idx_learnings_tags + ON public.learnings USING gin (tags gin_trgm_ops); + CREATE INDEX IF NOT EXISTS idx_project_skills_project_id_skill_id ON public.project_skills USING btree (project_id, skill_id); @@ -3810,6 +4144,86 @@ BEGIN END IF; END; $$;DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.table_constraints + WHERE table_schema = 'public' + AND table_name = 'learnings' + AND constraint_name = 'fk_learnings_duplicate_of_learning_id' + ) THEN + ALTER TABLE public.learnings + ADD CONSTRAINT fk_learnings_duplicate_of_learning_id + FOREIGN KEY (duplicate_of_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 = 'learnings' + AND constraint_name = 'fk_learnings_project_id' + ) THEN + ALTER TABLE public.learnings + ADD CONSTRAINT fk_learnings_project_id + FOREIGN KEY (project_id) + REFERENCES public.projects (guid) + 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 = 'learnings' + AND constraint_name = 'fk_learnings_related_skill_id' + ) THEN + ALTER TABLE public.learnings + ADD CONSTRAINT fk_learnings_related_skill_id + FOREIGN KEY (related_skill_id) + REFERENCES public.agent_skills (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 = 'learnings' + AND constraint_name = 'fk_learnings_related_thought_id' + ) THEN + ALTER TABLE public.learnings + ADD CONSTRAINT fk_learnings_related_thought_id + FOREIGN KEY (related_thought_id) + REFERENCES public.thoughts (guid) + 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 = 'learnings' + AND constraint_name = 'fk_learnings_supersedes_learning_id' + ) THEN + ALTER TABLE public.learnings + ADD CONSTRAINT fk_learnings_supersedes_learning_id + FOREIGN KEY (supersedes_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 @@ -3992,5 +4406,6 @@ $$; + diff --git a/schema/meta.dbml b/schema/meta.dbml index 792ccde..f83200d 100644 --- a/schema/meta.dbml +++ b/schema/meta.dbml @@ -30,3 +30,46 @@ Table tool_annotations { // Cross-file refs (for relspecgo merge) Ref: chat_histories.project_id > projects.guid [delete: set null] + +Table learnings { + id uuid [pk, default: `gen_random_uuid()`] + summary text [not null] + details text [not null, default: ''] + category text [not null, default: 'insight'] + area text [not null, default: 'other'] + status text [not null, default: 'pending'] + priority text [not null, default: 'medium'] + confidence text [not null, default: 'hypothesis'] + action_required boolean [not null, default: false] + source_type text + source_ref text + project_id uuid [ref: > projects.guid] + related_thought_id uuid [ref: > thoughts.guid] + related_skill_id uuid [ref: > agent_skills.id] + reviewed_by text + reviewed_at timestamptz + duplicate_of_learning_id uuid [ref: > learnings.id] + supersedes_learning_id uuid [ref: > learnings.id] + tags "text[]" [not null, default: `'{}'`] + created_at timestamptz [not null, default: `now()`] + updated_at timestamptz [not null, default: `now()`] + + indexes { + project_id + category + area + status + priority + reviewed_at + tags [type: gin] + summary [type: gin] + details [type: gin] + } +} + +// Cross-file refs (for relspecgo merge) +Ref: learnings.project_id > projects.guid [delete: set null] +Ref: learnings.related_thought_id > thoughts.guid [delete: set null] +Ref: learnings.related_skill_id > agent_skills.id [delete: set null] +Ref: learnings.duplicate_of_learning_id > learnings.id [delete: set null] +Ref: learnings.supersedes_learning_id > learnings.id [delete: set null]