# پشتیبان‌گیری و بازیابی

## چه چیزی پشتیبان گرفته می‌شود

`php bin/console backup:run` دو فایل در `BACKUP_PATH` (پیش‌فرض `storage/backups`) می‌سازد:

| فایل | محتوا |
|---|---|
| `gostardeh-YYYYmmdd-HHMMSS.sql.gz` | Dump کامل دیتابیس (`mysqldump --single-transaction --quick --routines`)، فشرده با gzip. شامل همه‌ی تنظیمات پنل (جدول `settings`). |
| `gostardeh-YYYYmmdd-HHMMSS.env` | کپی `.env` (شامل `APP_KEY`) |

- `--single-transaction` یعنی بدون قفل‌کردن جدول‌ها و بدون توقف ربات.
- رمز دیتابیس از طریق متغیر محیطی به `mysqldump` داده می‌شود، نه در خط فرمان.
- فایل‌ها `chmod 600` می‌شوند.
- **Rotation**: فایل‌های قدیمی‌تر از `BACKUP_RETENTION_DAYS` (پیش‌فرض ۱۴ روز) حذف می‌شوند.
- شکست پشتیبان‌گیری در لاگ ثبت و به چت مدیر اطلاع داده می‌شود؛ کد خروج ۱ است.

زمان‌بندی (از قبل در `deploy/cron/gostardeh`):

```cron
15 3 * * *  gostardeh  /usr/bin/php /var/www/gostardeh/bin/console backup:run >> /var/www/gostardeh/storage/logs/backup.log 2>&1
```

## نگهداری خارج از سرور

پشتیبانی که روی همان سرور بماند، پشتیبان نیست. فایل‌ها را رمزشده به جای دیگری بفرستید؛ مثلاً:

```bash
# /etc/cron.d/gostardeh-offsite  — بعد از backup:run
45 3 * * *  gostardeh  rclone copy /var/www/gostardeh/storage/backups remote-crypt:gostardeh --max-age 2d
```

(`remote-crypt` یک Remote از نوع `crypt` در rclone است.) فایل `.env` حاوی `APP_KEY` و کلیدهای درگاه است؛ فقط در مقصد رمزشده نگه‌داری شود. یک نسخه‌ی جداگانه از `APP_KEY` را هم در Password Manager داشته باشید.

## بازیابی

> بازیابی دیتابیس فعلی را **جایگزین** می‌کند.

```bash
# ۱. توقف پردازش
sudo supervisorctl stop 'gostardeh:*'
sudo systemctl stop php8.3-fpm            # Webhookها موقتاً 502 می‌گیرند؛ تلگرام دوباره می‌فرستد

# ۲. (اختیاری ولی توصیه‌شده) از وضعیت فعلی هم یک نسخه بگیرید
sudo -u gostardeh php bin/console backup:run

# ۳. بازیابی .env متناظر (حتماً همان APP_KEY)
sudo -u gostardeh cp storage/backups/gostardeh-20260101-031500.env .env && sudo chmod 600 .env

# ۴. بازیابی دیتابیس
sudo -u gostardeh php bin/console backup:restore storage/backups/gostardeh-20260101-031500.sql.gz --force

# ۵. اعمال Migrationهایی که بعد از آن پشتیبان اضافه شده‌اند
sudo -u gostardeh php bin/console migrate

# ۶. پاک‌کردن Cache و Stateهای قدیمی، سپس راه‌اندازی
redis-cli -a "$REDIS_PASSWORD" --scan --pattern 'gst:cache:*' | xargs -r redis-cli -a "$REDIS_PASSWORD" del
sudo systemctl start php8.3-fpm
sudo supervisorctl start 'gostardeh:*'
sudo -u gostardeh php bin/console health:check
```

نکته‌ها:

- **`APP_KEY` باید همان کلیدِ زمان پشتیبان باشد**؛ در غیر این صورت توکن ربات‌ها، کارت‌ها و اطلاعات هویتی خوانده نمی‌شوند. اگر کلید گم شده: `bot:add` را دوباره اجرا کنید (توکن از نو رمز می‌شود)؛ حساب‌های بانکی و درخواست‌های KYC باید دوباره ثبت شوند.
- صف Redis بعد از بازیابی ممکن است به ردیف‌هایی اشاره کند که دیگر وجود ندارند؛ Jobها در این حالت بی‌صدا رد می‌شوند. برای شروع تمیز می‌توانید کلیدهای `gst:q:*` را هم پاک کنید — کارهای جامانده (اعلان، سفارش پرداخت‌شده، پیام همگانی) توسط Jobهای دوره‌ای دوباره در صف قرار می‌گیرند.
- پرداخت‌هایی که بین زمان پشتیبان و بازیابی انجام شده‌اند در دیتابیس نیستند؛ فهرست تراکنش‌های درگاه/زنجیره را با `payments` تطبیق دهید و موارد جامانده را با «اصلاح موجودی» (با ثبت دلیل) جبران کنید.

## آزمون بازیابی

پشتیبانی که هیچ‌وقت بازیابی نشده قابل اتکا نیست. ماهی یک‌بار روی یک دیتابیس جدا:

```bash
mysql -e "CREATE DATABASE gostardeh_restore_test"
gunzip -c storage/backups/<آخرین فایل>.sql.gz | mysql gostardeh_restore_test
mysql gostardeh_restore_test -e "SELECT COUNT(*) FROM users; SELECT COUNT(*) FROM wallet_transactions; SELECT MAX(created_at) FROM wallet_transactions;"
mysql -e "DROP DATABASE gostardeh_restore_test"
```
