-- Mission Control Project View foundation -- Adds project domain tables and links from sag_sager. CREATE TABLE IF NOT EXISTS mission_projects ( id BIGSERIAL PRIMARY KEY, name VARCHAR(255) NOT NULL, description TEXT, status VARCHAR(32) NOT NULL DEFAULT 'planned' CHECK (status IN ('planned', 'active', 'paused', 'completed', 'cancelled')), score INTEGER NOT NULL DEFAULT 0, started_at TIMESTAMPTZ, ended_at TIMESTAMPTZ, created_by INTEGER REFERENCES users(user_id) ON DELETE SET NULL, payload JSONB NOT NULL DEFAULT '{}'::jsonb, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE INDEX IF NOT EXISTS idx_mission_projects_status ON mission_projects (status); CREATE INDEX IF NOT EXISTS idx_mission_projects_score ON mission_projects (score DESC); CREATE INDEX IF NOT EXISTS idx_mission_projects_updated_at ON mission_projects (updated_at DESC); CREATE TABLE IF NOT EXISTS mission_project_milestones ( id BIGSERIAL PRIMARY KEY, project_id BIGINT NOT NULL REFERENCES mission_projects(id) ON DELETE CASCADE, title VARCHAR(255) NOT NULL, description TEXT, status VARCHAR(32) NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'completed', 'cancelled')), target_date DATE, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE INDEX IF NOT EXISTS idx_mission_project_milestones_project_id ON mission_project_milestones (project_id); CREATE INDEX IF NOT EXISTS idx_mission_project_milestones_status ON mission_project_milestones (status); CREATE INDEX IF NOT EXISTS idx_mission_project_milestones_target_date ON mission_project_milestones (target_date); CREATE TABLE IF NOT EXISTS mission_project_blockers ( id BIGSERIAL PRIMARY KEY, project_id BIGINT NOT NULL REFERENCES mission_projects(id) ON DELETE CASCADE, title VARCHAR(255) NOT NULL, description TEXT, status VARCHAR(32) NOT NULL DEFAULT 'open' CHECK (status IN ('open', 'in_progress', 'resolved', 'cancelled')), severity VARCHAR(16) NOT NULL DEFAULT 'medium' CHECK (severity IN ('low', 'medium', 'high', 'critical')), resolved_at TIMESTAMPTZ, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE INDEX IF NOT EXISTS idx_mission_project_blockers_project_id ON mission_project_blockers (project_id); CREATE INDEX IF NOT EXISTS idx_mission_project_blockers_status ON mission_project_blockers (status); CREATE INDEX IF NOT EXISTS idx_mission_project_blockers_severity ON mission_project_blockers (severity); ALTER TABLE sag_sager ADD COLUMN IF NOT EXISTS project_id BIGINT, ADD COLUMN IF NOT EXISTS project_milestone_id BIGINT, ADD COLUMN IF NOT EXISTS is_project_blocker BOOLEAN NOT NULL DEFAULT FALSE, ADD COLUMN IF NOT EXISTS project_task_type VARCHAR(32); DO $$ BEGIN IF NOT EXISTS ( SELECT 1 FROM pg_constraint WHERE conname = 'fk_sag_sager_project_id' ) THEN ALTER TABLE sag_sager ADD CONSTRAINT fk_sag_sager_project_id FOREIGN KEY (project_id) REFERENCES mission_projects(id) ON DELETE SET NULL; END IF; IF NOT EXISTS ( SELECT 1 FROM pg_constraint WHERE conname = 'fk_sag_sager_project_milestone_id' ) THEN ALTER TABLE sag_sager ADD CONSTRAINT fk_sag_sager_project_milestone_id FOREIGN KEY (project_milestone_id) REFERENCES mission_project_milestones(id) ON DELETE SET NULL; END IF; END $$; CREATE INDEX IF NOT EXISTS idx_sag_sager_project_id ON sag_sager (project_id); CREATE INDEX IF NOT EXISTS idx_sag_sager_project_milestone_id ON sag_sager (project_milestone_id); CREATE INDEX IF NOT EXISTS idx_sag_sager_project_task_type ON sag_sager (project_task_type); CREATE INDEX IF NOT EXISTS idx_sag_sager_is_project_blocker ON sag_sager (is_project_blocker);