Files
telegram-shop/docs/API.md
NW d7680357af chore: repo cleanup + docs for admin API and DB schema (v1.2.8)
- remove stale docs/admin-frontend-spec.md (old Express/EJS admin), unused templates/ (SmartAdmin copy), dead scripts/sync-agents.cjs, committed dev.pid
- add docs/API.md (admin REST API reference) and docs/DATABASE.md (DB schema)
- refresh .env.example: drop stale ADMIN_PORT/SHOP_CONTAINER, add ADMIN_URL, HEALTH_PORT, DEFAULT_LANGUAGE, CHATBOT_API_*
- add npm run lint so Gitea workflows pass
- rebrand web-testing suite from APAW to telegram-shop
2026-08-09 00:22:22 +01:00

208 lines
13 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.
# Telegram Shop — Admin API Reference
Актуальная документация по REST API админ-панели (`admin-next/`, Next.js 16 + Prisma).
- **Базовый URL**: `http://<host>:3000`
- **Формат**: JSON (`Content-Type: application/json`)
- **Аутентификация**: cookie `admin_token` (httpOnly, 24ч), устанавливается через `POST /api/auth/login`
## Аутентификация
| Метод | Путь | Описание |
|---|---|---|
| POST | `/api/auth/login` | Вход по токену. Body: `{ "token": "..." }`. Rate-limit: 5 попыток / 15 мин на IP (429). Устанавливает cookie `admin_token` |
| GET | `/api/auth/session` | Проверка сессии. Ответ: `{ "role": "admin" \| "super_admin" }` (401 если нет/просрочен) |
| POST | `/api/auth/logout` | Выход, удаляет cookie |
### Роли
- `admin` — обычный администратор
- `super_admin` — доступ к seed-фразам, экспорту, импорту, очистке БД
Роль определяется при входе: если `SUPER_ADMIN_SECRET` не задан или равен `ADMIN_SECRET` — все админы получают `super_admin`. Иначе роль `super_admin` даёт только вход по `SUPER_ADMIN_SECRET`.
**Все эндпоинты ниже требуют cookie `admin_token`** (иначе 401). Эндпоинты с пометкой 🔒 требуют роль `super_admin` (иначе 403).
## Дашборд и статистика
### GET `/api/stats/dashboard`
Сводная статистика для дашборда:
- counts: `totalUsers`, `totalProducts`, `totalPurchases`, `totalSubcategories`, `bannedUsers`, `activeWallets`
- статусы покупок: `completedPurchases`, `pendingPurchases`, `cancelledPurchases`
- метрики: `totalRevenue` (сумма completed), `aov`, `conversionRate`
- временные ряды: `revenueByDay`, `purchasesByDay`, `newUsersByDay` (последние 30 дней)
- `topProducts`, `recentPurchases`, `recentUsers`
## Каталог
### GET `/api/catalog/tree`
Полное дерево каталога: локации, категории, подкатегории с `_count` (вложенные сущности).
### Локации
| Метод | Путь | Описание |
|---|---|---|
| GET | `/api/locations/bulk` | Список локаций (с `_count` категорий/товаров) |
| POST | `/api/locations/bulk` | Создать. Body: `{ country, city, district }` |
| PUT | `/api/locations/[id]` | Обновить. Body: `{ country?, city?, district? }` |
| PATCH | `/api/locations/[id]` | Переключить `is_active` (0/1) |
| DELETE | `/api/locations/[id]` | Удалить (409 если есть связанные сущности) |
### Категории
| Метод | Путь | Описание |
|---|---|---|
| GET | `/api/categories/bulk` | Список категорий (с локацией и `_count`) |
| POST | `/api/categories/bulk` | Создать. Body: `{ name, locationId }` |
| PUT | `/api/categories/[id]` | Обновить. Body: `{ name?, locationId? }` (409 при дубликате в локации) |
| PATCH | `/api/categories/[id]` | Переключить `is_active` |
| DELETE | `/api/categories/[id]` | Удалить (409 если есть связанные сущности) |
### Подкатегории
| Метод | Путь | Описание |
|---|---|---|
| GET | `/api/subcategories/bulk` | Список подкатегорий |
| POST | `/api/subcategories/bulk` | Создать. Body: `{ name, categoryId }` |
| PUT | `/api/subcategories/[id]` | Обновить. Body: `{ name?, categoryId? }` |
| PATCH | `/api/subcategories/[id]` | Переключить `is_active` |
| DELETE | `/api/subcategories/[id]` | Удалить |
### Товары
| Метод | Путь | Описание |
|---|---|---|
| GET | `/api/products/bulk` | Список. Query: `loc`, `cat`, `sub`, `search`, `page`, `limit` (≤100). Ответ: `{ data, total, page, limit }` |
| POST | `/api/products/add` | Создать. Body: `{ locationId, categoryId, subcategoryId?, name, description?, privateData?, price, quantityInStock?, photoUrl?, hiddenPhotoUrl?, hiddenCoordinates?, hiddenDescription?, isMono? }`. Обязательны: `locationId, categoryId, name, price`. `isMono=1``quantityInStock=999999` |
| GET | `/api/products/[id]` | Детали товара (с category, subcategory, location) |
| PUT | `/api/products/[id]` | Обновить (частично) |
| DELETE | `/api/products/[id]` | Удалить |
| POST | `/api/products/[id]/clone` | Клонировать (имя получает суффикс `(Copy)`) |
## Пользователи
| Метод | Путь | Описание |
|---|---|---|
| GET | `/api/users/bulk` | Список. Query: `search` (username/telegramId), `status` (0/2), `page`, `limit` (≤100). Ответ: `{ data, total, page, limit }` |
| GET | `/api/users/[id]` | Детали: пользователь + кошельки + последние 20 покупок + связанный лид |
| POST | `/api/users/[id]` | Обновить (username, country, city, district, notes и т.д.) |
| PATCH | `/api/users/[id]` | Переключить `status` (0=active, 2=blocked) |
| POST | `/api/users/[id]/adjust-balance` | Изменить баланс. Body: `{ amount: number, currency: "total_balance" \| "bonus_balance" }`. Пишет audit-запись |
| POST | `/api/users/batch-status` | Массово сменить статус. Body: `{ userIds: number[], newStatus: 0 \| 2 }` |
## Кошельки
| Метод | Путь | Описание |
|---|---|---|
| GET | `/api/wallets/bulk` | Пользователи, у которых есть кошельки. Query: `search`. Ответ: `{ users, totalWallets, totalBalance }` |
| GET | `/api/wallets/[userId]` | Кошельки конкретного пользователя |
| GET | `/api/wallets/overview` | Сводка: суммы и количество по типам (BTC/LTC/ETH/USDT/USDC), последние 20 комиссионных выплат |
| GET | `/api/wallets/seeds` | 🔒 Seed-фразы всех кошельков (пишет audit `seed_phrase_viewed`) |
| GET | `/api/wallets/export-seeds` | 🔒 Экспорт seed-фраз в CSV (Content-Disposition: attachment) |
| POST | `/api/wallets/record-payment` | Записать комиссионную выплату. Body: `{ paidAmount: number, note? }` |
## Покупки
| Метод | Путь | Описание |
|---|---|---|
| GET | `/api/purchases/bulk` | Список. Query: `status` (pending/completed/cancelled), `from`, `to` (YYYY-MM-DD), `page`, `limit` (≤100). Ответ: `{ data, total, page, limit }` |
| PATCH | `/api/purchases/[id]` | Сменить статус. Body: `{ status: "completed" \| "cancelled" }`. Только для `pending` |
| POST | `/api/purchases/batch-status` | Массово. Body: `{ purchaseIds: number[], status: "completed" \| "cancelled" }` (обновляет только pending) |
## Транзакции
| Метод | Путь | Описание |
|---|---|---|
| GET | `/api/transactions/bulk` | Список. Query: `userId`, `page`, `limit` (≤100, по умолчанию 20). Ответ: `{ data, total, page, limit }` |
## Лиды и чат
### Лиды
| Метод | Путь | Описание |
|---|---|---|
| GET | `/api/leads/bulk` | Список. Query: `search` (name/phone/email/telegram/telegramId), `status`, `page`, `limit` (≤100). Ответ: `{ data, total, page, limit }` |
| GET | `/api/leads/[id]` | Детали лида + связанный пользователь (баланс, покупки, кошельки) |
| PUT | `/api/leads/[id]` | Обновить (name, phone, email, telegram, status, notes, customFields и т.д.) |
| GET | `/api/leads/[id]/activity` | Активность: `{ hourly: number[24], yearly: { "YYYY-MM-DD": count }, total }` (по audit_log) |
| GET | `/api/leads/[id]/sessions` | Чат-сессии лида с распарсенными сообщениями |
### Чат (публичный виджет)
| Метод | Путь | Описание |
|---|---|---|
| POST | `/api/chat` | Отправить сообщение в чат-виджет. Body: `{ sessionId?, message, language?, device?, ip?, country? }`. Создаёт/обновляет `ChatSession`, извлекает данные лида (имя/телефон/email/telegram), вызывает ИИ-провайдера, при `chatbot_sleep_mode` отвечает sleep-сообщением |
### Оператор
| Метод | Путь | Описание |
|---|---|---|
| POST | `/api/operator` | Подключение/отключение оператора. Body: `{ sessionId, action: "connect" \| "disconnect", operatorName }`. Пишет audit `operator_connect` |
## Чатбот (настройки)
| Метод | Путь | Описание |
|---|---|---|
| GET | `/api/admin/chatbot` | Настройки чатбота из `site_settings` (ключи `chatbot_*`), API-ключ маскируется |
| PUT | `/api/admin/chatbot` | Обновить настройки. Валидация: `chatbot_temperature` 02, `chatbot_max_tokens` 504000, `chatbot_max_history` 150 |
| GET | `/api/chatbot/models?endpoint=&apiKey=` | Список моделей провайдера через OpenAI-совместимый `/models`. Без query — берёт сохранённые настройки. Поддерживает OpenAI (`data[]`) и Ollama (`models[]`) |
Ключи настроек чатбота (defaults):
`chatbot_enabled`, `chatbot_sleep_mode`, `chatbot_sleep_message`, `chatbot_system_prompt`, `chatbot_temperature` (0.7), `chatbot_max_tokens` (1024), `chatbot_max_history` (20), `chatbot_knowledge_base`, `chatbot_provider` (ollama), `chatbot_api_endpoint`, `chatbot_api_key`, `chatbot_model`.
## Аудит
| Метод | Путь | Описание |
|---|---|---|
| GET | `/api/audit/bulk` | Журнал аудита. Query: `page`, `limit` (≤200, по умолчанию 100), `userId`, `from`, `to`, `search`, `action`. Ответ: `{ data, total, page, limit }` |
## Локализация (i18n)
| Метод | Путь | Описание |
|---|---|---|
| GET | `/api/locales` | Все переводы: `{ en: {...}, es: {...}, de: {...} }` |
| PUT | `/api/locales` | Обновить ключ. Body: `{ lang, key, value }` |
## Настройки
| Метод | Путь | Описание |
|---|---|---|
| GET | `/api/settings` | Список настроек (секреты маскированы, список в `_masked`) |
| PUT | `/api/settings` | Обновить. Body: `{ key, value }`. Ответ: «Settings saved. Restart required.» |
| GET | `/api/settings/export` | Полный экспорт БД в JSON (users, wallets, purchases, categories, subcategories, locations, products, auditLogs, commissionPayments, userStates) |
| POST | `/api/settings/import` | 🔒 Импорт (заглушка: «Import not yet implemented») |
## Seed / Demo
| Метод | Путь | Описание |
|---|---|---|
| GET | `/api/seed/data` | Проверка: `{ seeded: boolean }` (есть ли пользователи) |
| POST | `/api/seed/demo` | Заполнить демо-данными. Body: `{ reauthToken }` (повторный ввод секрета) |
| POST | `/api/seed/clear` | 🔒 Очистить все данные. Body: `{ reauthToken }`. Пишет audit `clear_all` |
## Корневой
| Метод | Путь | Описание |
|---|---|---|
| GET | `/api` | Служебный ответ (health API) |
## Коды ошибок
| Код | Значение |
|---|---|
| 400 | Невалидный запрос / отсутствуют обязательные поля |
| 401 | Нет cookie `admin_token` или токен невалиден/просрочен |
| 403 | Недостаточно прав (нужен `super_admin`) |
| 404 | Сущность не найдена |
| 409 | Конфликт (дубликат, есть связанные записи) |
| 429 | Слишком много попыток входа |
| 500 | Внутренняя ошибка |
## Соглашения
- Пагинация: `page` (с 1), `limit` (кап зависит от эндпоинта: 50/100/200)
- Даты: `from`/`to` в формате `YYYY-MM-DD` (to инклюзивно до конца дня)
- `is_active`/`status` пользователей: `0` = активно, `2` = заблокировано
- Статусы покупок: `pending` / `completed` / `cancelled`
- Статусы лидов: `new` / `contacted` / `qualified` / `lost` / `spam`