Run Template Doctor in Docker containers for local testing or production deployment.
- Docker Desktop installed and running
.envfile configured (see.env.example)
./docker-start.shThis will:
- Build the Express server
- Build the Vite frontend
- Start both containers
- Set up networking between them
- Frontend: http://localhost:4000
- Backend: http://localhost:7071
- Health Check: http://localhost:7071/health
./docker-stop.shOr with cleanup:
./docker-stop.sh --clean# Start normally
./docker-start.sh
# Start with rebuild
./docker-start.sh --build
# Start and follow logs
./docker-start.sh --logs# All services
docker-compose logs -f
# Just backend
docker-compose logs -f server
# Just frontend
docker-compose logs -f app# Check status
docker-compose ps
# Restart services
docker-compose restart
# Restart specific service
docker-compose restart server
# Stop without removing
docker-compose stop
# Start stopped containers
docker-compose start# Rebuild and restart
./docker-start.sh --build
# Or manually
npm run build -w packages/server
npm run build -w packages/app
docker-compose up -d --build┌─────────────────────────────────────┐
│ Docker Host (localhost) │
├─────────────────────────────────────┤
│ │
│ ┌─────────────────────────────┐ │
│ │ Frontend Container │ │
│ │ - Vite build output │ │
│ │ - Served via 'serve' │ │
│ │ - Port: 4000 │ │
│ └─────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────┐ │
│ │ Backend Container │ │
│ │ - Express server │ │
│ │ - Node.js 20 │ │
│ │ - Port: 7071 │ │
│ └─────────────────────────────┘ │
│ │
└─────────────────────────────────────┘
Environment variables are read from .env and passed to containers:
Backend (server):
GITHUB_CLIENT_ID- OAuth app client IDGITHUB_CLIENT_SECRET- OAuth app secretGITHUB_TOKEN- PAT for GitHub APIGH_WORKFLOW_TOKEN- Workflow tokenGITHUB_TOKEN_ANALYZER- Analyzer tokenDEFAULT_RULE_SET- Default validation rulesetARCHIVE_ENABLED- Enable archiving- etc. (see
docker-compose.yml)
Frontend (app):
VITE_API_BASE_URL- Backend URL (set to http://localhost:7071)
Check Docker is running:
docker psCheck for port conflicts:
lsof -ti :4000 | xargs kill -9 # Kill process on 4000
lsof -ti :7071 | xargs kill -9 # Kill process on 7071View container logs:
docker-compose logs server
docker-compose logs app# Check if backend is responding
curl http://localhost:7071/health
# Check backend logs
docker-compose logs server
# Restart backend
docker-compose restart serverCheck network:
docker-compose ps
docker network inspect template-doctor_template-doctorVerify backend URL in frontend:
The frontend should connect to http://localhost:7071 (not the container name).
Clean rebuild:
./docker-stop.sh --clean
npm run clean -w packages/server
npm run clean -w packages/app
./docker-start.sh --buildCheck disk space:
docker system df
docker system prune # Clean up if neededcp .env.example .env
# Edit .env with your values# Build images
docker-compose build
# Tag for registry
docker tag template-doctor-server:latest your-registry/template-doctor-server:v1.0.0
docker tag template-doctor-app:latest your-registry/template-doctor-app:v1.0.0
# Push to registry
docker push your-registry/template-doctor-server:v1.0.0
docker push your-registry/template-doctor-app:v1.0.0# Create container app environment
az containerapp env create \
--name template-doctor-env \
--resource-group your-rg \
--location eastus
# Deploy backend
az containerapp create \
--name template-doctor-server \
--resource-group your-rg \
--environment template-doctor-env \
--image your-registry/template-doctor-server:v1.0.0 \
--target-port 7071 \
--ingress external \
--env-vars \
GITHUB_TOKEN=secretref:github-token \
GITHUB_CLIENT_ID=secretref:github-client-id
# Deploy frontend
az containerapp create \
--name template-doctor-app \
--resource-group your-rg \
--environment template-doctor-env \
--image your-registry/template-doctor-app:v1.0.0 \
--target-port 4000 \
--ingress externalFor active development, don't use Docker. Use the native dev servers:
# Terminal 1: Backend
cd packages/server
npm run dev
# Terminal 2: Frontend
cd packages/app
npm run devDocker is for:
- Testing the production build locally
- Validating deployment configuration
- Running integration tests
- Final pre-production verification
✅ Use Docker when:
- Testing production builds
- Validating environment variables
- Testing container deployment
- Running full integration tests
- Demonstrating to stakeholders
❌ Don't use Docker when:
- Actively coding (slow rebuild cycle)
- Debugging (harder to attach debugger)
- Running unit tests (slower)
- Making frequent changes
Current approximate sizes:
- Backend: ~150MB (Node 20 Alpine + dependencies)
- Frontend: ~80MB (Static files + serve)
Speed up builds:
- Use
.dockerignoreto exclude unnecessary files - Leverage Docker layer caching
- Use multi-stage builds (already implemented)
- Build locally before
docker-compose up
Cached layers:
- Base image (node:20-alpine)
- Dependencies (package.json + npm ci)
- Build output (only rebuilt when source changes)
Both containers have health checks:
# Check health status
docker-compose ps
# View health check logs
docker inspect template-doctor-server | jq '.[0].State.Health'
docker inspect template-doctor-app | jq '.[0].State.Health'# Real-time stats
docker stats
# Container info
docker-compose top/
├── docker-compose.yml # Multi-container orchestration
├── docker-start.sh # Start script
├── docker-stop.sh # Stop script
├── .dockerignore # Files to exclude from build
├── .env # Environment variables (not committed)
└── packages/
├── server/
│ └── Dockerfile # Backend container
└── app/
└── Dockerfile # Frontend container
- ✅ Start containers:
./docker-start.sh - ✅ Test locally: http://localhost:4000
- ⏳ Deploy to Azure Container Apps
- ⏳ Set up CI/CD pipeline
- ⏳ Configure production secrets
For more information:
- Express server:
packages/server/README.md - Frontend app:
packages/app/README.md - Migration status:
packages/server/MIGRATION_STATUS.md