Files
famapp/deploy/backups/README.md
T
ginnoirandClaude Sonnet 4.6 285a460eb8 Implement tasks 60, 61, 62: backups, rate limiting, structured logging
Task 60 — Postgres backups:
- deploy/backups/: backup.sh (pg_dump -Fc nightly), retain.sh (14/8/6 tiers),
  restore.sh, entrypoint.sh, crontab
- famapp-backup Alpine service + backups volume added to deploy/compose.yaml
- Restore procedure in deploy/backups/README.md

Task 61 — Rate limiting on share links:
- src/lib/rate-limit.ts: Edge-compatible sliding-window counter (50/min, LRU eviction)
  with consume(), isRateLimited(), recordFailure() exports
- middleware.ts: enforces 429 with Retry-After: 60 for /s/[token] (IP + token prefix)
- /s/[token]/page.tsx: tracks only failed resolveShareToken calls via recordFailure()

Task 62 — Structured logging:
- pino + pino-pretty installed; serverExternalPackages added to next.config.ts
- src/lib/logger.ts: JSON in production, pretty in dev, level from LOG_LEVEL env
- middleware.ts: structured JSON request log (method, path, status, ms, authenticated)
- _core/push.ts, notify.ts, reminders.ts: console.error/log → logger.error/info

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 17:23:29 -05:00

103 lines
2.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Backups
The `famapp-backup` service performs nightly compressed `pg_dump` of both
`famapp-db` and `authentik-db` at **02:00 server time**.
## Storage layout
```
/backups/ (named Docker volume: famapp_backups)
famapp/
daily/ ← last 14 days
weekly/ ← last 8 Sundays
monthly/ ← last 6 first-of-month dumps
authentik/
daily/
weekly/
monthly/
```
Dump files are named `YYYY-MM-DD.dump` in custom (`-Fc`) format (internal
compression, ~35× smaller than plain SQL).
## Retention
| Tier | Kept | Trigger |
| ------- | ---- | --------------------- |
| daily | 14 | every night |
| weekly | 8 | Sunday night |
| monthly | 6 | 1st of the month |
Retention is enforced by `retain.sh` at the end of each `backup.sh` run.
## Restore procedure
### 1. Identify the dump
```sh
# List available dumps
docker exec famapp-backup-1 ls /backups/famapp/daily/
```
### 2a. Restore inside the backup container (recommended)
```sh
docker exec famapp-backup-1 /scripts/restore.sh \
/backups/famapp/daily/2024-06-01.dump \
postgres://famapp:SECRET@famapp-db:5432/famapp
```
Replace `SECRET` with the value of `FAMAPP_DB_PASSWORD` in your `.env` file.
For authentik:
```sh
docker exec famapp-backup-1 /scripts/restore.sh \
/backups/authentik/daily/2024-06-01.dump \
postgres://authentik:SECRET@authentik-db:5432/authentik
```
### 2b. Restore to a separate database (safe — non-destructive)
Create a fresh target database first, then restore into it:
```sh
# Create the target DB
docker exec famapp-db-1 createdb \
-U "$FAMAPP_DB_USER" famapp_restore
# Restore
docker exec famapp-backup-1 /scripts/restore.sh \
/backups/famapp/daily/2024-06-01.dump \
postgres://famapp:SECRET@famapp-db:5432/famapp_restore
```
### 2c. Restore on a fresh host (disaster recovery)
```sh
# Copy the dump file out of the volume
docker cp famapp-backup-1:/backups/famapp/daily/2024-06-01.dump ./
# Spin up a temporary Postgres container and restore
docker run --rm \
-e PGPASSWORD=SECRET \
-v "$(pwd)/2024-06-01.dump:/dump.dump:ro" \
postgres:16-alpine \
pg_restore -h <new-db-host> -U famapp -d famapp \
--no-owner --no-acl /dump.dump
```
## Off-site replication
The backups live in the `famapp_backups` Docker named volume. To copy them
to another host, rsync the volume's data directory periodically (e.g. from a
host cron job):
```sh
# On the Docker host, add to /etc/cron.d/famapp-rsync:
30 3 * * * root rsync -a --delete \
/var/lib/docker/volumes/famapp_backups/_data/ \
user@offsite-server:/opt/famapp-backups/
```
Encryption at rest is handled at the disk/filesystem layer (e.g. LUKS).