A local-first AP Psychology sprint platform with React, Go/Gin, GORM, and SQLite.
- Imports the canonical AP Psychology concept list from
data/sources/keyterms.md. - Preserves local notes and downloaded source material under
data/sources/. - Supports multi-tenant registration and login.
- Separates global concept data from each user's ratings, review events, and progress.
- Restricts data import and concept-content editing to admin users.
- Lets each user rate every concept from 0 to 5.
- Provides a recognition-first review flow.
- Tracks review events and mastery changes.
- Imports compact AI enrichment from
data/sources/ai-enrichment.compactwhen available.
Install frontend dependencies:
cd frontend
npm installRun the backend:
cd ..
go run .Run the frontend in another terminal:
cd frontend
npm run devOpen http://localhost:5173.
The backend API runs on http://localhost:8080. On first startup, it creates data/app.db and imports the source data.
cd frontend
npm run build
cd ..
go run .After the frontend is built, the Go server also serves the built site from http://localhost:8080.
The Docker setup builds the frontend, compiles the Go server, and serves everything from one container. Runtime data is mounted from ./data:
docker compose up -d --buildSee docs/deploy-onepanel-compose.md for the full OnePanel/server deployment flow.
Runtime configuration lives in .env. Dashboard time buckets default to Shanghai time:
JWT_SECRET=replace-with-a-long-random-secret
CORS_ORIGIN=https://your-domain.example
REGISTRATION_INVITE_CODE=optional-class-code
APP_TIMEZONE=Asia/Shanghai
APP_USE_SYSTEM_TIMEZONE=false
Set APP_USE_SYSTEM_TIMEZONE=true to use the machine's current timezone instead.
For deployment, set APP_ENV=production or GIN_MODE=release. In production mode the server refuses to start unless JWT_SECRET is set to a unique value of at least 32 characters.
REGISTRATION_INVITE_CODE is optional. When set, new accounts must enter that code on the registration form; existing users can still log in normally.
The compact enrichment tool reads .env, calls the configured OpenAI-compatible chat endpoint, and writes:
data/sources/ai-enrichment.compact
Required when running enrichment:
OPENAI_API_KEY=
OPENAI_BASE_URL=https://api.openai.com/v1
OPENAI_MODEL=gpt-4.1-mini
AI_BATCH_SIZE=10
AI_TIMEOUT_MS=60000
AI_RETRIES=1
Run a small batch:
node tools/ai-enrich.mjs --limit=20Run all remaining concepts:
node tools/ai-enrich.mjs --limit=800Then re-import from the app Data page, or call:
Invoke-RestMethod -Method Post -Uri http://localhost:8080/api/import/run -Headers @{Authorization="Bearer TOKEN"} -Body "{}" -ContentType "application/json"go test ./...
cd frontend
npm run buildThe login form intentionally starts blank. Register a local account on first launch.
The first registered account is created as an admin so it can access the Data page. Later accounts are regular student users unless their role is changed directly in local development.




