---
name: zbr-stage-on-mehant-domain
description: "Стенд «Земли без риска» на домене Механта — СНЯТ 07.08.2026, код лежит на mini и поднимается обратно четырьмя правками; чем стенд был изолирован от боя и какие грабли при сборке"
metadata: 
  node_type: memory
  type: project
  originSessionId: b11e39bd-4f6f-47c9-ba7b-680ccf041a5b
  modified: 2026-08-07T05:46:34.242Z
---

**06.08.2026.** Владелец попросил дубль zbrcheck.ru, чтобы обкатать сайт и кабинет целиком —
в предпросмотре это невозможно. Домен взят у выключенного Механта ([[mehant_decommissioned_2026-08]]),
он уже смотрел на codoceh-edge и был свободен.

**СНЯТ 07.08.2026** по решению владельца — Механт снова выключен, ЗБР и ТБР оставлены нетронутыми.
Домен `mexunt.codoceh.ru` больше не отвечает (000), порты 20240/20241 свободны, плисты
переименованы в `*.plist.off`. Прод за всё время не тронут ни разу.

**Что осталось на mini:** дерево `~/Services/zbr-stage` целиком (400 МБ) со всеми правками
интерфейса — первый экран, кабинет, снятые эмодзи, контраст. Это единственная копия этой работы:
в бой она не переносилась. Ключ входа — `~/Services/zbr-stage/stage_login_key.txt`.

**Чем стенд изолирован от боя (каждый пункт обязателен):**
- код — отдельное дерево `~/Services/zbr-stage`, порты **20240** (FastAPI) и **20241** (Next);
  launchd `local.zbrstage-backend` / `local.zbrstage-frontend`;
- **база пустая**: схема боевой (58 объектов, 32 таблицы) без единой персональной строки;
  перенесены только справочники — промокоды, настройки уведомлений, сценарии (14 строк всего);
- **свой JWT_SECRET** — сессия стенда в бою невалидна и наоборот. Это единственная правка,
  которую нельзя пропустить;
- **Robokassa в тестовом режиме**, свой префикс счетов `9` — настоящих платежей быть не может;
- в Caddy на домен повешен `X-Robots-Tag: noindex, nofollow`;
- тяжёлые справочники (геокодер, 3,3 ГБ) подключены **ссылками**, а не копией: стенд весит 400 МБ.

**Почему отдельная дверь входа.** Боевой вход — виджет Telegram, а он привязан к домену через
`/setdomain` у @BotFather. Домен там один; перевести его на стенд = сломать вход в проде. Поэтому
`app/routes/stage_login.py` — маршрут регистрируется **только** при заданном `ZW_STAGE_LOGIN_KEY`,
ключ сверяется `secrets.compare_digest`, сессия выдаётся штатным jwt-модулем (кабинет проверяется
настоящий, а не имитация). **Этот файл не должен попасть в прод.**

**Грабли, найденные при сборке:**
- у бэкенда есть анти-бот: `score≥3` на `/api/*` → 429. Headless-Chromium и curl режутся по
  User-Agent — **правильно режутся**. Проверять стенд только с обычным десктопным UA и `Accept-Language: ru`;
- копия SQLite стартует не в WAL: первый запуск падал `database is locked`. Ставить
  `pragma journal_mode=WAL` при остановленном бэкенде;
- кабинет живёт на `/dashboard`, не на `/cabinet`.

**Как поднять обратно** (снятие 07.08.2026 сделано ровно этими четырьмя правками наоборот):
1. на mini вернуть имена `local.zbrstage-{backend,frontend}.plist` без `.off` и загрузить их;
2. вернуть `[client.services.zbrstage] local_addr = "127.0.0.1:20241"` в
   `~/Services/kodoceh-web/rathole/client.toml`, перезапустить `local.kodoceh-rathole-client`;
3. на VPS 195.133.147.176 вернуть `[server.services.zbrstage] bind_addr = "127.0.0.1:14011"`
   в `/etc/rathole/server.toml`;
4. там же вернуть блок `mexunt.codoceh.ru` в Caddyfile (`import sec`, `X-Robots-Tag: noindex`,
   `reverse_proxy 127.0.0.1:14011`), `caddy validate` → `systemctl reload caddy`.

Копии всех конфигов на момент снятия: `*.bak-zbrstage-off-<TS>` рядом с оригиналами; копии на
момент установки — `*.bak-zbrstage-<TS>`. Порт 14011 снова свободен.
См. [[codoceh_vps_edge]], [[zemlya_web_overview]], [[mehant_decommissioned_2026-08]].
