This commit is contained in:
sdarbinyan
2026-05-06 23:26:00 +04:00
parent 34f6c80e57
commit 742b2665e9
91 changed files with 6310 additions and 4723 deletions

214
BACKEND.md Normal file
View File

@@ -0,0 +1,214 @@
# 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** — сколько живёт?