feat: АРМ администратора — записи, состояние стенда, аудит, копии (lct-24)
Целый раздел ТЗ, от которого не было ни одной функции. - Учётные записи: завести, сменить роль и службу, заблокировать, сбросить пароль. Обучающемуся заводится и карточка курсанта — на ней висят профиль и проверка «это твой разбор». - Состояние компонентов: база, модели речи, эмбеддинги, провайдер LLM, версия классификатора, число живых занятий. Отдельной строкой — секрет сессии: значение по умолчанию не ошибка запуска, но на стенде это дыра, и увидеть её должен администратор, а не проверяющий на защите. - Журнал действий с фильтром, только на чтение. - Резервные копии: кнопка и make backup для cron. pg_dump берётся локальный, а если его нет — из контейнера базы; если нет ни того ни другого, администратор видит, чего не хватает, а кнопка не молчит. Границы роли выражены отсутствием маршрутов, а не проверками внутри них: в разделе нет ни одной точки, трогающей оценки или пишущей в аудит. Два теста проверяют это перебором маршрутов роутера — так запрет нельзя ослабить, случайно добавив обработчик. Найдено по ходу: тесты с базой падали в компании и проходили поодиночке. Движок SQLAlchemy кэшировался на процесс, а каждый TestClient поднимает свой событийный цикл — пул привязан к первому. Появился db.base.reset() и фикстура, дающая движок на тест. 193 теста зелёных (12 новых).
This commit is contained in:
parent
d55c8bc8cd
commit
641e505c67
13 changed files with 948 additions and 1 deletions
|
|
@ -3,6 +3,7 @@ import { createBrowserRouter, Navigate } from "react-router-dom";
|
|||
import { Call } from "@/pages/trainee/Call";
|
||||
import { Instructor } from "@/pages/instructor/Instructor";
|
||||
import { Dds } from "@/pages/dds/Dds";
|
||||
import { Admin } from "@/pages/admin/Admin";
|
||||
import { Profile } from "@/pages/profile/Profile";
|
||||
import { Wall } from "@/pages/wall/Wall";
|
||||
import { RequireAuth } from "@/features/auth/Login";
|
||||
|
|
@ -23,4 +24,5 @@ export const router = createBrowserRouter([
|
|||
{ path: "/wall", element: guarded("/wall", <Wall />) },
|
||||
{ path: "/profile", element: guarded("/profile", <Profile />) },
|
||||
{ path: "/dds", element: guarded("/dds", <Dds />) },
|
||||
{ path: "/admin", element: guarded("/admin", <Admin />) },
|
||||
]);
|
||||
|
|
|
|||
Loading…
Reference in a new issue