lila/documentation/ai-context/06-deployment.md
2026-05-16 01:59:43 +02:00

144 lines
6.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 06 — Deployment
> **Purpose:** Condensed infrastructure reference for LLMs working on deployment, CI/CD, or ops tasks. For full setup details (VPS provisioning, Forgejo configuration, backup scripts), see the human-readable DEPLOYMENT.md.
> **Last updated:** 2026-05-15
> **Depends on:** 00-project-overview.md
---
## Infrastructure Overview
```
Internet
Caddy (Docker container, ports 80/443)
├── lilastudy.com → web container (nginx:alpine, static files)
├── api.lilastudy.com → api container (Express, port 3000)
└── git.lilastudy.com → forgejo container (git + registry, port 3000)
SSH (port 2222) → forgejo container (git push/pull)
```
**VPS:** Hetzner, Debian 13, ARM64 (aarch64), 4GB RAM
**Domain:** lilastudy.com, wildcard `*.lilastudy.com` configured
**Only Caddy faces the internet.** All other services communicate over internal Docker network.
---
## Docker Compose Stack
Services on shared `lila-network`:
| Service | Image | Ports (internal) | Notes |
| -------- | ------------------------------------------------ | ---------------- | -------------------------------------------------- |
| caddy | caddy:alpine | 80, 443 | Only container with published ports |
| api | `git.lilastudy.com/forgejo-lila/lila-api:latest` | 3000 | Multi-stage Dockerfile, runs migrations on startup |
| web | `git.lilastudy.com/forgejo-lila/lila-web:latest` | 80 | nginx:alpine, SPA fallback via try_files |
| database | postgres:16 | 5432 | Named volume `lila-db` for persistence |
| forgejo | forgejo:... | 3000, 2222 | Git + container registry, SSH on 2222 |
**No ports exposed on internal services.** Only Caddy (80/443) and Forgejo SSH (2222) are public.
---
## Build & Deploy Flow
```
Dev laptop: git push to main
Forgejo Actions triggers (runner on VPS)
Build API image (target: runner)
Build Web image (target: production, VITE_API_URL baked in)
Push both to git.lilastudy.com registry
SSH into VPS, docker compose pull, restart containers
API container runs migrations on startup (migrate.js before server.js)
App updated (~25 min total)
```
**Cross-compilation:** Images built natively on ARM64 VPS (no QEMU). Dev laptop used for initial pushes before CI/CD was set up.
---
## Environment-Driven Config
Same code runs in dev and production. Environment variables control behavior:
| Variable | Dev | Production |
| ----------------- | ------------------------------------ | ------------------------------------------------- |
| `DATABASE_URL` | `postgres://...@localhost:5432/lila` | `postgres://...@database:5432/lila` |
| `BETTER_AUTH_URL` | `http://localhost:3000` | `https://api.lilastudy.com` |
| `CORS_ORIGIN` | `http://localhost:5173` | `https://lilastudy.com` |
| `COOKIE_DOMAIN` | undefined | `.lilastudy.com` |
| `VITE_API_URL` | `http://localhost:3000` | `https://api.lilastudy.com` (baked at build time) |
**Note:** `VITE_API_URL` is baked into the frontend at Docker build time via `--build-arg`. It cannot be changed at runtime.
---
## Database
### Migrations
Drizzle migrations run automatically on API container startup. The Dockerfile entrypoint:
```dockerfile
CMD ["node", "dist/src/migrate.js", "&&", "node", "dist/src/server.js"]
```
**Deploy order enforced automatically:** migrations before server starts.
### Backups
- Daily cron job at 3:00 AM: `pg_dump` → compressed SQL → `~/backups/`
- 7-day retention on VPS
- Dev laptop auto-syncs new backups on login via `rsync`
- **Offsite storage:** Planned (Hetzner Object Storage or S3-compatible)
### Seeding
Idempotent (`onConflictDoNothing`). Safe to re-run for adding new languages without affecting existing data or user tables.
---
## Auth & OAuth
**Better Auth** embedded in Express API. No separate auth service.
**Social providers:**
- Google OAuth — consent screen in testing mode (100 user cap). Must publish before reaching 80 users.
- GitHub OAuth — configured for both dev and production redirect URIs
**Cross-subdomain cookies:** `COOKIE_DOMAIN=.lilastudy.com` (leading dot) makes auth cookie valid across all subdomains.
---
## Known Issues & Limitations
| Issue | Impact | Status |
| --------------------------------- | ---------------------------------------------------------------------------------- | ---------------------------- |
| lila-web has no healthcheck | Vite dev server has no health endpoint; `depends_on` uses API healthcheck as proxy | Acceptable for dev |
| Valkey memory overcommit warning | Harmless in dev. Fix before production: `vm.overcommit_memory = 1` | Documented |
| No centralized monitoring/logging | No uptime alerts or log aggregation on VPS | Planned (BACKLOG.md) |
| Backups only on VPS + dev laptop | No offsite protection against VPS failure | Planned (BACKLOG.md) |
| Google OAuth in testing mode | 100 user cap | Must publish before 80 users |
---
## Key Files
| File | Purpose |
| ------------------------------- | ------------------------------------------------------ |
| `docker-compose.yml` (root) | Local dev stack |
| `docker-compose.yml` (VPS) | Production stack |
| `apps/api/Dockerfile` | Multi-stage: deps → dev → builder → runner |
| `apps/web/Dockerfile` | Multi-stage: deps → dev → builder → production (nginx) |
| `apps/web/nginx.conf` | SPA fallback routing |
| `Caddyfile` | Reverse proxy routing, automatic HTTPS |
| `.forgejo/workflows/deploy.yml` | CI/CD pipeline |
| `apps/api/src/migrate.ts` | Drizzle migration runner |