dcc1040f73
3 канала проверены вживую на тест-сервере (webhook/CSV reconcile/export), +предпосылки (Node20+Playwright+Chromium под /var/www/.cache, PlaywrightBridge 180s), secret/allowlist/supplier-portal/HTTPS TODO. +2 слова в cspell. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
131 lines
9.2 KiB
Markdown
131 lines
9.2 KiB
Markdown
# Лидерра — тест-сервер (Yandex Cloud) — runbook
|
||
|
||
**Создан:** 2026-05-21. Тестовое окружение для ручной проверки (заказчик + Claude). Не продакшен.
|
||
Спека: `docs/superpowers/specs/2026-05-21-test-deploy-yandex-cloud-design.md`.
|
||
План: `docs/superpowers/plans/2026-05-21-test-deploy-yandex-cloud.md`.
|
||
|
||
## Доступ
|
||
|
||
- **URL (HTTP, временно):** `http://111.88.246.137` — статический IP YC.
|
||
- **HTTPS / домен:** добавляется после покупки домена (см. «Включить HTTPS»).
|
||
- **Дверь сайта (HTTP Basic Auth):** логин `liderra` — пароль в `/home/ubuntu/liderra-secrets.txt` на сервере (ключ `basic_auth`).
|
||
- **Демо-вход в портал:** `admin@demo.local` / `password` (tenant `demo`, 3 проекта, демо-сделки).
|
||
- **SSH:** `ssh -i ~/.ssh/liderra_deploy ubuntu@111.88.246.137` (ключ на dev-машине; пароль входа отключён).
|
||
- **YC:** облако `cloud-sasha261185`, каталог `default`, VM `liderra-test` (ru-central1-a, 2vCPU/2GB/20%), SG `liderra-test-sg` (22/80/443).
|
||
|
||
## Состав
|
||
|
||
- Ubuntu 24.04: nginx (Basic Auth, webhook `/api/webhook/*` без auth) → PHP-FPM 8.3 → Laravel.
|
||
- PostgreSQL 16 (БД `liderra`), Redis (sessions+cache+queue, predis).
|
||
- Код в `/var/www/liderra/app`; фронтенд `public/build` (собирается на dev, заливается scp).
|
||
- Службы: `liderra-queue.service` (queue worker, systemd, enabled) + cron `/etc/cron.d/liderra-scheduler` (schedule:run). Все автозапускаются после ребута.
|
||
|
||
## Важные отклонения от прод-дизайна (на решение позже)
|
||
|
||
- **DB-роль приложения = `crm_app_user` (RLS включена)** — изоляция бизнес-данных между клиентами
|
||
**работает** (deals/projects/billing/… строгие политики). Чтобы вход работал под строгой ролью,
|
||
RLS-политики на таблицах `users` + `auth_log` сделаны «дружелюбными ко входу»: пропускают запрос,
|
||
когда tenant-контекст ещё не установлен (auth/login), и фильтруют по тенанту после. Это server-only
|
||
правка политик (не в schema.sql); для прода — кандидат в нормативную схему.
|
||
- **Админка SaaS `/admin/*` под `crm_app_user` НЕ работает** (нет доступа к saas-таблицам — REVOKE).
|
||
Для теста «от лица клиентов» не нужна. Понадобится — переключать admin-запросы на `crm_admin_user`
|
||
(connection-switch в middleware `EnsureSaasAdmin`) — отдельная доработка.
|
||
- **`SAAS_ADMIN_TEST_BYPASS=true`** — временный флаг (для будущей админки). Убрать после Yandex SSO (Б-1).
|
||
- **Почта** = `log` (письма в файл). **APP_DEBUG=false**, **APP_ENV=production**.
|
||
- Установлены dev-зависимости (faker нужен для сидов).
|
||
|
||
## Тестовые клиенты
|
||
|
||
| Логин | Пароль | Компания |
|
||
|---|---|---|
|
||
| `admin@demo.local` | `password` | Demo (3 проекта + демо-сделки) |
|
||
| `client1@liderra.test` | `password` | Компания 1 (2 проекта) |
|
||
| `client2@liderra.test` | `password` | Компания 2 (2 проекта) |
|
||
| `client3@liderra.test` | `password` | Компания 3 (2 проекта) |
|
||
| `client4@liderra.test` | `password` | Компания 4 (2 проекта) |
|
||
|
||
Изоляция проверена вживую: каждый видит только свои проекты (HTTP-логин + `/api/projects`).
|
||
|
||
## Каналы миграции с поставщиком (настроены 2026-05-21)
|
||
|
||
Все 3 канала с `crm.bp-gr.ru` подняты и проверены вживую на тест-сервере.
|
||
|
||
### Предпосылки (доустановлены сверх базового деплоя — в исходном runbook их не было)
|
||
|
||
- **Node.js 20** (NodeSource) + **Playwright** (`app/playwright/node_modules`, `npm install`) + **Chromium**
|
||
в `/var/www/.cache/ms-playwright/` (HOME у `www-data` = `/var/www`; ставить через
|
||
`sudo HOME=/var/www .../playwright install chromium` затем `chown -R www-data:www-data /var/www/.cache`,
|
||
иначе artisan от www-data не находит браузер). Без них логин к поставщику (Yii2-форма, JS) не работает
|
||
→ CSV-сверка и экспорт мертвы (`PlaywrightBridge exit code 127: node: not found`).
|
||
- `PlaywrightBridge::TIMEOUT_SECONDS` поднят **75 → 180** (`app/app/Services/Supplier/PlaywrightBridge.php`):
|
||
на 2 ГБ VM холодный старт Chromium ~65 c, в 75 не укладывался. Бэкап `*.bak.20260521`.
|
||
- `.env`: `SUPPLIER_LOGIN` / `SUPPLIER_PASSWORD` (те же, что на dev). Бэкап `.env.bak.20260521-*`.
|
||
- `system_settings.supplier_webhook_secret` — 48-hex (DemoSeeder ставит короткий → guard `<32` → webhook молча 404).
|
||
Копия в `/home/ubuntu/liderra-secrets.txt`.
|
||
- `system_settings.supplier_ip_allowlist` = `["0.0.0.0/0"]` — на `APP_ENV=production` пустой массив fail-closed (404 всем).
|
||
**TODO: сузить** до IP поставщика (в логе видели `92.53.65.242`).
|
||
|
||
### Канал 1 — приём webhook'а (вход, основной)
|
||
|
||
- POST `http://111.88.246.137/api/webhook/supplier/<secret>` (nginx `^~ /api/webhook/` без Basic Auth).
|
||
- Проверено: правильный secret → 202, дубль `vid` → 200 `already_processed`, битый secret → 404.
|
||
|
||
### Канал 2 — CSV-дочерпывание (вход, резерв)
|
||
|
||
- `CsvReconcileJob`, scheduler каждые 30 мин (cron `schedule:run` ежеминутно). Прогон вживую: 185 строк, status `ok`, drift 0.
|
||
- Ручной запуск: `sudo -u www-data php artisan tinker --execute='App\Jobs\Supplier\CsvReconcileJob::dispatchSync()'`.
|
||
|
||
### Канал 3 — экспорт проектов (выход)
|
||
|
||
- `SupplierProjectChannel::createProject` / `SupplierPortalClient::deleteProject`. Проверено: create+delete
|
||
тестового проекта (`external_id=12764235`), сверка `listProjects` — следов у поставщика нет.
|
||
|
||
### Supplier-портал
|
||
|
||
- `crm.bp-gr.ru → /admin/user/api`: «Апи ссылка» = `http://111.88.246.137/api/webhook/supplier/<secret>`,
|
||
«Апи протокол» = HTTP, «Апи статус» = Активный. Поставщик HTTP-URL принимает.
|
||
- ⚠️ Поле URL **одно** → после переключения на тест-сервер dev-машина живых лидов **не получает**.
|
||
- Сессия логина: Redis DB 1, ключ `liderra-database-liderra-cache-supplier:session` (TTL 6h, refresh-крон/`supplier:session:refresh`).
|
||
|
||
### Сделать позже
|
||
|
||
- Привязать `client1..4` к реальным каналам поставщика через pivot `project_supplier_links` (иначе лиды = ghost без сделок).
|
||
- HTTPS после покупки домена → URL у поставщика на https.
|
||
- Сузить `supplier_ip_allowlist`.
|
||
|
||
## Обновить версию
|
||
|
||
На dev-машине:
|
||
|
||
```powershell
|
||
npm --prefix app run build
|
||
git -C <repo> archive --format=tar HEAD app db -o $env:TEMP\liderra.tar
|
||
scp -i ~/.ssh/liderra_deploy $env:TEMP\liderra.tar ubuntu@111.88.246.137:/tmp/
|
||
scp -i ~/.ssh/liderra_deploy -r app\public\build ubuntu@111.88.246.137:/tmp/build
|
||
```
|
||
|
||
На сервере:
|
||
|
||
```bash
|
||
tar -xf /tmp/liderra.tar -C /var/www/liderra
|
||
rm -rf /var/www/liderra/app/public/build && cp -r /tmp/build /var/www/liderra/app/public/build
|
||
bash /var/www/liderra/redeploy.sh
|
||
```
|
||
|
||
## Включить HTTPS (после покупки домена)
|
||
|
||
1. DNS: A-запись `test.<домен>` (и/или `demo.<домен>` для subdomain-tenant) → `111.88.246.137`.
|
||
2. На сервере: в `/etc/nginx/sites-available/liderra` заменить `server_name _;` на домен, `nginx -t && systemctl reload nginx`.
|
||
3. `sudo certbot --nginx -d test.<домен> --non-interactive --agree-tos -m <email> --redirect`.
|
||
4. В `.env` обновить `APP_URL=https://test.<домен>`, затем `php artisan optimize`.
|
||
|
||
## Остановить / удалить (прекратить оплату)
|
||
|
||
- Остановить VM: `yc compute instance stop liderra-test` (диск/IP сохраняются, мелкая плата).
|
||
- Удалить совсем: `yc compute instance delete liderra-test` + `yc vpc address delete <id>`.
|
||
|
||
## После теста — обязательно
|
||
|
||
- **Отозвать OAuth-токен Yandex Cloud** (Яндекс ID → Безопасность → сторонние приложения).
|
||
- При переходе к прод-конфигу: убрать `SAAS_ADMIN_TEST_BYPASS`, вернуть `crm_app_user` (после auth-rework).
|