Reset clears the current block's elapsed time to zero and immediately
starts the timer. A shared compute_block_elapsed() utility (utils/timer.py)
handles the elapsed calculation in both the sessions and dashboard routers,
and correctly treats "reset" events as zero-elapsed restart markers so
page reloads after a reset show accurate times.
Layout: Start/Pause/Resume/Reset are grouped on the left; End Day sits
on the right via justify-content: space-between.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Blocks are now selected without auto-starting the timer. Clicking a block
makes it current (highlighted) but leaves it in a ready state. A "Start"
button (indigo) triggers timing for a fresh block; "Resume" appears for
previously-worked blocks; "Pause" remains while running.
Also fixes the sidebar duration label to show "Done!" when elapsed ≥ total
and "< 1 min" for sub-minute remaining time instead of "0 min".
Backend adds a "select" event type that records an implicit pause for the
previous block, updates current_block_id, and broadcasts is_paused=true
with prev_block_elapsed_seconds so the TV sidebar stays accurate.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
_broadcast_session was missing morning_routine in its payload, so the
TV dashboard's applySnapshot reset the list to [] whenever a session
started or updated via WebSocket. A page refresh was required to
restore the items since only the REST dashboard endpoint included them.
Now queries MorningRoutineItem via child→user_id and adds the list to
every session_update broadcast, matching the dashboard snapshot.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Block list on both dashboards now shows time remaining on each block's
timer (allocated duration minus elapsed) instead of total duration;
the active block counts down live every second
- Fix block switching requiring 2 clicks: replace separate pause+start
requests with a single start request; backend implicitly records a
pause event for the previous block atomically
- Export blockElapsedCache from store so views can compute per-block
elapsed for both running and paused blocks
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Double-click fix:
- After awaiting the pause, optimistically set current_block_id and
isPaused on the store so the UI switches instantly. The subsequent
WS start event confirms the state without requiring a second click.
TV elapsed reset fix:
- The TV's local cache was empty for blocks paused before it connected,
so returning to those blocks showed 0 elapsed.
- Backend now computes the block's accumulated elapsed from previous
start/pause cycles and includes it as block_elapsed_seconds in the
'start' WS event payload.
- All clients (Dashboard and TV) now use this authoritative server value
instead of relying solely on the local cache.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- On session start, insert a session_start TimerEvent so the action
appears in the activity log timeline
- Load DailySession.template via selectinload in the timeline query
so the template name is available without extra round-trips
- _to_timeline_out maps the template name into block_label for
session_start events, displaying as "Day started — Template Name"
- Add session_start to EVENT_META on the frontend (🏫 icon)
- Hide the Edit button for session_start entries since changing their
event type to a block-level action doesn't make sense
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Backend queries and model relationship now order by time_start.
Frontend also sorts blocks client-side for reliability across all views.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Subject options:
- New subject_options table (auto-created on startup)
- SubjectOut now includes options list; all eager-loading chains updated
- Admin: Options panel per subject with add, inline edit, and delete
- WS broadcast and dashboard API include options in block subject data
TV dashboard:
- Three equal columns: Timer | Activities | Schedule
- Activities column shows current subject's options in large readable text
- Activities area has subject-colored border and tinted background
- Subject name and label displayed correctly using embedded subject data
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The WS broadcast payload was missing day_start_time, day_end_time, and
duration_minutes, so applySnapshot nulled them out on session_update.
Now _broadcast_session fetches the template and includes all fields.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Broadcast is_active in WS timer payload so the frontend can immediately
clear the session when the backend marks it complete.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Full-stack homeschool web app with FastAPI backend, Vue 3 frontend,
MySQL database, and Docker Compose orchestration. Includes JWT auth,
WebSocket real-time TV dashboard, schedule builder, activity logging,
and multi-child support.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>