# Админ-панель Telegram Shop — Техническое описание фронтенда и API > **Назначение документа**: комплексное ТЗ для отдела фронтенда по реализации полноценного админ-кабинета поверх существующего бэкенда. > **Версия бэкенда**: v1.2.4 (2026-08-05) > **Дата**: 2026-08-05 > **Статус**: актуально на момент передачи --- ## Оглавление 1. [Обзор системы](#1-обзор-системы) 2. [Технологический стек](#2-технологический-стек) 3. [Архитектура развёртывания](#3-архитектура-развёртывания) 4. [Доступ и безопасность](#4-доступ-и-безопасность) 5. [Схема базы данных](#5-схема-базы-данных) 6. [Карта эндпоинтов (полная)](#6-карта-эндпоинтов-полная) 7. [Спецификация экранов](#7-спецификация-экранов) 8. [Роли и права](#8-роли-и-права) 9. [Формат данных](#9-формат-данных) 10. [Существующие ограничения и подводные камни](#10-существующие-ограничения-и-подводные-камни) 11. [Требования к новому фронтенду](#11-требования-к-новому-фронтенду) 12. [API-контракты JSON (дополнить бэкенду)](#12-api-контракты-json-дополнить-бэкенду) 13. [Чек-лист приёмки](#13-чек-лист-приёмки) --- ## 1. Обзор системы Telegram Shop — это **Telegram-бот-магазин** (Node.js) с **встроенной админ-панелью** на Express + EJS (шаблон SmartAdmin). Продажи идут через Telegram-бота, админка управляет всем магазином через браузер. Бизнес-сущности: | Сущность | Описание | |---|---| | **Users** | Покупатели из Telegram (id, ник, локация, статус, балансы, язык) | | **Locations** | Гео-иерархия: Страна → Город → Район (округа) | | **Categories / Subcategories** | Категории товаров, привязанные к локации; подкатегории внутри категории | | **Products** | Товары: цена, остаток, публичное фото, скрытый контент (фото/координаты/описание), private-заметки, цифровые (mono) | | **Purchases** | Заказы: пользователь, товар, валюта, tx_hash, количество, сумма, статус | | **Crypto Wallets** | Криптокошельки пользователей (BTC/LTC/ETH/USDT/USDC), с зашифрованными seed-фразами | | **Transactions** | Ончейн-транзакции пользователей | | **Commission payments** | Платежи комиссии владельцу платформы (SaaS-модель) | | **Audit log** | Журнал действий админов | | **Locales (i18n)** | JSON-файлы переводов бота (en/es/de), редактируются из админки | **Ключевой факт**: бот и админка живут в **одном процессе** и используют **одну SQLite-базу** (`db/shop.db`) — поэтому любые изменения в админке мгновенно видны боту и наоборот. Отдельного REST API **нет** — админка рендерит EJS на сервере и ходит в БД напрямую. --- ## 2. Технологический стек ### Текущий (серверная часть — НЕ трогать без отдельной задачи) | Слой | Технология | |---|---| | Язык | Node.js ≥ 18 (ES Modules, `"type": "module"`) | | Web-фреймворк | Express 4 | | Шаблонизация | EJS + `express-ejs-layouts` (layout: `views/layout.ejs`) | | Шаблон UI | SmartAdmin (собственные партиалы в `views/partials/`, SCSS в `public/sass/`, сборка `smartapp.min.css`) | | БД | SQLite через `better-sqlite3` (обёртка `db.runAsync/allAsync/getAsync` в `src/config/database.js`) | | Загрузка файлов | Multer (только картинки jpeg/png/webp/gif, ≤ 10 МБ) в `uploads/` | | QR | `qrcode` (для seed-фраз) | | CDN-ресурсы | Bootstrap 5.3.2, FontAwesome 6.4.2 с jsDelivr (только в legacy-`layout.js`) | ### Текущий фронтенд (что есть) - **Два параллельных набора вьюх**: 1. **EJS-шаблоны** (`views/*.ejs`) — используются роутами (dashboard, users, wallets, purchases, audit, settings, categories, locations, payment-wallets, seed, locales, catalog, products, product-edit, user-detail). 2. **JS-рендер-функции** (`views/*.js`) — legacy/дублирующий слой, возвращающий HTML-строки (`layout()`, `renderCatalog()`, `renderWalletLayout()` и т.д.). **На практике роуты рендерят EJS; JS-слой частично устарел** (дублирует catalog и wallets). Новый фронтенд их не использует. - Статика: Bootstrap 5 (SmartAdmin-тема), ApexCharts, jQuery, FontAwesome, собственные скрипты `public/scripts/`. - AJAX-вызовы есть только в нескольких местах (catalog-модалка, wallets-обновление балансов, locales). --- ## 3. Архитектура развёртывания ``` Internet │ ├── HTTPS/LAN ───────────────► telegram_shop_prod :3001 (Express: бот + админка) │ └── Tor Network ──► tor-proxy ──► HiddenService :80 ──► telegram_shop_prod :3001 (admin onion-адрес, работа без HTTPS) ``` - Единственный контейнер `telegram_shop_prod` (node:22-alpine) слушает порт `3001` (`ADMIN_PORT`). - Доступ к админке: напрямую `http://host:3001` или через `.onion` (Tor Browser). - Volume: `db/` (SQLite), `uploads/` (фото товаров, отдаются через `/uploads`), `.env` (только чтение). - WireGuard опционален (`WG_ENABLED`). **Следствие для фронтенда**: админка доступна по **HTTP без HTTPS** (в т.ч. через Tor). Это накладывает жёсткие ограничения: - нельзя использовать Secure-куки; - нельзя полагаться на Origin-проверку (Tor) — CSRF реализован вручную (см. §10); - весь JS/CSS должен быть либо локальным, либо закешированным (CDN может быть недоступен из Tor). --- ## 4. Доступ и безопасность ### 4.1. Аутентификация (важно для фронта) Реализована в `src/admin/auth.js`. **Не JWT, а самописный HMAC-токен**: | Параметр | Значение | |---|---| | Кука | `admin_token` (httpOnly, `sameSite=false`, maxAge 24ч) | | Формат токена | `base64(payload).hmac_sha256(payload)` | | Payload | `{ role, jti, iat, exp }` | | Секрет | `ADMIN_SECRET` (env) | | Вход | POST `/login` с полем `token` (пароль = админ-токен) | | Выход | GET `/logout` | Роли (определяются **каким секретом залогинились**): | Роль | Условие | Права | |---|---|---| | `admin` | токен = `ADMIN_SECRET` | Все страницы, кроме seed-выгрузки | | `super_admin` | токен = `SUPER_ADMIN_SECRET` (если задан и ≠ ADMIN_SECRET) | + просмотр/экспорт seed-фраз, комиссии | При `SUPER_ADMIN_SECRET` не заданном — **все админы считаются супер-админами** (`config.SUPER_ADMIN_IDS` по умолчанию = `ADMIN_IDS`, но роли в админке задаются именно через секреты, не через `ADMIN_IDS`). Rate-limit логина: 5 попыток / 15 минут с IP. **Деструктивные действия** (`/seed/*`) требуют повторного ввода токена в поле `reauth_token` (middleware `requireReAuth`). ### 4.2. Защита статики и загрузок - `/uploads/*` — только после `requireAuth`, заголовки `X-Content-Type-Options: nosniff` + `Content-Disposition: attachment` (фото не рендерятся inline из uploads, только скачивание). - Файлы uploads именуются `{timestamp}-{hex}.{ext}`, MIME-белый список. - CSRF: заглушка (`csrf.js` возвращает пустой токен и no-op) — **сознательно отключено ради совместимости с Tor**. См. §10. ### 4.3. Существующие уязвимости, которые фронтенд не должен усугублять 1. Нет реальной CSRF-защиты — все POST-формы уязвимы к cross-site-запросам. В новом фронте использовать токены, если бэкенд их вернёт, иначе как минимум не убирать подтверждения на деструктив. 2. Некоторые вьюхи выводят данные с ручным `esc()`/`escapeHtml()`; часть EJS использует `<%= %>` (экранируется) — но есть места с `JSON.stringify` прямо в `