Files
qr_vitanova/BACKEND.md
2026-04-30 01:17:17 +04:00

215 lines
9.6 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.
# Fastcheck Backend — требования к серверу
Документ для команды бэкенда. Описывает, что должен реализовать сервер `api.fastcheck.store`, чтобы веб-фронт (этот репозиторий) полностью заработал.
---
## 1. Общие требования
### 1.1 Транспорт
- **Протокол**: HTTPS обязателен (валидный TLS-сертификат, Let's Encrypt или иной).
- **Хост**: `api.fastcheck.store` (или другой — тогда поправить `FASTCHECK_API` в `src/app/api.ts`).
- **Формат тел запроса/ответа**: `application/json; charset=utf-8`.
### 1.2 CORS — **критично**
Браузер фронта пойдёт с другого origin. Без правильных CORS-заголовков **ничего не заработает** (preflight упадёт, fetch вернёт network error — ровно то, что мы видим сейчас).
Сервер должен на любой `OPTIONS` (preflight) и на ответы реальных запросов отдавать:
```
Access-Control-Allow-Origin: https://<домен-фронта> # либо * для dev
Access-Control-Allow-Methods: GET, POST, DELETE, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400
```
Если используются cookies/credentials — добавить `Access-Control-Allow-Credentials: true` и **нельзя** использовать `*` в `Allow-Origin`.
`OPTIONS` должен отвечать `204 No Content` без тела.
### 1.3 Авторизация
Заголовок передаётся как **JSON-строка**, а не Bearer:
```
Authorization: {"sessionID":"1AF3781BF6B94604B771AEA1D44FA63A"}
```
Парсинг на сервере: `JSON.parse(req.headers.authorization)``{ sessionID }`.
Если заголовок отсутствует или сессия невалидна — `404 { "message": "not authorized" }`.
### 1.4 Ошибки
Любая ошибка — JSON `{ "message": "<человекочитаемое описание>" }` + HTTP-статус (4xx/5xx). Фронт показывает `message` пользователю.
---
## 2. Эндпоинты
База: `https://api.fastcheck.store`
### 2.1 `GET /ping`
Healthcheck. Ответ: `200 { "message": "pong" }`. Без авторизации.
---
### 2.2 `GET /websession`
Создаёт новую веб-сессию для QR-логина через Telegram-бот.
**Запрос**: без тела, без авторизации.
**Ответ** `200`:
```json
{
"sessionId": "1AF3781BF6B94604B771AEA1D44FA63A",
"userId": "",
"expires": "sessionId",
"userSessionId": "",
"Status": false
}
```
`sessionId` фронт подставляет в QR-код и в deeplink на бот:
`https://t.me/DexarSupport_bot?start=<sessionId>`
**TTL сессии**: рекомендуем 510 минут. По истечении `GET /websession/:id` должен вернуть `Status: false` навсегда (фронт сам пересоздаст).
---
### 2.3 `GET /websession/:webSessionID`
Поллинг статуса логина. Фронт зовёт каждые **3 секунды**, пока попап открыт.
**Ответ** `200` пока пользователь не залогинился:
```json
{ "sessionId": "...", "userId": "", "expires": "sessionId", "userSessionId": "", "Status": false }
```
**Ответ** `200` после того, как Telegram-бот подтвердил вход:
```json
{
"sessionId": "1AF3781BF6B94604B771AEA1D44FA63A",
"userId": "kHaAe9roaC2uq63AKGE/8+Ti/t/iFro68QhEZ1dRGLo",
"expires": "sessionId",
"userSessionId": "8A94EFEFD003426A9B456C48CAC99BE6",
"Status": true
}
```
Если сессия не найдена/истекла — `404 { "message": "session expired" }`.
---
### 2.4 `DELETE /websession/:webSessionID`
Logout / закрытие попапа.
**Запрос**:
```json
{ "sessionId": "1AF3781BF6B94604B771AEA1D44FA63A" }
```
**Ответ** `200 {}`. Идемпотентно — повторный вызов не должен ломаться.
---
### 2.5 `GET /fastcheck`
Проверка существования и срока действия чека (используется опционально перед оплатой).
**Запрос** (тело в GET):
```json
{ "fastcheck": "1234-5678-0001" }
```
**Ответ** `200`:
```json
{
"fastcheck": "1234-5678-0001",
"expiration": "2026-07-07T09:08:18Z",
"Status": true
}
```
Не существует / просрочен → `404 { "message": "not found" }`.
---
### 2.6 `POST /fastcheck` — **создание чека**
Юзер уже залогинен, его `sessionID` есть на фронте. С этого аккаунта списывается `amount`, выпускается чек.
**Заголовок**: `Authorization: {"sessionID":"..."}` обязателен.
**Тело**:
```json
{ "amount": 158000, "currency": "RUB" }
```
`amount` — в минимальных единицах валюты (копейки для RUB). Уточнить с фронтом, если иначе.
**Ответ** `200`:
```json
{
"fastcheck": "1234-5678-0001",
"expiration": "2026-07-07T09:08:18Z",
"code": "5864",
"Status": true
}
```
**Ошибки**:
- `404 { "message": "not authorized" }` — нет/невалидная сессия.
- `400 { "message": "insufficient balance" }` — мало средств.
- `400 { "message": "invalid amount" }` — некорректная сумма/валюта.
---
### 2.7 `POST /fastcheck` — **приём чека (оплата)**
Этот же путь, отличается шейпом тела (без `amount`, с `code`).
**Заголовок**: `Authorization: {"sessionID":"..."}` обязателен (сессия получателя — того, кто оплачивает).
**Тело**:
```json
{ "fastcheck": "1234-5678-0001", "code": "5864" }
```
**Ответ** `200 { "message": "ok" }` — чек погашен, средства зачислены получателю.
**Ошибки**:
- `404 { "message": "not authorized" }` — сессия невалидна **или** код неверный, **или** чек уже использован, **или** просрочен. (Так в текущей доке. Если можно различать — лучше отдельные сообщения.)
> ⚠️ Серверу важно различать два POST-кейса по наличию поля `amount` vs `code` в теле. Альтернатива (предпочтительнее на проде) — развести на разные пути: `POST /fastcheck` (создание) и `POST /fastcheck/accept` (приём). Если разведёте — скажите, фронт правится за 5 минут.
---
## 3. Интеграция с Telegram-ботом
Фронт сам бот не дёргает — это задача бэкенда.
1. Юзер сканит QR / кликает deeplink → попадает в бот `@DexarSupport_bot` с параметром `?start=<sessionId>`.
2. Бот идентифицирует Telegram-аккаунт (по `from.id`) → находит/создаёт `userId` → биндит его к `sessionId` → ставит `Status: true`, заполняет `userId` и `userSessionId`.
3. Следующий поллинг с фронта вернёт `Status: true` — фронт переходит к `POST /fastcheck`.
Если юзер впервые в боте — стандартный onboarding, потом всё то же самое.
---
## 4. Чеклист «готово к проду»
- [ ] HTTPS с валидным сертификатом на `api.fastcheck.store`.
- [ ] CORS разрешает домен фронта на всех 6 эндпоинтах + OPTIONS.
- [ ] `GET /ping` отвечает.
- [ ] Полный цикл: `GET /websession` → бот ставит `Status:true``GET /websession/:id` это видит.
- [ ] `POST /fastcheck` (create) с заголовком `Authorization` создаёт чек, списывает баланс.
- [ ] `POST /fastcheck` (accept) погашает чек только один раз, зачисляет получателю.
- [ ] `DELETE /websession/:id` корректно завершает сессию.
- [ ] Все ошибки в формате `{ "message": "..." }` + правильный HTTP-код.
- [ ] Сессии экспайрятся (510 мин для websession, разумный TTL для userSession).
- [ ] Rate-limit на `GET /websession/:id` (фронт поллит каждые 3 с) и на `POST /fastcheck`.
---
## 5. Открытые вопросы (нужны ответы от бэкенда)
1. **Единица `amount`**: рубли или копейки?
2. **Currency**: какие коды поддерживаете кроме `RUB`? (фронт уже умеет показывать, но шлёт пока только RUB)
3. **Merchant callback** для эквайринга: после успешного `POST /fastcheck (accept)` нужно ли серверу самому пинговать мерчант-вебхук, или это полностью на фронте через `?return_url=`?
4. **Различение ошибок accept**: можно ли вместо общего `404 not authorized` отдавать `not found` / `wrong code` / `already used` / `expired`?
5. **WebSession TTL** — сколько живёт?