| index d4ca391..abe4f94 100644 |
| --- a/CLAUDE.md |
| +++ b/CLAUDE.md |
| @@ -95,39 +95,33 @@ Add tests as you go. Go handler tests use `newTestServer(t)` which returns |
| |
| ## Deploy |
| |
| -Hosted on a Hetzner box via **Miren**, cluster `luanchat`. Each chat is a |
| -fully-isolated instance — its own Miren app, disk, admin token, and subdomain |
| -(e.g. `lchat`→group.luan.chat, plus `test`/`paja`/`paulandciara`/`miren`/`gav`/…). |
| -`miren app list -C luanchat` is the source of truth for what's live. |
| - |
| -DNS is a **wildcard** `*.luan.chat → <server IP>`, so a new instance needs no DNS |
| -step and gets TLS in seconds (Miren completes ACME on route-set since the name |
| -already resolves). Point a subdomain elsewhere with a specific record (it beats |
| -the wildcard). |
| - |
| -```sh |
| -# New instance — wildcard DNS covers it; this is the whole thing. |
| -./deploy-instance.sh <name> <name>.luan.chat # then add a 1Password token item |
| - |
| -# Update an existing instance — DATA-SAFE. Reuse its token; never mint a new one. |
| -TOK="$(miren env get LCHAT_ADMIN_TOKEN -u -a <app> -C luanchat)" |
| -./deploy-instance.sh <app> <host> "$TOK" |
| -``` |
| - |
| -- A plain `miren deploy` (what `deploy-instance.sh` runs) **preserves the disk**. |
| - **Never `miren app delete` to update** — that wipes the disk. Use delete only |
| - to intentionally reset an instance. |
| -- `deploy-instance.sh` **mints a new admin token if arg 3 is omitted** — always |
| - pass the recovered token for an existing instance. |
| -- Miren gotchas: use `LCHAT_ADMIN_TOKEN` (a bare `ADMIN_TOKEN` is auto-overridden |
| - by Miren); set env with `-e`, not `-s` (sensitive vars aren't injected). |
| -- `test` is the throwaway for verifying on real devices; keep experiments there. |
| +Deployed as a single binary on a container platform. Each chat is a |
| +**fully-isolated instance** — its own app, disk, admin token, and subdomain. |
| +`deploy-instance.sh` is the committed deploy script: it templates a per-instance |
| +config with a unique app + disk name and sets the route. |
| + |
| +> Environment specifics — server, platform/cluster name, the instance↔subdomain |
| +> map, DNS, and secret locations — live in **`CLAUDE.local.md`** (gitignored), |
| +> not here. |
| + |
| +Principles that hold regardless of environment: |
| + |
| +- **Deploys are data-safe.** A plain redeploy (what `deploy-instance.sh` runs) |
| + **preserves the disk**. **Never delete the app to update it** — that wipes the |
| + disk; delete only to intentionally reset an instance. DB migrations are additive |
| + (`CREATE TABLE IF NOT EXISTS`), so new code over old data is safe. |
| +- **Reuse an existing instance's admin token on redeploy** — `deploy-instance.sh` |
| + mints a new one if the token arg is omitted, which would invalidate saved links. |
| +- **Env contract:** the app reads `LCHAT_ADMIN_TOKEN`, `LCHAT_DB`, `ADDR`. Use the |
| + `LCHAT_`-prefix deliberately (a bare `ADMIN_TOKEN` can be auto-provisioned/ |
| + overridden by the platform). |
| +- Keep a **throwaway instance** for verifying on real devices. |
| |
| ## Commits |
| |
| -- Author is `paul@rslw.com` (set locally for this repo). |
| - Group into **logical commits**; prefix by area: `web:`, `server:`, `admin:`, |
| - `sw:`, `crypto:`. Frontend files (`chat.js`/`style.css`) are often touched by |
| - several features at once — commit by layer when they can't be cleanly split. |
| + `sw:`, `crypto:`, `docs:`. Frontend files (`chat.js`/`style.css`) are often |
| + touched by several features at once — commit by layer when they can't be split. |
| - End commit messages with the `Co-Authored-By:` trailer for the assisting model. |
| -- Commit/push/deploy only when asked. |
| +- Commit/push/deploy only when asked. (Author is set in the repo's local git |
| + config — see `CLAUDE.local.md`.) |