Backups and recovery

A dump and a prune on a cron, and what to do when you need them.

The remote backend's state lives in a Docker volume. docker compose stop and docker compose down preserve it; docker compose down -v destroys it, as does a Docker Desktop reset.

Built-in backup commands

cd backend/

make backup         # writes backups/rememd-<utc-timestamp>.sql.gz
make backup-list    # ls the backups folder
make backup-prune   # keep the 20 most recent, delete the rest
make restore FILE=backups/rememd-20260413T120000Z.sql.gz

make restore is atomic: it stops the server, terminates any lingering DB connections, drops and re-creates the database, loads the dump, and restarts the server. Asks for explicit y confirmation first because it's destructive.

The ./backups folder is just a regular directory. Let Time Machine, iCloud Drive, a cron-pushed S3 upload, or a git repo take it from there - whichever matches how you back up the rest of your work.

Hourly automation (optional)

Add a launchd plist or a cron entry:

0 * * * * cd ~/Desktop/DEV/prompto/backend && /usr/bin/make backup >/dev/null && /usr/bin/make backup-prune >/dev/null

That's hourly backups, pruned to the 20 most recent. Roughly 70KB per dump for a small team - you won't notice the disk cost.

Tested disaster scenarios

The following has been verified end-to-end:

  1. make backup → wipe volume with docker compose down -vdocker compose upmake restore FILE=...all workspaces/users/tokens back, auth works with the same tokens as before.

What's NOT backed up

  • Your local ~/Recall/ (back that up separately - it's a plain folder).
  • The ~/.recall/remote.json token files on each user's machine. These are regeneratable via rememd join.

Scale ceiling you'll hit before needing these

  • Single-instance in-memory pub/sub means live push doesn't fan out across horizontally-scaled backends. Fine up to one backend box.
  • ILIKE-based search works up to ~100 workspaces; past that, add a Postgres tsvector generated column.
  • No rate limiting on /invites or /join yet - deploy behind your VPN or wait for rate limits before exposing to strangers.