docs: add detailed supabase and n8n setup guide
This commit is contained in:
parent
25fd894751
commit
30546bcb24
1 changed files with 188 additions and 0 deletions
188
docs/setup-guide.md
Normal file
188
docs/setup-guide.md
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
# Setup and Configuration Guide: AI Recruitment Platform
|
||||
|
||||
This guide covers the complete step-by-step setup process for the database (Supabase), the automation engine (n8n), the AI models, and the Next.js application.
|
||||
|
||||
---
|
||||
|
||||
## 1. Supabase (Database Setup)
|
||||
|
||||
Supabase provides the relational database, vector store, and API services.
|
||||
|
||||
### A. Extensions Needed
|
||||
The semantic similarity matching uses vector calculations. You must enable the `vector` extension.
|
||||
* Go to **Database** -> **Extensions** -> Search for `vector` -> Click **Enable**.
|
||||
|
||||
### B. Table Schemas
|
||||
You need to create the following five tables. Run these SQL commands in the Supabase **SQL Editor**:
|
||||
|
||||
```sql
|
||||
-- 1. Jobs Table
|
||||
CREATE TABLE jobs (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
title TEXT NOT NULL,
|
||||
requirements JSONB NOT NULL DEFAULT '{}'::jsonb, -- Store raw text + lowercase buzzwords list
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT timezone('utc'::text, now()) NOT NULL
|
||||
);
|
||||
|
||||
-- 2. Candidates Table
|
||||
CREATE TABLE candidates (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
name TEXT NOT NULL,
|
||||
email TEXT UNIQUE NOT NULL,
|
||||
phone TEXT,
|
||||
embedding VECTOR(1536), -- 1536 dimensions matching gemini-embedding-001
|
||||
contact_info JSONB DEFAULT '{}'::jsonb, -- Store A-Z summary, skills list, phone, etc.
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT timezone('utc'::text, now()) NOT NULL
|
||||
);
|
||||
|
||||
-- 3. Scores Table (Decoupled Evaluations)
|
||||
CREATE TABLE 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,
|
||||
ai_score INTEGER NOT NULL CHECK (ai_score >= 0 AND ai_score <= 100),
|
||||
risk_level TEXT NOT NULL, -- 'Low', 'Medium', 'High'
|
||||
evaluation JSONB NOT NULL DEFAULT '{}'::jsonb, -- Store { summary, classification, suggestions }
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT timezone('utc'::text, now()) NOT NULL
|
||||
);
|
||||
|
||||
-- 4. Interviews Table
|
||||
CREATE TABLE 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,
|
||||
interview_date TIMESTAMP WITH TIME ZONE NOT NULL,
|
||||
stage TEXT DEFAULT 'Screening'::text NOT NULL, -- 'Screening', 'Technical', 'Cultural', 'Offer', 'Hired', 'Rejected'
|
||||
feedback TEXT, -- Stores JSON string comments timeline array [{ id, text, timestamp, author, stage, isAi }]
|
||||
pinned BOOLEAN DEFAULT false NOT NULL,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT timezone('utc'::text, now()) NOT NULL,
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT timezone('utc'::text, now()) NOT NULL
|
||||
);
|
||||
```
|
||||
|
||||
### C. pgvector Similarity Match Function
|
||||
Next, create the PostgreSQL RPC function to rank candidates against job requirements using cosine distance. Run this in the SQL Editor:
|
||||
|
||||
```sql
|
||||
CREATE OR REPLACE FUNCTION match_candidates (
|
||||
query_embedding VECTOR(1536),
|
||||
match_threshold DOUBLE PRECISION,
|
||||
match_count INT
|
||||
)
|
||||
RETURNS TABLE (
|
||||
id UUID,
|
||||
name TEXT,
|
||||
email TEXT,
|
||||
phone TEXT,
|
||||
contact_info JSONB,
|
||||
similarity DOUBLE PRECISION
|
||||
)
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
BEGIN
|
||||
RETURN QUERY
|
||||
SELECT
|
||||
candidates.id,
|
||||
candidates.name,
|
||||
candidates.email,
|
||||
candidates.phone,
|
||||
candidates.contact_info,
|
||||
1 - (candidates.embedding <=> query_embedding) AS similarity
|
||||
FROM candidates
|
||||
WHERE 1 - (candidates.embedding <=> query_embedding) > match_threshold
|
||||
ORDER BY candidates.embedding <=> query_embedding
|
||||
LIMIT match_count;
|
||||
END;
|
||||
$$;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. n8n (Automation Engine Setup)
|
||||
|
||||
n8n acts as the central automation orchestrator, receiving hooks from Next.js, calling LLM chains, and saving responses.
|
||||
|
||||
### A. Minimum Requirements
|
||||
* **n8n instance**: Self-hosted (Docker / npm package) or n8n Cloud.
|
||||
* **Version**: n8n v1.0.0 or later (v1.30+ recommended for advanced LangChain integration features).
|
||||
* **Network Access**: The n8n instance must be publicly reachable (using domain/tunnel like ngrok/Cloudflare) so Vercel can post webhook payloads.
|
||||
|
||||
### B. Supported LLM Models & Providers
|
||||
The n8n Kickstarter script (`deploy-n8n-v2.ts`) supports credentials setup and deployment for:
|
||||
|
||||
| Provider | Choice ID | Default Model | Node Type | API Key Env Var |
|
||||
| :--- | :--- | :--- | :--- | :--- |
|
||||
| **Deepseek** | `1` | `deepseek-chat` | `@n8n/n8n-nodes-langchain.lmChatDeepSeek` | `DEEPSEEK_API_KEY` |
|
||||
| **OpenAI** | `2` | `gpt-4o-mini` | `@n8n/n8n-nodes-langchain.lmChatOpenAi` | `OPENAI_API_KEY` |
|
||||
| **Google Gemini** | `3` | `gemini-1.5-flash` | `@n8n/n8n-nodes-langchain.lmChatGoogleGemini` | `GEMINI_API_KEY` |
|
||||
| **Anthropic** | `4` | `claude-3-5-sonnet-latest` | `@n8n/n8n-nodes-langchain.lmChatAnthropic` | `ANTHROPIC_API_KEY` |
|
||||
|
||||
### C. Deploying via Script
|
||||
1. Configure the `.env` variables (`N8N_HOST`, `N8N_API_KEY`).
|
||||
2. Run the deployment script:
|
||||
```bash
|
||||
npx ts-node -O '{"module": "commonjs"}' scripts/deploy-n8n-v2.ts \
|
||||
--primary-provider=deepseek \
|
||||
--fallback \
|
||||
--fallback-provider=gemini
|
||||
```
|
||||
*Note: The script dynamically detects if a credential exists in n8n. If found, it safely reuses the credential to avoid entering keys repeatedly.*
|
||||
|
||||
---
|
||||
|
||||
## 3. Supported Webhooks / API Endpoints
|
||||
|
||||
The n8n workflow exposes the following endpoints (automatically registered upon deployment):
|
||||
|
||||
### 1. `POST /webhook/evaluate-candidate`
|
||||
Triggered by Next.js when parsing CVs or running AI evaluations.
|
||||
* **Payload**:
|
||||
```json
|
||||
{
|
||||
"candidateId": "uuid-here",
|
||||
"jobId": "uuid-here",
|
||||
"candidateName": "John Doe",
|
||||
"jobTitle": "React Developer",
|
||||
"jobRequirements": "Stack: React, TypeScript, Tailwind...",
|
||||
"text": "Extracted text contents of candidate resume..."
|
||||
}
|
||||
```
|
||||
* **Workflow Operations**:
|
||||
* Extracts resume data (Structured Output Parser).
|
||||
* Inserts parsed details (skills list, summary) into `candidates` table.
|
||||
* Runs the primary evaluation chain (Deepseek) with a fallback to Google Gemini.
|
||||
* Calculates calibrated scores (0-100), risk classifications (`Qualified`, `Unqualified`, `Review`), and appends next-step suggestions.
|
||||
* Stores result in `scores` table.
|
||||
|
||||
### 2. `POST /webhook/suggest-next-steps`
|
||||
Triggered by Next.js when clicking "Get AI Suggestion" inside Interviews.
|
||||
* **Payload**:
|
||||
```json
|
||||
{
|
||||
"candidateName": "John Doe",
|
||||
"jobTitle": "React Developer",
|
||||
"currentStage": "Technical",
|
||||
"candidateSummary": "Extracted summary...",
|
||||
"candidateSkills": ["react", "typescript"],
|
||||
"jobRequirements": "Stack: React...",
|
||||
"commentHistory": [ ... ],
|
||||
"lang": "en" | "es"
|
||||
}
|
||||
```
|
||||
* **Workflow Operations**:
|
||||
* Assembles context of the candidate, job description, and interview timeline.
|
||||
* Queries LLM to output a brief, actionable list of next steps.
|
||||
* Instructs LLM to write in Spanish if `lang` is `"es"`, otherwise English.
|
||||
|
||||
---
|
||||
|
||||
## 4. Next.js (Application Setup)
|
||||
|
||||
### A. Environment variables
|
||||
Make sure all items in `.env` are configured:
|
||||
* `APP_PASSWORD`: Protects the lock screen. Default fallback is `Semillero2026!`.
|
||||
* `GEMINI_API_KEY`: Mandatory for client-side embedding generation (`models/gemini-embedding-001`) and candidate comparisons.
|
||||
* `NEXT_PUBLIC_SUPABASE_URL` & `SUPABASE_SECRET_KEY`: Service role keys to read/write without RLS checks.
|
||||
|
||||
### B. Deployment
|
||||
Deploy to Vercel with all environment variables matching your local setup. Ensure the API routes can freely reach the database and the n8n webhooks.
|
||||
Loading…
Reference in a new issue