feat(db): resolve migration conflict and setup supabase client
This commit is contained in:
parent
9d32f1d605
commit
f663d04e10
4 changed files with 119 additions and 85 deletions
24
lib/supabase.ts
Normal file
24
lib/supabase.ts
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
import { createClient } from "@supabase/supabase-js";
|
||||
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL;
|
||||
const supabasePublishableKey = process.env.SUPABASE_PUBLISHABLE_KEY;
|
||||
|
||||
if (!supabaseUrl) {
|
||||
throw new Error("Missing env.NEXT_PUBLIC_SUPABASE_URL");
|
||||
}
|
||||
|
||||
if (!supabasePublishableKey) {
|
||||
throw new Error("Missing env.SUPABASE_PUBLISHABLE_KEY");
|
||||
}
|
||||
|
||||
// Client-side/public Supabase client
|
||||
export const supabase = createClient(supabaseUrl, supabasePublishableKey);
|
||||
|
||||
// Server-side admin/secret Supabase client
|
||||
export const createServerSupabaseClient = () => {
|
||||
const secretKey = process.env.SUPABASE_SECRET_KEY;
|
||||
if (!secretKey) {
|
||||
throw new Error("Missing env.SUPABASE_SECRET_KEY");
|
||||
}
|
||||
return createClient(supabaseUrl, secretKey);
|
||||
};
|
||||
94
package-lock.json
generated
94
package-lock.json
generated
|
|
@ -8,6 +8,7 @@
|
|||
"name": "temp-next-app",
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"@supabase/supabase-js": "^2.108.0",
|
||||
"next": "16.2.7",
|
||||
"pdf-parse": "^2.4.5",
|
||||
"react": "19.2.4",
|
||||
|
|
@ -1439,6 +1440,90 @@
|
|||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@supabase/auth-js": {
|
||||
"version": "2.108.0",
|
||||
"resolved": "https://registry.npmjs.org/@supabase/auth-js/-/auth-js-2.108.0.tgz",
|
||||
"integrity": "sha512-0CzVGVqHfNOhRQVEcAmu58Mex2Ce0zL3aGfyV+iFQjTK6OntLK/hLCLr/VDRX0E8/2CdsiY99L7fZ/8ys/op4w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tslib": "2.8.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@supabase/functions-js": {
|
||||
"version": "2.108.0",
|
||||
"resolved": "https://registry.npmjs.org/@supabase/functions-js/-/functions-js-2.108.0.tgz",
|
||||
"integrity": "sha512-lqEGDzT7QBUuKYzi5lHpV/XecXT9wikzcbXMbFo6krNpSDynD1sHM8wcsfB/BAqa4NkFuy3vF4JCV8MeakV8IQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tslib": "2.8.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@supabase/phoenix": {
|
||||
"version": "0.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@supabase/phoenix/-/phoenix-0.4.2.tgz",
|
||||
"integrity": "sha512-YSAGnmDAfuleFCVt3CeurQZAhxRfXWeZIIkwp7NhYzQ1UwW6ePSnzsFAiUm/mbCkfoCf70QQHKW/K6RKh52a4A==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@supabase/postgrest-js": {
|
||||
"version": "2.108.0",
|
||||
"resolved": "https://registry.npmjs.org/@supabase/postgrest-js/-/postgrest-js-2.108.0.tgz",
|
||||
"integrity": "sha512-8AwTkPqowDYv/qh016CyXeZ3Ukpw6NHyfqc7DWV4afLR2hAiapf3zRKV2ZLG+//T1LK84HrR6X8VBwfgHWmNyw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tslib": "2.8.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@supabase/realtime-js": {
|
||||
"version": "2.108.0",
|
||||
"resolved": "https://registry.npmjs.org/@supabase/realtime-js/-/realtime-js-2.108.0.tgz",
|
||||
"integrity": "sha512-N3xR0u7TNr+c5wuLSU60rcfu/H/8N0WBs7iHWwjI/NxKwY3XWSyLUbpbpU8bzmL0dA/Gk9Mupri8mxKUXBW+iw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@supabase/phoenix": "^0.4.2",
|
||||
"tslib": "2.8.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@supabase/storage-js": {
|
||||
"version": "2.108.0",
|
||||
"resolved": "https://registry.npmjs.org/@supabase/storage-js/-/storage-js-2.108.0.tgz",
|
||||
"integrity": "sha512-zMYQmh87CId7d8i/1FIfv4fMDcXPutmIJSpoY58GLXi7M266MNzxWGNabDk4i555Oj1Nqtsu2i3Qo3rpWUXO6A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"iceberg-js": "^0.8.1",
|
||||
"tslib": "2.8.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@supabase/supabase-js": {
|
||||
"version": "2.108.0",
|
||||
"resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.108.0.tgz",
|
||||
"integrity": "sha512-AjPoimM9MZLZbddnlDBGmpZ/Tas1dNcJvuZy/VD1AfmrjBC8J2RSw6UOqR4ISLLlEioOLca/5t1crFnAxa0wRQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@supabase/auth-js": "2.108.0",
|
||||
"@supabase/functions-js": "2.108.0",
|
||||
"@supabase/postgrest-js": "2.108.0",
|
||||
"@supabase/realtime-js": "2.108.0",
|
||||
"@supabase/storage-js": "2.108.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/helpers": {
|
||||
"version": "0.5.15",
|
||||
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz",
|
||||
|
|
@ -4172,6 +4257,15 @@
|
|||
"hermes-estree": "0.25.1"
|
||||
}
|
||||
},
|
||||
"node_modules/iceberg-js": {
|
||||
"version": "0.8.1",
|
||||
"resolved": "https://registry.npmjs.org/iceberg-js/-/iceberg-js-0.8.1.tgz",
|
||||
"integrity": "sha512-1dhVQZXhcHje7798IVM+xoo/1ZdVfzOMIc8/rgVSijRK38EDqOJoGula9N/8ZI5RD8QTxNQtK/Gozpr+qUqRRA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ignore": {
|
||||
"version": "5.3.2",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
"lint": "eslint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@supabase/supabase-js": "^2.108.0",
|
||||
"next": "16.2.7",
|
||||
"pdf-parse": "^2.4.5",
|
||||
"react": "19.2.4",
|
||||
|
|
|
|||
|
|
@ -1,85 +0,0 @@
|
|||
-- 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;
|
||||
$$;
|
||||
Loading…
Reference in a new issue