This document describes the complete deployment process for the Booking system, covering both development and production environments.
booking-deploy/
├── compose/ # Docker Compose configuration files
│ ├── docker-compose.dev.yml # Development environment orchestration
│ ├── docker-compose.prod.yml # Production environment orchestration
│ ├── dev.compose.env.example # Development environment variables template
│ └── prod.compose.env.example # Production environment variables template
├── env/ # Application environment variables
│ ├── dev/ # Development environment
│ │ ├── backend.env.example
│ │ └── frontend.env.example
│ └── prod/ # Production environment
│ ├── backend.env.example
│ └── frontend.env.example
└── scripts/ # Deployment scripts
├── deploy-dev.sh # Development environment deployment script
├── deploy-prod.sh # Production environment deployment script
└── verify-images.sh # Image verification script
- Docker Engine 20.10+ or Docker Desktop
- Docker Compose v2+ (recommended) or docker-compose v1.29+
# Copy template files
cd booking-deploy
# Compose environment variables
cp compose/dev.compose.env.example compose/dev.compose.env
# Edit dev.compose.env to update Docker Hub image addresses if needed
# Application environment variables
cp env/dev/backend.env.example env/dev/backend.env
cp env/dev/frontend.env.example env/dev/frontend.env
# Edit .env files and set actual values (e.g., JWT_SECRET, etc.)cd booking-deploy
cp compose/prod.compose.env.example compose/prod.compose.env
cp env/prod/backend.env.example env/prod/backend.env
cp env/prod/frontend.env.example env/prod/frontend.env
# Important: Production environment requires strong passwords and real secretsThe Booking system's CI/CD pipeline automatically generates multiple types of Docker image tags, each with different purposes and reliability characteristics:
| Tag Type | Format Example | Mutability | Recommended Use | Reliability |
|---|---|---|---|---|
| Branch Tags | dev, main |
Mutable - Updated on every push | Rapid development, integration testing | Low - Not suitable for production |
| Commit Tags | dev-abc123, main-def456 |
Immutable - Tied to specific commits | Reliable deployment, rollback, auditing | High - Recommended for production |
| Semantic Version | v1.0.0, v1.2.3 |
Immutable - Versioned releases | Official releases, version management | Highest - Best practice for production |
| PR Tags | pr-123 |
Mutable - PR builds | PR verification, code review | Low - For temporary use only |
| latest | latest |
Mutable - Latest from main branch | Development convenience | Low - Prohibited for production |
-
Development Environment:
- Rapid iteration: Use
devbranch tag - Reliable testing: Use
dev-<commit-hash>commit tag
- Rapid iteration: Use
-
Production Environment:
- Must use immutable tags: Commit tags or semantic version tags
- Emergency fixes: Use
main-<commit-hash> - Official releases: Use semantic versions like
v1.0.0 - Prohibited:
mainorlatesttags
All images are verified with real deployment topology:
- ✅ Include PostgreSQL and Redis dependencies
- ✅ Run database migrations
- ✅ Verify health endpoint (
/v1/health) - ✅ Check database and Redis connection status
- ✅ Verify frontend accessibility
Image tags are automatically generated by GitHub Actions workflows:
- Backend images: booking-backend/.github/workflows/backend-image.yml
- Frontend images: booking-frontend/.github/workflows/frontend-image.yml
- Migration images: Dedicated
booking-backend-migrationimage
To rollback to a previous version:
- Find the previous commit tag (e.g.,
main-abc123def) - Update image tags in
prod.compose.envfile - Re-run the deployment script
# Rollback to specific commit
BACKEND_IMAGE=docker.io/cho-geer/booking-backend:main-previous-commit
BACKEND_MIGRATION_IMAGE=docker.io/cho-geer/booking-backend-migration:main-previous-commit
FRONTEND_IMAGE=docker.io/cho-geer/booking-frontend:main-previous-commit# Enter booking-deploy directory
cd booking-deploy
# Run deployment script
./scripts/deploy-dev.shThe deployment script performs the following steps:
- Check for environment variable files existence
- Pull latest images from Docker Hub
- Execute database migrations (independent migration service)
- Start all services (PostgreSQL, Redis, Backend, Frontend)
- Health check to verify all services are available
- Backend health endpoint:
http://localhost:3001/v1/health - Backend Swagger:
http://localhost:3001/api/docs - Frontend page:
http://localhost:3000
- Backend health endpoint:
cd booking-deploy
./scripts/deploy-prod.shThe production environment deployment process is the same as development environment but uses different configurations:
- Different Docker Compose file (
docker-compose.prod.yml) - Different environment variable files (
prod.compose.env,env/prod/) - Possibly different network configurations and resource constraints
| Service | Image | Port | Description |
|---|---|---|---|
| PostgreSQL | postgres:16 |
5432 | Main database |
| Redis | redis:7-alpine |
6379 | Cache and session storage |
| Backend | ${BACKEND_IMAGE} |
3001 | NestJS API service |
| Frontend | ${FRONTEND_IMAGE} |
3000 | Next.js frontend application |
| Migration | ${BACKEND_MIGRATION_IMAGE} |
- | Database migration service |
- May use external databases (e.g., RDS) instead of containerized PostgreSQL
- May use external Redis clusters
- May add load balancing and monitoring services
- Different resource constraints and restart policies
The deployment process includes an independent migration service to ensure:
- Migrations execute before application startup
- Deployment stops on failure to prevent applications from connecting to inconsistent databases
- Idempotency:
prisma migrate deploycan be safely executed repeatedly
# Development environment
docker compose -f compose/docker-compose.dev.yml --env-file compose/dev.compose.env run --rm migration
# Production environment
docker compose -f compose/docker-compose.prod.yml --env-file compose/prod.compose.env run --rm migration- Backend:
GET /v1/health- Returns application, database, and Redis status - PostgreSQL: Docker health check uses
pg_isready - Redis: Docker health check uses
redis-cli ping
The deployment script automatically verifies:
- Backend health endpoint returns
200 OK - Swagger UI is accessible
- Frontend homepage is accessible
# Check backend health
curl http://localhost:3001/v1/health | jq .
# Check service status
docker compose -f compose/docker-compose.dev.yml --env-file compose/dev.compose.env psMissing booking-deploy/compose/dev.compose.env
Create it from booking-deploy/compose/dev.compose.env.example
Solution: Copy the template file and fill in actual values.
Error: P3009: migrate found failed migrations in the target database
Solution:
- Check database connection string
- Manually fix migrations:
docker compose exec postgres psql -U postgres -d booking_system - View migration logs
The deployment script times out after 80 seconds. Solution:
- Check service logs:
docker compose logs backend - Verify database connection:
docker compose exec backend npm run prisma:deploy - Check for port conflicts
Error response from daemon: pull access denied for cho-geer/booking-backend
Solution:
- Confirm the Docker Hub repository exists and is public
- Or update
compose/dev.compose.envto use locally built images
# View all service logs
docker compose -f compose/docker-compose.dev.yml --env-file compose/dev.compose.env logs
# View specific service logs
docker compose -f compose/docker-compose.dev.yml --env-file compose/dev.compose.env logs backend
# Tail logs in real-time
docker compose -f compose/docker-compose.dev.yml --env-file compose/dev.compose.env logs -f- Update image tags in
compose/dev.compose.envorcompose/prod.compose.env - Execute deployment script
- Verify new version functionality
- Restore old image tags in environment variable files
- Execute deployment script
- Database forward compatibility: Ensure old version applications can work with current database schema
The current deployment strategy uses rolling restarts, future extensions could include:
- Blue-green deployment
- Canary releases
- Using Docker Swarm or Kubernetes
- Never commit
.envfiles to version control - Use secret management services (e.g., AWS Secrets Manager) for production secrets
- Regularly rotate JWT secrets and database passwords
- Use dedicated networks for production environments
- Restrict external access to database and Redis
- Enable firewall rules
- Regularly scan images for vulnerabilities
- Use minimal base images
- Update dependencies promptly
Current deployment is manually triggered, future integration with CI/CD pipelines:
name: Deploy to Production
on:
push:
tags:
- 'v*'
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Deploy to Server
uses: appleboy/ssh-action@v0.1.5
with:
host: ${{ secrets.PROD_HOST }}
username: ${{ secrets.PROD_USER }}
key: ${{ secrets.PROD_SSH_KEY }}
script: |
cd /opt/booking-system/booking-deploy
./scripts/deploy-prod.shProduction deployments should include:
- Code review
- Automated test passing
- Manual approval
- Post-deployment verification
# Pull images
docker compose -f compose/docker-compose.dev.yml --env-file compose/dev.compose.env pull
# Execute migrations
docker compose -f compose/docker-compose.dev.yml --env-file compose/dev.compose.env run --rm migration
# Start services
docker compose -f compose/docker-compose.dev.yml --env-file compose/dev.compose.env up -d
# Stop services
docker compose -f compose/docker-compose.dev.yml --env-file compose/dev.compose.env down
# View status
docker compose -f compose/docker-compose.dev.yml --env-file compose/dev.compose.env psSee comments in each .env.example file.
Last updated: 2026-04-08 Maintained by: DevOps Team