Add the admin panel scaffold
A self-contained template: an Express backend with login, JWT, rate limiting and SPA serving, and a React 18 + Vite shell with the same tab registry and warm Material 3 design system the panel uses. No domain logic — routes and tabs are meant to be hung off it. node_modules and the frontend build stay out through the existing ignores.
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
# Admin — каркас админ-панели
|
||||
|
||||
Самодостаточный шаблон админки: бэкенд с авторизацией и фронтенд-оболочка
|
||||
с системой вкладок. Предметной логики нет — это основа, поверх которой
|
||||
навешиваются свои роуты и вкладки.
|
||||
|
||||
```
|
||||
admin/
|
||||
backend/ Express: /login, /logout, JWT, rate-limit, отдача SPA
|
||||
server.ts
|
||||
frontend/ React 18 + Vite: логин, тема, drawer/сайдбар, реестр вкладок
|
||||
src/App.tsx оболочка
|
||||
src/App.css дизайн-система (Material 3, тёплая палитра)
|
||||
src/tabs/ вкладки — см. src/tabs/README.md
|
||||
src/components/ общие компоненты и иконки (+ карта ICONS)
|
||||
src/lib/shared.ts общие типы/утилиты + PageProps
|
||||
src/lib/branding.ts название и версия панели
|
||||
```
|
||||
|
||||
## Запуск в деве
|
||||
|
||||
Два терминала:
|
||||
|
||||
```bash
|
||||
cd admin/backend && npm install && ADMIN_PASS=admin npm start # :8080
|
||||
cd admin/frontend && npm install && npm run dev # :5173
|
||||
```
|
||||
|
||||
Открыть http://localhost:5173 — логин `admin` / `admin`.
|
||||
Vite проксирует `/api`, `/login`, `/logout` на бэкенд, поэтому фронт всегда
|
||||
ходит по относительным путям и порт нигде не зашит.
|
||||
|
||||
## Прод
|
||||
|
||||
```bash
|
||||
cd admin/frontend && npm run build # → frontend/dist
|
||||
cd admin/backend && npm start # раздаёт dist и API с одного порта
|
||||
```
|
||||
|
||||
## Переменные окружения (backend)
|
||||
|
||||
| Переменная | По умолчанию | Смысл |
|
||||
|---------------|---------------------------|--------------------------------------------------------------|
|
||||
| `PORT` | `8080` | Порт бэкенда |
|
||||
| `ADMIN_USER` | `admin` | Логин в панель |
|
||||
| `ADMIN_PASS` | — (пусто ⇒ вход отключён) | Пароль; без него `/login` всегда отвечает 401 |
|
||||
| `JWT_SECRET` | случайный при старте | Подпись токенов; без него сессии рвутся при рестарте процесса |
|
||||
| `STATIC_DIR` | `../frontend/dist` | Каталог со сборкой фронта |
|
||||
|
||||
## Авторизация
|
||||
|
||||
`POST /login` (логин + пароль) → HS256 JWT на 24 часа, подписанный `JWT_SECRET`
|
||||
через встроенный `crypto` — без сторонних JWT-библиотек. Токен хранится в
|
||||
`localStorage` и уходит в заголовке `Authorization: Bearer`. `POST /logout`
|
||||
добавляет подпись токена в in-memory список отозванных — токен умирает сразу.
|
||||
Перебор пароля ограничен: 5 неудачных попыток с одного IP за 15 минут → 429.
|
||||
|
||||
Всё под `/api` закрыто мидлварой `requireAuth` — свои роуты добавляй ниже
|
||||
строки `app.use("/api", requireAuth)` в `server.ts`, и они получают авторизацию
|
||||
даром. `GET /api/session` уже есть: фронт зовёт его при загрузке, чтобы понять,
|
||||
жив ли сохранённый токен.
|
||||
|
||||
## Как добавить свой раздел
|
||||
|
||||
1. Роут на бэкенде — в `server.ts` под `/api/…`.
|
||||
2. Вкладку на фронте — папка в `src/tabs/`, реестр подхватит её сам.
|
||||
Подробности и формат `metadata.json` — в [src/tabs/README.md](frontend/src/tabs/README.md).
|
||||
Reference in New Issue
Block a user