A financial literacy simulation platform for high school gym events. Students are assigned AI-generated character profiles and walk between physical stations making purchase decisions on school-issued tablets. Admins manage sessions, monitor progress in real time, and trigger life events. At the end, students receive an AI-graded report.
- Framework: Next.js 16 (App Router, Turbopack)
- UI: Tailwind CSS, Radix UI, shadcn/ui
- Auth: Kinde (Google OAuth)
- AI: Amazon Bedrock (Claude) for profile generation and grading
- PDF: jsPDF for downloadable reports
- Charts: Recharts for spending visualization
- Data: JSON file-backed in-memory store (
data/db.json) - Real-time: Server-Sent Events (SSE)
- Node.js 20+
- pnpm
pnpm installCopy .env.local.example to .env.local and fill in:
KINDE_CLIENT_ID=...
KINDE_CLIENT_SECRET=...
KINDE_ISSUER_URL=https://your-app.kinde.com
KINDE_SITE_URL=https://fundingyourfutures.org
KINDE_POST_LOGOUT_REDIRECT_URL=https://fundingyourfutures.org
KINDE_POST_LOGIN_REDIRECT_URL=https://fundingyourfutures.org/initializing
BEDROCK_API_KEY=... # Amazon Bedrock API key (us-east-1)
# BEDROCK_MODEL_ID=... # Optional, defaults to Claude Sonnet
Kinde dashboard setup: Add https://fundingyourfutures.org/api/auth/callback as an allowed callback URL.
Without Bedrock: The app works fully without an API key -- it falls back to a pool of 8 pre-built character profiles and heuristic-based grading.
pnpm devAdmin access is controlled by email allowlist in lib/auth/adminAllowlist.ts.
pnpm build
pnpm start- Join -- Enter a 6-character session code on the landing page (OTP-style input)
- Authenticate -- Google OAuth via Kinde
- Wait -- Waiting room until the admin starts the session
- Onboard -- 7-step guided tour explaining the dashboard, stations, and how to get help
- Character Profile -- Shown automatically after onboarding; viewable anytime via the Profile button
- Visit Stations -- Navigate through 7-8 stations (randomized order per student), entering product codes at each physical booth to make purchases
- Complete -- After all stations, wait for the admin to end the session
- Results -- AI-graded letter grade (A-F), analysis paragraph, purchase history, and downloadable PDF report
| Station | Multiple Purchases | Conditional |
|---|---|---|
| Clothing | No | -- |
| Grocery | No | -- |
| Insurance | No | -- |
| Retail | Yes | -- |
| Transport | No | -- |
| Housing | No | -- |
| Bank | No | -- |
| Personal Care | Yes | -- |
| Childcare | No | Only if profile has children |
- Create Session -- Name it, get a 6-char join code
- Share Code -- Full-screen code display with live student count
- Start Simulation -- Moves all waiting students to onboarding
- Monitor -- Real-time student table showing current station, purchases, balance
- Manage Students -- Click any student to open a detail drawer (view/remove purchases, add money)
- Trigger Life Events -- Select students via checkboxes, apply a specific or random life event to all at once
- Export -- CSV export of all student data
- End Simulation -- Moves all students to the results screen
All state changes propagate instantly via SSE to both admin and student views:
- Student joins, makes a purchase, advances stations
- Admin removes a purchase (student is sent back to that station), adds money, triggers life events
- Session starts/ends
When an admin removes a purchase from an earlier station, only that station becomes "uncleared." The student must revisit it, but all other completed stations remain intact. The student sees the affected station highlighted with a "Tap to revisit" prompt.
Admins can trigger life events (from data/life-events.json) that add or subtract from student balances. Events can be applied to multiple students at once, with the option to assign random events. Students see a full-screen popup when a life event hits.
The student experience enforces fullscreen mode on any user interaction (click/touch). Pinch-to-zoom and text selection are disabled. Admin routes are excluded from fullscreen enforcement.
app/
page.tsx # Session code entry (OTP input)
initializing/page.tsx # Waiting room
onboarding/page.tsx # Guided tour
dashboard/page.tsx # Station list + budget chart
station/[stationId]/page.tsx # Purchase screen
complete/page.tsx # Post-stations waiting
summary/page.tsx # AI-graded results
admin/page.tsx # Session management
admin/session/[sessionId]/page.tsx # Live session view
api/
auth/[kindeAuth]/route.ts # Kinde OAuth
session/route.ts # CRUD sessions
student/route.ts # Student state
purchase/route.ts # Product code validation + purchase
admin/route.ts # Admin actions
events/route.ts # SSE endpoint
summary/route.ts # AI grading
report/route.ts # PDF generation
components/
student/ # Student-facing components
admin/ # Admin-facing components
ui/ # shadcn/ui primitives
FullscreenEnforcer.tsx # Tablet lockdown
lib/
ai/
bedrock.ts # Bedrock Converse API client
generateProfile.ts # AI character generation
generateSummary.ts # AI grading
reports/generateReport.ts # PDF generation (jsPDF)
auth/adminAllowlist.ts # Admin email gate
store.ts # JSON-file-backed session store
types.ts # TypeScript interfaces
hooks/
useSSE.ts # SSE client hook
useActiveSession.ts # Active session tracking
data/
products.json # All purchasable products by station
stations.json # Station definitions
life-events.json # Life event definitions
db.json # Runtime session data (gitignored)
Session data is stored in data/db.json -- an in-memory Map synced to disk on every write. Data survives server restarts but not redeployments to fresh environments. This is intentional for the single-event, gym-based use case.
| Feature | Model | Fallback |
|---|---|---|
| Character profiles | Claude via Bedrock | 8 pre-built profiles (round-robin) |
| Summary grading | Claude via Bedrock | Heuristic scoring (housing ratio, insurance, savings, balance) |
| PDF reports | jsPDF (no AI) | -- |
Profiles are generated with high temperature and random seeding to ensure diversity across students within the same session.