каркас: домен, генерация типов фронта, стенд и карточки задач
Контракт в коде: КИО по нормативу, 43 события WS по шести союзам направлений,
таймеры ГОСТ, таксономия E1–E6, шесть компетенций радара. make types гоняет
их через JSON Schema в generated.ts, тест ловит забытую регенерацию.
Стенд: docker compose postgres + backend, health отвечает, база досягаема
из контейнера бэкенда. Makefile не врёт — нереализованные цели падают
и называют карточку, которая их закроет.
frontend/.npmrc: под WSL2 npm install зависает на дефолтных 15 сокетах.
2026-09-15 19:35:03 +03:00
|
|
|
/* Казённая база: системный шрифт, плотная сетка, три состояния норматива.
|
|
|
|
|
Продуктовой эстетики здесь быть не должно (docs/arch/FRONTEND.md). */
|
|
|
|
|
:root {
|
|
|
|
|
--bg: #f2f3f5;
|
|
|
|
|
--panel: #ffffff;
|
|
|
|
|
--line: #b9bec6;
|
|
|
|
|
--text: #14171a;
|
|
|
|
|
--ok: #1f6f3d;
|
|
|
|
|
--warn: #9a6b00;
|
|
|
|
|
--violated: #a51d1d;
|
|
|
|
|
font-family: system-ui, "Segoe UI", Roboto, sans-serif;
|
|
|
|
|
font-size: 15px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
body {
|
|
|
|
|
margin: 0;
|
|
|
|
|
background: var(--bg);
|
|
|
|
|
color: var(--text);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.stub {
|
|
|
|
|
padding: 24px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.stub h1 {
|
|
|
|
|
font-size: 20px;
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
margin: 0 0 8px;
|
|
|
|
|
}
|
lct-08: каркас фронта, типизированный сокет, захват микрофона
Направление канала зашито в тип: у наблюдателя Out = never, отправить
нечего и нельзя; у преподавателя нет входящих. Разделение прав
архитектурное и на фронте тоже. Пока соединения нет, события не копятся:
истина на сервере, после переподключения придёт актуальное состояние.
Ресемплинг 48 → 16 кГц усредняет по окну выходного сэмпла: без фильтра
всё выше 8 кГц наложилось бы на речь и испортило распознавание. Проверено
числами: секунда звука — ровно 50 кадров по 320 сэмплов из 48 и 44.1 кГц,
помеха 15 кГц подавлена до 7.8%. Эхоподавление и автоусиление браузера
выключены: гарнитура эхо не даёт, а обработка портит речь для STT.
Бэкенд принимает бинарные кадры по тому же сокету, что и события; кадр
не того размера отбрасывается с одним предупреждением, а не 50 в секунду.
Логирование приложения не было настроено: uvicorn настраивает только
свои логгеры, и весь INFO модулей app.* молча терялся — нашлось, когда
в логе не оказалось строки о принятых кадрах.
make lesson запускает занятие и печатает ссылки на экраны — пульта
преподавателя ещё нет, а открыть АРМ курсанта без занятия не с чем.
Путь из браузера с живым микрофоном не проверен: нужен человек, шаги
записаны в карточке.
2026-09-17 14:19:38 +03:00
|
|
|
|
|
|
|
|
/* Плотная казённая сетка: таблица вместо карточек. */
|
|
|
|
|
.page { padding: 16px 24px; }
|
|
|
|
|
.page h1 { font-size: 20px; font-weight: 600; margin: 0 0 12px; }
|
|
|
|
|
.page h2 { font-size: 16px; font-weight: 600; margin: 20px 0 8px; }
|
|
|
|
|
.grid { border-collapse: collapse; background: var(--panel); min-width: 480px; }
|
|
|
|
|
.grid th, .grid td { border: 1px solid var(--line); padding: 4px 8px; text-align: left; vertical-align: top; }
|
|
|
|
|
.grid th { width: 200px; font-weight: 600; background: var(--bg); }
|
|
|
|
|
button { font: inherit; padding: 6px 16px; border: 1px solid var(--line); background: var(--panel); cursor: pointer; }
|
|
|
|
|
button:disabled { opacity: 0.5; cursor: default; }
|
|
|
|
|
.warn { color: var(--warn); }
|
|
|
|
|
.violated { color: var(--violated); }
|