hatch-surf/DEPLOYMENT.md
Chris Anderson 475fd95a59
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 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
2026-06-26 05:55:56 +02:00

232 lines
5.8 KiB
Markdown

# Hatch API — Deployment Guide
## Overview
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.
---
## Repository
**Location**: `/home/nara/apps/web/`
**Git Remotes**:
- `github``el-foundation/hatch-surf` (Gitea, source of truth)
- `origin``el-foundation/hatch-surf` (Gitea push-mirror)
**Structure**:
```
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
```
---
## Deployment Flow
### Automatic (Recommended)
1. Merge PR to `main`
2. Gitea webhook triggers `gitea-webhook.py`
3. Script runs `deploy.sh` automatically
### Manual
```bash
cd /home/nara/apps/web
./deploy.sh
```
**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. `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
**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 compose ps
docker compose logs hatch
docker compose logs caddy
```
---
## 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 Go source
```bash
cd /home/nara/apps/web
vim cmd/hatch/main.go # Server entrypoint
vim internal/handler/ # HTTP handlers
vim internal/face/ # Face detection service
vim internal/store/ # Database layer
```
### 2. Build and test locally
```bash
go build ./cmd/hatch/
go test ./...
```
### 3. Commit and push
```bash
git add .
git commit -m "Description of changes"
git push origin main
```
### 4. Deploy
Either wait for webhook or run manually:
```bash
./deploy.sh
```
### 5. Verify
```bash
curl -s http://localhost:8080/healthz
curl -s http://localhost:8080/readyz
```
---
## Common Mistakes to Avoid
**DON'T**: Edit files directly inside the Docker container
**DON'T**: Commit without testing
**DON'T**: Use `go run` in production
**DO**: Test with `go test ./...` before committing
**DO**: Use `docker compose build` for production builds
**DO**: Check health endpoints after deployment
---
## Rollback
If a deployment causes issues:
```bash
cd /home/nara/apps/web
# Revert to previous version
git revert HEAD
git push origin main
# Redeploy
./deploy.sh
```
---
## API Endpoints
| 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 |
---
## Troubleshooting
**Container not starting**:
```bash
docker compose logs hatch
docker compose logs caddy
```
**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
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
- **CTO**: Jordan Patel
- **Repository**: `/home/nara/apps/web/`
- **API**: http://localhost:8080 (internal) / https://hatch.surf (public)