Files
germanandClaude Opus 4.8 3f1c5dbd7b feat(bot): сайт-адаптер единого бота флота + фикс redirect на 1nika.ru
Реализован контракт /api/bot/* из servaki-webhub-bot/SPEC.md:
- GET  /api/bot/health (публичный) -> {ok, site}
- GET  /api/bot/publications?status=&limit= -> список works
- POST /api/bot/publications {title,body,media[]} -> черновик works -> {id}
- POST /api/bot/publications/:id/publish -> published -> {id,url}
- DELETE /api/bot/publications/:id -> удаление (media cascade)
- POST /api/bot/materials (multipart file) -> media -> {id,url}

Аутентификация Authorization: Bearer <BOT_API_TOKEN> (middleware/botAuth,
сравнение постоянного времени; 503 без токена в env, 401 при несовпадении).
Маппинг: публикация<->works, материал<->media. Миграция bot_adapter.sql
разрешает media.type='file'. multer 2.x.

Фикс Яндекс-redirect и домена: nika-gallery.ru -> 1nika.ru в .env.example
(YANDEX_REDIRECT_URI, FRONTEND_URL, SITE_URL, NEXT_PUBLIC_*, SMTP_USER) и
nginx server_name. Секреты не в git (client_id/secret - на Я.Диске).

Добавлен docs/DEPLOY.md (VPS runbook: DNS, .env, SSL, миграции, бот).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-05 23:24:20 +03:00

156 lines
7.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Деплой nika-gallery (1nika.ru)
Полный runbook подъёма сайта Ники на VPS: Docker Compose (backend Express + Next.js
фронт + Postgres 16 + nginx), вход через Яндекс ID и подключение к единому боту флота
(`@servaki_online_bot`) через сайт-адаптер `/api/bot/*`.
> ⚠️ **Живой VPS-деплой — решение владельца** (выбор ноды и DNS). Этот документ —
> команды и чек-лист; агент репо готовит, но на боевой узел не раскатывает.
---
## 0. Что уже готово в репо
- `docker-compose.yml` — db / backend / frontend / nginx.
- `db/schema.sql` (+ `db/migrations/club_access.sql`, `db/migrations/bot_adapter.sql`).
- Вход через Яндекс ID (`backend/src/routes/oauth.js`), redirect на `1nika.ru`.
- Сайт-адаптер бота (`backend/src/routes/bot.js`, `middleware/botAuth.js`).
- nginx для `1nika.ru` / `www.1nika.ru`.
---
## 1. DNS
На домен **1nika.ru** (регистратор/DNS владельца) добавить A-записи на IP выбранной ноды:
```
1nika.ru. A <VPS_IP>
www.1nika.ru. A <VPS_IP>
```
Дождаться распространения (`dig +short 1nika.ru` должен вернуть `<VPS_IP>`).
---
## 2. Подготовка сервера
Нужны: Docker + docker compose plugin, открытые порты 80/443.
```bash
git clone http://192.168.1.120/german/nika-gallery.git /opt/nika-gallery
cd /opt/nika-gallery
git checkout main # либо feat/bot-adapter до мержа
cp .env.example .env
```
---
## 3. Заполнить `.env` (боевые значения — только на сервере, НЕ в git)
| Переменная | Значение | Откуда |
|---|---|---|
| `POSTGRES_PASSWORD` | сильный пароль | сгенерировать |
| `DATABASE_URL` | `postgresql://postgres:<POSTGRES_PASSWORD>@db:5432/nika_gallery` | собрать |
| `JWT_SECRET` / `JWT_REFRESH_SECRET` | `openssl rand -hex 32` (каждый свой) | сгенерировать |
| `YANDEX_CLIENT_ID` | `1f64f6ebcd9c45f9af78987204af8e36` | Я.Диск `YANDEX-OAUTH-APPS.secret.txt` [NIKA ART] |
| `YANDEX_CLIENT_SECRET` | `a2b737fc…` | там же |
| `YANDEX_REDIRECT_URI` | `https://1nika.ru/api/auth/yandex/callback` | (уже в .env.example) |
| `FRONTEND_URL` / `SITE_URL` | `https://1nika.ru` | — |
| `BOT_API_TOKEN` | `openssl rand -hex 32` | сгенерировать; **тот же** токен → в реестр бота (`sites.api_token`) + Я.Диск |
| `BOT_SITE_KEY` | `nika` | — |
| `NEXT_PUBLIC_API_URL` | `https://1nika.ru/api` | — |
| `OWNER_EMAIL`, `SMTP_*`, `TELEGRAM_*` | по факту | владелец |
⚠️ **Секреты не коммитить.** В git — только `.env.example` с пустыми полями.
`YANDEX_REDIRECT_URI` должен **точно** совпадать со значением в кабинете
`oauth.yandex.ru` (приложение NIKA ART) — иначе Яндекс вернёт `redirect_uri_mismatch`.
---
## 4. SSL-сертификат (Let's Encrypt)
nginx ждёт `nginx/certs/fullchain.pem` и `nginx/certs/privkey.pem`. Выпустить certbot'ом
(standalone до старта nginx, либо webroot):
```bash
# порт 80 должен быть свободен
docker run --rm -p 80:80 \
-v /opt/nika-gallery/letsencrypt:/etc/letsencrypt \
certbot/certbot certonly --standalone \
-d 1nika.ru -d www.1nika.ru --agree-tos -m <OWNER_EMAIL> --no-eff-email
mkdir -p /opt/nika-gallery/nginx/certs
cp /opt/nika-gallery/letsencrypt/live/1nika.ru/fullchain.pem nginx/certs/
cp /opt/nika-gallery/letsencrypt/live/1nika.ru/privkey.pem nginx/certs/
```
Продление — cron/systemd-timer с `certbot renew` + копированием в `nginx/certs/` и
`docker compose exec nginx nginx -s reload`.
---
## 5. Старт и миграции
`db/schema.sql` и `db/seed.sql` применяются автоматически при **первой** инициализации
тома Postgres (см. `docker-entrypoint-initdb.d` в compose). Миграции из `db/migrations/`
надо применить вручную (они аддитивны и идемпотентны).
```bash
docker compose build
docker compose up -d db
# дождаться healthy:
docker compose exec db pg_isready -U postgres
# Миграции (клуб + Яндекс ID, затем адаптер бота):
docker compose exec -T db psql -U postgres -d nika_gallery < db/migrations/club_access.sql
docker compose exec -T db psql -U postgres -d nika_gallery < db/migrations/bot_adapter.sql
docker compose up -d # поднять backend + frontend + nginx
```
Назначить владельца (Ника) ролью `owner`:
```bash
docker compose exec -T db psql -U postgres -d nika_gallery \
-c "UPDATE users SET role='owner' WHERE email='<nika_email>';"
```
---
## 6. Проверка
```bash
curl -s https://1nika.ru/api/health # {status:ok}
curl -s https://1nika.ru/api/bot/health # {ok:true, site:"nika"}
curl -s -o /dev/null -w '%{http_code}\n' \
https://1nika.ru/api/bot/publications # 401 (без токена)
curl -s -H "Authorization: Bearer $BOT_API_TOKEN" \
https://1nika.ru/api/bot/publications # [] или список
```
Вход через Яндекс: открыть `https://1nika.ru/api/auth/yandex` → авторизация →
редирект на `https://1nika.ru/club#token=…`.
---
## 7. Подключение к боту флота
После деплоя владелец в реестре бота (`sites` на finik,
`/var/lib/webhub-bot/state.db`) выставляет для `site_key='nika'`:
- `base_url = https://1nika.ru`
- `api_token = <BOT_API_TOKEN из .env>`
- `status = live` (сейчас `soon`).
Бот дергает `/api/bot/*` с заголовком `Authorization: Bearer <api_token>`. Контракт —
`servaki-webhub-bot/SPEC.md`.
---
## 8. Обновления
```bash
cd /opt/nika-gallery && git pull && docker compose build && docker compose up -d
```
(автоматизировано в `.gitea/workflows/deploy.yml` при push в `main`; требует
секретов раннера `DEPLOY_HOST`, `DEPLOY_KEY`).
## Приложение: карта ручек адаптера
| Метод | Путь | Auth | Ника |
|---|---|---|---|
| GET | `/api/bot/health` | — | `{ok,site}` |
| GET | `/api/bot/publications?status=&limit=` | Bearer | список works |
| POST | `/api/bot/publications` `{title,body,media[]}` | Bearer | works(draft) → `{id}` |
| POST | `/api/bot/publications/:id/publish` | Bearer | works.status=published → `{id,url}` |
| DELETE | `/api/bot/publications/:id` | Bearer | delete works (+media cascade) |
| POST | `/api/bot/materials` (multipart `file`) | Bearer | media → `{id,url}` |