SmartfolioBackend / docs /schema-resume.sql
mahrooshishaq
new commit by Mahroosh
9a951d7
Raw History Blame Contribute Delete
8.65 kB
-- =============================================================
-- MODULE: Resume & AI Analysis
-- File: docs/schema-resume.sql
-- Managed by: TypeORM (synchronize: true in development)
-- =============================================================
-- -----------------------------------------------------------
-- ENUMS
-- -----------------------------------------------------------
CREATE TYPE lens_type_enum AS ENUM (
'targeted', -- Lens A: Job-specific analysis (requires job description)
'general' -- Lens B: General resume quality analysis
);
CREATE TYPE confidence_level_enum AS ENUM (
'High',
'Medium',
'Low'
);
-- -----------------------------------------------------------
-- TABLE: resumes
-- Entity: src/modules/resume/entities/resume.entity.ts
-- Description: Stores metadata for every uploaded resume file.
-- The actual file lives in uploads/ (not in DB).
-- Extracted text is cached here after Python service runs.
-- -----------------------------------------------------------
CREATE TABLE resumes (
-- Primary key
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
-- Ownership
user_id UUID NOT NULL
REFERENCES "user"(id) ON DELETE CASCADE,
-- File metadata
original_file_name VARCHAR(255) NOT NULL,
file_path VARCHAR(500) NOT NULL, -- Relative path: uploads/<uuid>-<filename>
file_size_bytes INTEGER NOT NULL,
-- Extracted content (populated by Python service POST /extract)
extracted_text TEXT, -- Full raw text from pdfplumber
extraction_metadata JSONB,
/*
* extraction_metadata structure:
* {
* "pageCount": 2,
* "hasTables": true,
* "hasImages": false,
* "confidence": 0.95
* }
*/
-- State flag
is_extracted BOOLEAN NOT NULL DEFAULT FALSE,
-- Timestamp
uploaded_at TIMESTAMP NOT NULL DEFAULT NOW()
);
-- Indexes
CREATE INDEX idx_resumes_user_id ON resumes (user_id);
CREATE INDEX idx_resumes_is_extracted ON resumes (user_id, is_extracted);
-- -----------------------------------------------------------
-- TABLE: resume_analyses
-- Entity: src/modules/resume/entities/resume-analysis.entity.ts
-- Description: AI-generated analysis result for one resume.
-- Each analysis is for a specific lens type.
-- A single resume can have multiple analyses over time.
-- -----------------------------------------------------------
CREATE TABLE resume_analyses (
-- Primary key
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
-- Foreign keys
resume_id UUID NOT NULL
REFERENCES resumes(id) ON DELETE CASCADE,
user_id UUID NOT NULL
REFERENCES "user"(id) ON DELETE CASCADE,
-- Analysis configuration
lens_type lens_type_enum NOT NULL,
-- Lens A (targeted) fields β€” NULL when lens_type = 'general'
job_description TEXT,
job_title VARCHAR(200),
company VARCHAR(200),
-- Scores (0-100, 2 decimal places)
overall_score NUMERIC(5, 2) NOT NULL,
ats_score NUMERIC(5, 2) NOT NULL, -- ATS keyword match
content_quality_score NUMERIC(5, 2) NOT NULL, -- Writing quality & clarity
experience_score NUMERIC(5, 2) NOT NULL, -- Impact of work history
skills_score NUMERIC(5, 2) NOT NULL, -- Skills section quality
achievement_score NUMERIC(5, 2) NOT NULL, -- Quantified achievements
formatting_score NUMERIC(5, 2) NOT NULL, -- Layout & structure
relevance_score NUMERIC(5, 2), -- Job-match relevance (Lens A only)
-- Qualitative outcome
interpretation_band VARCHAR(100) NOT NULL, -- e.g. "Strong Match", "Needs Work"
confidence_level confidence_level_enum NOT NULL DEFAULT 'High',
-- Detailed feedback (JSONB)
remarks JSONB NOT NULL,
/*
* remarks structure:
* {
* "strengths": ["Strong quantified achievements", "ATS-friendly keywords present"],
* "weaknesses": ["Missing skills section", "No measurable impact in role 2"],
* "actionable": ["Add 3 bullet points with metrics", "Include a skills section"]
* }
*/
-- Debug / audit
raw_llm_response TEXT, -- Full LLM JSON string before parsing
processing_time_ms INTEGER, -- End-to-end latency for this analysis
-- Timestamp
created_at TIMESTAMP NOT NULL DEFAULT NOW()
);
-- Indexes
CREATE INDEX idx_resume_analyses_resume_id ON resume_analyses (resume_id);
CREATE INDEX idx_resume_analyses_user_id ON resume_analyses (user_id);
CREATE INDEX idx_resume_analyses_lens ON resume_analyses (user_id, lens_type);
CREATE INDEX idx_resume_analyses_created ON resume_analyses (user_id, created_at DESC);
-- -----------------------------------------------------------
-- VARIABLE REFERENCE β€” RESUME & AI MODULE
-- -----------------------------------------------------------
--
-- resumes:
-- user_id β†’ Owner; used to scope all resume queries
-- original_file_name β†’ Displayed in UI; original filename from upload
-- file_path β†’ Server disk path; fed to Python extraction service
-- file_size_bytes β†’ Validated at upload (max 5 MB = 5,242,880 bytes)
-- extracted_text β†’ Full PDF text; injected into Groq LLM prompt
-- extraction_metadata β†’ JSONB: pageCount, hasTables, hasImages, confidence
-- is_extracted β†’ Guards analysis endpoint (400 if FALSE)
--
-- resume_analyses:
-- resume_id β†’ Which resume was analysed
-- user_id β†’ Redundant FK for fast per-user queries without JOIN
-- lens_type β†’ 'targeted' (Lens A) or 'general' (Lens B)
-- job_description β†’ Full JD text; used in targeted scoring prompt
-- job_title β†’ Job title for context; shown in results UI
-- company β†’ Company name for context; shown in results UI
-- overall_score β†’ Weighted average of all subscores (0-100)
-- ats_score β†’ Keyword/format ATS compatibility (0-100)
-- content_quality_score β†’ Writing clarity and resume content quality (0-100)
-- experience_score β†’ Depth and impact of work experience (0-100)
-- skills_score β†’ Skills section completeness and relevance (0-100)
-- achievement_score β†’ Quantified and measurable achievements (0-100)
-- formatting_score β†’ Layout, structure, visual readability (0-100)
-- relevance_score β†’ Job description match relevance β€” Lens A only (0-100)
-- interpretation_band β†’ Human-readable verdict: "Excellent" / "Good" / "Needs Work" / etc.
-- confidence_level β†’ LLM confidence: 'High' | 'Medium' | 'Low'
-- remarks β†’ JSONB: { strengths[], weaknesses[], actionable[] }
-- raw_llm_response β†’ Unprocessed Groq API response; kept for debugging
-- processing_time_ms β†’ Latency metric; useful for performance monitoring
--
-- -----------------------------------------------------------
-- AI MODULE VARIABLES (no database table β€” stateless service)
-- -----------------------------------------------------------
-- Defined in: src/modules/ai/groq.service.ts
--
-- GROQ_API_KEY β†’ .env β€” Groq API key (starts with gsk_...)
-- MODEL β†’ Hardcoded: 'llama-3.3-70b-versatile'
-- TEMPERATURE β†’ 0.1 (deterministic scoring output)
-- MAX_TOKENS β†’ 2048 (enough for full JSON analysis response)
-- System prompt β†’ Built by UserContextService.generateUserContext()
-- User prompt β†’ Built by ResumeAnalysisService with resume text + JD
--
-- ATS Checker (ats-checker.util.ts):
-- extractedText β†’ Resume plain text
-- jobDescription β†’ Job description (Lens A only)
-- Returns: { score, matchedKeywords[], missingKeywords[] }
--
-- Score Parser (score-parser.util.ts):
-- rawJson β†’ LLM JSON string
-- Returns typed AnalysisResult with all numeric scores parsed