SPB Git

Repository Public

OPERATIONS.md 5.8 KB 106 lines markdown

1# Operations23## Where things are45| What | Where |6|---|---|7| Site | https://calendar.spboucher.ai (Caddy on BHS64 → WireGuard → M4M64c:8660) |8| Node | **M4M64c** (pinned). Source of truth: `M4M64c:~/apps/sp-calendar` (git, origin `gitsrv:srv/git/sp-calendar.git`) |9| Processes (PM2) | `sp-calendar-web` (next start), `sp-calendar-worker` (tsx), `sp-calendar-backup` (cron 03:35) |10| Database | PostgreSQL 17 on M4M64c, database `sp_calendar`, role `spcal_app` |11| Secrets | `M4M64c:~/apps/sp-calendar/.env` (600), `~/.config/sp-calendar/backup-passphrase` (600); laptop copy `~/Desktop/Cluster/secrets/sp-calendar/` |12| Backups | `M4M64c:~/backups/sp-calendar/*.dump.enc` (30 days) |13| Enrolment link | `M4M64c:~/data/sp-calendar/setup-url.txt` (first passkey, valid 7 days from the first deploy) |14| mld manifest | `M1M32:~/dispatch/apps/sp-calendar.json` (copy: `infra/mld/sp-calendar.json`) |1516## First sign-in (owner)17181. `ssh M4M64c cat ~/data/sp-calendar/setup-url.txt` and open the link **on the device whose Touch ID / Face ID you19   want to use** (Safari or Chrome). Expired? `ssh M4M64c 'cd ~/apps/sp-calendar && node_modules/.bin/tsx scripts/setup-token.ts'`.202. Create the passkey, then store the eight recovery codes.213. In Settings → Security, add a second passkey from another device (the dashboard reminds you until you do).22   With iCloud Keychain the passkey syncs to your other Apple devices by itself.2324## Recovery2526- A device is lost but you have a recovery code: sign-in page → "Utiliser un code de récupération", then add a passkey.27- Everything is lost: `ssh M4M64c 'cd ~/apps/sp-calendar && node_modules/.bin/tsx scripts/setup-token.ts --recovery'`28  (30-minute link; enrolling with it removes every other passkey and signs out every session).2930## Changing the application (remote-first)3132```bash33ssh M4M64c34cd ~/apps/sp-calendar            # edit here35export PATH=/opt/homebrew/opt/postgresql@17/bin:/opt/homebrew/bin:$PATH36pnpm install --frozen-lockfile   # only if dependencies changed37node_modules/.bin/tsx scripts/migrate.ts          # applies new db/migrations/*.sql once each (checksummed)38node_modules/.bin/next build && pm2 restart sp-calendar-web sp-calendar-worker39curl -s http://127.0.0.1:8660/api/health40git add -A && git commit -m "…" && git push origin main41```4243Migrations are append-only: never edit an applied file (the runner refuses a changed checksum).44`mld deploy sp-calendar` redeploys from the gateway's staging and refuses when the node repo is ahead (by design).4546## E-mail4748`.env`: `MAIL_TRANSPORT=resend` + `RESEND_API_KEY=…` + `MAIL_FROM="SP Calendar <calendar@your-verified-domain>"`,49or `MAIL_TRANSPORT=smtp` + `SMTP_URL=smtps://user:pass@host:465`. Then50`pm2 restart sp-calendar-web sp-calendar-worker --update-env`, and in the admin area: Settings → Notifications →51send a test e-mail, then "Remettre en file" for the notifications parked while the transport was not configured.52The log shows, per message, the transport's message id or the error. `MAIL_TRANSPORT=none` parks everything.5354## Health and monitoring5556- `GET /api/health` → `{ ok, db, worker: { ok, ageSec }, mail: { configured } }` (503 when the database is down).57  `mld heal` (every 5 minutes on M1M32) restarts missing PM2 processes and repairs the tunnel route.58- Dashboard alerts: worker stopped, e-mail not configured / parked / dead, stale external calendar, request whose59  time is no longer free, single passkey.60- Logs: `pm2 logs sp-calendar-web`, `pm2 logs sp-calendar-worker`. No request body is logged.61- Audit trail: Settings → Audit (who did what, when).6263## Backups and restore6465Daily 03:35: `pg_dump` → AES-256 → `~/backups/sp-calendar/`, verified by decrypting and listing the archive.66Run now: `pm2 restart sp-calendar-backup` (or `bash scripts/backup.sh`).6768Restore test (do it after any change to the backup script, and from time to time):6970```bash71createdb sp_calendar_restore_test72bash scripts/restore.sh ~/backups/sp-calendar/<latest>.dump.enc postgres://127.0.0.1:5432/sp_calendar_restore_test73psql -d sp_calendar_restore_test -c "select count(*) from bookings"; dropdb sp_calendar_restore_test74```7576Real restore: stop both processes, restore into an empty `sp_calendar` owned by `spcal_app`, start them.77The passphrase is NOT in the backups: keep `~/Desktop/Cluster/secrets/sp-calendar/backup-passphrase` safe.78Off-node copy of the backups is not set up (see PLAN.md).7980## Moving to another node8182The database does not follow `mld move`. Stop the processes, `scripts/backup.sh`, create role and database on83the new node, copy `.env` and the passphrase, `scripts/restore.sh`, change the pin in the manifest, `mld deploy`.84Passkeys keep working (they are bound to the domain).8586## Tests8788```bash89pnpm typecheck && pnpm lint90pnpm test            # Vitest against a real PostgreSQL (database sp_calendar_test, created empty beforehand)91scripts/e2e.sh       # Playwright, desktop + mobile, production build, throw-away database sp_calendar_e2e,92                     # real SMTP transport into a local sink, WebAuthn with Chromium's virtual authenticator93pnpm secrets:scan94```9596## Troubleshooting9798| Symptom | Check |99|---|---|100| Passkey prompt refuses | The site must be opened at exactly `APP_URL`'s host; passkeys are bound to `calendar.spboucher.ai`. |101| "Lien d'enregistrement invalide" | One use, limited life: issue a new one with `scripts/setup-token.ts`. |102| Visitor links all invalid | `APP_SECRET` changed: links derive from it. Restore the previous value. |103| No e-mail leaves | Settings → Notifications: transport state and per-message error. |104| Public page shows no slots | Availability (weekly hours, exceptions), type's notice / horizon / limits, private events, external calendars set to block. |105| Automatic confirmations became requests | An external calendar is stale (Settings → Integrations); policy in Settings → Profile. |106
Files main
Menu

Theme