From b70035ad2f6a3a1bcac74966b7a05d5fa773b470 Mon Sep 17 00:00:00 2001 From: hailin Date: Sat, 24 Jan 2026 08:05:14 -0800 Subject: [PATCH] fix(migration): add production migration support for Docker - Add data-source.prod.ts for compiled JS migrations - Add migration:run:prod script to package.json - Update deploy.sh to try prod migration first, fallback to dev - Keep SQL fallback in full-reset as safety net with proper indexes This ensures migrations work in Docker where ts-node may not be available. Co-Authored-By: Claude Opus 4.5 --- deploy.sh | 12 ++++++---- .../conversation-service/package.json | 2 ++ .../src/data-source.prod.ts | 23 +++++++++++++++++++ 3 files changed, 33 insertions(+), 4 deletions(-) create mode 100644 packages/services/conversation-service/src/data-source.prod.ts diff --git a/deploy.sh b/deploy.sh index 00a8777..0f1c2ce 100755 --- a/deploy.sh +++ b/deploy.sh @@ -971,8 +971,9 @@ do_full_reset() { sleep 5 # 等待数据库完全初始化 do_db migrate - # 7.1 添加 V2 咨询流程所需的数据库列 - log_step "添加 V2 咨询流程数据库列..." + # 7.1 备用:确保 V2 咨询流程数据库列存在(迁移可能因各种原因失败) + # 这些 ALTER 语句使用 IF NOT EXISTS,与 TypeORM 迁移保持一致 + log_step "验证 V2 数据库列..." docker exec -i iconsulting-postgres psql -U postgres -d iconsulting -c " ALTER TABLE conversations ADD COLUMN IF NOT EXISTS consulting_stage VARCHAR(30) DEFAULT 'greeting'; ALTER TABLE conversations ADD COLUMN IF NOT EXISTS consulting_state JSONB; @@ -980,7 +981,9 @@ do_full_reset() { ALTER TABLE conversations ADD COLUMN IF NOT EXISTS recommended_programs TEXT[]; ALTER TABLE conversations ADD COLUMN IF NOT EXISTS conversion_path VARCHAR(30); ALTER TABLE conversations ADD COLUMN IF NOT EXISTS device_info JSONB; - " 2>/dev/null && log_success "V2 数据库列已添加" || log_warning "V2 数据库列添加跳过" + CREATE INDEX IF NOT EXISTS idx_conversations_consulting_stage ON conversations (consulting_stage); + CREATE INDEX IF NOT EXISTS idx_conversations_conversion_path ON conversations (conversion_path); + " 2>/dev/null && log_success "V2 数据库列已验证" || log_warning "V2 数据库列验证跳过" # 8. 启动所有后端服务 log_step "启动后端服务..." @@ -1317,7 +1320,8 @@ do_db() { # 在容器中执行迁移命令 for service in user payment knowledge conversation evolution; do local dir="${SERVICE_DIRS[$service]}" - run_in_builder "cd $dir && pnpm run migration:run 2>/dev/null" || log_warning "$service 无迁移或迁移失败" + # 先尝试生产环境迁移(使用编译后的JS),如果失败再尝试开发环境迁移(需要ts-node) + run_in_builder "cd $dir && (pnpm run migration:run:prod 2>/dev/null || pnpm run migration:run 2>/dev/null)" || log_warning "$service 无迁移或迁移失败" done log_success "数据库迁移完成" ;; diff --git a/packages/services/conversation-service/package.json b/packages/services/conversation-service/package.json index a63a294..209c8aa 100644 --- a/packages/services/conversation-service/package.json +++ b/packages/services/conversation-service/package.json @@ -13,7 +13,9 @@ "test:watch": "jest --watch", "test:cov": "jest --coverage", "typeorm": "typeorm-ts-node-commonjs", + "typeorm:prod": "typeorm", "migration:run": "npm run typeorm migration:run -- -d src/data-source.ts", + "migration:run:prod": "npm run typeorm:prod migration:run -- -d dist/data-source.prod.js", "migration:revert": "npm run typeorm migration:revert -- -d src/data-source.ts", "migration:generate": "npm run typeorm migration:generate -- -d src/data-source.ts" }, diff --git a/packages/services/conversation-service/src/data-source.prod.ts b/packages/services/conversation-service/src/data-source.prod.ts new file mode 100644 index 0000000..93e628e --- /dev/null +++ b/packages/services/conversation-service/src/data-source.prod.ts @@ -0,0 +1,23 @@ +import { DataSource } from 'typeorm'; +import * as dotenv from 'dotenv'; + +// Load environment variables +dotenv.config({ path: '.env.local' }); +dotenv.config({ path: '.env' }); + +/** + * Production data source for running migrations + * Uses compiled JS files instead of TypeScript + */ +export const AppDataSource = new DataSource({ + type: 'postgres', + host: process.env.POSTGRES_HOST || 'localhost', + port: parseInt(process.env.POSTGRES_PORT || '5432', 10), + username: process.env.POSTGRES_USER || 'iconsulting', + password: process.env.POSTGRES_PASSWORD, + database: process.env.POSTGRES_DB || 'iconsulting', + entities: [__dirname + '/**/*.entity.js'], + migrations: [__dirname + '/migrations/*.js'], + synchronize: false, + logging: true, +});