From 475fd95a59f03ab6e20a1f220cfe0dd978297c1e Mon Sep 17 00:00:00 2001 From: Chris Anderson Date: Fri, 26 Jun 2026 05:55:56 +0200 Subject: [PATCH] Update deployment: Go API backend with Docker Compose - Update Dockerfile to golang:1.26-alpine (matching go.mod) - Update deploy.sh for Docker Compose workflow - Rewrite DEPLOYMENT.md for new API architecture - Add env vars for face service and Redis configuration --- DEPLOYMENT.md | 183 ++++++++++++++++++++++++++++---------------------- deploy.sh | 27 ++++---- 2 files changed, 116 insertions(+), 94 deletions(-) diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md index ed994626..f70a9358 100644 --- a/DEPLOYMENT.md +++ b/DEPLOYMENT.md @@ -1,10 +1,10 @@ -# Hatch Landing Page — Deployment Guide +# Hatch API — Deployment Guide ## Overview -The Hatch landing page (`hatch.surf`) is a **static HTML** site deployed via **Docker** on the production server. +The Hatch API (`hatch.surf`) is a **Go backend** deployed via **Docker Compose** on the production server. -**Key principle**: All changes MUST go through the git repository and automated deployment. Never edit files directly on the server or use `/var/www`. +**Key principle**: All changes MUST go through the git repository and automated deployment. Never edit files directly on the server. --- @@ -13,17 +13,16 @@ The Hatch landing page (`hatch.surf`) is a **static HTML** site deployed via **D **Location**: `/home/nara/apps/web/` **Git Remotes**: -- `github` → `elfoundation/hatch` (source of truth) -- `origin` → `el-foundation/hatch-surf` (Gitea push-mirror, deploys to hatch.surf) +- `github` → `el-foundation/hatch-surf` (Gitea, source of truth) +- `origin` → `el-foundation/hatch-surf` (Gitea push-mirror) **Structure**: ``` -site/ # Static files served by nginx - index.html # Main landing page - style.css # Styles - main.js # Anime.js animations -Dockerfile # Docker build configuration (static files only) -docker-compose.yml # Container orchestration +cmd/hatch/ # Go server entrypoint +internal/ # Go packages (handler, store, face, etc.) +Dockerfile # Multi-stage Docker build (Go → scratch) +docker-compose.yml # Container orchestration (hatch + caddy) +Caddyfile # Caddy reverse proxy config deploy.sh # Deployment script ``` @@ -31,18 +30,11 @@ deploy.sh # Deployment script ## Deployment Flow -### Source of Truth - -**GitHub `main`** is the source of truth. Gitea is a push-mirror. - -All development happens via PRs to `elfoundation/hatch`. The deploy script pulls from GitHub and pushes to Gitea. - ### Automatic (Recommended) -1. Merge PR to GitHub `main` +1. Merge PR to `main` 2. Gitea webhook triggers `gitea-webhook.py` 3. Script runs `deploy.sh` automatically -4. `deploy.sh` pulls from GitHub, pushes to Gitea (push-mirror), rebuilds Docker, restarts ### Manual @@ -54,56 +46,66 @@ cd /home/nara/apps/web **What `deploy.sh` does**: 1. `git pull github main` — fetches latest from GitHub (source of truth) 2. `git push origin main` — syncs to Gitea (push-mirror) -3. `cd site && docker build -t hatch-web:latest .` — rebuilds image -4. Stops and removes old container -5. `docker run -d` — starts new container -6. Verifies deployment with health check +3. `docker compose down` — stops current containers +4. `docker compose build hatch` — rebuilds the Go binary in a multi-stage build +5. `docker compose --profile with-caddy up -d` — starts hatch + caddy +6. Verifies health endpoint responds 200 --- ## Docker Setup -**Container**: `hatch-web` -**Port**: `8080` (mapped to host) -**Internal**: nginx serving static files on port 80 -**Network**: `hatch-network` +**Services**: +| Service | Image | Port | Purpose | +|----------|----------------|-------|------------------------| +| `hatch` | web-hatch | 8080 | Go API server | +| `caddy` | caddy:2-alpine | 80/443| Reverse proxy + TLS | + +**Profiles**: +- Default: `hatch` only (API on port 8080) +- `with-caddy`: `hatch` + `caddy` (full HTTPS via Let's Encrypt) **Check status**: ```bash -docker ps | grep hatch-web -docker logs hatch-web +docker compose ps +docker compose logs hatch +docker compose logs caddy ``` -**Restart without rebuild**: -```bash -docker compose -f /home/nara/apps/web/docker-compose.yml restart -``` +--- + +## Environment Variables + +Configure in `.env` or pass to Docker Compose: + +| Variable | Default | Description | +|------------------------|----------------------|--------------------------------------| +| `HATCH_HOSTNAME` | `localhost` | Public hostname for TLS cert | +| `HATCH_BASE_URL` | `http://localhost` | Base URL for SSE and self-references | +| `FACE_SERVICE_ENABLED` | `false` | Enable AWS Rekognition face search | +| `AWS_REGION` | `us-east-1` | AWS region for Rekognition | +| `REKOGNITION_COLLECTION` | `hatch-faces` | Rekognition collection ID | +| `REDIS_URL` | — | Redis URL (optional, for caching) | --- ## Making Changes -### 1. Edit the static files +### 1. Edit Go source ```bash cd /home/nara/apps/web - -# Edit landing page -vim out/index.html - -# Edit styles -vim out/style.css - -# Edit animations -vim out/main.js +vim cmd/hatch/main.go # Server entrypoint +vim internal/handler/ # HTTP handlers +vim internal/face/ # Face detection service +vim internal/store/ # Database layer ``` -### 2. Test locally (optional) +### 2. Build and test locally ```bash -# Serve files locally -cd out && python3 -m http.server 3000 -# Visit http://localhost:3000 +go build ./cmd/hatch/ +go test ./... ``` ### 3. Commit and push @@ -124,23 +126,21 @@ Either wait for webhook or run manually: ### 5. Verify ```bash -curl -s http://localhost:8080 | head -20 -# Or visit https://hatch.surf +curl -s http://localhost:8080/healthz +curl -s http://localhost:8080/readyz ``` --- ## Common Mistakes to Avoid -❌ **DON'T**: Edit files in `/var/www/html/` ❌ **DON'T**: Edit files directly inside the Docker container -❌ **DON'T**: Work on static HTML/CSS files in a workspace without committing -❌ **DON'T**: Copy files to the server without using git +❌ **DON'T**: Commit without testing +❌ **DON'T**: Use `go run` in production -✅ **DO**: Edit files in `/home/nara/apps/web/out/` -✅ **DO**: Commit changes to git -✅ **DO**: Use `deploy.sh` for deployment -✅ **DO**: Test locally before pushing +✅ **DO**: Test with `go test ./...` before committing +✅ **DO**: Use `docker compose build` for production builds +✅ **DO**: Check health endpoints after deployment --- @@ -151,9 +151,6 @@ If a deployment causes issues: ```bash cd /home/nara/apps/web -# View recent commits -git log --oneline -10 - # Revert to previous version git revert HEAD git push origin main @@ -162,22 +159,21 @@ git push origin main ./deploy.sh ``` -Previous builds are backed up in `out.backup.*` directories. - --- -## Cache Headers +## API Endpoints -**HTML pages**: `no-cache, must-revalidate` — browsers always revalidate, ensuring fresh content after deploys. - -**Static assets** (CSS/JS/images): `public, immutable` with 1-year expiry. - -**Nginx config**: Built into the Dockerfile. - -If users report seeing old content after deployment: -1. Verify the container is running: `docker ps | grep hatch-web` -2. Check the HTML has new content: `curl -s http://localhost:8080 | head -5` -3. Ask user to hard refresh: Ctrl+Shift+R (Chrome/Firefox) or Cmd+Shift+R (Mac) +| Method | Path | Description | +|--------|-------------------------------|---------------------------------| +| GET | `/healthz` | Liveness probe | +| GET | `/readyz` | Readiness probe (checks DB) | +| GET | `/api/v1/spaces` | List public spaces | +| POST | `/api/v1/spaces` | Create a space | +| GET | `/api/v1/spaces/{slug}` | Get space by slug | +| POST | `/api/v1/spaces/{slug}/photos`| Upload photo to space | +| POST | `/api/v1/face/search` | Search faces by image | +| GET | `/e/{endpointID}` | Inspect captured requests | +| GET | `/e/{endpointID}/events` | SSE stream for live updates | --- @@ -185,26 +181,51 @@ If users report seeing old content after deployment: **Container not starting**: ```bash -docker logs hatch-web -docker compose -f /home/nara/apps/web/docker-compose.yml up -d +docker compose logs hatch +docker compose logs caddy ``` -**Changes not showing**: -1. Verify commit pushed: `git log --oneline -1` -2. Check container was rebuilt: `docker images | grep hatch-web` -3. Force rebuild: `cd /home/nara/apps/web && docker build -t hatch-web:latest . && docker compose up -d` +**Health check failing**: +```bash +curl -v http://localhost:8080/healthz +docker compose exec hatch /bin/hatch # Check binary exists +``` + +**Database issues**: +```bash +# SQLite database is persisted in a Docker volume +docker volume ls | grep hatch-data +docker run --rm -v hatch-data:/data alpine ls -la /data/ +``` **Port conflict**: ```bash -lsof -i :8080 +sudo lsof -i :8080 # Kill conflicting process or change port in docker-compose.yml ``` --- +## Integration Tests + +Integration tests require AWS credentials (build tag: `integration`): + +```bash +export AWS_REGION=us-east-1 +export REKOGNITION_COLLECTION=hatch-faces-test +go test -tags=integration ./internal/face/... -v +``` + +Performance benchmarks (build tag: `performance`): + +```bash +go test -tags=performance -bench=. ./internal/face/... +``` + +--- + ## Contact -- **DevOps**: Jing Yang (Sam Lee) - **CTO**: Jordan Patel - **Repository**: `/home/nara/apps/web/` -- **Live site**: https://hatch.surf +- **API**: http://localhost:8080 (internal) / https://hatch.surf (public) diff --git a/deploy.sh b/deploy.sh index 5154d1f7..b034c35e 100755 --- a/deploy.sh +++ b/deploy.sh @@ -1,9 +1,9 @@ #!/bin/bash -# Deploy hatch.surf - triggered by Gitea webhook or manually +# Deploy hatch.surf API — triggered by Gitea webhook or manually set -e -echo "=== Deploying hatch.surf ===" +echo "=== Deploying hatch API ===" cd /home/nara/apps/web # Pull latest changes from GitHub (primary source) @@ -12,20 +12,21 @@ git pull github main # Push to Gitea (push-mirror) git push origin main -# Build and deploy from site directory -cd site -docker build -t hatch-web:latest . -docker stop hatch-web 2>/dev/null || true -docker rm hatch-web 2>/dev/null || true -docker run -d --name hatch-web --restart unless-stopped -p 8080:80 hatch-web:latest -cd .. +# Stop old containers +docker compose down 2>/dev/null || true + +# Rebuild and start +docker compose build hatch +docker compose --profile with-caddy up -d # Verify -sleep 5 -if curl -s -o /dev/null -w "%{http_code}" http://localhost:8080 | grep -q "200"; then - echo "✅ hatch.surf deployed successfully!" +sleep 3 +if curl -s -o /dev/null -w "%{http_code}" http://localhost:8080/healthz | grep -q "200"; then + echo "✅ hatch API deployed successfully!" + echo " Health: http://localhost:8080/healthz" + echo " Ready: http://localhost:8080/readyz" else echo "❌ Deployment failed!" - docker logs hatch-web + docker compose logs --tail=20 hatch exit 1 fi