db: create initial schema migration with pgvector

This commit is contained in:
Gabriel Ramos 2026-06-08 11:27:02 -04:00
parent 608bf086ec
commit 18734726cb

View file

@ -0,0 +1,85 @@
-- Enable the pgvector extension to work with embeddings
CREATE EXTENSION IF NOT EXISTS vector;
-- Users Table (Recruiters / Managers)
CREATE TABLE IF NOT EXISTS users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email TEXT UNIQUE NOT NULL,
role TEXT NOT NULL CHECK (role IN ('recruiter', 'manager')),
created_at TIMESTAMP WITH TIME ZONE DEFAULT timezone('utc'::text, now()) NOT NULL
);
-- Jobs Table
CREATE TABLE IF NOT EXISTS jobs (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
title TEXT NOT NULL,
description TEXT NOT NULL,
requirements TEXT,
embedding vector(1536),
created_at TIMESTAMP WITH TIME ZONE DEFAULT timezone('utc'::text, now()) NOT NULL
);
-- Candidates Table
CREATE TABLE IF NOT EXISTS candidates (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name TEXT NOT NULL,
email TEXT UNIQUE NOT NULL,
phone TEXT,
resume_url TEXT,
summary TEXT,
seniority TEXT,
embedding vector(1536),
created_at TIMESTAMP WITH TIME ZONE DEFAULT timezone('utc'::text, now()) NOT NULL
);
-- Interviews Table
CREATE TABLE IF NOT EXISTS interviews (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
candidate_id UUID REFERENCES candidates(id) ON DELETE CASCADE NOT NULL,
job_id UUID REFERENCES jobs(id) ON DELETE CASCADE NOT NULL,
scheduled_at TIMESTAMP WITH TIME ZONE NOT NULL,
status TEXT NOT NULL CHECK (status IN ('scheduled', 'completed', 'cancelled')) DEFAULT 'scheduled',
notes TEXT,
created_at TIMESTAMP WITH TIME ZONE DEFAULT timezone('utc'::text, now()) NOT NULL
);
-- Scores Table
CREATE TABLE IF NOT EXISTS scores (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
candidate_id UUID REFERENCES candidates(id) ON DELETE CASCADE NOT NULL,
job_id UUID REFERENCES jobs(id) ON DELETE CASCADE NOT NULL,
interviewer_id UUID REFERENCES users(id) ON DELETE CASCADE,
score NUMERIC NOT NULL CHECK (score >= 0 AND score <= 100),
evaluation JSONB, -- MUST contain exactly: summary, classification, suggestions, riskLevel
created_at TIMESTAMP WITH TIME ZONE DEFAULT timezone('utc'::text, now()) NOT NULL
);
-- RPC Function to Match Candidates using Cosine Distance
CREATE OR REPLACE FUNCTION match_candidates (
query_embedding vector(1536),
match_threshold FLOAT,
match_count INT
)
RETURNS TABLE (
id UUID,
name TEXT,
email TEXT,
seniority TEXT,
similarity FLOAT
)
LANGUAGE plpgsql
AS $$
BEGIN
RETURN QUERY
SELECT
candidates.id,
candidates.name,
candidates.email,
candidates.seniority,
(1 - (candidates.embedding <=> query_embedding))::FLOAT AS similarity
FROM candidates
WHERE (1 - (candidates.embedding <=> query_embedding)) > match_threshold
ORDER BY candidates.embedding <=> query_embedding ASC
LIMIT match_count;
END;
$$;