Commit Graph

7 Commits

Author SHA1 Message Date
Maxim Dolgolyov 0d4c658d93 refactor(assignments): единый модуль assignment-utils.js (тип/«сдано»/срочность)
Логика классификации типа задания и статуса «сдано» дублировалась в трёх местах
(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>
2026-06-23 14:09:34 +03:00
Maxim Dolgolyov 5a4bc48027 feat(classes): вкладка «Долги» — что висит у учеников + удаление ДЗ класса/ученика
Новый 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>
2026-06-23 13:46:45 +03:00
Maxim Dolgolyov 2ec59c0fa5 refactor: unify assignment creation — 3 endpoints через общие helpers
Все три endpoint'а POST для создания assignment теперь используют
общую логику валидации, резолва FK и INSERT'а:

  POST /api/classes/:id/assignments  → createAssignment
  POST /api/assignments              → createDirectAssignment
  POST /api/assignments/bulk         → bulkCreateAssignment

Три новых private helper'а:
  _resolveAssignment(body) — валидирует и резолвит test_id/textbook_slug/
    file_id → возвращает {ok: {...resolved}, error: '...'}
  _insertAssignmentStmt — единственный prepared INSERT с полным
    набором колонок включая textbook_id, textbook_paragraphs
  _insertAssignment(target, fields, creatorId) — обёртка над INSERT,
    target = {class_id} или {user_id}
  _notifyAssignment(target, title) — pushNotif для class members или
    одного user в зависимости от target

Каждая из трёх public-функций теперь:
  - 25-40 строк (было 50-80)
  - Уникальная логика только в:
    • createAssignment       — проверка владения классом
    • createDirectAssignment — резолв ученика + class-membership
                                либо teacher_students проверка
    • bulkCreateAssignment   — цикл по class_ids в транзакции

Бонусы:
  - createAssignment (через /classes/:id/assignments) теперь
    поддерживает textbook_slug + textbook_paragraphs (раньше нет —
    скрытый баг, проявлялся бы при попытке назначить чтение через
    UI классов)
  - max_attempts теперь применяется во всех трёх (был только в
    createAssignment)
  - Все три используют stmts.getClass вместо inline db.prepare()

API совместимость не нарушена: схемы тел запросов, return value,
коды статусов идентичны. Existing UI работает без изменений.

Файл: 734 → 744 строки (+10, но дубликат-логика выкинута).
2026-05-16 17:29:22 +03:00
Maxim Dolgolyov eeb79246db @
feat: teacher_students — назначения ученикам без класса

Новая модель «Мои ученики» — учитель связывает с собой учеников
независимо от классов (репетиторский сценарий).

Backend:
  - Таблица teacher_students (teacher_id, student_id, added_at, note)
    + индекс на student_id для обратного поиска
  - GET/POST/PATCH/DELETE /api/teacher-students — управление списком
  - Добавление по email с проверкой роли student/free_student
  - Уведомление ученику при добавлении

  - createDirectAssignment: проверка inClass расширена до
    inClass OR (teacher_id, student_id) в teacher_students
  - listStudents (/api/classes/students): возвращает объединение
    учеников из классов + из teacher_students. Это автоматически
    обновляет student-picker в /textbooks без правок UI.

Frontend:
  - /my-students — таблица личных учеников + форма добавления
    по email + заметка + счётчик созданных заданий
  - Сайдбар: пункт «Мои ученики» (user-plus, только для учителей)

Миграция 006_teacher_students.sql.

Что работает end-to-end:
  - Добавить ученика на /my-students
  - Открыть /textbooks → «Назначить» → «Ученику» → ученик ищется
    в общем списке (классовые + личные)
  - Создаётся запись в assignments с user_id, видна ученику на
    дашборде с пометкой «Личное задание»
@
2026-05-16 17:01:11 +03:00
Maxim Dolgolyov 3ff2f01178 feat: textbooks Phase 4 — A1+A2+A3+B4+C7 + назначение ученику
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 + индексы.
2026-05-16 16:37:11 +03:00
Maxim Dolgolyov e8018d85c1 feat: textbooks — модуль учебников + чтение как ДЗ (3 фазы)
Фаза 1 — структура и каталог:
  - frontend/textbooks/chemistry_9.html (Шиманович, 60 §) + physics_9.html (Исаченкова, 38 §)
  - frontend/textbooks.html — каталог в стиле LearnSpace (карточки с обложками)
  - Маршруты: /textbooks (каталог), /textbook/<slug> (полноэкранный учебник)
  - Сайдбар: пункт «Учебники» (book-open-text)
  - Feature flag feature_textbooks_enabled, hideDisabledFeatures map

Фаза 2 — прогресс в localStorage + UI чтения:
  - frontend/js/textbook-tracker.js — инжектится в каждый учебник:
    - «← Учебники» overlay-кнопка (top-left, semi-transparent)
    - «Прочитано» чекбокс рядом с каждым §-заголовком
    - Зелёный dot на pill уже прочитанных параграфов
    - Авто-открытие последнего параграфа при возврате
  - Каталог показывает прогресс-бар «X из Y прочитано» + кнопку «Продолжить»

Фаза 3 — серверный прогресс + назначение чтения как ДЗ:
  - Таблица textbooks (slug, subject, grade, title, author, color, ...)
  - Таблица textbook_progress (user_id, textbook_id, JSON read[], last_para)
  - Колонки assignments.textbook_id + textbook_paragraphs
  - API: GET /api/textbooks (с прогрессом), GET /:slug, POST /:slug/progress,
    GET /:slug/class-progress (учитель)
  - tracker.js синхронизирует прогресс через POST /progress (если залогинен)
  - На каталоге у учителей кнопка «Назначить чтение» — модалка с выбором
    классов + параграфы («1-5» или «1,3,5») + deadline
  - bulkCreateAssignment расширен: принимает textbook_slug, резолвит в id

Миграция 004 идемпотентная; сиды двух учебников включены.
2026-05-16 14:05:19 +03:00
Maxim Dolgolyov be4d43105e LearnSpace: full-stack educational whiteboard platform
Node.js/Express backend + vanilla JS frontend.
Features: real-time collaborative whiteboard (SSE), multi-page support,
LaTeX formulas, shapes/connectors, coordinate systems, number lines,
compass, zoom/pan, Catmull-Rom pencil smoothing, ruler/protractor with
rotation & resize controls, minimap navigation overlay, auto-measurements,
multi-page thumbnails sidebar, PNG export, page templates.
Student/teacher workflows: classes, assignments, library, dashboard.
Mobile responsive. SQLite (better-sqlite3).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 10:10:37 +03:00