Логика классификации типа задания и статуса «сдано» дублировалась в трёх местах
(dashboard.html, homework.html, assignmentController.js) и начала расходиться. Вынес в
один UMD-модуль frontend/js/assignment-utils.js (грузится и в браузере, и в Node через
require — как svg-sanitize.js): type(a), isDone(a, sub, opts), urgencyScore(a).
Нюанс «сдано» для upload/file параметризован: вид ученика (acceptedOnly) — закрыто только
при принятой сдаче; учитель/обзор долгов — любая сдача не на доработке. Поведение всех трёх
поверхностей сохранено 1:1.
- homework.html: asgnType/asgnDone/urgencyScore → тонкие делегаты в AssignmentUtils.
- dashboard.html: urgencyScore делегирует; classify и upload-ветка buildAssignCard через
AssignmentUtils.type/isDone (заодно корректнее: учебник-ДЗ больше не путается с upload).
- assignmentController: classOutstanding/_assignTypeOf → AssignmentUtils.
Verified: AU-контракт 25/25 (типы, isDone teacher vs acceptedOnly, порядок urgency);
интеграция 8/8 (classOutstanding те же 14 уч./42 просрочено; homework делегирует). node --check
всех файлов + инлайна обоих HTML.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Раньше ученик видел лишь 1 тест на предмет (дефолтный). Теперь учитель/админ
может пометить любой свой тест доступным, и он появляется в каталоге на дашборде.
- Миграция 079: tests.available_to_students (default 0).
- testController: list для ученика отдаёт тесты с available_to_students=1 и вопросами;
create/update принимают флаг; update сделан частичным (не затирает поля при toggle).
- admin «Тесты»: бейдж «Доступен ученикам» + быстрый тумблер «Ученикам/Скрыть»
(toggleTstAvail; конструктор доступен и учителям — видят свои тесты).
- Дашборд: виджет «Тесты» → секция «Доступные тесты» (loadAvailableTests), клик
запускает фикс-тест. Прячется, если доступных нет.
⚠️ Живой БД нужен npm run migrate (колонка).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Рассогласование: админ-настройка допускала режимы topic/random, но POST /api/sessions
принимает только exam/practice → клик по такому предмету падал с 400. Убрал topic/random
из валидатора subjects.js и из админ-дропдауна (SC_MODES). Дашборд: старые значения
topic/random коэрсятся в practice; предметы без вопросов в банке И без фикс-теста больше
не показываются (раньше давали 404 «No questions found» при запуске).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Hero-карточка #hc-lab имела href="/lab", но loadLabOfDay меняет его на
/lab?sim=<id> → CSS [href="/lab"] больше не матчит, карточка оставалась видной.
Прячем по стабильному id: #hc-lab/#hc-pet/#hc-read добавлены в FEATURE_WIDGETS
(lab/pet/textbooks). .hero-row переведён на grid auto-fit (minmax 240) — сетка сама
подстраивается под видимые карточки без дыры; syncHeroRow прячет весь ряд, если
карточек не осталось (мобайл-медиазапрос не трогаем — без инлайн-колонок).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
#w-flashcard прятался, но он — секция внутри #w-progress-col (один .widget-бокс с
рамкой/паддингом: карточка + прогресс по предметам + результаты). Если все секции
скрыты (флешкарты выкл и нет данных), оставался пустой бокс. Добавлена
syncProgressCol(): прячет #w-progress-col, если ни одна секция не видна (computed-
display, учитывает и инъект-CSS флешкарт). Зовётся в конце loadFlashcardWidget /
loadLastResultsWidget / loadSubjProgressWidget.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- hero-строка: крупное число занятий + тренд-пилюля со стрелкой
- сегментированный контрол масштаба (6н/12н/6м)
- ячейки тепловой карты: скруглённые квадраты, интенсивность через alpha, glow при наведении
- легенда типов — чипы-пилюли
- календарь «Месяц»: оттенок активных дней по нагрузке, пилюля стрика, мягкий ring сегодня
- паритет тёмной темы
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Бэкенд /api/dashboard/activity: per-day агрегация активности по типам (тест/экзамен/карты/уроки/
онлайн/домашка) из 6 таблиц за ~182 дня (раньше карта считала только тесты).
- Карта раскрашивается по доминирующему типу активности + легенда типов; интенсивность/размер по числу.
- Недельный тренд в футере («эта неделя N · +K к прошлой»).
- Тултип и попап по клику показывают разбивку дня по типам.
- Empty-state для новичков (вместо пустой сетки — призыв + CTA). Календарь «Месяц» тоже от всех активностей.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
renderFlashcardWidget рисует front_image/back_image на обеих сторонах;
.fcw-inner.has-img расширяет высоту карточки под изображение.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Декоративный SVG-фон (открытая книга) поверх градиента
- Тег-пилл с frosted-glass эффектом
- Progress bar 7px с белым свечением
- Мета и процент сгруппированы слева, кнопка — справа с тенью
- Градиент обогащён третьим стопом (#8b3010)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Раньше карточка использовала захардкоженный список из 6 симуляций и не знала
о каталоге. Теперь ежедневный выбор берётся из /api/lab/sims: только включённые
симуляции, у которых есть превью (приоритет featured), title/категория — из БД,
поэтому переименование/выключение/рекомендация в админке отражаются автоматически.
Время/уровень/цель — из curated-карты по id (в каталоге их нет) c дефолтами.
Фолбэк на статичный список, если API недоступен. Заодно исправлен mismatch
isoprocess→molphys (href теперь = id симуляции).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Кнопка «Создать карточку» в пустом состоянии вызывала click() по FAB,
но исходный клик всплывал до document-листенера, который сразу закрывал
поп-ап — внешне ничего не происходило. Заменено на ссылку на /flashcards.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Источник — /api/textbooks (как страница «Учебники»):
- учебник в процессе (есть прочитанные §) → «Продолжить чтение» с
прогресс-баром и «N из M § прочитано», ссылка на last_para;
- иначе первый учебник каталога → «Начать чтение», «M § · новый учебник»;
- фон карточки = градиент обложки по t.color (TB_COVER — зеркало
.tb-cover из textbooks.html), полная синхронизация цвета.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Иконка Lucide 'running' не существует, поэтому createIcons() оставлял
<i> пустым — у испытания типа 'tests' не было иконки. Заменено на
валидную 'footprints'.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Раньше при отсутствии начатого курса карточка оставалась статичной
заглушкой («Учебники»). Теперь:
- при прогрессе — «Продолжить чтение»: курс, урок, прогресс-бар, %;
- иначе — рекомендованный учебник из /api/courses: название, описание,
число параграфов;
- фон-градиент карточки по предмету (SUBJ_GRADIENT, как обложки).
Синтаксис всех инлайн-скриптов проверен (0 ошибок).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- loadActivityWidget показывает блок всегда (пустое состояние рисует
renderHeatmap), даже при 0 сессий и при ошибке истории.
- .bottom-grid: align-items stretch + height 100% — карточки ряда
(Активность/Мои сдачи/Испытания) одной высоты.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Блок «Активность» (heatmap + календарь) вынесен из 3-й колонки в
отдельный нижний ряд .bottom-grid рядом с «Мои сдачи» и «Испытания».
- Удалён остаток разметки «Теория — в процессе» и разметка рейтинга
(lb-section) с дашборда; конфиг виджетов обновлён (Активность вместо
Теории/Рейтинга).
- Селектор скрытия для учителя и адаптив обновлены под .bottom-grid.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Полный XP и абсолютный порог уровня (d.xp / d.xpForNextLevel),
уровень пользователя d.level — как в pet.html, а не относительный
расчёт по petLevel.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Функция loadPetHero вызывалась, но её тело не попало в коммит
667054f (Edit не применился). Восстановлено: рендер питомца через
PetSprite + загрузка /api/pet, как и задумано.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Рейтинг (lb-section) перенесён в профиль — удалён с дашборда вместе
с вызовами loadLeaderboard()/_populateLbClasses() и тоглом конфига.
- Виджет «Теория» (w-theory-progress) удалён вместе с тоглом конфига.
- applyDashboardPrefs/toggleDashWidget null-безопасны к удалённым id.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Пересборка верхней зоны дашборда по скриншоту (редизайн был утерян):
- 3 hero-карточки вместо action-cards: «Начать чтение» (продолжение
курса через /api/courses/continue), «Лаборатория дня» (детерминир.
выбор по дню + SVG-превью из lab-previews.js), «Питомец» (синхрон
с модулем /pet через /api/pet + единый PetSprite.render).
- Подключены восстановленные ассеты pet-sprite.js и lab-previews.js.
- Убран weak-topics из hero; питомец показывает уровень/XP/стрик/
цель дня/настроение, синхронно со страницей /pet.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Админ при входе на /dashboard видит редизайн-обзор (порт макета
admin-dashboard-redesign.html) на реальных данных /api/admin/overview:
KPI-пульс со спарклайнами, инбокс «Требует внимания» с табами
(блокировки/зависшие/брошенные), лента топ-сессий, распределение по
предметам, здоровье контента, топ/худшие результаты, быстрые действия.
Стили заскоуплены под #admin-command-center. Учитель/ученик без изменений.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Backend:
- POST /api/flashcards/quick — добавить карточку из любой точки; колода по
выбору или автоколода «Быстрые карточки» (создаётся при первом обращении)
- GET /api/flashcards/random — случайная карточка из всего пула пользователя
Frontend:
- /js/flashcard-fab.js — плавающая кнопка «запомнить» на всех страницах
(учебник, лаборатория, симуляция…). Поповер: вопрос/ответ/колода, Ctrl+Enter.
Гейт по фиче-флагу flashcards; исключены classroom/login/error/сама /flashcards.
Загружается лениво из sidebar.js (на 45 страницах с шапкой).
- dashboard: виджет #w-flashcard в колонке прогресса — флип-карта (вопрос↔ответ),
кнопка «Другая», счётчик пула, CTA при пустом пуле; слушает событие
flashcard:added для авто-обновления.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
dashboard.html: 2 → 0 ✅
- join-modal — вступить в класс
- qs-modal — быстрый тест с выбором предмета + режим + кол-во
theory.html: 1 → 0 ✅
- new-course-modal — создание нового курса учителем
course.html: 4 → 0 ✅
- add-section-modal — новый раздел курса
- edit-course-modal — редактирование курса
- add-lesson-modal — новый урок
- save-course-tpl-modal — сохранить курс как шаблон
Везде:
- Inline <div class=\"modal-overlay\">...</div> → удалён
- openX(): создаёт modal через LS.modal({content, actions})
- closeX() удалена — _xModal.close()
- Глобальный selectQsSubject() inline'нут как listener на body модалки
- Enter-handler на главных inputs сохранён
Не трогаю:
- biochem.html#lib-modal — кастомная тёмная тема, не подходит под
светлый LS.modal без редизайна
- library.html — 3 сложные модалки (folder-access, assign, upload)
с tabs и dynamic state — отдельный заход
- classes.html — modal-assign (128 строк, complex) + review-modal
- flashcards.html — fc-modal (не modal-overlay, своя CSS)
Прогресс миграции: 12 простых модалок → LS.modal за серию (4 ранее
+ 2 ранее + 6 сейчас). 4 страницы полностью очищены от
modal-overlay. Унифицированы:
- ESC/backdrop/focus поведение
- z-index (9000)
- Анимация (scale .22s)
- Адаптив на мобилке
A1 — карточка ДЗ-чтения у ученика на /dashboard:
- Новая ветка в buildAssignCard для assignments с textbook_id
- Прогресс-бар «X из Y §», цвет берётся из textbook.color
- Кнопка «Открыть / Продолжить» с deep-link на первый требуемый параграф
- В classify(): textbook_all_read → done, deadline → overdue
A2 — авто-проверка выполнения:
- При POST /:slug/progress с mark_read: проверяются активные textbook-assignments
- Если все требуемые § прочитаны → INSERT в assignment_completion
- SSE-уведомление учителю «Ученик завершил чтение: <title>»
- myAssignments возвращает completed_at и textbook_all_read
A3 — учительский UI прогресса класса:
- Новая страница /textbook-progress (учитель/админ)
- Селекторы «учебник × класс» → таблица учеников с прогрессом
- Сортировка по количеству прочитанного, дата last_at
- Кнопка «Прогресс класса» добавлена в /textbooks (видна учителям)
B4 — admin-UI управления учебниками:
- /admin-textbooks (только admin) — таблица всех учебников
- Inline-редактирование title/author, тоггл is_active
- Колонка «Читателей» (count из textbook_progress)
- Endpoints: GET /api/textbooks/admin/all, PATCH /admin/:id
C7 — закладки/заметки внутри учебника:
- Таблица textbook_bookmarks (user, textbook, para, text, note, color)
- API: GET/POST/PATCH/DELETE для CRUD закладок
- В tracker: при выделении текста (8-400 симв) появляется плавающая «+ Закладка»
- Кнопка-иконка в overlay top-left открывает панель «Мои закладки»
- Хранится paragraph-якорь, цвет, заметка, кнопка удалить
Назначение ученику (в дополнение к классу):
- В модалке /textbooks — переключатель «Классу / Ученику»
- Поиск ученика по имени/email через /api/classes/students
- Submit использует POST /api/assignments (createDirectAssignment)
- createDirectAssignment расширен textbook_slug + textbook_paragraphs
- Учитель может назначать только ученикам своих классов
myAssignments расширен: возвращает textbook fields + post-process
считает textbook_required_count, textbook_read_count, textbook_all_read.
Deep-link поддержка: /textbook/<slug>#pN в tracker.js — на load и hashchange
вызывает setParaTab(pN) (нативная функция учебника).
Миграция 005: assignment_completion + textbook_bookmarks + индексы.
- Add js/sidebar.js: generates full sidebar HTML into #app-sidebar,
handles role-based visibility, active link (with prefix matching),
toggle wiring, collapsed state, board/features/notif init
- Replace <aside class="sidebar">...</aside> with <aside id="app-sidebar">
across all 35 standard-layout pages via scripts/apply-sidebar.js
- Add notifications.js to 5 pages that were missing it
- Fix api.js initPage(): skip toggle re-wiring if data-sb-wired set,
fix active link selector .sb-item → .sb-link
- Remove stale sbl-*/nav-admin/btn-upload-nav getElementById calls
that crashed after sidebar replacement (lab, classes, collection,
crossword, hangman, knowledge-map, library, pet, profile)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Classroom performance:
- WebSocket server (ws-server.js) for low-latency cursor & stroke preview
Replaces HTTP POST per event → eliminates per-message auth overhead
Session member cache (30s TTL) avoids SQLite query per WS message
Fallback to HTTP POST when WS not connected
- Cursor throttle reduced 100ms → 33ms (~30fps)
- Stroke preview throttle reduced 50ms → 20ms
- whiteboard.js: render() is now rAF-gated (_doRender/_rafPending)
Multiple render() calls within one frame collapse into one repaint
document.hidden check — zero CPU when tab is in background
visibilitychange listener restores canvas on tab focus
Guest board:
- guestClassroom.js route: public token-based read-only access
- guest-board.html: name entry + read-only whiteboard + SSE
- SSE: addGuestClient/removeGuestClient/emitToGuests
Screen share picker:
- Discord-style modal with tab switching (screen/window/tab)
- Live video preview before confirming share
- useExistingScreenStream() in ClassroomRTC
Fullscreen exit overlay:
- #cr-fs-exit-overlay button inside cr-board-wrap
- Visible only via CSS :fullscreen selector (touchpad users)
File sharing from library:
- Teacher picks file from library, sends as styled card in chat
- crDownloadLibraryFile() fetches with Bearer auth
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>