Backup & Maintenance

PicFast includes a Maintenance Dashboard in the admin console to view disk health, database statistics, and pHash coverage, along with a built-in cleanup tool. For deeper operations, the picfast maintenance CLI handles consistency checks, backups, restores, and thumbnail repairs.

Admin Dashboard

Navigate to Maintenance in the admin console to monitor system health and perform routine cleanups:

  • Disk Health: Real-time storage capacity, usage, and inode statistics for the local backend.
  • Database Stats: Overview of row counts, sizes, and pHash calculation coverage.
  • Cleanup Tool: Identify and delete unlinked objects from the storage backend (files without a database record).
  • Risk Audit: Check for configurations that might pose a security or operational risk.

CLI: Before you run

  • Use the same configuration as the running instance (config.yaml / environment) so the CLI can reach PostgreSQL and your storage backends.
  • In Docker Compose examples below, replace <service> with your actual Compose service name for PicFast (many examples use app; yours may differ — check docker-compose.yml).
  • Large deployments: prefer a maintenance window — doctor and full backups can read many objects.

Command shape

docker compose exec <service> picfast maintenance <subcommand> [flags]

Use picfast maintenance --help and picfast maintenance <subcommand> --help for flags (--json, --all, --pg-dump-container, etc.).

Subcommands

SubcommandRole
doctorRead‑only check of DB rows, stored objects, and thumbnails.
backupWrites a PostgreSQL custom‑format dump and can package object payloads into an archive.
inspectValidates manifest.json and checksums inside a backup tarball.
restorePreflight by default; --apply performs writes. Restoring into a non‑empty database requires --force.
repair-thumbnailsRebuilds missing thumbnails from source objects (dry‑run unless --apply).
recalc-phashRecalculates missing perceptual hashes (pHash) for all eligible images.

Typical order

  1. Check: picfast maintenance doctor --all --batch-size 500
  2. Backup: picfast maintenance backup --output /app/data/backups/picfast-backup.tar.gz (adjust path to match your volume mounts)
  3. Verify archive: picfast maintenance inspect /app/data/backups/picfast-backup.tar.gz
  4. Restore (on the target host, after checks): picfast maintenance restore … --apply — add --force only when you intend to overwrite a non‑empty database.

PostgreSQL client tools

If the host does not have pg_dump / pg_restore, the CLI can shell into a Postgres container (e.g. --pg-dump-container / --pg-restore-container) — see --help on backup and restore.

Automated Backups

Use host cron to schedule recurring backups — no code changes needed. Two complementary strategies:

TypeFrequencyScopeRetention
db-onlyHourlyPostgreSQL metadata onlyLast 48 copies
fullDailyDatabase + object filesLast 7 copies

Step 1: Database backup script

Create /opt/picfast/backup-db.sh:

#!/bin/bash
set -euo pipefail

CONTAINER="${1:-picfast-db}"
BACKUP_DIR="${2:-/opt/picfast/data/backups}"
DB_USER="${3:-picfast}"
DB_NAME="${4:-picfast}"
RETENTION="${5:-48}"

TIMESTAMP=$(date +%Y%m%d-%H%M)
OUTPUT="$BACKUP_DIR/db-$TIMESTAMP.dump.gz"
mkdir -p "$BACKUP_DIR"

docker exec "$CONTAINER" pg_dump --format=custom -U "$DB_USER" -d "$DB_NAME" \
    | gzip > "$OUTPUT"

echo "Backup written: $OUTPUT ($(du -h "$OUTPUT" | cut -f1))"

# Purge expired backups
ls -1t "$BACKUP_DIR"/db-*.dump.gz 2>/dev/null \
    | tail -n +$((RETENTION + 1)) \
    | xargs -r rm -v
chmod +x /opt/picfast/backup-db.sh

Step 2: Full backup script

Create /opt/picfast/backup-full.sh:

#!/bin/bash
set -euo pipefail

PROJECT_DIR="${1:-/opt/picfast}"
COMPOSE_FILE="${2:-$PROJECT_DIR/docker/docker-compose.yml}"
RETENTION="${3:-7}"

TIMESTAMP=$(date +%Y%m%d)
OUTPUT="$PROJECT_DIR/data/backups/full-$TIMESTAMP.tar.gz"

cd "$PROJECT_DIR"
docker compose -f "$COMPOSE_FILE" run --rm app \
    picfast maintenance backup \
    --output "/app/data/backups/full-$TIMESTAMP.tar.gz"

echo "Full backup written: $OUTPUT"
ls -1t "$PROJECT_DIR"/data/backups/full-*.tar.gz \
    | tail -n +$((RETENTION + 1)) \
    | xargs -r rm -v
chmod +x /opt/picfast/backup-full.sh

Step 3: Cron schedule

crontab -e
# PicFast automated backups
0 * * * * /opt/picfast/backup-db.sh picfast-db /opt/picfast/data/backups picfast picfast 48
0 3 * * * /opt/picfast/backup-full.sh /opt/picfast /opt/picfast/docker/docker-compose.yml 7

Step 4 (optional): Offsite sync

Push backup directory and static files to remote storage with rclone:

30 3 * * * rclone sync /opt/picfast/data/backups   remote:bucket/picfast-backups
30 3 * * * rclone sync /opt/picfast/data/uploads   remote:bucket/picfast-uploads
30 3 * * * rclone sync /opt/picfast/data/thumbnails remote:bucket/picfast-thumbnails

Restore from backup

# Database only
gunzip -c /opt/picfast/data/backups/db-20260728-1400.dump.gz | \
    docker exec -i picfast-db pg_restore --clean --if-exists --no-owner -U picfast -d picfast

# Full recovery
docker compose -f docker/docker-compose.yml run --rm app \
    picfast maintenance restore /app/data/backups/full-20260728.tar.gz --apply --force

Full archive specification

Manifest schema, objects.jsonl vs checksum ledger, compatibility rules, and safety notes for operators and contributors live in the PicFast repo: docs/maintenance.md.