- 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
369 lines
8.9 KiB
Markdown
369 lines
8.9 KiB
Markdown
# 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
|
|
|
|
1. **Clone the repository**
|
|
```bash
|
|
git clone <repository-url>
|
|
cd ai-recruit-site-template
|
|
```
|
|
|
|
2. **Install dependencies**
|
|
```bash
|
|
npm install
|
|
```
|
|
|
|
3. **Set up environment**
|
|
```bash
|
|
cp .env.example .env
|
|
# Edit .env with your configuration
|
|
```
|
|
|
|
4. **Start PostgreSQL** (if not using Docker)
|
|
```bash
|
|
# Install PostgreSQL and create database 'recruitment'
|
|
psql -U postgres -c "CREATE DATABASE recruitment;"
|
|
```
|
|
|
|
5. **Run migrations**
|
|
```bash
|
|
psql -U postgres -d recruitment -f migrations/001_init_schema.sql
|
|
psql -U postgres -d recruitment -f migrations/002_seed_data.sql
|
|
```
|
|
|
|
6. **Start the application**
|
|
```bash
|
|
npm start
|
|
```
|
|
|
|
7. **Access the site**
|
|
- Public site: http://localhost:3000
|
|
- Admin panel: http://localhost:3000/admin/login
|
|
|
|
### Docker Development
|
|
|
|
1. **Start all services**
|
|
```bash
|
|
docker-compose up -d
|
|
```
|
|
|
|
2. **View logs**
|
|
```bash
|
|
docker-compose logs -f app
|
|
```
|
|
|
|
3. **Stop services**
|
|
```bash
|
|
docker-compose down
|
|
```
|
|
|
|
## Deployment to Coolify
|
|
|
|
### Prerequisites
|
|
|
|
- Coolify account and API token
|
|
- Gitea repository
|
|
- Cloudflare account (for DNS)
|
|
|
|
### Environment Variables
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
ssh-keygen -t ed25519 -f /tmp/recruitai_deploy_key -C "coolify-recruitai-deploy" -N ""
|
|
```
|
|
|
|
### Step 2: Create Coolify Project
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
curl -s -X GET "${COOLIFY_API}/deploy?uuid=YOUR_APP_UUID&force=true" \
|
|
-H "Authorization: Bearer ${COOLIFY_TOKEN}"
|
|
```
|
|
|
|
## First Time Setup
|
|
|
|
### Admin Account
|
|
|
|
1. Navigate to `/admin/login`
|
|
2. On first visit, you'll be prompted to create an admin account
|
|
3. Enter your email, password, and full name
|
|
4. Click "Create Admin Account"
|
|
5. You'll be logged in automatically
|
|
|
|
### Add Jobs
|
|
|
|
1. Go to Admin Dashboard → Jobs
|
|
2. Click "Create New Job"
|
|
3. Fill in job details
|
|
4. 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 jobs
|
|
- `GET /api/jobs/:id` - Get job details
|
|
- `POST /api/apply` - Submit application (multipart/form-data)
|
|
- `POST /api/contact` - Submit contact form
|
|
|
|
### Admin APIs (Authentication Required)
|
|
|
|
- `POST /api/admin/login` - Login / Create first admin
|
|
- `GET /api/admin/check` - Check auth status
|
|
- `POST /api/admin/logout` - Logout
|
|
- `GET /api/admin/stats` - Dashboard statistics
|
|
- `GET /api/admin/applications` - List applications
|
|
- `GET /api/admin/applications/:id` - Get application details
|
|
- `GET /api/admin/applications/:id/cv` - Download CV
|
|
- `PATCH /api/admin/applications/:id` - Update application
|
|
- `GET /api/admin/jobs` - List all jobs
|
|
- `POST /api/admin/jobs` - Create job
|
|
- `PATCH /api/admin/jobs/:id` - Update job
|
|
- `DELETE /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
|
|
|
|
```bash
|
|
# Check if PostgreSQL is running
|
|
docker-compose ps
|
|
|
|
# View PostgreSQL logs
|
|
docker-compose logs postgres
|
|
|
|
# Restart PostgreSQL
|
|
docker-compose restart postgres
|
|
```
|
|
|
|
### Migration Errors
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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
|