Initial commit: AI Recruitment Site for Ryans Recruit Firm

- Complete PostgreSQL schema with migrations
- Node.js/Express backend with authentication
- Public website (home, about, services, jobs, apply, contact)
- Admin dashboard with applicant and job management
- CV upload and storage in PostgreSQL BYTEA
- Docker Compose setup for deployment
- Session-based authentication
- Responsive design with Ryan brand colors
This commit is contained in:
Mikael Westöö
2026-01-23 21:17:24 +01:00
commit 406d278a39
23 changed files with 3842 additions and 0 deletions

View File

@@ -0,0 +1,150 @@
-- AI Recruitment Site Database Schema
-- Using PostgreSQL with proper indexing and constraints
-- Admins table
CREATE TABLE IF NOT EXISTS admins (
id SERIAL PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
password_hash TEXT NOT NULL,
full_name VARCHAR(255) NOT NULL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
last_login TIMESTAMP WITH TIME ZONE
);
-- Create index for faster email lookups
CREATE INDEX IF NOT EXISTS idx_admins_email ON admins(email);
-- Job postings table
CREATE TABLE IF NOT EXISTS job_postings (
id SERIAL PRIMARY KEY,
title VARCHAR(255) NOT NULL,
department VARCHAR(100),
location VARCHAR(255),
employment_type VARCHAR(50), -- Full-time, Part-time, Contract
salary_range VARCHAR(100),
description TEXT NOT NULL,
requirements TEXT,
benefits TEXT,
is_active BOOLEAN DEFAULT true,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
created_by INTEGER REFERENCES admins(id)
);
-- Create index for active jobs
CREATE INDEX IF NOT EXISTS idx_job_postings_active ON job_postings(is_active, created_at DESC);
-- Applicants table
CREATE TABLE IF NOT EXISTS applicants (
id SERIAL PRIMARY KEY,
full_name VARCHAR(255) NOT NULL,
email VARCHAR(255) NOT NULL,
phone VARCHAR(50),
linkedin_url VARCHAR(500),
portfolio_url VARCHAR(500),
years_of_experience INTEGER,
current_position VARCHAR(255),
current_company VARCHAR(255),
preferred_location VARCHAR(255),
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
-- Create index for applicant searches
CREATE INDEX IF NOT EXISTS idx_applicants_email ON applicants(email);
CREATE INDEX IF NOT EXISTS idx_applicants_name ON applicants(full_name);
CREATE INDEX IF NOT EXISTS idx_applicants_created_at ON applicants(created_at DESC);
-- Applications table (links applicants to jobs with CV)
CREATE TABLE IF NOT EXISTS applications (
id SERIAL PRIMARY KEY,
applicant_id INTEGER NOT NULL REFERENCES applicants(id) ON DELETE CASCADE,
job_id INTEGER REFERENCES job_postings(id) ON DELETE SET NULL,
cover_letter TEXT,
cv_filename VARCHAR(500),
cv_content_type VARCHAR(100),
cv_file BYTEA, -- Store CV as binary data
status VARCHAR(50) DEFAULT 'new', -- new, reviewing, interview, rejected, hired
notes TEXT,
applied_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
-- Create indexes for application queries
CREATE INDEX IF NOT EXISTS idx_applications_applicant ON applications(applicant_id);
CREATE INDEX IF NOT EXISTS idx_applications_job ON applications(job_id);
CREATE INDEX IF NOT EXISTS idx_applications_status ON applications(status);
CREATE INDEX IF NOT EXISTS idx_applications_date ON applications(applied_at DESC);
-- Add check constraint for application status
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM pg_constraint
WHERE conname = 'applications_status_check'
) THEN
ALTER TABLE applications ADD CONSTRAINT applications_status_check
CHECK (status IN ('new', 'reviewing', 'interview', 'rejected', 'hired'));
END IF;
END $$;
-- Add check constraint for employment type
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM pg_constraint
WHERE conname = 'job_postings_employment_type_check'
) THEN
ALTER TABLE job_postings ADD CONSTRAINT job_postings_employment_type_check
CHECK (employment_type IN ('Full-time', 'Part-time', 'Contract', 'Internship', 'Freelance'));
END IF;
END $$;
-- Contact submissions table
CREATE TABLE IF NOT EXISTS contact_submissions (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
email VARCHAR(255) NOT NULL,
subject VARCHAR(500),
message TEXT NOT NULL,
is_read BOOLEAN DEFAULT false,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
-- Create index for contact submissions
CREATE INDEX IF NOT EXISTS idx_contact_submissions_date ON contact_submissions(created_at DESC);
CREATE INDEX IF NOT EXISTS idx_contact_submissions_unread ON contact_submissions(is_read, created_at DESC);
-- Function to update the updated_at timestamp
CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = CURRENT_TIMESTAMP;
RETURN NEW;
END;
$$ language 'plpgsql';
-- Trigger for job_postings
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM pg_trigger WHERE tgname = 'update_job_postings_updated_at'
) THEN
CREATE TRIGGER update_job_postings_updated_at
BEFORE UPDATE ON job_postings
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();
END IF;
END $$;
-- Trigger for applications
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM pg_trigger WHERE tgname = 'update_applications_updated_at'
) THEN
CREATE TRIGGER update_applications_updated_at
BEFORE UPDATE ON applications
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();
END IF;
END $$;

View File

@@ -0,0 +1,113 @@
-- Seed data for AI Recruitment Site
-- Insert sample job postings
INSERT INTO job_postings (title, department, location, employment_type, salary_range, description, requirements, benefits, is_active)
VALUES
(
'Senior Full-Stack Developer',
'Engineering',
'Remote / San Francisco, CA',
'Full-time',
'$120,000 - $180,000',
'We are seeking an experienced Full-Stack Developer to join our dynamic team. You will be responsible for designing, developing, and maintaining web applications that serve thousands of users daily. This role offers an opportunity to work with cutting-edge technologies and contribute to meaningful projects.',
'• 5+ years of experience in full-stack development
• Proficiency in JavaScript/TypeScript, React, Node.js
• Experience with PostgreSQL or similar relational databases
• Strong understanding of RESTful APIs and microservices
• Experience with Docker and cloud platforms (AWS/GCP/Azure)
• Excellent problem-solving and communication skills',
'• Competitive salary and equity package
• Health, dental, and vision insurance
• 401(k) matching
• Flexible work arrangements
• Professional development budget
• Unlimited PTO',
true
),
(
'DevOps Engineer',
'Engineering',
'New York, NY',
'Full-time',
'$100,000 - $150,000',
'Join our infrastructure team to build and maintain scalable, reliable systems. You will work on automation, monitoring, and deployment pipelines that power our applications.',
'• 3+ years of DevOps or Site Reliability Engineering experience
• Strong knowledge of Kubernetes, Docker, and container orchestration
• Experience with CI/CD tools (Jenkins, GitLab CI, GitHub Actions)
• Proficiency in scripting languages (Python, Bash)
• Experience with infrastructure as code (Terraform, Ansible)
• Understanding of cloud platforms and networking',
'• Competitive compensation
• Stock options
• Remote work flexibility
• Learning and development opportunities
• Team events and offsites
• Modern tech stack',
true
),
(
'UI/UX Designer',
'Design',
'Los Angeles, CA',
'Full-time',
'$90,000 - $130,000',
'We are looking for a creative UI/UX Designer to craft beautiful and intuitive user experiences. You will work closely with product managers and engineers to bring ideas to life.',
'• 3+ years of UI/UX design experience
• Strong portfolio demonstrating web and mobile design
• Proficiency in Figma, Sketch, or Adobe XD
• Understanding of user-centered design principles
• Experience conducting user research and usability testing
• Knowledge of HTML/CSS is a plus',
'• Creative and collaborative work environment
• Health and wellness benefits
• Flexible schedule
• Latest design tools and equipment
• Conference and workshop budget
• Generous vacation policy',
true
),
(
'Data Scientist',
'Data & Analytics',
'Remote',
'Full-time',
'$110,000 - $160,000',
'Help us unlock insights from data. As a Data Scientist, you will develop machine learning models, analyze complex datasets, and contribute to data-driven decision making.',
'• Master''s or PhD in Computer Science, Statistics, or related field
• 2+ years of experience in data science or machine learning
• Strong programming skills in Python (pandas, scikit-learn, TensorFlow)
• Experience with SQL and data warehousing
• Knowledge of statistical modeling and A/B testing
• Excellent communication skills to explain technical concepts',
'• Competitive salary
• Work with cutting-edge ML technologies
• Conference attendance opportunities
• Remote-first culture
• Comprehensive health benefits
• Equity compensation',
true
),
(
'Marketing Manager',
'Marketing',
'Chicago, IL',
'Full-time',
'$80,000 - $120,000',
'Lead our marketing initiatives and help grow our brand. You will develop and execute marketing strategies, manage campaigns, and analyze performance metrics.',
'• 5+ years of marketing experience
• Proven track record in B2B or B2C marketing
• Experience with digital marketing channels (SEO, SEM, social media)
• Strong analytical skills and data-driven mindset
• Excellent written and verbal communication
• Experience with marketing automation tools',
'• Competitive salary and bonuses
• Health insurance
• Professional development
• Collaborative team environment
• Flexible work options
• Career growth opportunities',
true
);
-- Note: Admin users are created on first login, no seed data needed
-- Note: Applicants and applications will be created through the application form