Initial commit: moon-household-budget

This commit is contained in:
Bonna
2026-06-06 19:12:43 -05:00
commit a3b91f6d6b
57 changed files with 11944 additions and 0 deletions

13
backup/Dockerfile Normal file
View File

@@ -0,0 +1,13 @@
# Tiny rclone + sqlite sidecar that backs up /data to Backblaze B2 on a loop.
FROM alpine:3.20
RUN apk add --no-cache rclone sqlite tzdata
COPY backup.sh /backup.sh
RUN chmod +x /backup.sh
ENV BACKUP_INTERVAL=86400
# Run once on boot, then every BACKUP_INTERVAL seconds. A failed run is logged
# but does not kill the loop.
CMD ["sh", "-c", "while true; do /backup.sh || echo '[backup] FAILED'; sleep \"${BACKUP_INTERVAL}\"; done"]

44
backup/backup.sh Normal file
View File

@@ -0,0 +1,44 @@
#!/bin/sh
# Back up the app's data under /data (the budget JSON files, imported PDFs/CSVs,
# and uploaded images). This app stores everything as plain JSON files — there
# is no SQLite database.
#
# Always writes a timestamped tar.gz to the local NAS path (/backups, mounted
# from the host). ALSO pushes to Backblaze B2 — but only when a real bucket and
# credentials are configured, so it's harmless before B2 is set up.
#
# rclone's B2 remote ("b2:") is configured from the RCLONE_CONFIG_B2_* env vars.
# Runs once; the container loops it on BACKUP_INTERVAL.
set -eu
STAMP=$(date +%Y%m%d-%H%M%S)
KEEP_DAYS="${BACKUP_KEEP_DAYS:-30}"
LOCAL_DIR="/backups"
echo "[backup ${STAMP}] starting"
# 1. Local timestamped snapshot of everything under /data ---------------------
mkdir -p "${LOCAL_DIR}"
ARCHIVE="${LOCAL_DIR}/moon-data-${STAMP}.tar.gz"
tar -czf "${ARCHIVE}" -C /data .
echo "[backup ${STAMP}] local snapshot: ${ARCHIVE} ($(du -h "${ARCHIVE}" | cut -f1))"
# prune old local snapshots
find "${LOCAL_DIR}" -name 'moon-data-*.tar.gz' -type f -mtime +"${KEEP_DAYS}" -delete 2>/dev/null || true
# 2. Optional Backblaze B2 push (only when a real bucket + key are set) --------
if [ -n "${B2_BUCKET:-}" ] && [ "${B2_BUCKET#__}" = "${B2_BUCKET}" ] \
&& [ -n "${RCLONE_CONFIG_B2_ACCOUNT:-}" ] && [ "${RCLONE_CONFIG_B2_ACCOUNT#__}" = "${RCLONE_CONFIG_B2_ACCOUNT}" ]; then
DEST="b2:${B2_BUCKET}/moon-household-budget"
if rclone copyto "${ARCHIVE}" "${DEST}/snapshots/moon-data-${STAMP}.tar.gz" 2>/tmp/rclone.err; then
rclone sync /data "${DEST}/current" 2>>/tmp/rclone.err || true
rclone delete --min-age "${KEEP_DAYS}d" "${DEST}/snapshots" 2>/dev/null || true
echo "[backup ${STAMP}] pushed to B2 (${B2_BUCKET})"
else
echo "[backup ${STAMP}] B2 push FAILED: $(head -1 /tmp/rclone.err 2>/dev/null)"
fi
else
echo "[backup ${STAMP}] B2 not configured — local snapshot only"
fi
echo "[backup ${STAMP}] done"