diff --git a/migrate.js b/migrate.js new file mode 100755 index 0000000..721ecbd --- /dev/null +++ b/migrate.js @@ -0,0 +1,194 @@ +#!/usr/bin/env node + +const { Pool } = require('pg'); + +const pool = new Pool({ + host: process.env.DB_HOST || 'localhost', + port: process.env.DB_PORT || 5432, + database: process.env.DB_NAME || 'agent_tasks_v2', + user: process.env.DB_USER || 'postgres', + password: process.env.DB_PASSWORD || 'postgres', +}); + +async function migrate() { + const client = await pool.connect(); + + try { + console.log('🔧 开始数据库迁移...'); + + // 创建智能体表 + console.log('创建 agents 表...'); + await client.query(` + CREATE TABLE IF NOT EXISTS agents ( + id VARCHAR(255) PRIMARY KEY, + name VARCHAR(255) NOT NULL, + type VARCHAR(100), + capabilities JSONB, + status VARCHAR(50) DEFAULT 'idle', + registered_at BIGINT, + last_heartbeat BIGINT + ) + `); + + // 创建项目表 + console.log('创建 projects 表...'); + await client.query(` + CREATE TABLE IF NOT EXISTS projects ( + id VARCHAR(255) PRIMARY KEY, + name VARCHAR(500) NOT NULL, + description TEXT, + created_by VARCHAR(255), + created_at BIGINT, + updated_at BIGINT, + status VARCHAR(50) DEFAULT 'active' + ) + `); + + // 创建全局协作规约表 + console.log('创建 global_collaboration_rules 表...'); + await client.query(` + CREATE TABLE IF NOT EXISTS global_collaboration_rules ( + id VARCHAR(255) PRIMARY KEY, + content TEXT NOT NULL, + created_by VARCHAR(255), + created_at BIGINT, + updated_at BIGINT + ) + `); + + // 创建项目协作规约表 + console.log('创建 collaboration_rules 表...'); + await client.query(` + CREATE TABLE IF NOT EXISTS collaboration_rules ( + id VARCHAR(255) PRIMARY KEY, + project_id VARCHAR(255), + content TEXT NOT NULL, + created_by VARCHAR(255), + created_at BIGINT, + updated_at BIGINT + ) + `); + + // 创建项目信息共享清单表 + console.log('创建 project_notes 表...'); + await client.query(` + CREATE TABLE IF NOT EXISTS project_notes ( + id VARCHAR(255) PRIMARY KEY, + project_id VARCHAR(255), + content TEXT NOT NULL, + created_by VARCHAR(255), + created_at BIGINT, + updated_at BIGINT + ) + `); + + // 创建任务表 + console.log('创建 tasks 表...'); + await client.query(` + CREATE TABLE IF NOT EXISTS tasks ( + id VARCHAR(255) PRIMARY KEY, + project_id VARCHAR(255), + parent_task_id VARCHAR(255), + title VARCHAR(500) NOT NULL, + description TEXT, + task_type VARCHAR(50) DEFAULT 'development', + priority VARCHAR(50) DEFAULT 'normal', + status VARCHAR(50) DEFAULT 'initial', + created_by VARCHAR(255), + assigned_to VARCHAR(255), + created_at BIGINT, + updated_at BIGINT, + completed_at BIGINT, + result TEXT + ) + `); + + // 创建附件表 + console.log('创建 attachments 表...'); + await client.query(` + CREATE TABLE IF NOT EXISTS attachments ( + id VARCHAR(255) PRIMARY KEY, + task_id VARCHAR(255), + filename VARCHAR(500) NOT NULL, + original_name VARCHAR(500) NOT NULL, + file_path VARCHAR(1000) NOT NULL, + file_size BIGINT, + mime_type VARCHAR(100), + uploaded_by VARCHAR(255), + uploaded_at BIGINT + ) + `); + + // 现在添加外键约束 + console.log('添加外键约束...'); + await client.query(` + DO $$ + BEGIN + -- collaboration_rules 外键 + IF NOT EXISTS ( + SELECT 1 FROM pg_constraint WHERE conname = 'collaboration_rules_project_id_fkey' + ) THEN + ALTER TABLE collaboration_rules + ADD CONSTRAINT collaboration_rules_project_id_fkey + FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE; + END IF; + + -- project_notes 外键 + IF NOT EXISTS ( + SELECT 1 FROM pg_constraint WHERE conname = 'project_notes_project_id_fkey' + ) THEN + ALTER TABLE project_notes + ADD CONSTRAINT project_notes_project_id_fkey + FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE; + END IF; + + -- tasks 外键 + IF NOT EXISTS ( + SELECT 1 FROM pg_constraint WHERE conname = 'tasks_project_id_fkey' + ) THEN + ALTER TABLE tasks + ADD CONSTRAINT tasks_project_id_fkey + FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE; + END IF; + + IF NOT EXISTS ( + SELECT 1 FROM pg_constraint WHERE conname = 'tasks_parent_task_id_fkey' + ) THEN + ALTER TABLE tasks + ADD CONSTRAINT tasks_parent_task_id_fkey + FOREIGN KEY (parent_task_id) REFERENCES tasks(id) ON DELETE SET NULL; + END IF; + + -- attachments 外键 + IF NOT EXISTS ( + SELECT 1 FROM pg_constraint WHERE conname = 'attachments_task_id_fkey' + ) THEN + ALTER TABLE attachments + ADD CONSTRAINT attachments_task_id_fkey + FOREIGN KEY (task_id) REFERENCES tasks(id) ON DELETE CASCADE; + END IF; + END $$; + `); + + // 创建索引 + console.log('创建索引...'); + await client.query(`CREATE INDEX IF NOT EXISTS idx_agents_status ON agents(status)`); + await client.query(`CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status)`); + await client.query(`CREATE INDEX IF NOT EXISTS idx_tasks_project ON tasks(project_id)`); + await client.query(`CREATE INDEX IF NOT EXISTS idx_tasks_parent ON tasks(parent_task_id)`); + await client.query(`CREATE INDEX IF NOT EXISTS idx_tasks_assigned ON tasks(assigned_to)`); + await client.query(`CREATE INDEX IF NOT EXISTS idx_attachments_task ON attachments(task_id)`); + await client.query(`CREATE INDEX IF NOT EXISTS idx_project_notes_project ON project_notes(project_id)`); + + console.log('✅ 数据库迁移完成!'); + + } catch (err) { + console.error('❌ 迁移失败:', err); + process.exit(1); + } finally { + client.release(); + await pool.end(); + } +} + +migrate(); diff --git a/server-v2.js b/server-v2.js index c0761dc..d9ad7d7 100644 --- a/server-v2.js +++ b/server-v2.js @@ -57,7 +57,8 @@ pool.connect((err, client, release) => { } else { console.log('✅ 已连接到 PostgreSQL 数据库'); release(); - initDatabase(); + // 数据库表已通过 migrate.js 初始化 + console.log('💡 提示: 如需初始化数据库,请运行: node migrate.js'); } });