Switch admin doc viewer from view mode to comment-only mode so the
parent can annotate student work without editing the text.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Student editor:
- Add body.docs-editor-open class when editor opens; hide hero, nav,
confetti so nothing bleeds behind the fixed overlay
Admin docs panel:
- New "Documents" sidebar entry listing all submitted docs with student
name, date, and unread badge
- Click any doc to open it in OnlyOffice in view (read-only) mode
- Download button for offline access
- /api/docs/bykey/:key/editor-config server route for admin viewer
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Student section: new hero gradient header, fixed bottom nav bar with
icon+label pills (Today/Courses/Spelling/Inbox/Docs)
- Today rows: card style with left accent stripe, lift on hover
- Course cards: grid layout with top color bar per course
- Docs tab: list view with doc cards, OnlyOffice editor embedded via
iframe using server-signed JWT config
- Server: documents table, CRUD routes, OnlyOffice callback endpoint
for auto-save, /api/docs/:id/editor-config returns signed config
- Blank DOCX template embedded as base64 for new document creation
- OnlyOffice server: https://onlyoffice.necloud.us (set ONLYOFFICE_JWT_SECRET
env var to match your Document Server JWT secret)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Include .admin-sidebar-footer .nav-pill in click listener so Settings is reachable
- Update showPanel to toggle active class on both .admin-nav and footer pills
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Replace horizontal top-nav with a dark sidebar (grouped: People / Academics / Tools)
- Add Dashboard landing page with kid stat cards, today's schedule, and recent scores
- Add /api/admin/schedule and /api/admin/recent-scores endpoints for dashboard data
- Add Lock button and mobile sidebar toggle in top bar
- Redesign planner toolbar: two-section layout (nav left, actions right)
- Elevate auto-schedule out of hidden accordion into always-visible inline bar
- Richer planner task cards: course color stripe, course name label, completion counter per day
- Dashed "+ Add task" empty state instead of plain dash
- Fix nav-pill CSS conflict: student tabs (light bg) now use dark text; admin sidebar keeps white text
- Add seed.js demo data script for two students (Emma and Liam)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Spelling: "Blank test" print button per word list (numbered lines, no words shown) for dictated paper tests
- Spelling: "Record Paper Test" form in admin to log a paper test score to the gradebook
- Gradebook: "Record Paper Score" form to log a paper quiz/assignment score for any course item
- Flashcards: "Print" button per deck generates a cut-and-fold card sheet (fronts page + backs page)
- Crossword: print now includes a second page with a filled answer key
- Lessons + Assignments: 🖨 Print button in student view generates a clean printable page
- Word lists: new "CSV file" import tab — upload a .csv with word, sentence, definition columns
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Polls every 30s for unread messages on both kid and admin sides.
Kid app shows a tappable in-page toast and fires a browser OS
notification when a parent message arrives while the tab is open.
Admin app shows a toast and OS notification when a student replies.
Clicking the OS notification focuses the tab and opens the messages view.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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>
- Replace reply-by-message-ID endpoint with POST /api/admin/messages/:studentId so parent can send without a prior message existing
- Switch GET /api/admin/messages to LEFT JOIN so all students appear in the thread list, not just those who have sent messages
- Remove guard that blocked sending when no messages existed in the thread
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Grading queue now shows short-answer questions and student responses inline so the parent can read answers before scoring
- Student inbox tab shows all graded items with score, percentage, and parent feedback; unread badge appears on login
- Parent-student messaging: students send messages from the Inbox tab; Messages panel in admin shows threads with unread count badge, full conversation history, and reply compose
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Each time a student completes a pass through a spelling_practice course
item — initial round, missed-words drill, or a retry — a row is now
written to submission_history so the parent sees individual attempts
instead of a single day-grouped entry.
- app.js: send sessionAttempted/sessionCorrect with /complete calls
- server.js: write to submission_history on each spelling_practice
completion; add GET /api/spelling-sessions endpoint
- admin.html/js: new "Practice Sessions" table shows one row per pass
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Shows per-student, per-day practice history in the Spelling panel: date,
time range, word list(s), and first-try correct rate. Clicking a row opens
a detail modal with every word attempted, what the student typed, and
whether it was a first try or retype.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- School name now appears on the student home screen and updates the page title
- Logo can be uploaded in Settings (PNG/JPG/GIF/WebP/SVG, max 2 MB); stored in the data volume so it persists across container restarts
- When a logo is uploaded the text school name is hidden in favour of the logo
- Admin header shows the school name instead of hardcoded "Homeschool", updates live when saved
- New server endpoints: GET /api/logo, POST /api/admin/upload-logo, DELETE /api/admin/logo
- /api/public-settings now includes school_name and has_logo
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Parents can set a birthday (MM-DD) per student in the Kids panel. During the student's birthday week (Mon–Sun), a festive overlay appears on login with balloons, birthday cake, confetti, and a personalized message — shown once per day via sessionStorage. Summer birthdays (June–Aug) show a note in admin suggesting the parent set an alternate school-week date to celebrate early.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Show full word list before practice starts so students can study words first
- Add per-student young learner mode (set in admin): word stays visible while typing
- Center all practice card content (speak button, prompt, feedback, check button)
- Remove 10-word-per-session cap so large lists (25-30 words) practice all words
- Double the misspelled-word study countdown from 4s to 8s
- Fix word list preview numbering for 10+ items (inline numbers, no clipping)
- Add young_learner column to students table with admin toggle
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Parent can turn the floating school emoji on/off from Settings > Student home screen. Setting persists in the DB and is read via a public /api/public-settings endpoint on the student home page.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Grading: add student filter dropdown, Enter-to-save, and point max always defaults to 100
- Student side: show next-item/back-to-course actions after completing a lesson or assignment
- Lesson body: apply prose typography styles (headings, lists, blockquotes, links, hr)
- Gradebook: fix % display when points_possible is 0 (default to 100 on grade save)
- Auto-schedule: skip items that already have a submission
- Item editor: default new/existing item point values to 100 instead of 10
- Planner: friendly week date header, per-day short date, today highlight, course color on task pills, done toggle, within-day drag reorder, Today button
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Today button jumps planner to current week; today column highlighted with accent outline
- Week label now shows friendly format (Aug 3–7, 2026) instead of ISO dates
- Course color shown as left border on scheduled course items
- Parent-side done toggle on every planner task (works for offline + course items)
- Within-day drag-to-reorder tasks via new /api/schedule/reorder endpoint
- Grading queue shows visible "/ N pts" max-points label (defaults to 100 when unset)
- New item default points changed from 10 to 100
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Single "Add task" button in the planner header opens a modal
- Day tabs (Mon–Fri with dates) let you switch the target day without closing
- Live search filters all course items across all courses instantly
- Items pre-fetched in background when planner loads — no per-click delay
- Clicking an item schedules it immediately (no separate Save step)
- Column "+ Add" buttons still work and open the modal pre-selected to that day
- Offline task field at the bottom for non-course entries
- Backdrop click or ✕ closes modal and re-renders the planner
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- School/family name: saved to DB, appears in printed week/month report headers
- Passing grade threshold: replaces hardcoded 80% in all gradebook/history views
- Week start day (Mon vs Sun): shifts the planner 5-day grid and month view accordingly
- Settings are loaded at unlock time so they apply before any panel opens
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Removes the scan-a-page workflow (photo → lesson/quiz content), all
Ollama/cloud provider code, the scan settings panel, and the related
DB seed values.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- New `worksheet` item type: admin pastes raw worksheet text, parser auto-detects fill-in-the-blank (___), true/false (T F ...), section headers (Part N —), and short-answer questions
- Admin editor shows each parsed question with inputs to set correct answers for FITB and T/F; short answers are marked parent-grades
- Kid view renders FITB as inline underline inputs, T/F as tap-to-toggle T/F buttons, and short answer as a textarea; Name/Date header auto-populated
- Auto-grades T/F (exact) and FITB (case-insensitive); worksheets with short answers go to grading queue as status=done
- Print blank button opens a formatted print window with underlines, circled T/F, and ruled lines for short answers
- "I handed in my paper copy" button lets kids mark a printed worksheet as turned in without digital submission, queuing it for parent grading
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- requirePin: prepare pin-lookup statement once at module level instead of per-request
- Gradebook: replace O(students × items × 3) per-item queries with 2 bulk INs + in-memory Maps
- List/deck PUT: wrap DELETE + re-INSERT in a transaction to prevent partial-write corruption
- Print views: detect HTML vs plain-text lesson bodies before escaping, fixing rich-text output
- Planner add-task: parallelize course detail fetches with Promise.all
- Planner save-all: parallelize schedule inserts with Promise.all
- HOMESCHOOL_DIR: read from env var with existing path as fallback
- Remove unused isDown function in crossword-submit handler
- Remove dead empty-if stub in docx import change handler
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Export any course as a .json bundle (GET /api/admin/courses/:id/export)
- Import a .json bundle as a new course (POST /api/admin/import-course)
- Import one or more unit .docx files directly in the browser — server
parses each file with mammoth, extracts Week N: headings as lesson
items and the Unit Quiz section as a graded quiz with answer key
(POST /api/admin/import-course-docx, multer memory storage)
- Admin UI: Export button on course detail; Import card with JSON and
Word docs tabs; multi-file picker for docx uploads
- scripts/import-kitchen-course.js: one-time converter that produced
the Kitchen, Tools & Electrical Skills course JSON bundle (already
imported as course id 3: 8 units, 44 items)
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>
Instead of embedding an iframe, mammoth HTML is inserted straight into
the contenteditable body so the admin can edit it like any other content.
A download link to the original .docx sits above the content.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replaces the plain textarea with a contenteditable div + full toolbar
(bold, italic, underline, H2/H3, paragraph, bullet/numbered lists, link,
YouTube embed) — same as the lesson editor.
Toolbar buttons use mousedown+preventDefault so selection is preserved
when clicking format buttons. Both editors share the same button wiring
via closest('.rte-group') rather than hardcoded element IDs.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Removed narrow max-width/margin from generated HTML page
- iframe now spans full card width (100%)
- onload JS auto-sizes iframe height to content so nothing is cut off
- Falls back to 500px if cross-origin restriction ever applies
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace the <iframe> with an inline <div> containing the mammoth HTML.
Content now flows full-width with the page instead of being cramped in
a fixed-height scrolling box. Download link still available below.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Each imported doc now shows as a collapsed summary line (📄 filename.docx)
that expands to reveal the iframe and download link when clicked.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Each imported .docx now adds its iframe below any existing body content
so multiple documents can be attached to a single item.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
On upload, mammoth converts the doc to a styled HTML page saved alongside
the .docx. The item body gets an <iframe> pointing to the HTML so students
see the document inline. A download link below gives access to the original.
Falls back to a plain download link if HTML conversion fails.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Instead of parsing .docx content via mammoth and inserting raw text/HTML,
the import flow now saves the file to data/attachments/ (UUID filename) and
inserts an <a> link into the item body so students can open/download the doc.
- Added GET /api/attachments/:filename (no PIN — students access directly)
- Added POST /api/admin/upload-attachment (PIN required)
- Removed mammoth dependency from server
- Updated admin.js import handler to POST to new endpoint and set link HTML
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Lesson body is a contenteditable div — must use innerHTML, not .value.
Assignment body is a plain textarea — strip HTML tags before setting .value.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove all AI processing from the import-docx endpoint. Instead:
- Convert the .docx to HTML with mammoth.convertToHtml (preserves
bold, headings, lists, etc.) — the result goes straight into the
item body and renders in the lesson viewer
- Extract raw text in parallel to pick the document title from the
first non-empty line
- No external services, no AI, works on the deployed server
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
btoa(String.fromCharCode(...new Uint8Array(buf))) exceeds V8's function
argument stack limit for files larger than ~65k bytes. Process in 8k
chunks instead to handle any file size.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The old import scanned a hardcoded Seafile CloudStorage path that only
worked on one specific machine. Replaced with a standard <input type=file>
browser picker that reads the .docx as base64 and uploads it directly, so
the feature works everywhere. Server endpoint now accepts either a base64
payload or the legacy path. Also fixed a crash where resetImportSection()
still referenced the removed select element, which was breaking the item
editor for all item types.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Gradebook now groups items by unit with collapsible cards (same card
style as course detail) and a Course overall summary table at the bottom
- server.js: add unit_id/unit_name to gradebook API so items can be grouped
- Course detail: preserve which units are open and scroll position across
any in-place re-render (add unit, delete unit, save meta, return from
item editor) — no more jumping to the top with everything reset
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Student view auto-opens the unit whose item due-dates span today (falls back
to most-recent past unit, earliest future unit, then first with incomplete
work). Admin view starts all units expanded. Both share the same card design:
unit-number badge, name, progress/count indicator, animated chevron toggle.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove sessionStorage caching of the PIN so the gate always shows on
page load instead of auto-unlocking from a previous session.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Toast: replace buried #admin-msg hint with a floating green/red toast
(bottom-right, auto-dismisses after 3s) covering every save action —
lists, decks, items, grades, kids, units, courses, bulk imports, and
planner saves.
Planner batch add: clicking '+ Add' now queues items locally (shown
as dashed pending badges) without saving. A '💾 Save N items' button
appears in the toolbar; clicking it commits everything at once and
refreshes the planner. Queue clears on student change.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Gradebook: period dropdown (all time / 30 / 90 days) and CSV export for
Spelling Test History section
- Student portal spelling tab: shows last 10 tests as a Recent Tests list
- Planner: completed standalone spelling tests appear as read-only ⭐ badges
on the day they were taken (week and month views)
- Removed dead s.tests query from /api/overview (now served by dedicated endpoints)
- New endpoints: GET /api/spelling-tests/csv, GET /api/students/:id/tests,
GET /api/admin/students/:id/tests-range
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a GET /api/spelling-tests endpoint that returns all standalone test
results grouped by student. The Gradebook panel now shows a "Spelling Test
History" section below the course gradebook table. Removed the "Test results"
section from the Spelling panel left column.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>