Дамп backup.sh — это одна база, а роли живут в кластере и уезжают соседним
файлом gendesign_globals_<ts>.sql.gz. Сам дамп на эти роли ссылается: OWNER TO
и GRANT. psql здесь идёт с ON_ERROR_STOP=1, поэтому на кластере, где ролей ещё
нет, восстановление обрывается на первом же таком операторе — но данные к тому
моменту уже залиты и закоммичены, в одну транзакцию psql дамп не оборачивает.
Итог: наполовину собранная база и невнятная ошибка в самом конце, после всей
работы.
Ровно этот путь и нужен при переезде: на новом хосте кластер пустой, ролей нет.
Теперь соседний globals подхватывается автоматически и грузится первым — так
уже давно устроен ops/restore-drill.sh, разошлись только эти два скрипта.
Правило имени взято оттуда же.
Побочный эффект назван в шапке прямо: globals несёт пароли ролей на момент
снятия дампа, и если пароль меняли после, он вернётся к старому. Для поднятия
кластера с нуля это правильное поведение, для точечного отката данных в живой
базе — нет, поэтому есть RESTORE_SKIP_GLOBALS=1 и RESTORE_GLOBALS_FILE.
Сам globals грузится БЕЗ ON_ERROR_STOP: на живом кластере роли уже есть и
CREATE ROLE для каждой законно падает с already exists. Значимая часть — идущие
следом ALTER ROLE, они отрабатывают.
Если соседа нет и он не отключён явно — печатаем предупреждение ДО заливки,
чтобы «упадёт через час» не стало сюрпризом. Не падаем: на живом кластере роли
на месте и всё пройдёт как раньше.
Проверено: bash -n; ветка автоопределения прогнана на паре файлов с реальными
именами — сосед находится. Поведение на живом кластере не меняется: globals
идёт первым, дальше всё как было.
Refs #3057
Оба скрипта закоммичены как 100644, хотя соседние по каталогу backup.sh и
uptime-healthcheck.sh — 100755. На прод-VM файлы лежат с +x, поэтому
`git status` в /opt/gendesign постоянно показывает их как modified:
M ops/docker-prune.sh
M ops/restore.sh (old mode 100644 / new mode 100755, контент идентичен)
Функционально это ничего не ломает: cron зовёт docker-prune.sh через
`bash <путь>`, restore.sh запускают руками так же. Проблема в другом —
постоянный M в прод-репозитории обесценивает единственный дешёвый сигнал,
по которому видно ручную правку файла на проде. Шум надо убирать, а не
привыкать к нему.
Приводим режим к тому, что реально на диске и что уже стоит у соседей.
- backend/alembic/* — alembic infra (env.py, script.py.mako). versions/ empty
for now; first migration goes in Stage 2a when models are finalized.
- backend/Dockerfile: bake alembic.ini + alembic/ into the image so
`docker compose exec backend alembic upgrade head` works in prod.
- backend/db/init/99_drop_unused_extensions.sql + bind-mount in both compose
files: drops postgis-image's TIGER/topology/fuzzystrmatch on fresh volumes.
- .pre-commit-config.yaml + pre-commit in dev deps: ruff/prettier on commit
to stop CI failures like UP035 from leaking out.
- ops/backup.sh, ops/restore.sh: pg_dump cron script with optional Selectel S3
upload. 7-day local retention. Restore guard: requires RESTORE_CONFIRM=yes.
- Makefile: new targets `make migration NAME=...`, `make pre-commit-install`.
- backend/.env.example: SENTRY_DSN comment with sentry.io reference.