derekc 4a14f8b3f1 Fix timezone resetting to UTC on page reload
On reload, the access token existed in localStorage so isAuthenticated
was true, but user.value was null — fetchMe was never called, so
authStore.timezone fell back to 'UTC' before the component mounted.

Router guard now calls fetchMe() when authenticated but user data is
not yet loaded, ensuring user preferences are available to all
auth-required pages on the first render after a reload.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 21:13:05 -08:00
2026-02-27 22:56:56 -08:00
2026-02-27 22:56:56 -08:00

Homeschool Dashboard

A self-hosted web app for managing homeschool schedules, tracking daily learning sessions, and logging activities. Features a full-screen TV dashboard with live timers and real-time updates via WebSockets.


Features

  • TV Dashboard — Full-screen display for the living room TV. Shows the current subject, countdown timer, day progress, and upcoming schedule blocks. Updates live without page refresh.
  • Schedule Builder — Create named schedule templates with time blocks assigned to subjects. Assign templates per-child or share across all children.
  • Daily Sessions — Start a school day against a schedule template. Track which blocks are active, paused, or complete. Timer state (including paused) is preserved when navigating between pages.
  • Activity Log — Automatically records every timer event (day started, block start/pause/resume/complete/skip) as a timeline, including which schedule template was used. Supports manual notes with subject, duration, and free text. Browse and filter history by child and date.
  • Behavior Tracking (Strikes) — Issue up to 3 strikes per child from the Dashboard. Strike count is shown on the TV dashboard and resets automatically when a new school day begins.
  • Timezone Support — Set your local timezone in Admin → Settings. All activity log timestamps display in your timezone, including the TV dashboard clock.
  • Multi-Child Support — Manage multiple students under one parent account, each with their own color, schedule, and history.
  • JWT Authentication — Secure parent login with access tokens and httpOnly refresh cookies. TV dashboard is public (no login required).

Tech Stack

Layer Technology
Frontend Vue 3 + Vite + Pinia + Vue Router
Frontend server nginx (Docker)
Backend API FastAPI (Python 3.12)
Real-time WebSockets via FastAPI
Database MySQL 8
ORM SQLAlchemy 2.0 (async)
Migrations Alembic
Auth JWT — python-jose + passlib/bcrypt
Orchestration Docker Compose

Project Structure

homeschool/
├── docker-compose.yml            # Production stack (3 services)
├── docker-compose.override.yml   # Dev overrides (hot reload)
├── .env.example                  # Environment variable template
│
├── backend/
│   ├── Dockerfile
│   ├── requirements.txt
│   ├── alembic/                  # Database migrations
│   └── app/
│       ├── main.py               # FastAPI app entry point
│       ├── config.py             # Settings (reads from .env)
│       ├── database.py           # Async SQLAlchemy engine
│       ├── dependencies.py       # Auth dependencies (get_current_user)
│       ├── auth/jwt.py           # Token creation, password hashing
│       ├── models/               # SQLAlchemy ORM models
│       ├── schemas/              # Pydantic request/response schemas
│       ├── routers/              # API route handlers
│       └── websocket/manager.py  # WebSocket connection manager
│
└── frontend/
    ├── Dockerfile                # Multi-stage: Node build → nginx serve
    ├── nginx.conf                # Proxy /api/ and /ws/ to backend
    └── src/
        ├── composables/
        │   ├── useApi.js         # Axios with auto token-refresh
        │   └── useWebSocket.js   # Auto-reconnecting WebSocket
        ├── stores/               # Pinia: auth, children, schedule
        ├── views/                # LoginView, TVView, DashboardView, etc.
        └── components/           # TimerDisplay, ScheduleBlock, NavBar, etc.

Getting Started

Prerequisites

1. Clone the repo

git clone https://git.chns.tech/CooperandGoodman/homeschool.git
cd homeschool

2. Create your .env file

cp .env.example .env

Open .env and fill in the values:

MYSQL_ROOT_PASSWORD=your_secure_root_password
MYSQL_DATABASE=homeschool
MYSQL_USER=homeschool
MYSQL_PASSWORD=your_secure_db_password

# Generate with: openssl rand -hex 32
SECRET_KEY=your_generated_secret_key

ALGORITHM=HS256
ACCESS_TOKEN_EXPIRE_MINUTES=30
REFRESH_TOKEN_EXPIRE_DAYS=30

# Your host IP or domain (no trailing slash)
CORS_ORIGINS=http://localhost:8054

3. Build and start

docker compose up --build

The first build takes a few minutes (npm install + pip install). On subsequent starts it's fast.

4. Register your parent account

Open http://localhost:8054/login and register. This creates your admin account.

5. Set up your data (in order)

  1. Admin (/admin) → Add each child, pick a color
  2. Admin → Add subjects (Math, Reading, Science, etc.) with emoji icons and colors
  3. Admin → Scroll to Settings and select your local timezone — this ensures activity log times and the TV clock display correctly
  4. Schedules (/schedules) → Create a schedule template, add time blocks assigned to subjects
  5. Dashboard (/dashboard) → Click "Start Day", choose a template
  6. TV → Open http://your-lan-ip:8054/tv/1 on the living room TV (replace 1 with the child's ID)

Usage

Parent Views (require login)

URL Description
/dashboard Overview, start/stop sessions, timer controls, issue behavior strikes
/schedules Create and edit schedule templates and time blocks
/logs Browse timer event history and manual activity notes; filter by child and date
/admin Manage children, subjects, schedule templates, and account settings (timezone)

TV Dashboard (no login)

URL Description
/tv/:childId Full-screen display — current block, countdown timer, day progress

Point a browser on the living room TV at http://your-lan-ip:8054/tv/1. The page connects via WebSocket and updates automatically when a parent starts/stops/advances the timer from the Dashboard.

API Documentation

FastAPI auto-generates interactive API docs:

  • Swagger UIhttp://localhost:8054/api/docs
  • ReDochttp://localhost:8054/api/redoc

Development Mode

The docker-compose.override.yml file enables hot reload automatically when running locally:

  • Backend — uvicorn --reload watches backend/app/ for changes
  • Frontend — Vite HMR on port 5173 (mapped to 8054 in dev mode)
docker compose up --build   # override is applied automatically in dev

To run production mode explicitly (no hot reload):

docker compose -f docker-compose.yml up --build

Database Migrations

Alembic is configured for async SQLAlchemy migrations.

# Generate a new migration after changing models
docker compose exec backend alembic revision --autogenerate -m "description"

# Apply pending migrations
docker compose exec backend alembic upgrade head

# Roll back one migration
docker compose exec backend alembic downgrade -1

Note: On first startup the app auto-creates all tables via SQLAlchemy's create_all. Alembic is used for schema changes after the initial setup.


WebSocket Events

The TV dashboard connects to ws://host/ws/{child_id} and receives JSON events:

Event Triggered by Payload
session_update Session start/end Full session snapshot
start Timer started session_id, block_id, current_block_id
pause Timer paused session_id, block_id
resume Timer resumed session_id, block_id
complete Block completed session_id, block_id
skip Block skipped session_id, block_id
strikes_update Strike issued/cleared child_id, strikes

Environment Variables Reference

Variable Required Description
MYSQL_ROOT_PASSWORD Yes MySQL root password
MYSQL_DATABASE Yes Database name (default: homeschool)
MYSQL_USER Yes App database user
MYSQL_PASSWORD Yes App database password
SECRET_KEY Yes JWT signing key — generate with openssl rand -hex 32
ALGORITHM No JWT algorithm (default: HS256)
ACCESS_TOKEN_EXPIRE_MINUTES No Access token lifetime (default: 30)
REFRESH_TOKEN_EXPIRE_DAYS No Refresh token lifetime (default: 30)
CORS_ORIGINS No Comma-separated allowed origins (default: http://localhost:8054)

Stopping and Restarting

# Stop containers (data preserved in Docker volume)
docker compose down

# Stop and wipe the database volume (full reset)
docker compose down -v

# Restart without rebuilding
docker compose up
Description
A self-hosted web app for managing homeschool schedules, tracking daily learning sessions, and logging activities. Features a full-screen TV dashboard with live timers and real-time updates via WebSockets.
Readme 708 KiB
Languages
Vue 50.3%
Python 35.9%
JavaScript 13.2%
Dockerfile 0.2%
Mako 0.2%
Other 0.2%