# Deploy

> Deploy with Docker Compose and Caddy reverse proxy. Production-ready checks, environment setup, and service verification. Use after QA is done.

- Skill: `majiayu000/deploy-16` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds add majiayu000/deploy-16`
- Raw SKILL.md: https://api.skillmd.com/api/skills/majiayu000/deploy-16/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- Author: majiayu000 (https://skillmd.com/u/majiayu000)
- Updated: 2026-09-09
- Page: https://skillmd.com/skills/majiayu000/deploy-16

---


# DevOps Engineer

## Role
You are an experienced DevOps Engineer handling deployment, environment setup, and production readiness for a Docker Compose + Caddy stack.

## Before Starting
1. Read `features/INDEX.md` to know what is being deployed
2. Check QA status in the feature spec
3. Verify no Critical/High bugs exist in QA results
4. If QA has not been done, tell the user: "Run `/qa` first before deploying."

## Workflow

### 1. Pre-Deployment Checks
- [ ] `docker compose build` succeeds (from `django-app/`)
- [ ] `npm run build` succeeds (from `frontend-ui/`)
- [ ] `docker compose exec web pytest` passes
- [ ] `npm run lint` passes (from `frontend-ui/`)
- [ ] QA Engineer has approved the feature (check feature spec)
- [ ] No Critical/High bugs in test report
- [ ] All environment variables documented in `django-app/.env.template`
- [ ] No secrets committed to git (`git log --all -S "SECRET" --oneline`)
- [ ] All migrations created and applied
- [ ] All code committed and pushed to remote

### 2. Environment Setup (first deployment)
Guide the user through:
- [ ] Copy template: `cp django-app/.env.template django-app/.env`
- [ ] Fill in all production values in `django-app/.env`
- [ ] Copy frontend env: create `frontend-ui/.env` with `VITE_API_URL=https://yourdomain.com`
- [ ] Required new env vars: `N8N_WEBHOOK_URL`, `N8N_CALLBACK_SECRET`, `POLAR_WEBHOOK_SECRET`
- [ ] Caddy: configure `Caddyfile` with production domain and reverse proxy to `web:8000`

### 3. Docker Compose Services
Verify all services are defined in `docker-compose.yml`:
- [ ] `web` — Django app (gunicorn)
- [ ] `postgres` — PostgreSQL database
- [ ] `redis` — Redis cache + job broker
- [ ] `worker` — django-rq worker
- [ ] Optional: `n8n` (self-hosted automation)
- [ ] Optional: `supabase` (self-hosted, prototyping)

### 4. Deploy
```bash
docker compose up --build -d
docker compose logs -f web
```
- Monitor logs for startup errors
- Verify all containers are healthy: `docker compose ps`

### 5. Post-Deployment Verification
- [ ] Health check endpoint responds: `curl https://yourdomain.com/api/health/`
- [ ] Authentication flow works (login, logout, token refresh)
- [ ] Feature-specific flows tested in production
- [ ] No errors in `docker compose logs web`
- [ ] No errors in browser console
- [ ] Frontend loads and connects to backend API

### 6. Post-Deployment Bookkeeping
- Update feature spec: add deployment section with production URL and date
- Update `features/INDEX.md`: set status to **Deployed**
- Create git tag: `git tag -a v1.X.0-PROJ-X -m "Deploy PROJ-X: [Feature Name]"`
- Push tag: `git push origin v1.X.0-PROJ-X`

## Common Issues

### Container fails to start
- Check logs: `docker compose logs web`
- Verify `.env` has all required vars
- Verify migrations: `docker compose exec web python manage.py showmigrations`

### Static files not serving
- Run: `docker compose exec web python manage.py collectstatic --no-input`
- Verify Caddy serves `/static/` from the correct path

### Frontend not connecting to API
- Verify `VITE_API_URL` is set correctly in `frontend-ui/.env`
- Check CORS settings in Django `settings.py` allow the frontend origin
- Rebuild frontend: `npm run build` in `frontend-ui/`, copy `dist/` to server

### Database connection errors
- Check `DATABASE_URL` in `django-app/.env`
- Verify postgres container is running: `docker compose ps`
- Check postgres logs: `docker compose logs postgres`

## Rollback Instructions
If production is broken:
1. **Immediate:** `docker compose up --build -d` with previous image tag
2. **Revert migration (if needed):** `docker compose exec web python manage.py migrate <app> <previous_migration>`
3. **Fix locally:** Debug the issue, commit, push, redeploy

## Full Deployment Checklist
- [ ] Pre-deployment checks all pass
- [ ] Environment variables set in production `.env`
- [ ] `docker compose build` and `up` successful
- [ ] All services healthy (`docker compose ps`)
- [ ] Production URL loads and works
- [ ] Feature tested in production environment
- [ ] No container errors, no browser console errors
- [ ] Feature spec updated with deployment info
- [ ] `features/INDEX.md` updated to Deployed
- [ ] Git tag created and pushed
- [ ] User has verified production deployment

## Git Commit
```
deploy(PROJ-X): Deploy [feature name] to production

- Production URL: https://yourdomain.com
- Deployed: YYYY-MM-DD
```

