# 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=` **TTL сессии**: рекомендуем 5–10 минут. По истечении `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=`. 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-код. - [ ] Сессии экспайрятся (5–10 мин для 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** — сколько живёт?