# Бэкап и восстановление

Артефакты в репозитории (`deploy/`):

- `food-market-backup.sh` — скрипт бэкапа БД + uploads с ротацией.
- `food-market-backup.service` — systemd oneshot-юнит, запускающий скрипт.
- `food-market-backup.timer` — ежедневный таймер (03:00, с догоном пропущенных).

> Установку на prod-vm выполняет отдельный деплой-шаг (см. ниже) — здесь только
> подготовленные артефакты.

## Что бэкапится

| Что | Как | Файл |
|---|---|---|
| База данных | `pg_dump -Fc` из контейнера `food-market-postgres` | `db-<TS>.dump` (custom-format) |
| Загруженные файлы (картинки товаров) | `tar czf` каталога uploads | `uploads-<TS>.tgz` |

Папка назначения по умолчанию — `/opt/food-market-data/backups`. Хранение —
30 дней (`FM_BACKUP_RETENTION_DAYS`), старые удаляются ротацией. Конфиг —
переменными `FM_*` (см. шапку `food-market-backup.sh`).

## Установка таймера на сервере (деплой-шаг)

Предполагается, что репозиторий выложен в `/opt/food-market` (иначе скорректировать
`ExecStart`/`EnvironmentFile` в `.service` и пути ниже).

```bash
sudo install -m 0755 /opt/food-market/deploy/food-market-backup.sh /opt/food-market/deploy/food-market-backup.sh
sudo cp /opt/food-market/deploy/food-market-backup.service /etc/systemd/system/
sudo cp /opt/food-market/deploy/food-market-backup.timer   /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now food-market-backup.timer

# Проверить расписание и последний запуск
systemctl list-timers food-market-backup.timer
# Прогнать бэкап немедленно (разово)
sudo systemctl start food-market-backup.service
journalctl -u food-market-backup.service --no-pager | tail -20
```

## Ручной бэкап

```bash
sudo /opt/food-market/deploy/food-market-backup.sh
# или с переопределением каталога:
FM_BACKUP_DIR=/mnt/backups sudo -E /opt/food-market/deploy/food-market-backup.sh
```

## Восстановление БД

> ⚠️ Восстановление перезаписывает данные. Сначала остановить API, чтобы не было
> записи во время восстановления.

```bash
cd /opt/food-market/deploy
docker compose stop api web

DUMP=/opt/food-market-data/backups/db-YYYYMMDD-HHMMSS.dump

# Скопировать дамп внутрь контейнера БД
docker cp "$DUMP" food-market-postgres:/tmp/restore.dump

# Вариант A — восстановить в чистую БД (рекомендуется):
docker exec food-market-postgres psql -U food_market -d postgres -c \
  "DROP DATABASE IF EXISTS food_market WITH (FORCE); CREATE DATABASE food_market OWNER food_market;"
docker exec food-market-postgres pg_restore -U food_market -d food_market --no-owner /tmp/restore.dump

# Вариант B — в существующую БД, заменив объекты (без пересоздания БД):
# docker exec food-market-postgres pg_restore -U food_market -d food_market --clean --if-exists --no-owner /tmp/restore.dump

docker exec food-market-postgres rm -f /tmp/restore.dump
docker compose start api web
```

После старта API применит миграции (`Migrate()` идемпотентен) и поднимется. Проверить:

```bash
curl -fsS http://localhost:8080/health/ready
```

## Восстановление uploads

```bash
TGZ=/opt/food-market-data/backups/uploads-YYYYMMDD-HHMMSS.tgz
# tar содержит каталог uploads/ — распаковать в родителя смонтированного пути
sudo tar xzf "$TGZ" -C /opt/food-market-data/
```

(Каталог `/opt/food-market-data/uploads` смонтирован в контейнер api как `/app/uploads`.)

## Проверка дампа без восстановления

```bash
docker cp <dump> food-market-postgres:/tmp/v.dump
docker exec food-market-postgres pg_restore --list /tmp/v.dump | head   # TOC валидного архива
docker exec food-market-postgres rm -f /tmp/v.dump
```

Скрипт и формат проверены локально (2026-05-27): дамп `PGDMP`, custom-format,
248 TOC-записей, `pg_restore --list` читает.
