Initial commit
This commit is contained in:
		
							
								
								
									
										141
									
								
								backend/src/database/schema.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								backend/src/database/schema.sql
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,141 @@ | ||||
| -- MysteryApp-Cursor Database Schema | ||||
|  | ||||
| -- Users table (for authentication and user management) | ||||
| CREATE TABLE IF NOT EXISTS users ( | ||||
|     id UUID PRIMARY KEY DEFAULT gen_random_uuid(), | ||||
|     email VARCHAR(255) UNIQUE NOT NULL, | ||||
|     password_hash VARCHAR(255) NOT NULL, | ||||
|     first_name VARCHAR(100) NOT NULL, | ||||
|     last_name VARCHAR(100) NOT NULL, | ||||
|     role VARCHAR(50) NOT NULL CHECK (role IN ('admin', 'recruiter', 'employer', 'candidate')), | ||||
|     is_active BOOLEAN DEFAULT true, | ||||
|     created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, | ||||
|     updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP | ||||
| ); | ||||
|  | ||||
| -- Employers table | ||||
| CREATE TABLE IF NOT EXISTS employers ( | ||||
|     id UUID PRIMARY KEY DEFAULT gen_random_uuid(), | ||||
|     user_id UUID REFERENCES users(id) ON DELETE CASCADE, | ||||
|     company_name VARCHAR(255) NOT NULL, | ||||
|     industry VARCHAR(100), | ||||
|     company_size VARCHAR(50), | ||||
|     website VARCHAR(255), | ||||
|     description TEXT, | ||||
|     address TEXT, | ||||
|     phone VARCHAR(20), | ||||
|     created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, | ||||
|     updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP | ||||
| ); | ||||
|  | ||||
| -- Candidates table | ||||
| CREATE TABLE IF NOT EXISTS candidates ( | ||||
|     id UUID PRIMARY KEY DEFAULT gen_random_uuid(), | ||||
|     user_id UUID REFERENCES users(id) ON DELETE CASCADE, | ||||
|     phone VARCHAR(20), | ||||
|     location VARCHAR(255), | ||||
|     linkedin_url VARCHAR(255), | ||||
|     github_url VARCHAR(255), | ||||
|     portfolio_url VARCHAR(255), | ||||
|     bio TEXT, | ||||
|     skills TEXT[], | ||||
|     experience_level VARCHAR(50), | ||||
|     availability VARCHAR(50), | ||||
|     salary_expectation INTEGER, | ||||
|     created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, | ||||
|     updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP | ||||
| ); | ||||
|  | ||||
| -- Job postings table | ||||
| CREATE TABLE IF NOT EXISTS jobs ( | ||||
|     id UUID PRIMARY KEY DEFAULT gen_random_uuid(), | ||||
|     employer_id UUID REFERENCES employers(id) ON DELETE CASCADE, | ||||
|     title VARCHAR(255) NOT NULL, | ||||
|     description TEXT NOT NULL, | ||||
|     requirements TEXT[], | ||||
|     responsibilities TEXT[], | ||||
|     location VARCHAR(255), | ||||
|     employment_type VARCHAR(50) CHECK (employment_type IN ('full-time', 'part-time', 'contract', 'internship')), | ||||
|     salary_min INTEGER, | ||||
|     salary_max INTEGER, | ||||
|     currency VARCHAR(3) DEFAULT 'USD', | ||||
|     status VARCHAR(50) DEFAULT 'active' CHECK (status IN ('active', 'paused', 'closed', 'draft')), | ||||
|     remote_allowed BOOLEAN DEFAULT false, | ||||
|     experience_level VARCHAR(50), | ||||
|     skills_required TEXT[], | ||||
|     benefits TEXT[], | ||||
|     application_deadline DATE, | ||||
|     created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, | ||||
|     updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP | ||||
| ); | ||||
|  | ||||
| -- Applications table | ||||
| CREATE TABLE IF NOT EXISTS applications ( | ||||
|     id UUID PRIMARY KEY DEFAULT gen_random_uuid(), | ||||
|     job_id UUID REFERENCES jobs(id) ON DELETE CASCADE, | ||||
|     candidate_id UUID REFERENCES candidates(id) ON DELETE CASCADE, | ||||
|     status VARCHAR(50) DEFAULT 'applied' CHECK (status IN ('applied', 'reviewed', 'shortlisted', 'interviewed', 'offered', 'rejected', 'withdrawn')), | ||||
|     cover_letter TEXT, | ||||
|     notes TEXT, | ||||
|     applied_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, | ||||
|     updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, | ||||
|     UNIQUE(job_id, candidate_id) | ||||
| ); | ||||
|  | ||||
| -- Resumes table | ||||
| CREATE TABLE IF NOT EXISTS resumes ( | ||||
|     id UUID PRIMARY KEY DEFAULT gen_random_uuid(), | ||||
|     candidate_id UUID REFERENCES candidates(id) ON DELETE CASCADE, | ||||
|     filename VARCHAR(255) NOT NULL, | ||||
|     original_name VARCHAR(255) NOT NULL, | ||||
|     file_path VARCHAR(500) NOT NULL, | ||||
|     file_size INTEGER NOT NULL, | ||||
|     mime_type VARCHAR(100) NOT NULL, | ||||
|     is_primary BOOLEAN DEFAULT false, | ||||
|     uploaded_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP | ||||
| ); | ||||
|  | ||||
| -- Interviews table | ||||
| CREATE TABLE IF NOT EXISTS interviews ( | ||||
|     id UUID PRIMARY KEY DEFAULT gen_random_uuid(), | ||||
|     application_id UUID REFERENCES applications(id) ON DELETE CASCADE, | ||||
|     scheduled_at TIMESTAMP NOT NULL, | ||||
|     duration_minutes INTEGER DEFAULT 60, | ||||
|     interview_type VARCHAR(50) CHECK (interview_type IN ('phone', 'video', 'in-person', 'technical')), | ||||
|     location VARCHAR(255), | ||||
|     meeting_link VARCHAR(500), | ||||
|     notes TEXT, | ||||
|     status VARCHAR(50) DEFAULT 'scheduled' CHECK (status IN ('scheduled', 'completed', 'cancelled', 'rescheduled')), | ||||
|     created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, | ||||
|     updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP | ||||
| ); | ||||
|  | ||||
| -- Create indexes for better performance | ||||
| CREATE INDEX IF NOT EXISTS idx_users_email ON users(email); | ||||
| CREATE INDEX IF NOT EXISTS idx_users_role ON users(role); | ||||
| CREATE INDEX IF NOT EXISTS idx_employers_user_id ON employers(user_id); | ||||
| CREATE INDEX IF NOT EXISTS idx_candidates_user_id ON candidates(user_id); | ||||
| CREATE INDEX IF NOT EXISTS idx_jobs_employer_id ON jobs(employer_id); | ||||
| CREATE INDEX IF NOT EXISTS idx_jobs_status ON jobs(status); | ||||
| CREATE INDEX IF NOT EXISTS idx_applications_job_id ON applications(job_id); | ||||
| CREATE INDEX IF NOT EXISTS idx_applications_candidate_id ON applications(candidate_id); | ||||
| CREATE INDEX IF NOT EXISTS idx_applications_status ON applications(status); | ||||
| CREATE INDEX IF NOT EXISTS idx_resumes_candidate_id ON resumes(candidate_id); | ||||
| CREATE INDEX IF NOT EXISTS idx_interviews_application_id ON interviews(application_id); | ||||
|  | ||||
| -- Create updated_at trigger function | ||||
| CREATE OR REPLACE FUNCTION update_updated_at_column() | ||||
| RETURNS TRIGGER AS $$ | ||||
| BEGIN | ||||
|     NEW.updated_at = CURRENT_TIMESTAMP; | ||||
|     RETURN NEW; | ||||
| END; | ||||
| $$ language 'plpgsql'; | ||||
|  | ||||
| -- Apply updated_at triggers | ||||
| CREATE TRIGGER update_users_updated_at BEFORE UPDATE ON users FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); | ||||
| CREATE TRIGGER update_employers_updated_at BEFORE UPDATE ON employers FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); | ||||
| CREATE TRIGGER update_candidates_updated_at BEFORE UPDATE ON candidates FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); | ||||
| CREATE TRIGGER update_jobs_updated_at BEFORE UPDATE ON jobs FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); | ||||
| CREATE TRIGGER update_applications_updated_at BEFORE UPDATE ON applications FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); | ||||
| CREATE TRIGGER update_interviews_updated_at BEFORE UPDATE ON interviews FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); | ||||
		Reference in New Issue
	
	Block a user