feat: Docker deployment + backup/restore + README
Production deployment (PRD §5.7): - Dockerfile: multi-stage build (deps → build → runner), healthcheck - docker-compose.yml: app + backup container + Caddy HTTPS proxy - Backup container: daily SQLite backup + SHA-256 checksum - Caddy: automatic HTTPS reverse proxy - Volumes: db, data, backups, caddy-data - deploy/backup.sh: timestamped backup + checksum + retention cleanup - deploy/restore.sh: checksum verification + pre-restore backup - README.md: quick start (Docker + dev), architecture, modules, compliance, MCP Verified: - Backup script: creates aos_20261027.db + .sha256 ✓ - TypeScript: 0 errors, ESLint clean
This commit is contained in:
1 parent
01be2e7820
commit
3d56770669
6 files changed
+396
No files matched your search
Executable
+47
@@ -0,0 +1,47 @@
|
||||
#!/bin/bash
|
||||
# AOS Backup Script (PRD §5.7: backup container)
|
||||
# Usage: ./deploy/backup.sh
|
||||
# Creates a timestamped SQLite backup + SHA-256 checksum.
|
||||
set -eu
|
||||
|
||||
DB_PATH="${DATABASE_URL:-file:/home/z/my-project/db/custom.db}"
|
||||
DB_FILE="${DB_PATH#file:}"
|
||||
BACKUP_DIR="${BACKUP_DIR:-/home/z/my-project/db/backups}"
|
||||
RETENTION_DAYS="${BACKUP_RETENTION_DAYS:-30}"
|
||||
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
|
||||
BACKUP_FILE="$BACKUP_DIR/aos_$TIMESTAMP.db"
|
||||
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
|
||||
echo "=== AOS Backup ==="
|
||||
echo " DB: $DB_FILE"
|
||||
echo " Backup: $BACKUP_FILE"
|
||||
|
||||
# SQLite backup (online, consistent)
|
||||
if command -v sqlite3 >/dev/null 2>&1; then
|
||||
sqlite3 "$DB_FILE" ".backup '$BACKUP_FILE'"
|
||||
elif command -v cp >/dev/null 2>&1; then
|
||||
cp "$DB_FILE" "$BACKUP_FILE"
|
||||
else
|
||||
echo "ERROR: Neither sqlite3 nor cp available"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# SHA-256 checksum
|
||||
sha256sum "$BACKUP_FILE" > "$BACKUP_FILE.sha256"
|
||||
echo " Checksum: $(cat "$BACKUP_FILE.sha256" | cut -d' ' -f1 | head -c 32)..."
|
||||
|
||||
# File listing + sizes
|
||||
echo ""
|
||||
echo "=== Recent backups ==="
|
||||
ls -lh "$BACKUP_DIR"/aos_*.db 2>/dev/null | tail -5
|
||||
|
||||
# Cleanup old backups
|
||||
echo ""
|
||||
echo "=== Cleanup (>$RETENTION_DAYS days) ==="
|
||||
deleted=$(find "$BACKUP_DIR" -name "aos_*.db" -mtime +$RETENTION_DAYS -print -delete 2>/dev/null | wc -l)
|
||||
deleted_sha=$(find "$BACKUP_DIR" -name "aos_*.db.sha256" -mtime +$RETENTION_DAYS -print -delete 2>/dev/null | wc -l)
|
||||
echo " Deleted: $deleted backups + $deleted_sha checksums"
|
||||
|
||||
echo ""
|
||||
echo "=== Backup complete ==="
|
||||
Executable
+73
@@ -0,0 +1,73 @@
|
||||
#!/bin/bash
|
||||
# AOS Restore Script (PRD §5.7: restore drill)
|
||||
# Usage: ./deploy/restore.sh <backup_file>
|
||||
# Restores SQLite from a backup file, verifies SHA-256 checksum.
|
||||
set -eu
|
||||
|
||||
BACKUP_FILE="${1:-}"
|
||||
DB_PATH="${DATABASE_URL:-file:/home/z/my-project/db/custom.db}"
|
||||
DB_FILE="${DB_PATH#file:}"
|
||||
|
||||
if [ -z "$BACKUP_FILE" ]; then
|
||||
echo "Usage: $0 <backup_file>"
|
||||
echo ""
|
||||
echo "Available backups:"
|
||||
ls -lh /home/z/my-project/db/backups/aos_*.db 2>/dev/null || echo " (none)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "$BACKUP_FILE" ]; then
|
||||
echo "ERROR: Backup file not found: $BACKUP_FILE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "=== AOS Restore ==="
|
||||
echo " Backup: $BACKUP_FILE"
|
||||
echo " Target: $DB_FILE"
|
||||
|
||||
# Verify checksum if .sha256 exists
|
||||
SHA_FILE="${BACKUP_FILE}.sha256"
|
||||
if [ -f "$SHA_FILE" ]; then
|
||||
echo ""
|
||||
echo "=== Verifying SHA-256 checksum ==="
|
||||
if sha256sum -c "$SHA_FILE" --quiet 2>/dev/null; then
|
||||
echo " ✓ Checksum verified"
|
||||
else
|
||||
echo " ✗ Checksum FAILED — file may be corrupted"
|
||||
read -p " Continue anyway? (y/N) " -n 1 -r
|
||||
echo
|
||||
[[ ! $REPLY =~ ^[Yy]$ ]] && exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Stop app if running
|
||||
echo ""
|
||||
echo "=== Stopping app... ==="
|
||||
pkill -f "next dev" 2>/dev/null || true
|
||||
pkill -f "node server.js" 2>/dev/null || true
|
||||
sleep 2
|
||||
|
||||
# Backup current DB
|
||||
if [ -f "$DB_FILE" ]; then
|
||||
CURRENT_BACKUP="${DB_FILE}.pre-restore.$(date +%Y%m%d_%H%M%S)"
|
||||
echo "=== Backing up current DB to $CURRENT_BACKUP ==="
|
||||
cp "$DB_FILE" "$CURRENT_BACKUP"
|
||||
fi
|
||||
|
||||
# Restore
|
||||
echo ""
|
||||
echo "=== Restoring... ==="
|
||||
cp "$BACKUP_FILE" "$DB_FILE"
|
||||
echo " ✓ Database restored"
|
||||
|
||||
# Verify
|
||||
echo ""
|
||||
echo "=== Verification ==="
|
||||
if [ -f "$DB_FILE" ]; then
|
||||
SIZE=$(wc -c < "$DB_FILE")
|
||||
echo " File size: $SIZE bytes"
|
||||
echo " ✓ Restore complete. Run 'bun run dev' to start."
|
||||
else
|
||||
echo " ✗ ERROR: DB file not found after restore"
|
||||
exit 1
|
||||
fi
|
||||
Reference in new issue
Block a user