feat(web): React-фронтенд вместо Flet + fix restore rmtree на bind-mount

web-react/: SPA Vite+React+TS, nginx раздаёт статику и проксирует /api на api:8000 по локалке. docker-compose: web(Flet)->web-react на :80. transfer_crud.backup_restore: чистим содержимое data/radar вместо rmtree точки монтирования (EBUSY).
This commit is contained in:
jze9
2026-06-02 13:56:44 +00:00
parent 71887b084a
commit eac61923f4
38 changed files with 4480 additions and 10 deletions

58
web-react/README.md Normal file
View File

@@ -0,0 +1,58 @@
# web-react — фронтенд на React (Vite + TypeScript)
Замена Flet-интерфейса (`../web`). Обычный SPA: грузится в браузер один раз и работает
локально, обращаясь к API по HTTP. **Нет WebSocket и серверного UI-стейта** — это убирает
зависания, которые были у Flet (он рендерил UI на сервере и держал WS на каждого юзера).
Flet-сервис `web` намеренно оставлен в `docker-compose.yml` как запасной. Этот новый
фронтенд публикуется на **порту 3000**.
## Архитектура
```
Браузер ──▶ [ nginx :80 (контейнер web-react) ]
├── / → статика React (SPA, fallback на index.html)
└── /api/* → proxy_pass http://api:8000/ (включая SVG-диаграммы)
```
API-контейнер доступен только внутри Docker-сети, поэтому браузер ходит к нему через
nginx-прокси на том же origin (`/api/...`). SVG-диаграмма тянется напрямую `<img>`/`<a download>`.
## Разработка (локально)
```bash
# 1. Поднять API + БД (из корня репозитория)
docker compose up -d api postgres redis # postgres/redis — из docker-compose_db.yml
# 2. Dev-сервер фронтенда
cd web-react
npm install
npm run dev # http://localhost:5173, /api проксируется на http://localhost:8000
```
Адрес API для dev-прокси переопределяется переменной `API_URL` (см. `vite.config.ts`).
## Сборка / прод
```bash
# из корня репозитория
docker compose up -d --build web-react # http://localhost:3000
```
Либо вручную: `npm run build` → статика в `dist/`, раздаётся nginx (см. `Dockerfile`, `nginx.conf`).
## Структура
| Путь | Назначение |
|---|---|
| `src/api/client.ts` | все запросы к API (порт `web/api_client.py`) |
| `src/auth/` | `AuthContext` — токен в localStorage + `/users/me` |
| `src/theme/` | 5 тем + слайдер масштаба через CSS-переменные |
| `src/components/` | переиспользуемые компоненты (Button, TextField, SearchableDropdown, Layout, Modal, RadarBlock…) |
| `src/pages/` | экраны: Login, Register, Home, TestList, Poll, MyTests, Response, Profile |
| `src/styles/global.css` | стили на CSS-переменных |
## Маршруты
`/login`, `/register`, `/` (домашняя), `/tests`, `/poll/:pollId`, `/my-tests`,
`/response/:responseId`, `/profile`. Защищённые маршруты требуют токен (`ProtectedRoute`).