Новый read-only эндпоинт GET /api/classes/:id/outstanding (teacher/admin, ownership):
по каждому ученику класса — его незакрытые задания (классовые + личные от этого учителя)
со статусом не начато / в процессе / на доработке / просрочено и дедлайном. Логика «сдано»
совпадает с /homework (тест — завершён/исчерпаны попытки; учебник — всё прочитано;
загрузка/файл — есть сдача не на доработке). Общий запрос вынесен в assignmentRowsForUser(uid)
— им же теперь питается /assignments/my (поведение не изменилось, +поле created_by).
Фронт (classes.html): вкладка «Долги» в карточке класса — сводка «должников X из Y,
просрочено Z», по каждому должнику карточка со статус-чипами и списком зависших заданий;
бейдж с числом просрочек на вкладке. Удаление прямо из списка: личное → «у ученика»,
классовое → «у всего класса» (через DELETE /assignments/:id, ownership на бэке).
Verified: classOutstanding смоук на живой БД (14 учеников/58 позиций/42 просрочено,
ownership 403/404/admin); node --check; lint:routes 0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
(1) На /homework блок «Актуальные задания» и выпадашка загрузки теперь показывают
только задания с флагом ДЗ (is_homework). Обычные тесты/экзамены и не-ДЗ файлы сюда
не попадают. Выпадашка привязки — только типы upload/file (куда ученик реально сдаёт
файл), без тест-ДЗ и учебников.
(2) В конструкторе задания (classes.html) вкладка типа «Сдать работу» → «Загрузка
работы»: остальные вкладки — существительные-типы контента (Файл, Готовый тест), а
«Сдать работу» читалась как действие ученика. Это тип upload — ДЗ, куда ученик грузит
файл (saveAssignment: is_homework=1, count=1); сам тип нужен, поправлена только подпись.
Headless-смоук фильтра ДЗ 6/6.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- flashcards.html: колоды коллекции рендерятся сворачиваемой папкой «Подготовка к ЦТ»
(deckCardHtml вынесен, секции <details> по collection; метки из LS.prepListTracks)
- classes.html: в таблице учеников колонка «ЦТ» с тумблером флага + кнопки «Весь класс → ЦТ»/
«Снять ЦТ» (LS.prepClassStatus/prepSetStudent/prepUnsetStudent/prepSetClass)
Иконки — inline SVG, без эмодзи.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- server: requireFeature('imggen') на /api/imggen (глобальный гейт).
- imggenController: enforcement через isFeatureEnabledForUser в status()/generate()
— учитывает глобальный флаг + оверлей класса + free_student (403 если выкл.).
- admin «games/features» + free-student: тумблер «Генерация картинок (ИИ)».
- classes.html: переключатель модуля imggen в настройках класса (per-class).
Дефолт — ON (opt-in disable), как у остальных фич. Проверено на features-движке.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- 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>