feat(stack): full overhaul — hardening, ops tooling, monitoring, analytics, chatbot

Security: deep /api/health (DB+MinIO probes, 503 on failure) + /api/live;
rate-limited public forms with honeypots; real client IP behind Traefik
(--proxy-headers); TipTap URL sanitization on write (nh3); non-root
containers + slim .dockerignore; prod MinIO console bound to 127.0.0.1;
HSTS/nosniff on TLS routers; JWT 8h; no default credentials in code.

Reliability: Alembic migrations (create_all baseline); graceful shutdown
(exec uvicorn); hardened backups (checksums, sanity check, freshness gauge,
optional rclone off-site) + restore.sh + hourly db-backup sidecar (ops
profile); stack.sh ops tooling (deploy/logs/health/backup/restore/monitoring);
.gitattributes LF for shell scripts.

Orchestration: json-file log rotation, pinned images, per-service memory
limits, edge/internal networks, Traefik ping/accesslog/metrics + flood
limiter, conditional minio-setup, pgvector db image, one-shot db-init
(umami + aramesh_chatbot databases).

Chatbot: unified from site-chatbot branch (RAG + pgvector, SSE, ChatWidget).

Monitoring: Prometheus/Alertmanager/Loki/Promtail/Grafana + cAdvisor,
node/postgres/blackbox exporters, provisioned dashboards and 10 alert
rules; alerts delivered to Bale (tapi.bale.ai — Telegram-compatible).

Analytics: Umami on shared Postgres, build-time tracker injection, custom
events (contact/newsletter/phone/chat/lang) via frontend/src/analytics.ts.

Hygiene: CSV export for contact messages and subscribers; upload image
optimization (Pillow); CI script + GitHub-compatible workflow; audit.sh;
gen-env.sh for strong credentials.
This commit is contained in:
MMD
2026-09-19 00:24:57 +03:30
parent 805f4594d4
commit ce0735d775
75 changed files with 4287 additions and 153 deletions
+32 -3
View File
@@ -4,8 +4,12 @@
# اجرا: bash scripts/backup.sh
# زمان‌بندی: cron (لینوکس) یا Task Scheduler (ویندوز)، مثلا هر شب ساعت ۳:
# 0 3 * * * cd /path/to/aramesh-backend && bash scripts/backup.sh >> backups/backup.log 2>&1
# یا سرویس db-backup در پروفایل ops (پشتیبان ساعتی DB بدون cron میزبان).
#
# نگهداری: فایل‌های قدیمی‌تر از RETENTION_DAYS (پیش‌فرض ۱۴) حذف می‌شوند.
# انتشار خارج از سرور: اگر OFFSITE_RCLONE_REMOTE تنظیم شده باشد (در .env، مثل
# OFFSITE_RCLONE_REMOTE=storage:aramesh-backups)، بعد از هر پشتیبان rclone copy انجام می‌شود.
# تازگی پشتیبان: backups/backup_freshness.prom برای هشدار «پشتیبان کهنه» در Grafana نوشته می‌شود.
set -euo pipefail
cd "$(dirname "$0")/.."
@@ -14,7 +18,7 @@ RETENTION_DAYS="${RETENTION_DAYS:-14}"
STAMP="$(date +%Y%m%d-%H%M%S)"
mkdir -p backups
# متغیرهای .env (برای MINIO_ROOT_*) در دسترس قرار می‌گیرند
# متغیرهای .env (برای MINIO_ROOT_* و OFFSITE_RCLONE_REMOTE) در دسترس قرار می‌گیرند
if [ -f .env ]; then
set -a
# shellcheck disable=SC1091
@@ -26,7 +30,18 @@ echo "[backup] $STAMP"
# ۱) دیتابیس — همه متن‌ها، مقاله‌ها و تنظیمات سایت
DB_FILE="backups/db-${STAMP}.sql.gz"
docker compose exec -T db pg_dump -U aramesh arameshplaza | gzip > "$DB_FILE"
# --exit-on-error: اگر pg_dump وسط کار خطا بگیرد، پشتیبان ناقص تولید نمی‌شود
docker compose exec -T db pg_dump --exit-on-error -U aramesh arameshplaza | gzip > "$DB_FILE"
# پشتیبان خالی/کوچک یعنی خرابی — زودتر بفهمیم تا «روز نیاز»
MIN_DB_BYTES=1024
DB_BYTES=$(wc -c < "$DB_FILE" | tr -d ' ')
if [ "$DB_BYTES" -lt "$MIN_DB_BYTES" ]; then
echo "[backup] ✗ پشتیبان دیتابیس شکسته است (${DB_BYTES} بایت)" >&2
rm -f "$DB_FILE"
exit 1
fi
sha256sum "$DB_FILE" > "${DB_FILE}.sha256"
echo "[backup] db: $DB_FILE ($(du -h "$DB_FILE" | cut -f1))"
# ۲) تصاویر MinIO — باکت aramesh-media
@@ -36,9 +51,23 @@ docker compose run --rm -v "$(pwd)/backups:/backups" --entrypoint sh mc -c "
"
echo "[backup] images: backups/images-${STAMP}"
# ۳) پاک‌سازی نسخه‌های قدیمی‌تر
# ۳) انتشار خارج از سرور (اختیاری) — هر شب کپی به حافظهٔ دیگری
if [ -n "${OFFSITE_RCLONE_REMOTE:-}" ]; then
if command -v rclone >/dev/null 2>&1; then
rclone copy backups "${OFFSITE_RCLONE_REMOTE}" --max-age 48h
echo "[backup] offsite: ${OFFSITE_RCLONE_REMOTE}"
else
echo "[backup] هشدار: OFFSITE_RCLONE_REMOTE تنظیم است اما rclone نصب نیست" >&2
fi
fi
# ۴) پاک‌سازی نسخه‌های قدیمی‌تر
find backups -name 'db-*.sql.gz' -mtime "+${RETENTION_DAYS}" -delete
find backups -name 'db-*.sql.gz.sha256' -mtime "+${RETENTION_DAYS}" -delete
find backups -maxdepth 1 -type d -name 'images-*' -mtime "+${RETENTION_DAYS}" -exec rm -rf {} +
echo "[backup] پاک‌سازی نسخه‌های قدیمی‌تر از ${RETENTION_DAYS} روز انجام شد"
# ۵) سنجهٔ تازگی پشتیبان — Prometheus آن را می‌خواند؛ کهنه‌شدن یعنی کرون خفتی است
printf 'backup_success_time %s\n' "$(date +%s)" > backups/backup_freshness.prom
echo "[backup] ✔ تمام شد"