85 lines
2.7 KiB
PL/PgSQL
85 lines
2.7 KiB
PL/PgSQL
-- 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;
|
|
$$;
|