Repository navigation
Expand file tree
/
Copy pathdatabase_schema.sql
More file actions
164 lines (137 loc) · 6.21 KB
/
Copy pathdatabase_schema.sql
File metadata and controls
164 lines (137 loc) · 6.21 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
-- ============================================================
-- Developer Intelligence Platform — PostgreSQL Schema (Supabase)
-- Run this in: Supabase Dashboard → SQL Editor → New Query
-- ============================================================
-- ============================================================
-- PROFILES
-- ============================================================
CREATE TABLE IF NOT EXISTS profiles (
id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
username VARCHAR(255) UNIQUE NOT NULL,
name VARCHAR(255),
bio TEXT,
location VARCHAR(255),
email VARCHAR(255),
blog VARCHAR(500),
company VARCHAR(255),
public_repos INT DEFAULT 0,
followers INT DEFAULT 0,
following INT DEFAULT 0,
account_age_days INT DEFAULT 0,
profile_url VARCHAR(500),
avatar_url VARCHAR(500),
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_profiles_username ON profiles (username);
CREATE INDEX IF NOT EXISTS idx_profiles_updated_at ON profiles (updated_at);
-- Trigger function: sets NEW.updated_at — used by the profiles trigger
CREATE OR REPLACE FUNCTION set_updated_at()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
DROP TRIGGER IF EXISTS trg_profiles_updated_at ON profiles;
CREATE TRIGGER trg_profiles_updated_at
BEFORE UPDATE ON profiles
FOR EACH ROW EXECUTE FUNCTION set_updated_at();
-- ============================================================
-- REPOSITORIES
-- UNIQUE(profile_id, repo_name) enables INSERT ... ON CONFLICT upsert
-- ============================================================
CREATE TABLE IF NOT EXISTS repositories (
id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
profile_id INT NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
repo_name VARCHAR(255) NOT NULL,
description TEXT,
language VARCHAR(100),
stars INT DEFAULT 0,
forks INT DEFAULT 0,
watchers INT DEFAULT 0,
size_kb INT DEFAULT 0,
has_readme BOOLEAN DEFAULT FALSE,
topics JSONB DEFAULT '[]'::jsonb,
repo_url VARCHAR(500),
homepage VARCHAR(500),
is_fork BOOLEAN DEFAULT FALSE,
pushed_at TIMESTAMPTZ,
created_at TIMESTAMPTZ DEFAULT NOW(),
CONSTRAINT unique_profile_repo UNIQUE (profile_id, repo_name)
);
CREATE INDEX IF NOT EXISTS idx_repos_profile_id ON repositories (profile_id);
CREATE INDEX IF NOT EXISTS idx_repos_language ON repositories (language);
CREATE INDEX IF NOT EXISTS idx_repos_stars ON repositories (stars);
-- ============================================================
-- SKILLS
-- ============================================================
CREATE TABLE IF NOT EXISTS skills (
id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
profile_id INT NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
skill VARCHAR(100) NOT NULL,
confidence NUMERIC(4,2) NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW(),
CONSTRAINT unique_profile_skill UNIQUE (profile_id, skill)
);
CREATE INDEX IF NOT EXISTS idx_skills_profile_id ON skills (profile_id);
CREATE INDEX IF NOT EXISTS idx_skills_skill ON skills (skill);
-- ============================================================
-- ANALYSIS RESULTS (latest snapshot per profile)
-- ============================================================
CREATE TABLE IF NOT EXISTS analysis_results (
id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
profile_id INT UNIQUE NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
-- Career Score
career_score INT DEFAULT 0,
score_documentation INT DEFAULT 0,
score_diversity INT DEFAULT 0,
score_deployment INT DEFAULT 0,
score_tech_breadth INT DEFAULT 0,
score_activity INT DEFAULT 0,
score_open_source INT DEFAULT 0,
-- Summary stats
total_stars INT DEFAULT 0,
total_forks INT DEFAULT 0,
most_used_language VARCHAR(100),
top_projects JSONB DEFAULT '[]'::jsonb,
-- Sprint 3: Developer Type
developer_type VARCHAR(100),
developer_confidence NUMERIC(4,2),
developer_reasons JSONB DEFAULT '[]'::jsonb,
-- Sprint 3: Recruiter Layer
strengths JSONB DEFAULT '[]'::jsonb,
concerns JSONB DEFAULT '[]'::jsonb,
gaps JSONB DEFAULT '[]'::jsonb,
recommendations JSONB DEFAULT '[]'::jsonb,
-- AI Native Hiring Intelligence
analysis_json JSONB DEFAULT '{}'::jsonb,
analyzed_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_analysis_profile_id ON analysis_results (profile_id);
CREATE INDEX IF NOT EXISTS idx_analysis_career_score ON analysis_results (career_score);
-- Fix: separate trigger function that updates analyzed_at (not updated_at)
-- analysis_results has no updated_at column — using set_updated_at() here
-- would throw: ERROR: record "new" has no field "updated_at"
CREATE OR REPLACE FUNCTION set_analyzed_at()
RETURNS TRIGGER AS $$
BEGIN
NEW.analyzed_at = NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
DROP TRIGGER IF EXISTS trg_analysis_updated_at ON analysis_results;
CREATE TRIGGER trg_analysis_updated_at
BEFORE UPDATE ON analysis_results
FOR EACH ROW EXECUTE FUNCTION set_analyzed_at();
-- ============================================================
-- ANALYSIS HISTORY (append-only — score evolution over time)
-- ============================================================
CREATE TABLE IF NOT EXISTS analysis_history (
id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
profile_id INT NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
career_score INT NOT NULL,
analyzed_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_history_profile_id ON analysis_history (profile_id);
CREATE INDEX IF NOT EXISTS idx_history_analyzed_at ON analysis_history (analyzed_at);