-- Initial schema for Containr platform -- This migration creates the core tables for users, projects, services, and deployments -- Users table CREATE TABLE IF NOT EXISTS users ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), email VARCHAR(255) UNIQUE NOT NULL, password_hash VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, avatar_url VARCHAR(500), created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); -- Projects table CREATE TABLE IF NOT EXISTS projects ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name VARCHAR(255) NOT NULL, description TEXT, owner_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); -- Environments table CREATE TABLE IF NOT EXISTS environments ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name VARCHAR(50) NOT NULL, -- 'production', 'preview', 'development' project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), UNIQUE(name, project_id) ); -- Services table CREATE TABLE IF NOT EXISTS services ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name VARCHAR(255) NOT NULL, description TEXT, project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE, environment_id UUID NOT NULL REFERENCES environments(id) ON DELETE CASCADE, service_type VARCHAR(50) NOT NULL, -- 'web', 'worker', 'database', 'cron' source_type VARCHAR(50) NOT NULL, -- 'github', 'dockerfile', 'image', 'template' source_url VARCHAR(500), image_name VARCHAR(500), build_command TEXT, start_command TEXT, cpu_limit INTEGER, memory_limit INTEGER, -- in MB public_url VARCHAR(500), health_check_url VARCHAR(500), status VARCHAR(50) DEFAULT 'created', -- 'created', 'building', 'running', 'stopped', 'failed' created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); -- Environment variables table CREATE TABLE IF NOT EXISTS environment_variables ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), service_id UUID NOT NULL REFERENCES services(id) ON DELETE CASCADE, key VARCHAR(255) NOT NULL, value TEXT, is_secret BOOLEAN DEFAULT false, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), UNIQUE(service_id, key) ); -- Deployments table CREATE TABLE IF NOT EXISTS deployments ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), service_id UUID NOT NULL REFERENCES services(id) ON DELETE CASCADE, version VARCHAR(100) NOT NULL, commit_hash VARCHAR(100), image_digest VARCHAR(500), status VARCHAR(50) DEFAULT 'created', -- 'created', 'building', 'deploying', 'running', 'failed', 'rolled_back' build_log TEXT, deployment_log TEXT, started_at TIMESTAMP WITH TIME ZONE, completed_at TIMESTAMP WITH TIME ZONE, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); -- Service dependencies table (for service-to-service relationships) CREATE TABLE IF NOT EXISTS service_dependencies ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), service_id UUID NOT NULL REFERENCES services(id) ON DELETE CASCADE, depends_on_service_id UUID NOT NULL REFERENCES services(id) ON DELETE CASCADE, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), UNIQUE(service_id, depends_on_service_id), CHECK (service_id != depends_on_service_id) ); -- Project members table (for collaboration) CREATE TABLE IF NOT EXISTS project_members ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE, user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, role VARCHAR(50) NOT NULL DEFAULT 'developer', -- 'owner', 'admin', 'developer', 'viewer' created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), UNIQUE(project_id, user_id) ); -- Indexes for better performance CREATE INDEX IF NOT EXISTS idx_users_email ON users(email); CREATE INDEX IF NOT EXISTS idx_projects_owner_id ON projects(owner_id); CREATE INDEX IF NOT EXISTS idx_services_project_id ON services(project_id); CREATE INDEX IF NOT EXISTS idx_services_environment_id ON services(environment_id); CREATE INDEX IF NOT EXISTS idx_deployments_service_id ON deployments(service_id); CREATE INDEX IF NOT EXISTS idx_deployments_status ON deployments(status); CREATE INDEX IF NOT EXISTS idx_environment_variables_service_id ON environment_variables(service_id); CREATE INDEX IF NOT EXISTS idx_project_members_project_id ON project_members(project_id); CREATE INDEX IF NOT EXISTS idx_project_members_user_id ON project_members(user_id); -- Update timestamp trigger function CREATE OR REPLACE FUNCTION update_updated_at_column() RETURNS TRIGGER AS $$ BEGIN NEW.updated_at = NOW(); RETURN NEW; END; $$ language 'plpgsql'; -- Add update triggers to tables with updated_at columns (only if they don't exist) DO $$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_trigger WHERE tgname = 'update_users_updated_at') THEN CREATE TRIGGER update_users_updated_at BEFORE UPDATE ON users FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); END IF; IF NOT EXISTS (SELECT 1 FROM pg_trigger WHERE tgname = 'update_projects_updated_at') THEN CREATE TRIGGER update_projects_updated_at BEFORE UPDATE ON projects FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); END IF; IF NOT EXISTS (SELECT 1 FROM pg_trigger WHERE tgname = 'update_environments_updated_at') THEN CREATE TRIGGER update_environments_updated_at BEFORE UPDATE ON environments FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); END IF; IF NOT EXISTS (SELECT 1 FROM pg_trigger WHERE tgname = 'update_services_updated_at') THEN CREATE TRIGGER update_services_updated_at BEFORE UPDATE ON services FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); END IF; IF NOT EXISTS (SELECT 1 FROM pg_trigger WHERE tgname = 'update_environment_variables_updated_at') THEN CREATE TRIGGER update_environment_variables_updated_at BEFORE UPDATE ON environment_variables FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); END IF; IF NOT EXISTS (SELECT 1 FROM pg_trigger WHERE tgname = 'update_deployments_updated_at') THEN CREATE TRIGGER update_deployments_updated_at BEFORE UPDATE ON deployments FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); END IF; END $$;