Update deployment: Go API backend with Docker Compose
Some checks are pending
CI / go (push) Waiting to run
CI / docker (push) Waiting to run
CI / lint-go (push) Waiting to run
CI / lint-docs (push) Waiting to run
CI / check-paperclip (push) Waiting to run

- 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
This commit is contained in:
Chris Anderson 2026-06-26 05:55:56 +02:00
parent ad0e78c9c9
commit 475fd95a59
2 changed files with 116 additions and 94 deletions

View File

@ -1,10 +1,10 @@
# Hatch Landing Page — Deployment Guide # Hatch API — Deployment Guide
## Overview ## 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/` **Location**: `/home/nara/apps/web/`
**Git Remotes**: **Git Remotes**:
- `github``elfoundation/hatch` (source of truth) - `github``el-foundation/hatch-surf` (Gitea, source of truth)
- `origin``el-foundation/hatch-surf` (Gitea push-mirror, deploys to hatch.surf) - `origin``el-foundation/hatch-surf` (Gitea push-mirror)
**Structure**: **Structure**:
``` ```
site/ # Static files served by nginx cmd/hatch/ # Go server entrypoint
index.html # Main landing page internal/ # Go packages (handler, store, face, etc.)
style.css # Styles Dockerfile # Multi-stage Docker build (Go → scratch)
main.js # Anime.js animations docker-compose.yml # Container orchestration (hatch + caddy)
Dockerfile # Docker build configuration (static files only) Caddyfile # Caddy reverse proxy config
docker-compose.yml # Container orchestration
deploy.sh # Deployment script deploy.sh # Deployment script
``` ```
@ -31,18 +30,11 @@ deploy.sh # Deployment script
## Deployment Flow ## 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) ### Automatic (Recommended)
1. Merge PR to GitHub `main` 1. Merge PR to `main`
2. Gitea webhook triggers `gitea-webhook.py` 2. Gitea webhook triggers `gitea-webhook.py`
3. Script runs `deploy.sh` automatically 3. Script runs `deploy.sh` automatically
4. `deploy.sh` pulls from GitHub, pushes to Gitea (push-mirror), rebuilds Docker, restarts
### Manual ### Manual
@ -54,56 +46,66 @@ cd /home/nara/apps/web
**What `deploy.sh` does**: **What `deploy.sh` does**:
1. `git pull github main` — fetches latest from GitHub (source of truth) 1. `git pull github main` — fetches latest from GitHub (source of truth)
2. `git push origin main` — syncs to Gitea (push-mirror) 2. `git push origin main` — syncs to Gitea (push-mirror)
3. `cd site && docker build -t hatch-web:latest .` — rebuilds image 3. `docker compose down` — stops current containers
4. Stops and removes old container 4. `docker compose build hatch` — rebuilds the Go binary in a multi-stage build
5. `docker run -d` — starts new container 5. `docker compose --profile with-caddy up -d` — starts hatch + caddy
6. Verifies deployment with health check 6. Verifies health endpoint responds 200
--- ---
## Docker Setup ## Docker Setup
**Container**: `hatch-web` **Services**:
**Port**: `8080` (mapped to host) | Service | Image | Port | Purpose |
**Internal**: nginx serving static files on port 80 |----------|----------------|-------|------------------------|
**Network**: `hatch-network` | `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**: **Check status**:
```bash ```bash
docker ps | grep hatch-web docker compose ps
docker logs hatch-web 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 ## Making Changes
### 1. Edit the static files ### 1. Edit Go source
```bash ```bash
cd /home/nara/apps/web cd /home/nara/apps/web
vim cmd/hatch/main.go # Server entrypoint
# Edit landing page vim internal/handler/ # HTTP handlers
vim out/index.html vim internal/face/ # Face detection service
vim internal/store/ # Database layer
# Edit styles
vim out/style.css
# Edit animations
vim out/main.js
``` ```
### 2. Test locally (optional) ### 2. Build and test locally
```bash ```bash
# Serve files locally go build ./cmd/hatch/
cd out && python3 -m http.server 3000 go test ./...
# Visit http://localhost:3000
``` ```
### 3. Commit and push ### 3. Commit and push
@ -124,23 +126,21 @@ Either wait for webhook or run manually:
### 5. Verify ### 5. Verify
```bash ```bash
curl -s http://localhost:8080 | head -20 curl -s http://localhost:8080/healthz
# Or visit https://hatch.surf curl -s http://localhost:8080/readyz
``` ```
--- ---
## Common Mistakes to Avoid ## Common Mistakes to Avoid
**DON'T**: Edit files in `/var/www/html/`
**DON'T**: Edit files directly inside the Docker container **DON'T**: Edit files directly inside the Docker container
**DON'T**: Work on static HTML/CSS files in a workspace without committing **DON'T**: Commit without testing
**DON'T**: Copy files to the server without using git **DON'T**: Use `go run` in production
**DO**: Edit files in `/home/nara/apps/web/out/` **DO**: Test with `go test ./...` before committing
**DO**: Commit changes to git **DO**: Use `docker compose build` for production builds
**DO**: Use `deploy.sh` for deployment **DO**: Check health endpoints after deployment
**DO**: Test locally before pushing
--- ---
@ -151,9 +151,6 @@ If a deployment causes issues:
```bash ```bash
cd /home/nara/apps/web cd /home/nara/apps/web
# View recent commits
git log --oneline -10
# Revert to previous version # Revert to previous version
git revert HEAD git revert HEAD
git push origin main git push origin main
@ -162,22 +159,21 @@ git push origin main
./deploy.sh ./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. | Method | Path | Description |
|--------|-------------------------------|---------------------------------|
**Static assets** (CSS/JS/images): `public, immutable` with 1-year expiry. | GET | `/healthz` | Liveness probe |
| GET | `/readyz` | Readiness probe (checks DB) |
**Nginx config**: Built into the Dockerfile. | GET | `/api/v1/spaces` | List public spaces |
| POST | `/api/v1/spaces` | Create a space |
If users report seeing old content after deployment: | GET | `/api/v1/spaces/{slug}` | Get space by slug |
1. Verify the container is running: `docker ps | grep hatch-web` | POST | `/api/v1/spaces/{slug}/photos`| Upload photo to space |
2. Check the HTML has new content: `curl -s http://localhost:8080 | head -5` | POST | `/api/v1/face/search` | Search faces by image |
3. Ask user to hard refresh: Ctrl+Shift+R (Chrome/Firefox) or Cmd+Shift+R (Mac) | 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**: **Container not starting**:
```bash ```bash
docker logs hatch-web docker compose logs hatch
docker compose -f /home/nara/apps/web/docker-compose.yml up -d docker compose logs caddy
``` ```
**Changes not showing**: **Health check failing**:
1. Verify commit pushed: `git log --oneline -1` ```bash
2. Check container was rebuilt: `docker images | grep hatch-web` curl -v http://localhost:8080/healthz
3. Force rebuild: `cd /home/nara/apps/web && docker build -t hatch-web:latest . && docker compose up -d` 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**: **Port conflict**:
```bash ```bash
lsof -i :8080 sudo lsof -i :8080
# Kill conflicting process or change port in docker-compose.yml # 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 ## Contact
- **DevOps**: Jing Yang (Sam Lee)
- **CTO**: Jordan Patel - **CTO**: Jordan Patel
- **Repository**: `/home/nara/apps/web/` - **Repository**: `/home/nara/apps/web/`
- **Live site**: https://hatch.surf - **API**: http://localhost:8080 (internal) / https://hatch.surf (public)

View File

@ -1,9 +1,9 @@
#!/bin/bash #!/bin/bash
# Deploy hatch.surf - triggered by Gitea webhook or manually # Deploy hatch.surf API — triggered by Gitea webhook or manually
set -e set -e
echo "=== Deploying hatch.surf ===" echo "=== Deploying hatch API ==="
cd /home/nara/apps/web cd /home/nara/apps/web
# Pull latest changes from GitHub (primary source) # Pull latest changes from GitHub (primary source)
@ -12,20 +12,21 @@ git pull github main
# Push to Gitea (push-mirror) # Push to Gitea (push-mirror)
git push origin main git push origin main
# Build and deploy from site directory # Stop old containers
cd site docker compose down 2>/dev/null || true
docker build -t hatch-web:latest .
docker stop hatch-web 2>/dev/null || true # Rebuild and start
docker rm hatch-web 2>/dev/null || true docker compose build hatch
docker run -d --name hatch-web --restart unless-stopped -p 8080:80 hatch-web:latest docker compose --profile with-caddy up -d
cd ..
# Verify # Verify
sleep 5 sleep 3
if curl -s -o /dev/null -w "%{http_code}" http://localhost:8080 | grep -q "200"; then if curl -s -o /dev/null -w "%{http_code}" http://localhost:8080/healthz | grep -q "200"; then
echo "✅ hatch.surf deployed successfully!" echo "✅ hatch API deployed successfully!"
echo " Health: http://localhost:8080/healthz"
echo " Ready: http://localhost:8080/readyz"
else else
echo "❌ Deployment failed!" echo "❌ Deployment failed!"
docker logs hatch-web docker compose logs --tail=20 hatch
exit 1 exit 1
fi fi