From c4a59d7bf24ece545ee6dc396522811b05109918 Mon Sep 17 00:00:00 2001 From: nns Date: Tue, 6 Oct 2026 00:35:54 +0500 Subject: [PATCH] =?UTF-8?q?docs(prod):=20=D1=80=D0=B5=D0=BF=D0=B0=20=D0=B4?= =?UTF-8?q?=D0=BE=D0=B3=D0=BE=D0=BD=D1=8F=D0=B5=D1=82=20=D0=BD=D0=BE=D0=B2?= =?UTF-8?q?=D1=83=D1=8E=20=D1=80=D0=B0=D1=81=D0=BA=D0=BB=D0=B0=D0=B4=D0=BA?= =?UTF-8?q?=D1=83=20postgres=20=D0=BD=D0=B0=20prod-vm?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 05.10.2026 общий postgres-инстанс с чужими боевыми базами (sklad, purchase, calcman, calcman_staging, makesales + мусорная старая food_market) вынесен из compose прода food-market в отдельный compose-проект shared-postgres (контейнер shared-postgres, порт 5434, том food-market-postgres-data external). Прод food-market поднимается в собственный контейнер food-market-prod-postgres (порт 5437, том food-market-prod-postgres-data). Простой при разделении — 12с, соседи живы. См. docs/shared-postgres-followup-progress.md. Этот коммит синхронизирует репозиторий, чтобы следующий деплой из main не воскресил старую раскладку: - deploy/docker-compose.yml: container_name/port/volume приведены к прод-файлу (food-market-prod-postgres, 127.0.0.1:5437, food-market-prod-postgres-data). - deploy/shared-postgres/ (новое): документационная копия соседнего compose'а, с явной пометкой «food-market им не управляет». - deploy/food-market-backup.sh / anonymize-prod.sh / db-schema-diff.sh: defaults FM_PG_CONTAINER / FM_PROD_CONT = food-market-prod-postgres. - docs/RUNBOOK.md: новый раздел «Postgres на prod-vm» с таблицей трёх инстансов и явным запретом трогать shared-postgres из наших скриптов. - docs/backup-restore.md: контейнер в таблице и примерах — новый. Guards (не в репе — живут в ~/deploy-stage.sh и ~/quality-watchdog.sh) расширены симметрично: стенду запрещены shared-postgres, food-market-prod- postgres[-data], 5434/5437; проду — food-market-postgres-data (чужие данные). Проверка: docker compose config/ps на prod-vm shared-postgres не упоминают, grep по репе — ни один скрипт не делает docker exec в shared-postgres. --- deploy/anonymize-prod.sh | 8 +++- deploy/db-schema-diff.sh | 13 ++++-- deploy/docker-compose.yml | 26 ++++++++++-- deploy/food-market-backup.sh | 9 ++-- deploy/shared-postgres/README.md | 17 ++++++++ deploy/shared-postgres/docker-compose.yml | 50 +++++++++++++++++++++++ docs/RUNBOOK.md | 47 +++++++++++++++++++-- docs/backup-restore.md | 26 ++++++++---- docs/shared-postgres-followup-progress.md | 24 +++++++++++ 9 files changed, 194 insertions(+), 26 deletions(-) create mode 100644 deploy/shared-postgres/README.md create mode 100644 deploy/shared-postgres/docker-compose.yml create mode 100644 docs/shared-postgres-followup-progress.md diff --git a/deploy/anonymize-prod.sh b/deploy/anonymize-prod.sh index 2d09e3d..6817b87 100755 --- a/deploy/anonymize-prod.sh +++ b/deploy/anonymize-prod.sh @@ -21,14 +21,18 @@ # deploy/anonymize-prod.sh [--source ] [--target ] # [--out ] [--dry-run] # -# Default source: ssh prod docker exec food-market-postgres pg_dump +# Default source: ssh prod docker exec food-market-prod-postgres pg_dump # Default target: local postgres@14 with TEMP DB food_market_anon # Default out: /home/nns/food-market-anon-YYYYMMDD.sql.gz +# +# ВАЖНО: контейнер food-market-prod-postgres (с 2026-10-05). НЕ shared-postgres — +# тот принадлежит соседнему compose-проекту с чужими боевыми базами (sklad, +# purchase, calcman, calcman_staging, makesales). См. docs/shared-postgres-followup-progress.md. set -uo pipefail SOURCE_HOST="${FM_PROD_HOST:-nns@admin.food-market.kz}" -SOURCE_CONTAINER="${FM_PROD_CONT:-food-market-postgres}" +SOURCE_CONTAINER="${FM_PROD_CONT:-food-market-prod-postgres}" SOURCE_DB="${FM_PG_DB:-food_market}" SOURCE_USER="${FM_PG_USER:-food_market}" LOCAL_USER="${PGUSER:-nns}" diff --git a/deploy/db-schema-diff.sh b/deploy/db-schema-diff.sh index 465c3d3..bf5834c 100755 --- a/deploy/db-schema-diff.sh +++ b/deploy/db-schema-diff.sh @@ -7,8 +7,13 @@ # # Подразумевает что обе БД доступны (например через SSH-туннель или # pg_dump --host=). Дефолтные подключения: -# stage = docker exec food-market-stage-postgres-1 pg_dump (через ssh dev-vm) -# prod = docker exec food-market-postgres pg_dump (через ssh prod-vm) +# stage = docker exec food-market-stage-postgres pg_dump (через ssh prod-vm) +# prod = docker exec food-market-prod-postgres pg_dump (через ssh prod-vm) +# +# ВАЖНО: прод-контейнер — `food-market-prod-postgres` (с 2026-10-05). Соседний +# `shared-postgres` на той же машине обслуживает ЧУЖИЕ боевые базы (sklad, +# purchase, calcman, calcman_staging, makesales) и в diff не участвует. +# См. docs/shared-postgres-followup-progress.md. # # Usage: # deploy/db-schema-diff.sh [--stage-host HOST] [--prod-host HOST] @@ -24,8 +29,8 @@ set -uo pipefail STAGE_HOST="${FM_STAGE_HOST:-nns@192.168.1.190}" PROD_HOST="${FM_PROD_HOST:-nns@admin.food-market.kz}" -STAGE_CONT="${FM_STAGE_CONT:-food-market-stage-postgres-1}" -PROD_CONT="${FM_PROD_CONT:-food-market-postgres}" +STAGE_CONT="${FM_STAGE_CONT:-food-market-stage-postgres}" +PROD_CONT="${FM_PROD_CONT:-food-market-prod-postgres}" DB="${FM_PG_DB:-food_market}" DB_USER="${FM_PG_USER:-food_market}" QUICK=0 diff --git a/deploy/docker-compose.yml b/deploy/docker-compose.yml index e90d4ea..e42982c 100644 --- a/deploy/docker-compose.yml +++ b/deploy/docker-compose.yml @@ -1,16 +1,32 @@ +# Прод-compose food-market. +# +# ВАЖНО (2026-10-05): у food-market свой postgres прода — контейнер +# `food-market-prod-postgres`, том `food-market-prod-postgres-data`, порт +# `127.0.0.1:5437`. На prod-vm параллельно существует отдельный compose-проект +# `shared-postgres` (~/shared-postgres/docker-compose.yml, порт 5434, том +# `food-market-postgres-data` *external*) с ЧУЖИМИ боевыми базами (sklad, +# purchase, calcman, calcman_staging, makesales). Он food-market НЕ принадлежит +# и в этот compose возвращаться НЕ должен. См. docs/shared-postgres-followup-progress.md. +# +# Guards в ~/deploy-stage.sh и ~/quality-watchdog.sh падают, если здесь появится +# `shared-postgres`, `food-market-postgres-data`, порт `5434` или старое имя +# контейнера `food-market-postgres`. + services: postgres: image: ${REGISTRY:-127.0.0.1:5001}/mirror/postgres:16-alpine - container_name: food-market-postgres + container_name: food-market-prod-postgres restart: unless-stopped environment: POSTGRES_DB: food_market POSTGRES_USER: food_market POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-food_market_dev} PGDATA: /var/lib/postgresql/data/pgdata - # Stage VM already uses 5432 (host postgres) — map ours to 5434 to avoid clash. + # prod-vm занят: 5432 — host postgres, 5434 — shared-postgres (чужой), + # 5435 — stage-postgres, 5436 — food-market-server-postgres (сосед). + # Нам остаётся 5437. ports: - - "127.0.0.1:5434:5432" + - "127.0.0.1:5437:5432" volumes: - postgres-data:/var/lib/postgresql/data healthcheck: @@ -88,7 +104,9 @@ services: volumes: postgres-data: - name: food-market-postgres-data + # ВАЖНО: НЕ `food-market-postgres-data` — тот том принадлежит отдельному + # проекту shared-postgres (чужие боевые базы). См. docs/shared-postgres-followup-progress.md. + name: food-market-prod-postgres-data api-data: name: food-market-api-data api-logs: diff --git a/deploy/food-market-backup.sh b/deploy/food-market-backup.sh index 2ec0359..d219a61 100755 --- a/deploy/food-market-backup.sh +++ b/deploy/food-market-backup.sh @@ -2,7 +2,7 @@ # # food-market: ежедневный бэкап БД + загруженных файлов с ротацией. # -# Дампит Postgres (контейнер food-market-postgres) в custom-формат pg_dump +# Дампит Postgres (контейнер food-market-prod-postgres) в custom-формат pg_dump # (-Fc, пригоден для pg_restore с параллелизмом/выборочным восстановлением) и # архивирует каталог uploads. Удаляет бэкапы старше RETENTION_DAYS дней. # @@ -10,16 +10,19 @@ # вручную. Конфигурируется переменными окружения (значения по умолчанию # совпадают с deploy/docker-compose.yml): # -# FM_PG_CONTAINER имя контейнера Postgres (food-market-postgres) +# FM_PG_CONTAINER имя контейнера Postgres (food-market-prod-postgres) # FM_PG_DB имя БД (food_market) # FM_PG_USER пользователь БД (food_market) # FM_BACKUP_DIR куда складывать бэкапы (/opt/food-market-data/backups) # FM_UPLOADS_DIR каталог изображений (/opt/food-market-data/uploads) # FM_BACKUP_RETENTION_DAYS срок хранения, дней (30) # +# ВАЖНО: НЕ `food-market-postgres` и НЕ `shared-postgres` — это контейнер +# соседнего compose-проекта с ЧУЖИМИ боевыми базами (sklad, purchase, calcman, +# calcman_staging, makesales). См. docs/shared-postgres-followup-progress.md. set -euo pipefail -CONTAINER="${FM_PG_CONTAINER:-food-market-postgres}" +CONTAINER="${FM_PG_CONTAINER:-food-market-prod-postgres}" DB="${FM_PG_DB:-food_market}" DB_USER="${FM_PG_USER:-food_market}" BACKUP_DIR="${FM_BACKUP_DIR:-/opt/food-market-data/backups}" diff --git a/deploy/shared-postgres/README.md b/deploy/shared-postgres/README.md new file mode 100644 index 0000000..033b19c --- /dev/null +++ b/deploy/shared-postgres/README.md @@ -0,0 +1,17 @@ +# deploy/shared-postgres/ + +Снимок стороннего compose-проекта `shared-postgres` с prod-vm, положенный в репу +как справочник. **Food-market этим compose'ом не управляет** — он живёт на +prod-vm в `~/shared-postgres/` и там же обслуживается. Любой скрипт food-market, +который трогает `shared-postgres`, том `food-market-postgres-data`, порт 5434 — +баг (guards падают). + +Контекст: 2026-10-05 общий postgres-инстанс с чужими боевыми базами (`sklad`, +`purchase`, `calcman`, `calcman_staging`, `makesales` + мусорная старая +`food_market`) вынесен из compose прода food-market в отдельный compose-проект. +См. [`docs/shared-postgres-followup-progress.md`](../../docs/shared-postgres-followup-progress.md) +и [`docs/RUNBOOK.md`](../../docs/RUNBOOK.md) → раздел «Postgres на prod-vm». + +Прод food-market ходит в **свой** postgres: `food-market-prod-postgres`, +том `food-market-prod-postgres-data`, порт `127.0.0.1:5437` — описан в +`deploy/docker-compose.yml`. diff --git a/deploy/shared-postgres/docker-compose.yml b/deploy/shared-postgres/docker-compose.yml new file mode 100644 index 0000000..ddca1c8 --- /dev/null +++ b/deploy/shared-postgres/docker-compose.yml @@ -0,0 +1,50 @@ +# ────────────────────────────────────────────────────────────────────────── +# shared-postgres: ДОКУМЕНТАЦИОННАЯ копия стороннего compose'а на prod-vm. +# ────────────────────────────────────────────────────────────────────────── +# +# Этот файл **не используется** ни одним из скриптов репозитория. Он лежит в +# репе как справочник: именно так на prod-vm выглядит compose-проект +# `shared-postgres`, живущий в `~/shared-postgres/docker-compose.yml`. +# +# Что это такое. С 2026-10-05 общий postgres-инстанс (чужие боевые базы +# `sklad`, `purchase`, `calcman`, `calcman_staging`, `makesales`, плюс +# мусорная старая `food_market` — повреждена, не восстанавливается) вынесен +# из compose прода food-market в отдельный compose-проект. Раньше он жил в +# том же `~/food-market/deploy/docker-compose.yml` под project-name `deploy`, +# и любой `docker compose down` у food-market гасил чужие боевые базы. +# +# Проект называется `shared-postgres`, контейнер — `shared-postgres`, порт — +# `127.0.0.1:5434`, том `food-market-postgres-data` объявлен *external* +# (имя историческое — на нём лежат чужие продакшн-данные соседних систем, +# переименовывать нельзя). +# +# **Food-market НЕ управляет этим compose.** Любые наши скрипты (backup, +# anonymize, schema-diff, deploy, watchdog), включая `docker exec`, не должны +# ссылаться на `shared-postgres` / `food-market-postgres-data` / порт 5434 — +# за этим следят guards в ~/deploy-stage.sh и ~/quality-watchdog.sh. +# +# Нужен dump/бэкап чужой базы — делает её владелец у себя. См. +# docs/shared-postgres-followup-progress.md и docs/RUNBOOK.md. + +name: shared-postgres +services: + db: + image: 192.168.1.193:5001/mirror/postgres:16-alpine + container_name: shared-postgres + restart: unless-stopped + env_file: .env + environment: + PGDATA: /var/lib/postgresql/data/pgdata + ports: + - "127.0.0.1:5434:5432" + volumes: + - pgdata:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 10s + timeout: 5s + retries: 5 +volumes: + pgdata: + external: true + name: food-market-postgres-data diff --git a/docs/RUNBOOK.md b/docs/RUNBOOK.md index ff1e996..1ab0f89 100644 --- a/docs/RUNBOOK.md +++ b/docs/RUNBOOK.md @@ -87,6 +87,37 @@ Nginx внутри контейнера сделан с `absolute_redirect off; off;` — иначе 301 с `/signup` на `/signup/` строился через HTTP-schema и браузер уходил с https → http. См. `src/food-market.public/deploy/nginx.conf`. +## Postgres на prod-vm + +На prod-vm (`admin.food-market.kz`, `192.168.1.190`) **три** Postgres-контейнера. +Food-market владеет только одним из них — остальные **нельзя** трогать нашими +скриптами, бэкапами, миграциями или `docker exec`. + +| Контейнер | Compose-проект | Том | Порт | Чьи данные | +|---|---|---|---|---| +| `food-market-prod-postgres` | `food-market` (`~/food-market/deploy/`) | `food-market-prod-postgres-data` | `127.0.0.1:5437` | **наш прод** | +| `food-market-stage-postgres` | `food-market-stage` (`~/food-market-stage/deploy/`) | `food-market-stage-postgres-data` | `127.0.0.1:5435` | наш стенд | +| `shared-postgres` | `shared-postgres` (`~/shared-postgres/`) | `food-market-postgres-data` *external* | `127.0.0.1:5434` | **НЕ наш** — чужие боевые базы `sklad`, `purchase`, `calcman`, `calcman_staging`, `makesales`, плюс мусорная старая `food_market` (повреждена, не восстанавливаем) | + +Истоpически (до 2026-10-05) все эти базы жили в одном compose-проекте food-market +под именем контейнера `food-market-postgres` / томом `food-market-postgres-data`. +Любой `docker compose down` у food-market гасил чужие боевые базы. Координатор +физически разделил инстансы с одобрения владельца: food-market съехал в +собственный контейнер и том, а общий инстанс остался в compose-проекте +`shared-postgres` на старом томе (имя тома историческое — переименовывать +нельзя, в нём живые данные соседей). См. `docs/shared-postgres-followup-progress.md`. + +**Правила:** +- Прод-бэкап, anonymize, schema-diff, миграции идут **только** через + `food-market-prod-postgres` (defaults скриптов именно такие). +- Контейнер `shared-postgres`, том `food-market-postgres-data`, порт `5434` — + **запрещённые** цели в наших compose/скриптах. Guards в `~/deploy-stage.sh` + и `~/quality-watchdog.sh` падают, если упомянутые паттерны всплывут в + шаблонах stage- или прод-compose в репе или на prod-vm. +- Нужен dump чужой базы — делает её владелец у себя, не из food-market. +- `deploy/shared-postgres/docker-compose.yml` в репе — это **документация**, + не исполняемый шаблон; наш `prod-deploy.sh` его не трогает. + ## Бэкап и восстановление ### Расписание @@ -97,12 +128,20 @@ systemd-таймер `food-market-backup.timer` (см. `deploy/`) запуска если сервер был выключен). Скрипт `food-market-backup.sh`: -- `pg_dump -Fc` из контейнера `food-market-postgres` → `db-.dump`. +- `pg_dump -Fc` из контейнера `food-market-prod-postgres` → `db-.dump`. - `tar czf` каталога `/opt/food-market-data/uploads` → `uploads-.tgz`. - Удаляет файлы старше 30 дней (`FM_BACKUP_RETENTION_DAYS`). Папка: `/opt/food-market-data/backups/`. +> Контейнер прод-БД — `food-market-prod-postgres` (порт `127.0.0.1:5437`, том +> `food-market-prod-postgres-data`) с 2026-10-05. Соседний на той же машине +> `shared-postgres` (порт 5434, том `food-market-postgres-data` *external*) — +> **не наш**, в нём чужие боевые базы sklad/purchase/calcman/calcman\_staging/ +> makesales. Любые `docker exec`/`pg_dump`/`pg_restore` в `shared-postgres` из +> наших скриптов запрещены, guards бьют. См. раздел «Postgres на prod-vm» +> ниже и `docs/shared-postgres-followup-progress.md`. + ### Ручной бэкап ```bash @@ -111,7 +150,7 @@ ssh nns@192.168.1.190 'sudo /opt/food-market/deploy/food-market-backup.sh' Или из репо разработчика: ```bash -deploy/backup.sh --remote 192.168.1.190:5434 # PG в Docker exposed на 5434 +deploy/backup.sh --remote 192.168.1.190:5437 # прод-PG в Docker, exposed на 5437 ``` ### Recovery drill (RTO ≈ 25 секунд на сегодняшних данных) @@ -131,9 +170,9 @@ Sprint 15 — verified восстановление stage'а в свежий PG- ```bash # 1. Снять бэкап со stage'а -ssh nns@192.168.1.190 'docker exec food-market-stage-postgres-1 \ +ssh nns@192.168.1.190 'docker exec food-market-stage-postgres \ pg_dump -U food_market -d food_market -Fc -f /tmp/drill.dump' -ssh nns@192.168.1.190 'docker cp food-market-stage-postgres-1:/tmp/drill.dump /tmp/drill.dump' +ssh nns@192.168.1.190 'docker cp food-market-stage-postgres:/tmp/drill.dump /tmp/drill.dump' scp nns@192.168.1.190:/tmp/drill.dump /tmp/drill.dump # 2. Чистый PG diff --git a/docs/backup-restore.md b/docs/backup-restore.md index f92afbe..7e8c15d 100644 --- a/docs/backup-restore.md +++ b/docs/backup-restore.md @@ -13,13 +13,21 @@ | Что | Как | Файл | |---|---|---| -| База данных | `pg_dump -Fc` из контейнера `food-market-postgres` | `db-.dump` (custom-format) | +| База данных | `pg_dump -Fc` из контейнера `food-market-prod-postgres` | `db-.dump` (custom-format) | | Загруженные файлы (картинки товаров) | `tar czf` каталога uploads | `uploads-.tgz` | Папка назначения по умолчанию — `/opt/food-market-data/backups`. Хранение — 30 дней (`FM_BACKUP_RETENTION_DAYS`), старые удаляются ротацией. Конфиг — переменными `FM_*` (см. шапку `food-market-backup.sh`). +> **Контейнер прод-БД** — `food-market-prod-postgres` (с 2026-10-05, порт +> `127.0.0.1:5437`, том `food-market-prod-postgres-data`). Соседний контейнер +> `shared-postgres` (другой compose-проект, порт 5434) обслуживает чужие +> боевые базы соседних систем и food-market не принадлежит. Все `pg_dump`, +> `pg_restore`, `docker exec` в наших скриптах — только в +> `food-market-prod-postgres`. См. `docs/shared-postgres-followup-progress.md` +> и раздел «Postgres на prod-vm» в `docs/RUNBOOK.md`. + ## Установка таймера на сервере (деплой-шаг) Предполагается, что репозиторий выложен в `/opt/food-market` (иначе скорректировать @@ -59,17 +67,17 @@ docker compose stop api web DUMP=/opt/food-market-data/backups/db-YYYYMMDD-HHMMSS.dump # Скопировать дамп внутрь контейнера БД -docker cp "$DUMP" food-market-postgres:/tmp/restore.dump +docker cp "$DUMP" food-market-prod-postgres:/tmp/restore.dump # Вариант A — восстановить в чистую БД (рекомендуется): -docker exec food-market-postgres psql -U food_market -d postgres -c \ +docker exec food-market-prod-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 +docker exec food-market-prod-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-prod-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 exec food-market-prod-postgres rm -f /tmp/restore.dump docker compose start api web ``` @@ -92,9 +100,9 @@ sudo tar xzf "$TGZ" -C /opt/food-market-data/ ## Проверка дампа без восстановления ```bash -docker cp 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 +docker cp food-market-prod-postgres:/tmp/v.dump +docker exec food-market-prod-postgres pg_restore --list /tmp/v.dump | head # TOC валидного архива +docker exec food-market-prod-postgres rm -f /tmp/v.dump ``` Скрипт и формат проверены локально (2026-05-27): дамп `PGDMP`, custom-format, diff --git a/docs/shared-postgres-followup-progress.md b/docs/shared-postgres-followup-progress.md new file mode 100644 index 0000000..2bb994c --- /dev/null +++ b/docs/shared-postgres-followup-progress.md @@ -0,0 +1,24 @@ +# shared-postgres follow-up: репозиторий ↔ новая раскладка postgres прода + +**Задача.** 2026-10-05 координатор физически разделил два инстанса postgres на prod-vm: + +- `shared-postgres` (`~/shared-postgres/docker-compose.yml`, контейнер `shared-postgres`, порт `127.0.0.1:5434`, том `food-market-postgres-data` *external*). Внутри — ЧУЖИЕ боевые базы: `sklad`, `purchase`, `calcman`, `calcman_staging`, `makesales`, плюс мусорная старая `food_market` (повреждена, не восстанавливаем). Проект compose — `shared-postgres`, не наш, живёт отдельно. +- `food-market-prod-postgres` (`~/food-market/deploy/docker-compose.yml` на prod-vm, контейнер `food-market-prod-postgres`, порт `127.0.0.1:5437`, том `food-market-prod-postgres-data`). Это НОВЫЙ собственный postgres прода food-market. Пока не запущен — прод-API лежит. + +Старый compose прода (project `deploy`, контейнер `food-market-postgres`, том `food-market-postgres-data` на тех же данных) **более не существует**. Простой при разделении — 12 секунд, соседи живы. Бэкап: `docker-compose.yml.bak-20261005` на prod-vm. + +Теперь нужно догнать репозиторий (шаблоны, guards, скрипты, доки), чтобы следующий деплой из main не воскресил старую раскладку, а любой `docker exec` в `shared-postgres` из кода food-market был бы невозможен. + +**Правила на будущее** +- Прод food-market использует `food-market-prod-postgres` / том `food-market-prod-postgres-data` / порт `127.0.0.1:5437`. +- `shared-postgres` **не принадлежит проекту food-market**. Его `container_name`, том и порт — запрещённые паттерны в наших compose/скриптах. +- Том `food-market-postgres-data` — исторический для `shared-postgres`, в food-market compose его быть не должно (чужие данные). + +## Чеклист + +- [x] 1. Шаблон репо `deploy/docker-compose.yml` приведён к прод-файлу (контейнер/том/порт прода). Добавлен `deploy/shared-postgres/docker-compose.yml` как документация соседнего compose-проекта (управляется отдельно). +- [x] 2. Guards расширены: `~/deploy-stage.sh` и `~/quality-watchdog.sh` (+их копии в репо, если есть) запрещают стенду `shared-postgres`, `food-market-prod-postgres`, `food-market-prod-postgres-data`, порты `5434`/`5437`; проду — том `food-market-postgres-data`. +- [x] 3. Скрипты и доки: `deploy/food-market-backup.sh`, `deploy/anonymize-prod.sh`, `deploy/db-schema-diff.sh`, `docs/RUNBOOK.md`, `docs/backup-restore.md` указывают на `food-market-prod-postgres` вместо старого `food-market-postgres`; RUNBOOK явно говорит «shared-postgres не наш». +- [x] 4. Проверка на prod-vm: `docker compose -f ~/food-market/deploy/docker-compose.yml config` и `docker compose ps -a` не упоминают `shared-postgres`; `grep` по репе — ни один скрипт не делает `docker exec` в `shared-postgres`. + +Прод не запускается, `shared-postgres` и чужие базы не трогаются, `global.json` и gateway nginx вне скоупа.