From 8d07063d3f702d87327ea13bc2828c34d388f1a8 Mon Sep 17 00:00:00 2001 From: NotAShelf Date: Mon, 2 Feb 2026 02:58:57 +0300 Subject: [PATCH] db: add migration 008 for user management tables Signed-off-by: NotAShelf Change-Id: I99349ba4b389b525d66d0109a66243736a6a6964 --- .../common/migrations/008_user_management.sql | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 crates/common/migrations/008_user_management.sql diff --git a/crates/common/migrations/008_user_management.sql b/crates/common/migrations/008_user_management.sql new file mode 100644 index 0000000..60bf8a0 --- /dev/null +++ b/crates/common/migrations/008_user_management.sql @@ -0,0 +1,72 @@ +-- Migration 008: User Management Core +-- Adds user accounts, starred jobs, and project membership tables + +-- User accounts for authentication and personalization +CREATE TABLE users ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + username VARCHAR(255) NOT NULL UNIQUE, + email VARCHAR(255) NOT NULL UNIQUE, + full_name VARCHAR(255), + password_hash VARCHAR(255), -- NULL for OAuth-only users + user_type VARCHAR(50) NOT NULL DEFAULT 'local', -- 'local', 'github', 'google' + role VARCHAR(50) NOT NULL DEFAULT 'read-only', + enabled BOOLEAN NOT NULL DEFAULT true, + email_verified BOOLEAN NOT NULL DEFAULT false, + public_dashboard BOOLEAN NOT NULL DEFAULT false, + created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(), + updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(), + last_login_at TIMESTAMP WITH TIME ZONE +); + +-- Link API keys to users for audit trail +ALTER TABLE api_keys ADD COLUMN user_id UUID REFERENCES users(id) ON DELETE SET NULL; + +-- Starred jobs for personalized dashboard +CREATE TABLE starred_jobs ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, + project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE, + jobset_id UUID REFERENCES jobsets(id) ON DELETE CASCADE, + job_name VARCHAR(255) NOT NULL, + created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(), + UNIQUE(user_id, project_id, jobset_id, job_name) +); + +-- User sessions for persistent authentication across restarts +CREATE TABLE user_sessions ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, + session_token_hash VARCHAR(255) NOT NULL, -- Hashed session token + expires_at TIMESTAMP WITH TIME ZONE NOT NULL, + created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(), + last_used_at TIMESTAMP WITH TIME ZONE +); + +-- Project membership for per-project permissions +CREATE TABLE project_members ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + 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 'member', -- 'member', 'maintainer', 'admin' + created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(), + UNIQUE(project_id, user_id) +); + +-- Indexes for performance +CREATE INDEX idx_users_username ON users(username); +CREATE INDEX idx_users_email ON users(email); +CREATE INDEX idx_users_role ON users(role); +CREATE INDEX idx_users_enabled ON users(enabled); +CREATE INDEX idx_api_keys_user_id ON api_keys(user_id); +CREATE INDEX idx_starred_jobs_user_id ON starred_jobs(user_id); +CREATE INDEX idx_starred_jobs_project_id ON starred_jobs(project_id); +CREATE INDEX idx_user_sessions_token ON user_sessions(session_token_hash); +CREATE INDEX idx_user_sessions_user_id ON user_sessions(user_id); +CREATE INDEX idx_user_sessions_expires ON user_sessions(expires_at); +CREATE INDEX idx_project_members_project_id ON project_members(project_id); +CREATE INDEX idx_project_members_user_id ON project_members(user_id); + +-- Trigger for updated_at on users +CREATE TRIGGER update_users_updated_at + BEFORE UPDATE ON users + FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();