This repository has no description
README.md

Deployment #

Local Docker stack mirroring the planned Fly.io topology: a public Caddy front that serves our built SPA and reverse-proxies the AppView, plus a private HappyView instance. Same-origin, so no CORS and the atproto OAuth admin UI is reachable.

browser ─▶ http://127.0.0.1:8099  (caddy)
             /            → our SPA (../dist)
             /hv/*        → happyview  (dashboard, admin API, OAuth, client-metadata)
             /xrpc/*      → happyview  (rewritten to /hv/xrpc/*)
             /health      → happyview

First run #

# 1. Build the HappyView image from source (several minutes the first time)
./build-happyview.sh

# 2. Create secrets
cp .env.example .env
printf 'SESSION_SECRET=%s\n' "$(openssl rand -base64 48)" >> .env   # or edit .env by hand
printf 'TOKEN_ENCRYPTION_KEY=%s\n' "$(openssl rand -base64 32)" >> .env

# 3. Build the SPA (from the project root)
cd .. && npm run build && cd deploy

# 4. Up
docker compose up -d

Then:

Rebuild the SPA (npm run build) and refresh; Caddy serves ../dist live (no container rebuild).

Notes #

  • HappyView is not published to the host — only Caddy is. Caddy reaches it as happyview:3000 over the compose network (the Fly .internal equivalent).
  • PUBLIC_URL must be the Caddy origin and must NOT include /hv; HappyView appends BASE_PATH automatically when building OAuth callbacks.
  • The HappyView API client credentials (key hvc_… + secret hvs_…) are injected server-side by Caddy as the X-Client-Key / X-Client-Secret headers (see the (happyview_key) snippet in Caddyfile), sourced from HAPPYVIEW_CLIENT_KEY and HAPPYVIEW_CLIENT_SECRET in deploy/.env. Caddy strips any client-supplied values first, so they never have to ship in the SPA bundle and can't be spoofed by callers. {env.…} is read from Caddy's process at startup — after changing either value, run docker compose up -d --force-recreate caddy (a reload alone won't pick up a new env var).
  • The SPA is local-first (records in IndexedDB); wiring it to HappyView XRPC for sync is a later phase. This stack proves the serving + proxy topology.
  • After editing Caddyfile, run docker compose up -d --force-recreate caddy. Docker on macOS bind-mounts a single file by inode, so replacing the file (any editor that writes atomically) leaves the container on the stale copy — caddy reload then validates the old content. Force-recreating re-binds the current file.
  • Host port is 8099 (8080 was already taken locally). Change it in docker-compose.yml and PUBLIC_URL together — PUBLIC_URL feeds OAuth redirect URIs.