require('dotenv').config(); const { query } = require('./db'); const migrate = async () => { console.log('Running database migrations...'); await query(` CREATE TABLE IF NOT EXISTS organizations ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name VARCHAR(255) NOT NULL, slug VARCHAR(100) UNIQUE NOT NULL, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); `); await query(` CREATE TABLE IF NOT EXISTS users ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), organization_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE, name VARCHAR(255) NOT NULL, email VARCHAR(255) NOT NULL, password_hash VARCHAR(255), role VARCHAR(50) NOT NULL DEFAULT 'member' CHECK (role IN ('admin', 'member')), oauth_provider VARCHAR(50), oauth_provider_id VARCHAR(255), is_active BOOLEAN DEFAULT TRUE, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW(), UNIQUE(email, organization_id) ); `); await query(`CREATE INDEX IF NOT EXISTS idx_users_org ON users(organization_id);`); await query(`CREATE INDEX IF NOT EXISTS idx_users_email ON users(email);`); await query(` CREATE TABLE IF NOT EXISTS tasks ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), organization_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE, title VARCHAR(500) NOT NULL, description TEXT, status VARCHAR(50) NOT NULL DEFAULT 'todo' CHECK (status IN ('todo', 'in_progress', 'in_review', 'done', 'cancelled')), priority VARCHAR(50) NOT NULL DEFAULT 'medium' CHECK (priority IN ('low', 'medium', 'high', 'critical')), creator_id UUID NOT NULL REFERENCES users(id) ON DELETE SET NULL, assignee_id UUID REFERENCES users(id) ON DELETE SET NULL, due_date TIMESTAMPTZ, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); `); await query(`CREATE INDEX IF NOT EXISTS idx_tasks_org ON tasks(organization_id);`); await query(`CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(organization_id, status);`); await query(`CREATE INDEX IF NOT EXISTS idx_tasks_assignee ON tasks(assignee_id);`); await query(`CREATE INDEX IF NOT EXISTS idx_tasks_priority ON tasks(organization_id, priority);`); await query(`CREATE INDEX IF NOT EXISTS idx_tasks_due_date ON tasks(organization_id, due_date);`); await query(` CREATE TABLE IF NOT EXISTS task_comments ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), task_id UUID NOT NULL REFERENCES tasks(id) ON DELETE CASCADE, organization_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE, author_id UUID NOT NULL REFERENCES users(id) ON DELETE SET NULL, body TEXT NOT NULL, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); `); await query(`CREATE INDEX IF NOT EXISTS idx_comments_task ON task_comments(task_id);`); await query(` CREATE TABLE IF NOT EXISTS audit_logs ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), organization_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE, task_id UUID REFERENCES tasks(id) ON DELETE SET NULL, actor_id UUID REFERENCES users(id) ON DELETE SET NULL, actor_name VARCHAR(255) NOT NULL, actor_email VARCHAR(255) NOT NULL, action VARCHAR(100) NOT NULL, entity_type VARCHAR(50) NOT NULL DEFAULT 'task', old_values JSONB, new_values JSONB, metadata JSONB, created_at TIMESTAMPTZ DEFAULT NOW() ); `); await query(`CREATE INDEX IF NOT EXISTS idx_audit_org ON audit_logs(organization_id);`); await query(`CREATE INDEX IF NOT EXISTS idx_audit_task ON audit_logs(task_id);`); await query(`CREATE INDEX IF NOT EXISTS idx_audit_created ON audit_logs(organization_id, created_at DESC);`); await query(` CREATE TABLE IF NOT EXISTS invites ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), organization_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE, email VARCHAR(255) NOT NULL, role VARCHAR(50) NOT NULL DEFAULT 'member', token VARCHAR(255) UNIQUE NOT NULL, invited_by UUID REFERENCES users(id) ON DELETE SET NULL, expires_at TIMESTAMPTZ NOT NULL, used_at TIMESTAMPTZ, created_at TIMESTAMPTZ DEFAULT NOW() ); `); await query(`CREATE INDEX IF NOT EXISTS idx_invites_token ON invites(token);`); await query(`CREATE INDEX IF NOT EXISTS idx_invites_org ON invites(organization_id);`); console.log('✅ Migrations complete.'); process.exit(0); }; migrate().catch(err => { console.error('Migration failed:', err); process.exit(1); });