Files
portfolio/DEPLOYMENT_SETUP.md
denshooter 8c223db2a8
Some checks failed
Dev Deployment (Zero Downtime) / deploy-dev (push) Has been cancelled
feat: Setup zero-downtime deployments for production and dev branches
- Created separate workflows for production and dev deployments
- Production branch → dk0.dev (port 3000)
- Dev branch → dev.dk0.dev (port 3002)
- Zero-downtime deployment pattern (start new, wait for health, remove old)
- Complete isolation between environments (separate containers, databases, networks)
- Cleaned up unused code and files:
  - Removed unused GhostEditor and ResizableGhostEditor components
  - Removed old/unused workflows and markdown files
  - Fixed docker-compose references
- Upgraded dependencies to latest compatible versions
- Fixed TypeScript errors in editor page
- Updated staging to use dev.dk0.dev domain
2026-01-09 14:21:03 +01:00

5.2 KiB

🚀 Deployment Setup Guide

Overview

This project uses a dual-branch deployment strategy with zero-downtime deployments:

  • Production Branch (production) → Serves https://dk0.dev on port 3000
  • Dev Branch (dev) → Serves https://dev.dk0.dev on port 3002

Both environments are completely isolated with separate:

  • Docker containers
  • Databases (PostgreSQL)
  • Redis instances
  • Networks
  • Volumes

Branch Strategy

Production Branch

  • Branch: production
  • Domain: https://dk0.dev
  • Port: 3000
  • Container: portfolio-app
  • Database: portfolio_db (port 5432)
  • Redis: portfolio-redis (port 6379)
  • Image Tag: portfolio-app:production / portfolio-app:latest

Dev Branch

  • Branch: dev
  • Domain: https://dev.dk0.dev
  • Port: 3002
  • Container: portfolio-app-staging
  • Database: portfolio_staging_db (port 5434)
  • Redis: portfolio-redis-staging (port 6381)
  • Image Tag: portfolio-app:staging

Automatic Deployment

How It Works

  1. Push to production branch:

    • Triggers .gitea/workflows/production-deploy.yml
    • Runs tests, builds, and deploys to production
    • Zero-downtime deployment (starts new container, waits for health, removes old)
  2. Push to dev branch:

    • Triggers .gitea/workflows/dev-deploy.yml
    • Runs tests, builds, and deploys to dev/staging
    • Zero-downtime deployment

Zero-Downtime Process

  1. Build new Docker image
  2. Start new container with updated image
  3. Wait for new container to be healthy (health checks)
  4. Verify HTTP endpoints respond correctly
  5. Remove old container (if different)
  6. Cleanup old images

Manual Deployment

Production

# Build and deploy production
docker build -t portfolio-app:latest .
docker compose -f docker-compose.production.yml up -d --build

Dev/Staging

# Build and deploy dev
docker build -t portfolio-app:staging .
docker compose -f docker-compose.staging.yml up -d --build

Environment Variables

Required Gitea Variables

  • NEXT_PUBLIC_BASE_URL - Base URL for the application
  • MY_EMAIL - Email address for contact
  • MY_INFO_EMAIL - Info email address
  • LOG_LEVEL - Logging level (info/debug)

Required Gitea Secrets

  • MY_PASSWORD - Email password
  • MY_INFO_PASSWORD - Info email password
  • ADMIN_BASIC_AUTH - Admin basic auth credentials
  • N8N_SECRET_TOKEN - Optional: n8n webhook secret

Optional Variables

  • N8N_WEBHOOK_URL - n8n webhook URL for automation

Health Checks

Both environments have health check endpoints:

  • Production: http://localhost:3000/api/health
  • Dev: http://localhost:3002/api/health

Monitoring

Check Container Status

# Production
docker compose -f docker-compose.production.yml ps

# Dev
docker compose -f docker-compose.staging.yml ps

View Logs

# Production
docker logs portfolio-app --tail=100 -f

# Dev
docker logs portfolio-app-staging --tail=100 -f

Health Check

# Production
curl http://localhost:3000/api/health

# Dev
curl http://localhost:3002/api/health

Troubleshooting

Container Won't Start

  1. Check logs: docker logs <container-name>
  2. Verify environment variables are set
  3. Check database/redis connectivity
  4. Verify ports aren't already in use

Deployment Fails

  1. Check Gitea Actions logs
  2. Verify all required secrets/variables are set
  3. Check if old containers are blocking ports
  4. Verify Docker image builds successfully

Zero-Downtime Issues

  • Old container might still be running - check with docker ps
  • Health checks might be failing - check container logs
  • Port conflicts - verify ports 3000 and 3002 are available

Rollback

If a deployment fails or causes issues:

# Production rollback
docker compose -f docker-compose.production.yml down
docker tag portfolio-app:previous portfolio-app:latest
docker compose -f docker-compose.production.yml up -d

# Dev rollback
docker compose -f docker-compose.staging.yml down
docker tag portfolio-app:staging-previous portfolio-app:staging
docker compose -f docker-compose.staging.yml up -d

Best Practices

  1. Always test on dev branch first before pushing to production
  2. Monitor health checks after deployment
  3. Keep old images for quick rollback (last 3 versions)
  4. Use feature flags for new features
  5. Document breaking changes before deploying
  6. Run tests locally before pushing

Network Configuration

  • Production Network: portfolio_net + proxy (external)
  • Dev Network: portfolio_staging_net
  • Isolation: Complete separation ensures no interference

Database Management

Production Database

  • Container: portfolio-postgres
  • Port: 5432 (internal only)
  • Database: portfolio_db
  • User: portfolio_user

Dev Database

  • Container: portfolio-postgres-staging
  • Port: 5434 (external), 5432 (internal)
  • Database: portfolio_staging_db
  • User: portfolio_user

Redis Configuration

Production Redis

  • Container: portfolio-redis
  • Port: 6379 (internal only)

Dev Redis

  • Container: portfolio-redis-staging
  • Port: 6381 (external), 6379 (internal)