Files
Containr/migrations/001_initial_schema.sql
T
Tomas Dvorak 0977d95539 fix
2026-02-23 16:43:39 +01:00

158 lines
6.6 KiB
PL/PgSQL

-- 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 $$;