feat: Create PM2 + Docker production deployment system
Some checks failed
ParentFlow CI/CD Pipeline / Backend Tests (push) Has been cancelled
ParentFlow CI/CD Pipeline / Frontend Tests (push) Has been cancelled
ParentFlow CI/CD Pipeline / Security Scanning (push) Has been cancelled
ParentFlow CI/CD Pipeline / Build Docker Images (map[context:maternal-app/maternal-app-backend dockerfile:Dockerfile.production name:backend]) (push) Has been cancelled
ParentFlow CI/CD Pipeline / Build Docker Images (map[context:maternal-web dockerfile:Dockerfile.production name:frontend]) (push) Has been cancelled
ParentFlow CI/CD Pipeline / Deploy to Development (push) Has been cancelled
ParentFlow CI/CD Pipeline / Deploy to Production (push) Has been cancelled
CI/CD Pipeline / Lint and Test (push) Has been cancelled
CI/CD Pipeline / E2E Tests (push) Has been cancelled
CI/CD Pipeline / Build Application (push) Has been cancelled

- Replaced old production script with PM2-based deployment
- Created start-production.sh: automated startup script
  - Starts Docker containers for databases
  - Waits for database health checks
  - Runs migrations automatically
  - Builds backend/frontend if needed
  - Starts PM2 processes with ecosystem.config.js
  - Verifies all services are running

- Created stop-production.sh: graceful shutdown script
  - Stops PM2 processes
  - Stops Docker containers
  - Verifies shutdown

- Created PRODUCTION_DEPLOYMENT.md: comprehensive deployment guide
  - Prerequisites and installation steps
  - Configuration instructions
  - Nginx reverse proxy setup
  - SSL certificate setup with Certbot
  - Management commands for PM2 and Docker
  - Backup strategy
  - Troubleshooting guide
  - Security checklist

Production setup:
- Backend:  Port 3020 → api.parentflowapp.com
- Frontend: Port 3030 → web.parentflowapp.com
- Docker:   PostgreSQL, Redis, MongoDB, MinIO
- PM2:      Backend and Frontend applications
- Target:   Server 10.0.0.240

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-10-06 21:20:26 +00:00
parent ebf92aff14
commit 2622512ae2
3 changed files with 731 additions and 30 deletions

453
PRODUCTION_DEPLOYMENT.md Normal file
View File

@@ -0,0 +1,453 @@
# ParentFlow Production Deployment Guide
**Target Server**: 10.0.0.240
**Deployment Method**: PM2 + Docker
**Last Updated**: October 6, 2025
## Overview
Production deployment uses a hybrid approach:
- **Docker Compose**: For databases (PostgreSQL, Redis, MongoDB, MinIO)
- **PM2**: For application services (Backend, Frontend)
## Architecture
```
┌─────────────────────────────────────────────┐
│ Server: 10.0.0.240 │
├─────────────────────────────────────────────┤
│ PM2 Processes: │
│ - Backend: Port 3020 (Node.js/NestJS) │
│ - Frontend: Port 3030 (Next.js) │
├─────────────────────────────────────────────┤
│ Docker Containers: │
│ - PostgreSQL: Port 5432 │
│ - Redis: Port 6379 │
│ - MongoDB: Port 27017 │
│ - MinIO: Port 9000 (API) │
│ Port 9001 (Console) │
└─────────────────────────────────────────────┘
↓ ↓
api.parentflowapp.com web.parentflowapp.com
```
## Prerequisites
### 1. Install Required Software
```bash
# Install Node.js 18+ and npm
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt-get install -y nodejs
# Install PM2 globally
sudo npm install -g pm2
# Install Docker
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER
# Install Docker Compose
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
```
### 2. Clone Repository
```bash
cd /root
git clone https://git.noru1.ro/andrei/maternal-app.git
cd maternal-app
```
### 3. Install Dependencies
```bash
# Backend dependencies
cd maternal-app/maternal-app-backend
npm install
# Frontend dependencies
cd ../../maternal-web
npm install
cd ../..
```
## Configuration
### 1. Environment Variables
Copy the example environment file and update with production values:
```bash
cp .env.production.example .env.production
nano .env.production
```
**Critical variables to update:**
- `POSTGRES_PASSWORD`: Strong password for PostgreSQL
- `REDIS_PASSWORD`: Strong password for Redis
- `MONGO_PASSWORD`: Strong password for MongoDB
- `JWT_SECRET`: 64-character random string
- `JWT_REFRESH_SECRET`: Different 64-character random string
- `OPENAI_API_KEY`: Your OpenAI API key (for AI features)
Generate secure secrets:
```bash
# Generate JWT secrets
openssl rand -base64 64
openssl rand -base64 64
```
### 2. Update ecosystem.config.js
Ensure the production environment variables in `ecosystem.config.js` match your `.env.production` file.
### 3. Configure Nginx (Reverse Proxy)
Create Nginx configuration for domain routing:
```nginx
# /etc/nginx/sites-available/parentflow
# Backend API
server {
listen 80;
server_name api.parentflowapp.com;
location / {
proxy_pass http://localhost:3020;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
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;
}
}
# Frontend
server {
listen 80;
server_name web.parentflowapp.com;
location / {
proxy_pass http://localhost:3030;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
```
Enable the site:
```bash
sudo ln -s /etc/nginx/sites-available/parentflow /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
```
### 4. SSL Certificates (Optional but Recommended)
```bash
# Install Certbot
sudo apt-get install certbot python3-certbot-nginx
# Obtain certificates
sudo certbot --nginx -d api.parentflowapp.com -d web.parentflowapp.com
```
## Deployment
### First-Time Deployment
```bash
cd /root/maternal-app
# Start production environment
./start-production.sh
```
The script will:
1. ✅ Start Docker containers (databases)
2. ✅ Wait for databases to be healthy
3. ✅ Run database migrations
4. ✅ Build backend (if needed)
5. ✅ Build frontend (if needed)
6. ✅ Start PM2 processes
7. ✅ Verify all services
### Subsequent Deployments
```bash
cd /root/maternal-app
# Pull latest changes
git pull origin main
# Rebuild applications
cd maternal-app/maternal-app-backend
npm install
npm run build
cd ../../maternal-web
npm install
npm run build
cd ../..
# Restart PM2 processes
pm2 restart all
# Or use the full restart script
./stop-production.sh
./start-production.sh
```
## Management Commands
### PM2 Commands
```bash
# View process status
pm2 status
# View logs
pm2 logs
# View specific service logs
pm2 logs parentflow-backend
pm2 logs parentflow-frontend
# Restart services
pm2 restart all
pm2 restart parentflow-backend
pm2 restart parentflow-frontend
# Stop services
pm2 stop all
# Delete processes
pm2 delete all
# Save PM2 process list
pm2 save
# Setup PM2 to start on system boot
pm2 startup
pm2 save
```
### Docker Commands
```bash
# View running containers
docker ps
# View logs
docker logs parentflow-postgres-prod
docker logs parentflow-redis-prod
docker logs parentflow-mongodb-prod
docker logs parentflow-minio-prod
# Follow logs in real-time
docker logs -f parentflow-postgres-prod
# Access database shell
docker exec -it parentflow-postgres-prod psql -U parentflow_user -d parentflow_production
# Access Redis CLI
docker exec -it parentflow-redis-prod redis-cli -a parentflow_redis_password_2024
# Access MongoDB shell
docker exec -it parentflow-mongodb-prod mongo -u parentflow_admin -p parentflow_mongo_password_2024
# Stop all containers
docker-compose -f docker-compose.production.yml down
# Stop and remove volumes (WARNING: deletes data)
docker-compose -f docker-compose.production.yml down -v
```
### Application Management
```bash
# Start production
./start-production.sh
# Stop production
./stop-production.sh
# Check migration status
cd maternal-app/maternal-app-backend
./scripts/check-migrations.sh
# Run migrations manually
./scripts/master-migration.sh
```
## Monitoring
### Health Checks
- **Backend**: http://localhost:3020/api/health
- **Frontend**: http://localhost:3030
- **MinIO Console**: http://localhost:9001
### Log Files
PM2 logs are stored in:
- `~/.pm2/logs/parentflow-backend-out.log`
- `~/.pm2/logs/parentflow-backend-error.log`
- `~/.pm2/logs/parentflow-frontend-out.log`
- `~/.pm2/logs/parentflow-frontend-error.log`
Docker logs via:
```bash
docker logs <container-name>
```
### System Resources
```bash
# Monitor PM2 processes
pm2 monit
# Monitor Docker containers
docker stats
# System resources
htop
```
## Backup Strategy
### Database Backups
```bash
# PostgreSQL backup
docker exec parentflow-postgres-prod pg_dump -U parentflow_user parentflow_production > backup-$(date +%Y%m%d).sql
# Restore PostgreSQL
cat backup-20251006.sql | docker exec -i parentflow-postgres-prod psql -U parentflow_user -d parentflow_production
# MongoDB backup
docker exec parentflow-mongodb-prod mongodump --username parentflow_admin --password parentflow_mongo_password_2024 --out /data/backup
# Redis backup (automatic with AOF persistence)
docker exec parentflow-redis-prod redis-cli -a parentflow_redis_password_2024 BGSAVE
```
### Automated Backups
Add to crontab:
```bash
# Daily database backup at 2 AM
0 2 * * * /root/maternal-app/scripts/backup-database.sh
```
## Troubleshooting
### Backend Won't Start
```bash
# Check logs
pm2 logs parentflow-backend --err
# Check if port is already in use
lsof -i:3020
# Verify database connection
docker exec -it parentflow-postgres-prod psql -U parentflow_user -d parentflow_production -c "SELECT version();"
```
### Frontend Won't Start
```bash
# Check logs
pm2 logs parentflow-frontend --err
# Rebuild frontend
cd maternal-web
rm -rf .next
npm run build
```
### Database Connection Issues
```bash
# Check if containers are running
docker ps
# Check container health
docker inspect parentflow-postgres-prod --format='{{.State.Health.Status}}'
# View container logs
docker logs parentflow-postgres-prod
```
### Migrations Failed
```bash
# Check migration status
cd maternal-app/maternal-app-backend
./scripts/check-migrations.sh
# Manually run specific migration
PGPASSWORD=parentflow_secure_password_2024 psql -h localhost -p 5432 -U parentflow_user -d parentflow_production -f src/database/migrations/V001_create_core_auth.sql
```
## Security Checklist
- [ ] Updated all default passwords in `.env.production`
- [ ] Generated secure JWT secrets
- [ ] Configured firewall (ufw/iptables) to restrict database ports
- [ ] Enabled SSL certificates with Certbot
- [ ] Configured Nginx rate limiting
- [ ] Set up PM2 with non-root user (recommended)
- [ ] Enabled Docker container resource limits
- [ ] Configured backup strategy
- [ ] Set up monitoring/alerting
## Performance Optimization
### PM2 Cluster Mode
For better performance, run backend in cluster mode:
```javascript
// ecosystem.config.js
{
name: 'parentflow-backend',
instances: 'max', // Use all CPU cores
exec_mode: 'cluster',
// ... other settings
}
```
### Database Optimization
- Enable PostgreSQL connection pooling (already configured)
- Monitor slow queries
- Add indexes for frequently queried fields
- Configure Redis maxmemory policy
## CI/CD Integration
See `docs/REMAINING_FEATURES.md` for Gitea Actions workflow setup for automated deployments to 10.0.0.240.
## Support
For issues or questions:
- Check logs: `pm2 logs` and `docker logs`
- Review documentation: `/root/maternal-app/docs/`
- Check migration status: `./scripts/check-migrations.sh`
---
**Last Updated**: October 6, 2025
**Deployment Version**: 1.0.0

View File

@@ -1,53 +1,224 @@
#!/bin/bash
# Start Production Servers Script
# ParentFlow Production Startup Script
# Uses PM2 for frontend/backend, Docker for databases
# Ports: Backend 3020, Frontend 3030
# Server: 10.0.0.240 (or localhost for local production testing)
echo "Starting ParentFlow Production Servers..."
set -e # Exit on any error
# Kill any existing processes on the ports
echo "Cleaning up existing processes..."
lsof -ti:3020 | xargs kill -9 2>/dev/null
lsof -ti:3030 | xargs kill -9 2>/dev/null
# Color codes
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
echo "=========================================="
echo "ParentFlow Production Startup"
echo "=========================================="
echo ""
# Check if PM2 is installed
if ! command -v pm2 &> /dev/null; then
echo -e "${RED}ERROR: PM2 is not installed!${NC}"
echo "Install PM2 globally with: npm install -g pm2"
exit 1
fi
# Check if Docker is installed
if ! command -v docker &> /dev/null; then
echo -e "${RED}ERROR: Docker is not installed!${NC}"
exit 1
fi
# Check if docker-compose is installed
if ! command -v docker-compose &> /dev/null && ! docker compose version &> /dev/null; then
echo -e "${RED}ERROR: Docker Compose is not installed!${NC}"
exit 1
fi
# Step 1: Start Docker services (databases)
echo -e "${BLUE}Step 1: Starting Docker services (databases)...${NC}"
if docker compose version &> /dev/null; then
docker compose -f docker-compose.production.yml up -d
else
docker-compose -f docker-compose.production.yml up -d
fi
if [ $? -eq 0 ]; then
echo -e "${GREEN}✓ Docker services started${NC}"
else
echo -e "${RED}✗ Failed to start Docker services${NC}"
exit 1
fi
# Wait for databases to be ready
echo -e "${YELLOW}Waiting for databases to be healthy...${NC}"
sleep 10
# Check database health
echo -e "${BLUE}Checking database health...${NC}"
MAX_RETRIES=30
RETRY_COUNT=0
while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do
POSTGRES_HEALTHY=$(docker inspect parentflow-postgres-prod --format='{{.State.Health.Status}}' 2>/dev/null || echo "starting")
REDIS_HEALTHY=$(docker inspect parentflow-redis-prod --format='{{.State.Health.Status}}' 2>/dev/null || echo "starting")
MONGO_HEALTHY=$(docker inspect parentflow-mongodb-prod --format='{{.State.Health.Status}}' 2>/dev/null || echo "starting")
if [ "$POSTGRES_HEALTHY" = "healthy" ] && [ "$REDIS_HEALTHY" = "healthy" ] && [ "$MONGO_HEALTHY" = "healthy" ]; then
echo -e "${GREEN}✓ All databases are healthy${NC}"
break
fi
echo -e "${YELLOW}Waiting for databases... ($RETRY_COUNT/$MAX_RETRIES)${NC}"
sleep 2
((RETRY_COUNT++))
done
# Start Backend on port 3020
echo "Starting backend on port 3020..."
if [ $RETRY_COUNT -eq $MAX_RETRIES ]; then
echo -e "${RED}✗ Databases failed to become healthy${NC}"
echo "Check Docker logs with: docker logs parentflow-postgres-prod"
exit 1
fi
# Step 2: Run database migrations
echo ""
echo -e "${BLUE}Step 2: Running database migrations...${NC}"
cd /root/maternal-app/maternal-app/maternal-app-backend
PORT=3020 API_PORT=3020 NODE_ENV=production nohup node dist/main.js > /root/maternal-app/logs/backend-prod.log 2>&1 &
BACKEND_PID=$!
echo "Backend started with PID: $BACKEND_PID"
# Start Frontend on port 3030
echo "Starting frontend on port 3030..."
# Check if migration script exists
if [ -f "./scripts/master-migration.sh" ]; then
echo -e "${YELLOW}Running master migration script...${NC}"
DATABASE_HOST=localhost \
DATABASE_PORT=5432 \
DATABASE_NAME=parentflow_production \
DATABASE_USER=parentflow_user \
DATABASE_PASSWORD=parentflow_secure_password_2024 \
./scripts/master-migration.sh || {
echo -e "${YELLOW}Warning: Migrations may have partially failed. Continuing...${NC}"
}
else
echo -e "${YELLOW}Warning: Migration script not found. Skipping migrations.${NC}"
fi
# Step 3: Build backend (if needed)
echo ""
echo -e "${BLUE}Step 3: Building backend...${NC}"
cd /root/maternal-app/maternal-app/maternal-app-backend
if [ ! -d "dist" ]; then
echo -e "${YELLOW}Building backend for the first time...${NC}"
npm run build
if [ $? -ne 0 ]; then
echo -e "${RED}✗ Backend build failed${NC}"
exit 1
fi
echo -e "${GREEN}✓ Backend built successfully${NC}"
else
echo -e "${GREEN}✓ Backend dist directory exists${NC}"
fi
# Step 4: Build frontend (if needed)
echo ""
echo -e "${BLUE}Step 4: Building frontend...${NC}"
cd /root/maternal-app/maternal-web
PORT=3030 NODE_ENV=production nohup npm run start > /root/maternal-app/logs/frontend-prod.log 2>&1 &
FRONTEND_PID=$!
echo "Frontend started with PID: $FRONTEND_PID"
# Wait a moment for servers to start
if [ ! -d ".next" ]; then
echo -e "${YELLOW}Building frontend for the first time...${NC}"
npm run build
if [ $? -ne 0 ]; then
echo -e "${RED}✗ Frontend build failed${NC}"
exit 1
fi
echo -e "${GREEN}✓ Frontend built successfully${NC}"
else
echo -e "${GREEN}✓ Frontend .next directory exists${NC}"
fi
# Step 5: Start PM2 processes
echo ""
echo -e "${BLUE}Step 5: Starting PM2 processes...${NC}"
# Check if ecosystem.config.js exists
if [ ! -f "/root/maternal-app/ecosystem.config.js" ]; then
echo -e "${RED}✗ ecosystem.config.js not found${NC}"
exit 1
fi
# Stop any existing PM2 processes
echo -e "${YELLOW}Stopping any existing PM2 processes...${NC}"
pm2 delete all 2>/dev/null || true
# Start PM2 with ecosystem config (production environment)
cd /root/maternal-app
pm2 start ecosystem.config.js --env production
if [ $? -eq 0 ]; then
echo -e "${GREEN}✓ PM2 processes started${NC}"
else
echo -e "${RED}✗ Failed to start PM2 processes${NC}"
exit 1
fi
# Save PM2 process list
pm2 save
# Step 6: Verify services are running
echo ""
echo -e "${BLUE}Step 6: Verifying services...${NC}"
sleep 5
# Check if servers are running
# Check PM2 status
echo -e "${YELLOW}PM2 Status:${NC}"
pm2 list
# Check if ports are listening
echo ""
echo "Checking server status..."
echo -e "${YELLOW}Port Status:${NC}"
if lsof -i:3020 > /dev/null 2>&1; then
echo "✅ Backend is running on port 3020"
echo -e "${GREEN} Backend is running on port 3020${NC}"
else
echo "❌ Backend failed to start on port 3020"
echo -e "${RED}✗ Backend not detected on port 3020${NC}"
fi
if lsof -i:3030 > /dev/null 2>&1; then
echo "✅ Frontend is running on port 3030"
echo -e "${GREEN} Frontend is running on port 3030${NC}"
else
echo "❌ Frontend failed to start on port 3030"
echo -e "${RED}✗ Frontend not detected on port 3030${NC}"
fi
# Check Docker containers
echo ""
echo "Production servers started!"
echo "Backend: http://localhost:3020"
echo -e "${YELLOW}Docker Containers:${NC}"
docker ps --filter name=parentflow --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
# Summary
echo ""
echo "=========================================="
echo -e "${GREEN}Production Environment Started!${NC}"
echo "=========================================="
echo ""
echo "Services:"
echo " Backend API: http://localhost:3020"
echo " Frontend: http://localhost:3030"
echo " PostgreSQL: localhost:5432"
echo " Redis: localhost:6379"
echo " MongoDB: localhost:27017"
echo " MinIO: localhost:9000"
echo " MinIO Console: localhost:9001"
echo ""
echo "To check logs:"
echo " Backend: tail -f /root/maternal-app/logs/backend-prod.log"
echo " Frontend: tail -f /root/maternal-app/logs/frontend-prod.log"
echo "Management Commands:"
echo " PM2 status: pm2 status"
echo " PM2 logs: pm2 logs"
echo " PM2 restart: pm2 restart all"
echo " PM2 stop: pm2 stop all"
echo " Docker logs: docker logs parentflow-postgres-prod"
echo " Stop all: pm2 stop all && docker-compose -f docker-compose.production.yml down"
echo ""
echo "Domains (configure in Nginx/DNS):"
echo " Frontend: web.parentflowapp.com → localhost:3030"
echo " Backend: api.parentflowapp.com → localhost:3020"
echo ""
echo -e "${GREEN}✓ Startup complete!${NC}"

77
stop-production.sh Executable file
View File

@@ -0,0 +1,77 @@
#!/bin/bash
# ParentFlow Production Stop Script
# Stops PM2 processes and Docker containers gracefully
set -e
# Color codes
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
echo "=========================================="
echo "Stopping ParentFlow Production"
echo "=========================================="
echo ""
# Step 1: Stop PM2 processes
echo -e "${BLUE}Step 1: Stopping PM2 processes...${NC}"
if command -v pm2 &> /dev/null; then
pm2 stop all 2>/dev/null || true
echo -e "${GREEN}✓ PM2 processes stopped${NC}"
else
echo -e "${YELLOW}Warning: PM2 not found${NC}"
fi
# Step 2: Stop Docker containers
echo ""
echo -e "${BLUE}Step 2: Stopping Docker containers...${NC}"
if docker compose version &> /dev/null; then
docker compose -f docker-compose.production.yml down
else
docker-compose -f docker-compose.production.yml down 2>/dev/null || true
fi
if [ $? -eq 0 ]; then
echo -e "${GREEN}✓ Docker containers stopped${NC}"
else
echo -e "${YELLOW}Warning: Failed to stop some Docker containers${NC}"
fi
# Verify everything is stopped
echo ""
echo -e "${BLUE}Verification:${NC}"
# Check PM2
if command -v pm2 &> /dev/null; then
RUNNING_PROCESSES=$(pm2 jlist 2>/dev/null | jq -r '.[] | select(.pm2_env.status == "online") | .name' | wc -l)
if [ "$RUNNING_PROCESSES" -eq 0 ]; then
echo -e "${GREEN}✓ No PM2 processes running${NC}"
else
echo -e "${YELLOW}Warning: $RUNNING_PROCESSES PM2 processes still running${NC}"
fi
fi
# Check Docker
RUNNING_CONTAINERS=$(docker ps --filter name=parentflow --format "{{.Names}}" | wc -l)
if [ "$RUNNING_CONTAINERS" -eq 0 ]; then
echo -e "${GREEN}✓ No ParentFlow Docker containers running${NC}"
else
echo -e "${YELLOW}Warning: $RUNNING_CONTAINERS containers still running${NC}"
docker ps --filter name=parentflow
fi
echo ""
echo "=========================================="
echo -e "${GREEN}Production environment stopped${NC}"
echo "=========================================="
echo ""
echo "To completely remove Docker volumes (WARNING: deletes data):"
echo " docker-compose -f docker-compose.production.yml down -v"
echo ""
echo "To remove PM2 processes from startup:"
echo " pm2 delete all"
echo " pm2 save"