修复: - 分离数据库初始化逻辑到独立的 migrate.js - 避免启动时索引创建顺序问题 - 服务启动不再自动运行 initDatabase 新增: - migrate.js - 独立的数据库迁移脚本 - 先创建表,再添加外键,最后创建索引 使用方法: 1. 运行迁移: DB_HOST=localhost DB_PORT=5433 DB_NAME=agent_tasks_v2 node migrate.js 2. 启动服务: DB_HOST=localhost DB_PORT=5433 DB_NAME=agent_tasks_v2 node server-v2.js 已测试功能: ✅ 全局规约设置和获取 ✅ 项目创建 ✅ 项目规约设置 ✅ 任务创建 ✅ 智能体注册 ✅ 任务领取(同时返回全局规约和项目规约)
195 lines
6.1 KiB
JavaScript
Executable File
195 lines
6.1 KiB
JavaScript
Executable File
#!/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();
|