feat: add recommended courses and quiz multiple attempts
- Add is_recommended field to Course model - Add allow_multiple_attempts field to Quiz model - Create RecommendedCoursesController for admin management - List all approved courses - Get course by ID - Toggle recommendation status - Add is_recommended filter to CoursesService.ListCourses - Add allow_multiple_attempts to quiz update and response types - Update ChaptersLessonService.updateQuiz to support allow_multiple_attempts
This commit is contained in:
parent
623f797763
commit
f7330a7b27
17 changed files with 3963 additions and 5 deletions
403
.agent/workflows/deployment.md
Normal file
403
.agent/workflows/deployment.md
Normal file
|
|
@ -0,0 +1,403 @@
|
|||
---
|
||||
description: How to deploy the backend to production
|
||||
---
|
||||
|
||||
# Deployment Workflow
|
||||
|
||||
Follow these steps to deploy the E-Learning Platform backend to production.
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Production server with Node.js 18+
|
||||
- PostgreSQL database
|
||||
- MinIO/S3 storage
|
||||
- Domain name and SSL certificate
|
||||
|
||||
---
|
||||
|
||||
## Step 1: Prepare Production Server
|
||||
|
||||
```bash
|
||||
# Update system
|
||||
sudo apt update && sudo apt upgrade -y
|
||||
|
||||
# Install Node.js 18
|
||||
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
|
||||
sudo apt install -y nodejs
|
||||
|
||||
# Install PM2
|
||||
sudo npm install -g pm2
|
||||
|
||||
# Install nginx
|
||||
sudo apt install -y nginx
|
||||
|
||||
# Install certbot for SSL
|
||||
sudo apt install -y certbot python3-certbot-nginx
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 2: Clone Repository
|
||||
|
||||
```bash
|
||||
# Create app directory
|
||||
sudo mkdir -p /var/www/elearning-backend
|
||||
sudo chown $USER:$USER /var/www/elearning-backend
|
||||
|
||||
# Clone repository
|
||||
cd /var/www/elearning-backend
|
||||
git clone <repository-url> .
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 3: Install Dependencies
|
||||
|
||||
```bash
|
||||
npm ci --production
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 4: Setup Environment Variables
|
||||
|
||||
Create `.env` file:
|
||||
|
||||
```bash
|
||||
# Application
|
||||
NODE_ENV=production
|
||||
PORT=4000
|
||||
APP_URL=https://api.elearning.com
|
||||
|
||||
# Database
|
||||
DATABASE_URL=postgresql://user:password@db-host:5432/elearning_prod
|
||||
|
||||
# MinIO/S3
|
||||
S3_ENDPOINT=https://s3.elearning.com
|
||||
S3_ACCESS_KEY=<access-key>
|
||||
S3_SECRET_KEY=<secret-key>
|
||||
S3_BUCKET_COURSES=courses
|
||||
S3_BUCKET_VIDEOS=videos
|
||||
S3_BUCKET_DOCUMENTS=documents
|
||||
S3_BUCKET_IMAGES=images
|
||||
S3_BUCKET_ATTACHMENTS=attachments
|
||||
|
||||
# JWT
|
||||
JWT_SECRET=<strong-random-secret>
|
||||
JWT_EXPIRES_IN=24h
|
||||
|
||||
# Email
|
||||
SMTP_HOST=smtp.gmail.com
|
||||
SMTP_PORT=587
|
||||
SMTP_USER=<email>
|
||||
SMTP_PASSWORD=<password>
|
||||
SMTP_FROM=noreply@elearning.com
|
||||
|
||||
# CORS
|
||||
CORS_ORIGIN=https://elearning.com,https://admin.elearning.com
|
||||
|
||||
# Rate Limiting
|
||||
RATE_LIMIT_WINDOW_MS=900000
|
||||
RATE_LIMIT_MAX_REQUESTS=100
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 5: Run Database Migrations
|
||||
|
||||
```bash
|
||||
npx prisma migrate deploy
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 6: Setup PM2
|
||||
|
||||
Create `ecosystem.config.js`:
|
||||
|
||||
```javascript
|
||||
module.exports = {
|
||||
apps: [{
|
||||
name: 'elearning-backend',
|
||||
script: './src/server.js',
|
||||
instances: 'max',
|
||||
exec_mode: 'cluster',
|
||||
env: {
|
||||
NODE_ENV: 'production'
|
||||
},
|
||||
error_file: './logs/err.log',
|
||||
out_file: './logs/out.log',
|
||||
log_file: './logs/combined.log',
|
||||
time: true
|
||||
}]
|
||||
};
|
||||
```
|
||||
|
||||
Start application:
|
||||
|
||||
```bash
|
||||
pm2 start ecosystem.config.js
|
||||
pm2 save
|
||||
pm2 startup
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 7: Configure Nginx
|
||||
|
||||
Create `/etc/nginx/sites-available/elearning-backend`:
|
||||
|
||||
```nginx
|
||||
upstream backend {
|
||||
server localhost:4000;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name api.elearning.com;
|
||||
|
||||
# Redirect to HTTPS
|
||||
return 301 https://$server_name$request_uri;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
server_name api.elearning.com;
|
||||
|
||||
# SSL Configuration
|
||||
ssl_certificate /etc/letsencrypt/live/api.elearning.com/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/api.elearning.com/privkey.pem;
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers HIGH:!aNULL:!MD5;
|
||||
|
||||
# Security Headers
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||
|
||||
# Logging
|
||||
access_log /var/log/nginx/elearning-backend-access.log;
|
||||
error_log /var/log/nginx/elearning-backend-error.log;
|
||||
|
||||
# File Upload Size
|
||||
client_max_body_size 500M;
|
||||
|
||||
location / {
|
||||
proxy_pass http://backend;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
|
||||
# Timeouts
|
||||
proxy_connect_timeout 600s;
|
||||
proxy_send_timeout 600s;
|
||||
proxy_read_timeout 600s;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Enable site:
|
||||
|
||||
```bash
|
||||
sudo ln -s /etc/nginx/sites-available/elearning-backend /etc/nginx/sites-enabled/
|
||||
sudo nginx -t
|
||||
sudo systemctl restart nginx
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 8: Setup SSL Certificate
|
||||
|
||||
```bash
|
||||
sudo certbot --nginx -d api.elearning.com
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 9: Setup Monitoring
|
||||
|
||||
### PM2 Monitoring
|
||||
|
||||
```bash
|
||||
pm2 install pm2-logrotate
|
||||
pm2 set pm2-logrotate:max_size 10M
|
||||
pm2 set pm2-logrotate:retain 30
|
||||
```
|
||||
|
||||
### Health Check Endpoint
|
||||
|
||||
Add to your app:
|
||||
|
||||
```javascript
|
||||
app.get('/health', (req, res) => {
|
||||
res.status(200).json({
|
||||
status: 'ok',
|
||||
timestamp: new Date().toISOString(),
|
||||
uptime: process.uptime()
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 10: Setup Backup
|
||||
|
||||
Create backup script `/opt/scripts/backup-db.sh`:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
DATE=$(date +%Y%m%d_%H%M%S)
|
||||
BACKUP_DIR="/var/backups/elearning"
|
||||
DB_NAME="elearning_prod"
|
||||
|
||||
mkdir -p $BACKUP_DIR
|
||||
|
||||
# Backup database
|
||||
pg_dump $DB_NAME | gzip > $BACKUP_DIR/db_$DATE.sql.gz
|
||||
|
||||
# Keep only last 7 days
|
||||
find $BACKUP_DIR -name "db_*.sql.gz" -mtime +7 -delete
|
||||
|
||||
echo "Backup completed: db_$DATE.sql.gz"
|
||||
```
|
||||
|
||||
Add to crontab:
|
||||
|
||||
```bash
|
||||
# Daily backup at 2 AM
|
||||
0 2 * * * /opt/scripts/backup-db.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 11: Verify Deployment
|
||||
|
||||
```bash
|
||||
# Check PM2 status
|
||||
pm2 status
|
||||
|
||||
# Check logs
|
||||
pm2 logs elearning-backend --lines 50
|
||||
|
||||
# Test health endpoint
|
||||
curl https://api.elearning.com/health
|
||||
|
||||
# Test API
|
||||
curl https://api.elearning.com/api/courses
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Update Deployment
|
||||
|
||||
```bash
|
||||
# Pull latest code
|
||||
cd /var/www/elearning-backend
|
||||
git pull origin main
|
||||
|
||||
# Install dependencies
|
||||
npm ci --production
|
||||
|
||||
# Run migrations
|
||||
npx prisma migrate deploy
|
||||
|
||||
# Restart application
|
||||
pm2 restart elearning-backend
|
||||
|
||||
# Check status
|
||||
pm2 status
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Rollback
|
||||
|
||||
```bash
|
||||
# Revert to previous commit
|
||||
git reset --hard HEAD~1
|
||||
|
||||
# Reinstall dependencies
|
||||
npm ci --production
|
||||
|
||||
# Rollback migration (if needed)
|
||||
npx prisma migrate resolve --rolled-back <migration-name>
|
||||
|
||||
# Restart
|
||||
pm2 restart elearning-backend
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Checklist
|
||||
|
||||
- [ ] Production server setup
|
||||
- [ ] Repository cloned
|
||||
- [ ] Dependencies installed
|
||||
- [ ] Environment variables configured
|
||||
- [ ] Database migrated
|
||||
- [ ] PM2 configured and running
|
||||
- [ ] Nginx configured
|
||||
- [ ] SSL certificate installed
|
||||
- [ ] Monitoring setup
|
||||
- [ ] Backup script configured
|
||||
- [ ] Health check working
|
||||
- [ ] API endpoints tested
|
||||
|
||||
---
|
||||
|
||||
## Security Checklist
|
||||
|
||||
- [ ] Strong JWT secret
|
||||
- [ ] Database credentials secured
|
||||
- [ ] CORS configured correctly
|
||||
- [ ] Rate limiting enabled
|
||||
- [ ] SSL/TLS enabled
|
||||
- [ ] Security headers configured
|
||||
- [ ] File upload limits set
|
||||
- [ ] Environment variables not in git
|
||||
- [ ] Firewall configured
|
||||
- [ ] SSH key-based authentication
|
||||
|
||||
---
|
||||
|
||||
## Monitoring
|
||||
|
||||
### PM2 Commands
|
||||
|
||||
```bash
|
||||
# View logs
|
||||
pm2 logs
|
||||
|
||||
# Monitor resources
|
||||
pm2 monit
|
||||
|
||||
# Restart app
|
||||
pm2 restart elearning-backend
|
||||
|
||||
# Stop app
|
||||
pm2 stop elearning-backend
|
||||
|
||||
# Delete app
|
||||
pm2 delete elearning-backend
|
||||
```
|
||||
|
||||
### Check System Resources
|
||||
|
||||
```bash
|
||||
# CPU and Memory
|
||||
htop
|
||||
|
||||
# Disk usage
|
||||
df -h
|
||||
|
||||
# Network connections
|
||||
netstat -tulpn
|
||||
```
|
||||
Loading…
Add table
Add a link
Reference in a new issue