# Public test URL — прогресс (5/5 ✓) Фикс: `https://test.food-market.kz` (публичный сайт) должен вести на `https://test.admin.food-market.kz` (стенд-админку), а не на прод `admin.food-market.kz`. Координатор уже вручную пересобрал образ `food-market-public:test` с правильным `PUBLIC_APP_URL` и переключил контейнер (`PUBLIC_TAG=test` в `~/food-market/deploy/.env` на prod-vm). Теперь это закреплено в репе, автосборка CI не откатит. ## Контекст (prod-vm 192.168.1.190) - `~/food-market/deploy/` — публичный сайт **test.food-market.kz** раздаёт контейнер `food-market-public:test`. API/web тоже тут, но на отдельных портах; prod-API 2 месяца `Exited`. - `~/food-market-stage/deploy/` — stage-стек (admin API/web) с тегом `:stage`. ## Чек-лист - [x] 1. `.forgejo/workflows/docker-public.yml`: сборка `:test`-тега с `PUBLIC_APP_URL=https://test.admin.food-market.kz`, деплой апдейтит именно его. Прод-сборка `:latest` → `admin.food-market.kz` собирается и пушится, но job `deploy_prod` ОТСУТСТВУЕТ (food-market.kz закрыт решением владельца; включать когда разрешат). Smoke в CI: `curl .../signup/ | grep test.admin` должен найти, `grep -E 'href="https://admin\.food-market\.kz'` НЕ должен найти. - [x] 2. Нет захардкоженных `admin.food-market.kz` в `src/food-market.public` кроме env-fallback'ов в `Header.astro` и `SignupForm.tsx` (`?? 'https://admin.food-market.kz'`). Fallback активен только когда env-переменная не задана — для автосборки через workflow она ЕСТЬ всегда. `.env.example` обновлён с явным комментарием про test vs prod. - [x] 3. Smoke выполнил: - `curl https://test.food-market.kz/` → ссылка «Войти» ведёт на `https://test.admin.food-market.kz/login`. - `curl https://test.food-market.kz/signup/` → все `href`/`action` указывают на `test.admin.food-market.kz`. Нет ни одного `admin.food- market.kz` (без `test.` префикса). - `POST /api/auth/signup` c `Origin: https://test.food-market.kz`: юзер `publicsmoke-1791116018@food-market.local` создан в **food-market-stage-postgres-1** (STAGE-БД). В `food-market-postgres` (прод-adjacent) этого юзера НЕТ. - [x] 4. `docs/RUNBOOK.md` — добавлен раздел «Публичный сайт: какой образ ↔ какой домен» с таблицей `:test` ↔ `test.food-market.kz` / `test.admin.food-market.kz` и `:latest` ↔ `food-market.kz` / `admin. food-market.kz`, и note'ом про `absolute_redirect off`. - [x] 5. `src/food-market.public/deploy/nginx.conf`: - `absolute_redirect off;` — Location в 301 становится относительным (`/signup/` вместо `http://test.food-market.kz/signup/`); браузер использует текущий scheme → https сохраняется. - `port_in_redirect off;` — на случай cross-port сценариев. Проверено: `curl -sI https://test.food-market.kz/signup` → теперь `location: /signup/` без схемы. Отбились от скатывания на http. ## Что в коде | Что | Где | |---|---| | Workflow (два build + один deploy) | `.forgejo/workflows/docker-public.yml` | | nginx-config публичного образа | `src/food-market.public/deploy/nginx.conf` | | Dockerfile с ARG | `src/food-market.public/Dockerfile` | | Env-fallback'и к admin-URL | `src/food-market.public/src/components/{Header.astro,SignupForm.tsx}` (без изменений — работают через PUBLIC_APP_URL) | | Env-пример | `src/food-market.public/.env.example` (комментарий про test vs prod) | | RUNBOOK раздел | `docs/RUNBOOK.md` «Публичный сайт: какой образ ↔ какой домен» | ## Проверка после деплоя ```bash curl -sI https://test.food-market.kz/signup | grep -i location # location: /signup/ ← без http://; значит absolute_redirect off работает curl -s https://test.food-market.kz/signup/ | grep -oE 'href="[^"]*login[^"]*"' | sort -u # href="https://test.admin.food-market.kz/login" # href="/signup" curl -s https://test.food-market.kz/signup/ | grep -oE 'admin\.food-market\.kz' # (пусто — ни одного вхождения прод-admin) ``` Прод (`admin.food-market.kz`) и `food-market.kz` НЕ ТРОНУТЫ. Прод-API по-прежнему остановлен ~2 месяца (это пре-существующий outage, отдельная задача). Prod-БД `food-market-postgres` не получила ни одного запроса от публичного сайта.