Skip to content

docs(operating): object storage first-class, and a disaster-recovery runbook - #167

Merged
jouwdan merged 1 commit into
mainfrom
claude/redis-horizontal-scaling-9ubvr2
Aug 20, 2026
Merged

docs(operating): object storage first-class, and a disaster-recovery runbook#167
jouwdan merged 1 commit into
mainfrom
claude/redis-horizontal-scaling-9ubvr2

Conversation

@jouwdan

@jouwdan jouwdan commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator

Two documentation gaps at the operations layer, closed. The S3 file store has existed and worked (R2, MinIO, Spaces via S3_ENDPOINT) with no guide saying how to adopt it, and there was no page for the day the server is gone.

Object storage, documented for real

operating.md § Where uploads go gains:

  • A per-provider table for the parts that actually vary — S3_REGION/S3_ENDPOINT for AWS, Cloudflare R2, DigitalOcean Spaces and MinIO — plus the path-style-addressing note and the scope the credential needs.
  • A fact verified in the code before writing it down: the board serves every avatar, attachment and logo through its own routes with its own permission checks, so the bucket stays private — no public access, no CORS, nothing to get right.
  • Moving a board from local disk to S3, step by step. Store keys map 1:1 (.uploads/avatars/7.webp → object avatars/7.webp; the database stores keys, not URLs), so the migration is copy → cut over on web and worker → incremental second copy to close the upload window → verify before deleting the volume. The reverse migration gets a sentence.

scaling.md's uploads step now links this as the canonical procedure.

The disaster-recovery runbook

New docs/disaster-recovery.md, written to be followed under stress:

  • What recovery consumes — the three artifacts held off the machine, and what losing each one costs (a lost AUTH_SECRET strands every enrolled authenticator app; sessions survive because they are hashed tokens in the database).
  • The order — provision at the same release tag, environment, database, uploads (on S3: nothing to restore, which the page calls most of the argument for S3), verify against localhost while DNS still points at the corpse, cut over, and restart the backup cron the new machine does not have.
  • Partial losses are smaller pages — a routing table for the common bad days, including "the Valkey cache died: do nothing".
  • Rehearse it, and write the number down — the measured-recovery-time guidance, extended from the backup section's existing advice.

Registered in the manifest under Running the server and linked from the docs index, the backup section, self-hosting.md and scaling.md; the root README table is regenerated from the manifest. site:docs:check, docs:index:check and lint pass. Docs only — no code changes.

🤖 Generated with Claude Code

https://claude.ai/code/session_01RZsbkeeetS4Fh9nvGLC97M


Generated by Claude Code

…runbook

The S3 file store existed and worked with R2, MinIO and Spaces, and no
guide said how to adopt it. Where uploads go now carries the provider
endpoint table, the fact that the bucket stays private because the board
serves every file through its own permission checks, and the local-to-S3
migration — copy, cut over, copy again to close the gap, verify before
deleting anything.

docs/disaster-recovery.md is the new full-loss runbook: the three
artifacts recovery consumes and what losing each one costs, the order of
operations from provisioning to DNS cutover, the partial losses that have
shorter answers, and the rehearsal that turns the page from a hope into a
measured recovery time. Registered in the manifest and linked from the
index, the backup section, self-hosting and the scaling guide.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RZsbkeeetS4Fh9nvGLC97M
@jouwdan
jouwdan merged commit 7edf5f1 into main Aug 20, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants