/** * Seed script for GTS-X local development * Run with: npx tsx scripts/seed.ts */ import pg from "pg"; import { drizzle } from "drizzle-orm/node-postgres"; import * as schema from "../src/schema/schema"; const DATABASE_URL = process.env.DATABASE_URL || "postgresql://cpx_user:cpx_password@localhost:5432/cpx_studio"; async function seed() { const pool = new pg.Pool({ connectionString: DATABASE_URL }); const db = drizzle(pool, { schema }); console.log("Seeding GTS-X development data...\n"); // 1. Create resources console.log("Creating resources..."); const [resource1] = await db .insert(schema.resources) .values({ name: "Alice Kim", email: "alice.kim@iyuno.com", atlasResourceId: "atlas-r-001", branchId: "seoul", }) .onConflictDoNothing() .returning(); const [resource2] = await db .insert(schema.resources) .values({ name: "Bob Tanaka", email: "bob.tanaka@iyuno.com", atlasResourceId: "atlas-r-002", branchId: "tokyo", }) .onConflictDoNothing() .returning(); const [resource3] = await db .insert(schema.resources) .values({ name: "Clara Nowak", email: "clara.nowak@iyuno.com", atlasResourceId: "atlas-r-003", branchId: "warsaw", }) .onConflictDoNothing() .returning(); if (!resource1 || !resource2 || !resource3) { console.log( " Resources already exist (skipping). Drop tables first to re-seed." ); await pool.end(); return; } console.log(` Created: ${resource1.name}, ${resource2.name}, ${resource3.name}`); // 2. Create skill sets console.log("Creating skill sets..."); await db.insert(schema.resourceSkillSets).values([ { resourceId: resource1.id, platform: "GTS_X", grade: "senior", sourceLanguageId: "en", targetLanguageId: "ko", }, { resourceId: resource2.id, platform: "GTS_X", grade: "mid", sourceLanguageId: "en", targetLanguageId: "ja", }, { resourceId: resource3.id, platform: "GTS_X", grade: "senior", sourceLanguageId: "en", targetLanguageId: "pl", }, ]); // 3. Create sample jobs console.log("Creating sample jobs..."); // Sample GTSDocument for testing const sampleDocument = { info: { title: "Sample Episode S01E01", episode: "S01E01", fps: 23.976, }, tracks: [ { language: "en", subtitles: [ { tcIn: "00:00:05:00", tcOut: "00:00:08:00", text: "Welcome to the show.", speaker: "NARRATOR", }, { tcIn: "00:00:10:00", tcOut: "00:00:13:00", text: "It's a beautiful day outside.", speaker: "CHARACTER_A", }, { tcIn: "00:00:14:00", tcOut: "00:00:17:00", text: "I couldn't agree more.\nLet's go for a walk.", speaker: "CHARACTER_B", }, { tcIn: "00:00:20:00", tcOut: "00:00:23:00", text: "The park should be lovely this time of year.", speaker: "CHARACTER_A", }, { tcIn: "00:00:25:00", tcOut: "00:00:28:00", text: "♪ Background music plays ♪", speaker: "", }, ], }, ], }; const [job1] = await db .insert(schema.jobs) .values({ arcJobId: "arc-job-001", orderId: "ORD-2026-001", sourceLanguage: "en", targetLanguage: "ko", clientId: "netflix", status: "pending", initialDocument: sampleDocument, currentDocument: sampleDocument, metadata: { clientProfile: "netflix-standard", maxCPL: 42 }, }) .returning(); const [job2] = await db .insert(schema.jobs) .values({ arcJobId: "arc-job-002", orderId: "ORD-2026-002", sourceLanguage: "en", targetLanguage: "ja", clientId: "disney", status: "assigned", initialDocument: sampleDocument, currentDocument: sampleDocument, metadata: { clientProfile: "disney-plus", maxCPL: 40 }, }) .returning(); const [job3] = await db .insert(schema.jobs) .values({ arcJobId: "arc-job-003", orderId: "ORD-2026-003", sourceLanguage: "en", targetLanguage: "pl", clientId: "hbo", status: "in_progress", initialDocument: sampleDocument, currentDocument: sampleDocument, }) .returning(); const [job4] = await db .insert(schema.jobs) .values({ arcJobId: "arc-job-004", orderId: "ORD-2026-004", sourceLanguage: "en", targetLanguage: "ko", clientId: "netflix", status: "completed", initialDocument: sampleDocument, currentDocument: sampleDocument, }) .returning(); console.log(` Created ${4} sample jobs`); // 4. Create assignments for assigned/in_progress jobs console.log("Creating assignments..."); await db.insert(schema.jobAssignments).values([ { jobId: job2.id, resourceId: resource2.id, assignmentType: "manual", acceptanceStatus: "accepted", startedAt: new Date(), deadline: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000), }, { jobId: job3.id, resourceId: resource3.id, assignmentType: "manual", acceptanceStatus: "accepted", startedAt: new Date(), }, { jobId: job4.id, resourceId: resource1.id, assignmentType: "auto", acceptanceStatus: "accepted", startedAt: new Date(Date.now() - 3 * 24 * 60 * 60 * 1000), completedAt: new Date(), }, ]); // 5. Create sample diffs for the completed job console.log("Creating sample edit diffs..."); await db.insert(schema.editDiffs).values([ { jobId: job4.id, subtitleIndex: 1, field: "text", oldValue: "It's a beautiful day outside.", newValue: "밖은 정말 아름다운 날이에요.", rationale: "LSX translation was too literal — adjusted to natural Korean phrasing", changeCategory: "translation_fix", }, { jobId: job4.id, subtitleIndex: 2, field: "tc_out", oldValue: "00:00:17:00", newValue: "00:00:16:12", rationale: "Subtitle was overlapping with next cue by 1 frame — shortened to fix gap", changeCategory: "timing_fix", }, { jobId: job4.id, subtitleIndex: 3, field: "text", oldValue: "The park should be lovely this time of year.", newValue: "이맘때 공원이 좋을 거예요.", rationale: "CPL exceeded 42 chars — shortened translation while preserving meaning", changeCategory: "cpl_fix", }, ]); // 6. Create sample feedback analysis for the completed job console.log("Creating sample feedback analysis..."); await db.insert(schema.feedbackAnalyses).values([ { jobId: job4.id, errorType: "cicd_needed", confidenceScore: 0.87, description: "Editor shortened subtitle 3 due to CPL violation (42 char limit). LSX should have enforced Netflix Korean CPL during translation.", affectedInput: "lsx_prompt", reviewStatus: "pending", }, { jobId: job4.id, errorType: "style_preference", confidenceScore: 0.65, description: "Editor rephrased subtitle 1 for more natural Korean. This is a style improvement, not an error in LSX output.", reviewStatus: "pending", }, ]); console.log("\nSeed complete!"); console.log(" 3 resources"); console.log(" 4 jobs (pending, assigned, in_progress, completed)"); console.log(" 3 assignments"); console.log(" 3 edit diffs"); console.log(" 2 feedback analyses"); await pool.end(); } seed().catch((err) => { console.error("Seed failed:", err); process.exit(1); });