From f90af4c78e0f38c9be98670659bf75e6c778fae0 Mon Sep 17 00:00:00 2001 From: NW Date: Wed, 5 Aug 2026 12:07:56 +0100 Subject: [PATCH] docs(admin): frontend spec for admin panel + endpoint architecture (issue #131) --- docs/admin-frontend-spec.md | 750 ++++++++++++++++++++++++++++++++++++ 1 file changed, 750 insertions(+) create mode 100644 docs/admin-frontend-spec.md diff --git a/docs/admin-frontend-spec.md b/docs/admin-frontend-spec.md new file mode 100644 index 0000000..f5f8af8 --- /dev/null +++ b/docs/admin-frontend-spec.md @@ -0,0 +1,750 @@ +# Админ-панель 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` прямо в `