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
@@ -0,0 +1,90 @@
|
||||
# AOS — Agency Operating System
|
||||
# Docker Compose for production (PRD §5.7: Containers: app, postgres, caddy, backup)
|
||||
# Usage: docker compose up -d
|
||||
|
||||
services:
|
||||
app:
|
||||
build: .
|
||||
container_name: aos-app
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "3000:3000"
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
- DATABASE_URL=file:/app/db/custom.db
|
||||
- PORT=3000
|
||||
- HOSTNAME=0.0.0.0
|
||||
# Set these in .env or docker-compose.override.yml
|
||||
- ENCRYPTION_KEY=${ENCRYPTION_KEY:-change-me-32-bytes}
|
||||
- AUTH_SECRET=${AUTH_SECRET:-change-me-auth-secret}
|
||||
volumes:
|
||||
- aos-db:/app/db
|
||||
- aos-data:/app/data
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:3000/api/health"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
|
||||
# Backup container (PRD §5.7: backup container)
|
||||
# Runs daily at 03:00, backs up SQLite + uploads volume
|
||||
backup:
|
||||
image: alpine:latest
|
||||
container_name: aos-backup
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
app:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
- BACKUP_SCHEDULE=0 3 * * *
|
||||
- BACKUP_RETENTION_DAYS=30
|
||||
volumes:
|
||||
- aos-db:/data/db:ro
|
||||
- aos-backups:/backups
|
||||
entrypoint:
|
||||
- sh
|
||||
- -c
|
||||
- |
|
||||
apk add --no-cache sqlite curl
|
||||
echo "AOS Backup service started. Schedule: $$BACKUP_SCHEDULE"
|
||||
while true; do
|
||||
sleep 86400
|
||||
TIMESTAMP=$$(date +%Y%m%d_%H%M%S)
|
||||
echo "[$$TIMESTAMP] Starting backup..."
|
||||
# Backup SQLite
|
||||
sqlite3 /data/db/custom.db ".backup /backups/aos_$$TIMESTAMP.db"
|
||||
# Checksum
|
||||
sha256sum /backups/aos_$$TIMESTAMP.db > /backups/aos_$$TIMESTAMP.db.sha256
|
||||
# Cleanup old backups
|
||||
find /backups -name "aos_*.db" -mtime +$$BACKUP_RETENTION_DAYS -delete
|
||||
find /backups -name "aos_*.db.sha256" -mtime +$$BACKUP_RETENTION_DAYS -delete
|
||||
echo "[$$TIMESTAMP] Backup complete: aos_$$TIMESTAMP.db"
|
||||
done
|
||||
|
||||
# Caddy reverse proxy (HTTPS)
|
||||
caddy:
|
||||
image: caddy:2-alpine
|
||||
container_name: aos-caddy
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
app:
|
||||
condition: service_healthy
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
volumes:
|
||||
- caddy-data:/data
|
||||
- caddy-config:/config
|
||||
command: |
|
||||
caddy reverse-proxy --from :443 --to app:3000
|
||||
|
||||
volumes:
|
||||
aos-db:
|
||||
driver: local
|
||||
aos-data:
|
||||
driver: local
|
||||
aos-backups:
|
||||
driver: local
|
||||
caddy-data:
|
||||
caddy-config:
|
||||
Reference in new issue
Block a user