Replaced db.transaction() wrapper (unreliable in node:sqlite at this
version) with a plain loop. Added try/catch in the JS save handler so
any server error surfaces as a visible toast instead of failing silently.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a "Correct" button to each test in the Spelling Test History table.
Clicking it opens a modal showing each word, what the student typed, and a
checkbox to mark it correct or incorrect. Saving PATCHes the server, which
updates test_answers, recalculates the test score, and keeps any linked
course submission in sync.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove cross-list review words (Leitner spaced repetition) from practice
sessions so only the currently assigned list's words are shown. Also remove
the now-unused dueReviews count from the state endpoint and student UI.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace scrollIntoView (which escapes to the window when the list isn't
tall enough to scroll) with manual scrollTop logic that stays strictly
within the clue list container.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
preventScroll was blocking the viewport from scrolling to the grid cell
when a clue was clicked from the sidebar. The clue list overflow fix is
sufficient to contain scrollIntoView without needing preventScroll.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Widen quiz, flashcards, practice, test, and crossword views to match the
960px max-width already used by course/lesson/assignment. Fix crossword
jumping to top on cell focus by using preventScroll and containing clue
list scrollIntoView within a max-height overflow container.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Admin enters Across/Down words and clues; server auto-generates the grid
using a backtracking placement algorithm (longest-first, intersection-based).
Students fill in the interactive grid with click-to-select, direction toggle,
arrow-key navigation, and Tab-to-next-word. Auto-graded per word on submit,
with correct/wrong color highlighting on the results view. Includes a print
worksheet option for blank paper practice.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Instructions are optional free text shown to the student above the questions/word bank.
Admin enters them in the item editor; stored in items.body for quiz and matching types.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Bind mount (./data:/app/data) was relative to the working directory,
so data was lost whenever the project was re-cloned or compose was run
from a different path. A named volume is managed by Docker and persists
across container rebuilds and image pulls.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replaces the plain textarea with a WYSIWYG contenteditable editor so
the formatting the parent sees while writing matches what the student
sees when reading. Toolbar supports bold, italic, underline, H2/H3,
bullet/numbered lists, links, and YouTube embeds. Selection is saved
on editor blur and restored before each execCommand so toolbar clicks
don't lose the user's selection.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Practice: fire streak badge, first-letter hint on wrong answers, missed-words drill session after practice completes.
Test: audio-only mode with listening state before input appears, larger re-read button.
Words: definition field (DB migration + admin editor + TTS playback).
TTS: replace speechSynthesis with local Piper via /api/tts, WAV cached in data/tts-cache, falls back to browser voice when Piper is not installed.
Dockerfile: switched to node:26-slim, installs Piper binary + en_US-lessac-medium voice.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>