Coolify uses docker-compose.yml directly, so the .coolify.yml variant is redundant and causes confusion. Only docker-compose.yml is needed.
Ryans Recruit Firm - AI Recruitment Site
A professional recruitment website built with Node.js, Express, and PostgreSQL. Features include job listings, application management, CV storage, and admin dashboard.
Features
Public Features
- Job Listings - Browse open positions with detailed information
- Online Applications - Submit applications with CV upload
- Contact Form - Get in touch with the recruitment team
- Responsive Design - Works on desktop, tablet, and mobile
Admin Features
- Dashboard - Overview statistics and quick access
- Application Management - View, filter, and manage applicants
- CV Downloads - Download applicant CVs directly
- Job Management - Create, edit, and manage job postings
- First-time Setup - Automatic admin account creation on first login
Technology Stack
- Backend: Node.js + Express
- Database: PostgreSQL with BYTEA for CV storage
- Authentication: Session-based with bcrypt
- File Upload: Multer (PDF, DOC, DOCX support)
- Deployment: Docker + Docker Compose + Coolify
Quick Start
Local Development
-
Clone the repository
git clone <repository-url> cd ai-recruit-site-template -
Install dependencies
npm install -
Set up environment
cp .env.example .env # Edit .env with your configuration -
Start PostgreSQL (if not using Docker)
# Install PostgreSQL and create database 'recruitment' psql -U postgres -c "CREATE DATABASE recruitment;" -
Run migrations
psql -U postgres -d recruitment -f migrations/001_init_schema.sql psql -U postgres -d recruitment -f migrations/002_seed_data.sql -
Start the application
npm start -
Access the site
- Public site: http://localhost:3000
- Admin panel: http://localhost:3000/admin/login
Docker Development
-
Start all services
docker-compose up -d -
View logs
docker-compose logs -f app -
Stop services
docker-compose down
Deployment to Coolify
Prerequisites
- Coolify account and API token
- Gitea repository
- Cloudflare account (for DNS)
Environment Variables
export COOLIFY_TOKEN="your-coolify-api-token"
export GITEA_TOKEN="your-gitea-access-token"
export CLOUDFLARE_TOKEN="your-cloudflare-api-token"
export COOLIFY_API="https://app.coolify.io/api/v1"
export GITEA_API="https://git.startanaicompany.com/api/v1"
export CLOUDFLARE_API="https://api.cloudflare.com/client/v4"
Step 1: Generate SSH Deploy Keys
ssh-keygen -t ed25519 -f /tmp/recruitai_deploy_key -C "coolify-recruitai-deploy" -N ""
Step 2: Create Coolify Project
curl -s -X POST "${COOLIFY_API}/projects" \
-H "Authorization: Bearer ${COOLIFY_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"name": "RecruitAI",
"description": "AI Recruitment Site"
}'
Step 3: Add Deploy Key to Coolify
PRIVATE_KEY=$(cat /tmp/recruitai_deploy_key | jq -R -s .)
curl -s -X POST "${COOLIFY_API}/private-keys" \
-H "Authorization: Bearer ${COOLIFY_TOKEN}" \
-H "Content-Type: application/json" \
-d "{
\"name\": \"recruitai-deploy-key\",
\"description\": \"Deploy key for recruitai repository\",
\"private_key\": ${PRIVATE_KEY}
}"
Step 4: Push to Gitea
git remote add origin git@git.startanaicompany.com:username/ai-recruit-site-template.git
git add .
git commit -m "Initial commit: AI Recruitment Site"
git push -u origin main
Step 5: Add Deploy Key to Gitea
cat > /tmp/gitea_deploy_key.json << EOF
{
"title": "Coolify Deploy Key",
"key": "$(cat /tmp/recruitai_deploy_key.pub)",
"read_only": true
}
EOF
curl -s -X POST "${GITEA_API}/repos/username/ai-recruit-site-template/keys" \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
-d @/tmp/gitea_deploy_key.json
Step 6: Create Coolify Application
curl -s -X POST "${COOLIFY_API}/applications/public" \
-H "Authorization: Bearer ${COOLIFY_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"project_uuid": "YOUR_PROJECT_UUID",
"environment_name": "production",
"server_uuid": 0,
"type": "public",
"source": {
"type": "git",
"url": "git@git.startanaicompany.com:username/ai-recruit-site-template",
"branch": "main",
"private_key_uuid": "YOUR_PRIVATE_KEY_UUID"
},
"build_pack": "dockerfile",
"ports_exposes": "3000",
"name": "recruitai"
}'
Step 7: Add Webhook to Gitea
curl -s -X POST "${GITEA_API}/repos/username/ai-recruit-site-template/hooks" \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"type": "gitea",
"config": {
"url": "https://app.coolify.io/api/v1/deploy?uuid=YOUR_APP_UUID",
"content_type": "json",
"http_method": "GET"
},
"events": ["push"],
"active": true
}'
Step 8: Configure Cloudflare DNS
curl -s -X POST "${CLOUDFLARE_API}/zones/YOUR_ZONE_ID/dns_records" \
-H "Authorization: Bearer ${CLOUDFLARE_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"type": "CNAME",
"name": "recruitai",
"content": "YOUR_COOLIFY_FQDN",
"ttl": 1,
"proxied": false
}'
Step 9: Update Application Domain
curl -s -X PATCH "${COOLIFY_API}/applications/YOUR_APP_UUID" \
-H "Authorization: Bearer ${COOLIFY_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"domains": "http://recruitai.startanaicompany.com"
}'
Step 10: Deploy
curl -s -X GET "${COOLIFY_API}/deploy?uuid=YOUR_APP_UUID&force=true" \
-H "Authorization: Bearer ${COOLIFY_TOKEN}"
First Time Setup
Admin Account
- Navigate to
/admin/login - On first visit, you'll be prompted to create an admin account
- Enter your email, password, and full name
- Click "Create Admin Account"
- You'll be logged in automatically
Add Jobs
- Go to Admin Dashboard → Jobs
- Click "Create New Job"
- Fill in job details
- Click "Save"
Database Schema
Tables
- admins - Admin user accounts
- job_postings - Job listings
- applicants - Applicant information
- applications - Application submissions with CV storage (BYTEA)
- contact_submissions - Contact form messages
Migrations
Migrations are located in /migrations/ and run automatically on first Docker startup.
API Endpoints
Public APIs
GET /api/jobs- List all active jobsGET /api/jobs/:id- Get job detailsPOST /api/apply- Submit application (multipart/form-data)POST /api/contact- Submit contact form
Admin APIs (Authentication Required)
POST /api/admin/login- Login / Create first adminGET /api/admin/check- Check auth statusPOST /api/admin/logout- LogoutGET /api/admin/stats- Dashboard statisticsGET /api/admin/applications- List applicationsGET /api/admin/applications/:id- Get application detailsGET /api/admin/applications/:id/cv- Download CVPATCH /api/admin/applications/:id- Update applicationGET /api/admin/jobs- List all jobsPOST /api/admin/jobs- Create jobPATCH /api/admin/jobs/:id- Update jobDELETE /api/admin/jobs/:id- Delete job
Security Features
- Password Hashing - bcrypt with 10 rounds
- Session Management - Secure HTTP-only cookies
- SQL Injection Protection - Parameterized queries
- File Upload Validation - Type and size checks
- CSRF Protection - Session-based authentication
- Rate Limiting - (Recommended to add in production)
Environment Variables
| Variable | Description | Default |
|---|---|---|
DB_HOST |
PostgreSQL host | postgres |
DB_PORT |
PostgreSQL port | 5432 |
DB_NAME |
Database name | recruitment |
DB_USER |
Database user | postgres |
DB_PASSWORD |
Database password | changeme123 |
PORT |
Application port | 3000 |
NODE_ENV |
Environment | production |
SESSION_SECRET |
Session encryption key | (required) |
File Upload Limits
- Max CV Size: 5MB
- Allowed Types: PDF, DOC, DOCX
- Storage: PostgreSQL BYTEA column
Troubleshooting
Database Connection Issues
# Check if PostgreSQL is running
docker-compose ps
# View PostgreSQL logs
docker-compose logs postgres
# Restart PostgreSQL
docker-compose restart postgres
Migration Errors
# Connect to database
docker-compose exec postgres psql -U postgres -d recruitment
# Check tables
\dt
# Re-run migrations manually
docker-compose exec postgres psql -U postgres -d recruitment -f /docker-entrypoint-initdb.d/001_init_schema.sql
Application Won't Start
# Check application logs
docker-compose logs app
# Rebuild and restart
docker-compose down
docker-compose build --no-cache
docker-compose up -d
License
MIT
Support
For issues or questions, contact: info@ryansrecruit.com Webhook configured successfully!
Repository moved to organization
Description
Languages
HTML
55.2%
JavaScript
31.8%
CSS
8.5%
PLpgSQL
4.1%
Dockerfile
0.4%