From f1d90b60975ef59ba296f19c8252f162d2f4e829 Mon Sep 17 00:00:00 2001 From: mytheclipsebotreview Date: Thu, 20 Aug 2026 19:08:32 +0700 Subject: [PATCH] =?UTF-8?q?fix(materi):=20align=20tags=20column=20type=20t?= =?UTF-8?q?o=20jsonb=20(schema=20=E2=86=94=20migration=20mismatch)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Drizzle schema used pgText('tags').array() which emits a Postgres text[] column, but the migration defines tags as jsonb. The mismatch caused INSERT/LIST on materi_documents to throw INTERNAL_SERVER_ERROR (500) because Drizzle sent a text[] where the column expected jsonb. - schema.ts: tags → pgJsonb('tags').notNull().default('[]') - migration: dropped+recreated to match schema (jsonb, ms epoch defaults, owner_user_id default 'anonymous') --- scripts/add-materi-documents.sql | 38 ++++++++++--------- .../backend/src/shared/database/schema.ts | 2 +- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/scripts/add-materi-documents.sql b/scripts/add-materi-documents.sql index 5361a6a..19b99ea 100644 --- a/scripts/add-materi-documents.sql +++ b/scripts/add-materi-documents.sql @@ -1,27 +1,29 @@ -- Migration: Add materi_documents table for learning materials + RAG -- Run: PGPASSWORD= psql -h -U -d -f scripts/add-materi-documents.sql +-- Schema mirrors services/backend/src/shared/database/schema.ts (pgMateriDocumentsTable). BEGIN; -CREATE TABLE IF NOT EXISTS "materi_documents" ( - "id" uuid PRIMARY KEY DEFAULT gen_random_uuid(), - "title" text NOT NULL, - "description" text, - "content" text NOT NULL, - "category" text NOT NULL DEFAULT 'general', - "tags" jsonb NOT NULL DEFAULT '[]', - "owner_user_id" text NOT NULL DEFAULT 'anonymous', - "guild_id" text, - "channel_id" text, - "is_public" boolean NOT NULL DEFAULT true, - "view_count" integer NOT NULL DEFAULT 0, - "created_at" bigint NOT NULL DEFAULT extract(epoch from now())::bigint, - "updated_at" bigint NOT NULL DEFAULT extract(epoch from now())::bigint +CREATE TABLE IF NOT EXISTS public.materi_documents ( + id uuid PRIMARY KEY DEFAULT gen_random_uuid(), + title text NOT NULL, + description text, + content text NOT NULL, + category text NOT NULL DEFAULT 'general', + tags jsonb NOT NULL DEFAULT '[]', + owner_user_id text NOT NULL DEFAULT 'anonymous', + guild_id text, + channel_id text, + is_public boolean NOT NULL DEFAULT true, + view_count integer NOT NULL DEFAULT 0, + created_at bigint NOT NULL DEFAULT (EXTRACT(epoch FROM now())::bigint * 1000), + updated_at bigint NOT NULL DEFAULT (EXTRACT(epoch FROM now())::bigint * 1000) ); -CREATE INDEX IF NOT EXISTS "idx_materi_category" ON "materi_documents" ("category"); -CREATE INDEX IF NOT EXISTS "idx_materi_is_public" ON "materi_documents" ("is_public"); -CREATE INDEX IF NOT EXISTS "idx_materi_owner" ON "materi_documents" ("owner_user_id"); -CREATE INDEX IF NOT EXISTS "idx_materi_created" ON "materi_documents" ("created_at"); +-- Indexes mirror the Drizzle index definitions (idx_materi_category, idx_materi_owner, idx_materi_guild, idx_materi_search). +CREATE INDEX IF NOT EXISTS idx_materi_category ON public.materi_documents (category); +CREATE INDEX IF NOT EXISTS idx_materi_owner ON public.materi_documents (owner_user_id); +CREATE INDEX IF NOT EXISTS idx_materi_guild ON public.materi_documents (guild_id); +CREATE INDEX IF NOT EXISTS idx_materi_search ON public.materi_documents (title, category); COMMIT; diff --git a/services/backend/src/shared/database/schema.ts b/services/backend/src/shared/database/schema.ts index 473e7a8..d20c63a 100644 --- a/services/backend/src/shared/database/schema.ts +++ b/services/backend/src/shared/database/schema.ts @@ -616,7 +616,7 @@ export const pgMateriDocumentsTable = pgTable( description: pgText("description"), content: pgText("content").notNull(), category: pgText("category").notNull().default("general"), - tags: pgText("tags").array(), + tags: pgJsonb("tags").notNull().default("[]"), owner_user_id: pgText("owner_user_id").notNull(), guild_id: pgText("guild_id"), channel_id: pgText("channel_id"),