Files
mechanic-pwa/driver-pwa/frontend/README.md
T
tremble7681andClaude Opus 5 ceec3db364 feat(pwa): вход для сотрудника, просмотр от лица водителя и вкладка «Отладка»
Приложение обкатывается на боевом контуре, поэтому интерфейс надо проверять на
живых данных — а живые данные лежат у настоящих водителей.

* «Вход для сотрудника» (/dev) — логин учётки CRM, поддержан второй шаг 2FA;
  дальше поиск водителя по ФИО/телефону/id и просмотр его экранов.
* Плашка «Смотрю как …» над всеми экранами: интерфейс в этом режиме неотличим
  от водительского, и чужой баланс легко принять за свой.
* Вкладка «Отладка» (/debug, водителю недоступна): смена водителя, driver_id,
  режим, срок токена, адрес API, коммит и время сборки, журнал последних
  40 ответивших запросов, сброс кэша сервис-воркера.
* Пополнение под просмотром идёт в учебный контур: экран /mock-pay/:orderId
  выбирает, что «ответит» банк, а настоящий экран оплаты разбирает эти статусы
  своим боевым кодом. Ни рубля, ни чека 54-ФЗ.

Заодно доезжает незакоммиченная работа прошлой сессии: дев-прокси в
vite.config.ts, его тест и разобранный .env.example.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 13:15:02 +10:00

148 lines
8.9 KiB
Markdown
Raw 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.
# Премиум Водитель — PWA водителя
React + Vite + TypeScript. Прод: **https://app.pptaxi.ru**.
Бэкенд — модуль `payments` в Premium CRM (`https://crm.pptaxi.ru/api`,
репозиторий `crm2`, `backend/app/modules/payments/`).
## Как поднять локально
```bash
npm install
npm run dev # http://localhost:5174
```
Отдельно поднимается бэкенд `crm2` на **127.0.0.1:8000** (тот же порт, что в
`backend/Dockerfile`). Больше настраивать нечего: dev-сервер сам подставляет
`VITE_API_BASE=/api` и проксирует `/api` на бэкенд — см. `vite.config.ts`.
**Почему через прокси, а не «разрешить localhost в CORS бэкенда».** Прокси
делает запрос ОДНОГО происхождения со страницей (`http://localhost:5174/api/…`),
поэтому CORS в разработке не участвует вообще. Боевой список origin'ов на
бэкенде остаётся закрытым, а `CORS_ALLOW_LOCALHOST=true` в `backend/.env` для
этого фронта включать не надо. (Раньше рецепт с `CORS_ALLOW_LOCALHOST` тут и не
работал: прокси не было, и фронт по умолчанию уходил на боевой домен, а не на
локальный бэкенд.)
Сервис-воркер в режиме разработки не регистрируется (`devOptions` у
`vite-plugin-pwa` по умолчанию выключены) — старый кэш прод-версии в дев не
лезет.
### Бэкенд не на `127.0.0.1:8000`
```bash
VITE_API_TARGET=http://127.0.0.1:8090 npm run dev
```
В PowerShell инлайн-префикса `VAR=... команда` нет — переменную ставят отдельно:
```powershell
$env:VITE_API_TARGET="http://127.0.0.1:8090"; npm run dev
```
Имя переменной то же, что в CRM (`crm2/frontend/vite.config.ts`), — рецепт один
на оба фронта.
### Ходить в API напрямую, мимо прокси
`.env.local` (в git не попадает):
```
VITE_API_BASE=http://127.0.0.1:8000/api
```
Своя настройка приоритетнее дев-дефолта — специально, чтобы `npm run dev` её не
перебивал. Для похода в чужой origin бэкенду понадобится
`CORS_ALLOW_LOCALHOST=true` в `backend/.env` и рестарт.
> ⚠️ `crm.pptaxi.ru` — боевой терминал Т-Банка и боевая касса АТОЛ. Пополнение,
> сделанное «просто посмотреть», — это реальные деньги водителя, реальный чек
> 54-ФЗ и реальная проводка в леджере. Поэтому прокси по умолчанию смотрит в
> локальный бэкенд, а не в прод.
## Проверки
```bash
npx tsc -b # типы
npm test # vitest run
```
`npx tsc --noEmit` **без `-b`** здесь всегда зелёный и ничего не значит:
корневой `tsconfig.json` — solution-файл (`files: []` + `references`), под него
не попадает ни один файл (`tsc --noEmit --listFiles` печатает пустоту). Типы
живут в `tsconfig.app.json` (`src`) и `tsconfig.node.json` (конфиги +
`dev-proxy.test.ts`), и до обоих добирается только `tsc -b`.
## Сборка
```bash
npm run build # tsc -b && vite build → dist/
```
Дев-дефолт `VITE_API_BASE=/api` подставляется только при запущенном dev-сервере
и в бандл не попадает: в собранном `assets/index-*.js` лежит
`https://crm.pptaxi.ru/api` (проверено сборкой). Поэтому `VITE_API_BASE` боевой
сборке задавать не обязательно — без неё `src/api/client.ts` подставляет ровно
этот адрес.
> ⚠️ `npm run preview` поднимает **уже собранный** бандл, а база в нём
> абсолютная: запросы уходят на боевой `crm.pptaxi.ru` мимо прокси dev-сервера.
> Смотреть локальные правки — только `npm run dev`.
Куда выкладывается `dist/` — в плане проекта:
`../../docs/superpowers/plans/2026-06-18-premium-driver-pwa.md`, раздел
«Deployment notes»: статика на `app.pptaxi.ru`, Caddy с фолбэком на `index.html`.
## Обкатка: кто может войти и как смотреть чужой экран
Приложение выложено на боевой домен, а обкатывается интерфейс. Поэтому на время
обкатки включены две вещи.
### 1. Вход только по списку номеров
Переменная бэкенда (`crm2/backend/.env`, читается в `app/config.py`):
```
DRIVER_APP_ALLOWED_PHONES=+7 (914) 123-45-67, 79990001122
```
Разделители — запятая, точка с запятой, перенос строки (пробел разделителем не
считается: номер вписывают в привычном виде). Сверяются последние 10 цифр.
**Пусто — гейт выключен, вход открыт всем водителям.**
Проверка стоит в единственной воронке выдачи токена
(`modules/payments/driver_auth.create_driver_token_for`), поэтому закрыты сразу
все пять путей входа: код в бот, кнопка «Войти через Telegram», колбэки своего
бота и два аварийных отката на n8n. Бот отвечает человеку текстом, остальные
пути — 403. Логика гейта: `modules/payments/login_gate.py`.
### 2. Просмотр от лица водителя (сотрудник)
На экране входа внизу — «Вход для сотрудника» (`/dev`): логин и пароль **учётки
CRM**, при включённой двухфакторке спросит код. Дальше поиск по ФИО, телефону
или id — и приложение открывается от лица выбранного водителя.
* Токен помечен claim'ом `imp`, живёт 8 часов (обычный водительский — 30 дней).
* Гейт — `is_admin` в CRM. Каждая выдача пишется в аудит (`driver_app.impersonate`).
* Кнопка «Отозвать доступ» в CRM гасит и просмотр сотрудника — поколение общее.
* Гейт обкатки на этот путь не распространяется: смотреть надо как раз на
водителей, которых в allowlist нет.
Пока просмотр действует, сверху на всех экранах висит плашка «Смотрю как …» со
ссылкой на вкладку **«Отладка»** (`/debug`, водителю недоступна):
* от чьего лица открыт экран и кнопка сменить водителя;
* `driver_id`, режим, сотрудник, когда истекает токен, адрес API, коммит и время
сборки, состояние сети;
* журнал последних 40 ответивших запросов (метод, путь, статус, миллисекунды);
* сброс кэша сервис-воркера с перезагрузкой — лечит «правка не приехала»;
* выходы: из просмотра, из учётки сотрудника.
### Деньги под просмотром: учебный платёж
Пополнение под `imp`-токеном **не идёт в банк**. Проверки суммы, категории и
расчёт комиссии настоящие, а вместо Init на терминале заводится учебный заказ в
Redis (`modules/payments/mock_pay.py`, префикс `mock-`, час жизни). Экран
`/mock-pay/:orderId` даёт выбрать, что «ответит» банк — оплачено, отказ,
истёкший счёт, возврат, — и настоящий экран оплаты разбирает эти статусы своим
боевым кодом. В `driver_payments` не попадает ни строки, чек 54-ФЗ не пробивается.