Student Progress Tracker
A full-stack FastAPI + Next.js application for tracking individual student progress across a training cohort.
Project Overview
A cohort-facing tool for recording and reviewing individual student progress, built as a full-stack exercise in getting the unglamorous parts of a backend right: correct data isolation, correct API contracts, and correct cross-origin behavior between a separately hosted frontend and API.
The Problem
Early versions of the tracker mixed up student records under concurrent use — one student's submitted progress could bleed into another's view. That's a data-isolation bug, and in a training-progress tool it's the single worst thing the system can get wrong.
Target Users
Trainees recording their own progress, and trainers/mentors reviewing progress across a full cohort.
Goals
- Guarantee that each student's data is strictly isolated from every other student's
- Return well-formed, predictable JSON from every write endpoint
- Serve a Next.js frontend hosted separately from the FastAPI backend without CORS failures
Challenges
- A multi-student data isolation bug where records were not being scoped correctly per user, causing cross-contamination between student views
- POST endpoints returning inconsistent or incomplete response objects, breaking the frontend's ability to immediately reflect a successful write
- CORS misconfiguration blocking the deployed frontend from reaching the API in certain environments
Proposed Solution
Traced the data-isolation bug to missing scoping on the query layer (records were being fetched without a strict per-student filter) and fixed it at the query level rather than patching it in the frontend. Standardized every POST route to return the full created/updated object, matching what the frontend expected. Corrected CORS middleware configuration to explicitly allow the deployed frontend origin.
System & Technical Architecture
Next.js frontend (deployed separately) → FastAPI REST API with CORS middleware → SQLAlchemy ORM → SQLite (dev) — each request scoped to an authenticated student or trainer context before hitting the database layer.
Database Design
Students, progress_entries (linked to a student_id foreign key with an enforced query-time filter), and cohort metadata.
API Design
Every mutating endpoint (POST/PUT) returns the full resulting object rather than a bare status message, so the frontend can update its state directly from the response instead of issuing a follow-up GET.
Key Features
- Per-student progress logging with strict data isolation
- Trainer-facing cohort overview
- Consistent REST response contracts across all endpoints
- Deployed frontend/backend split with correctly configured CORS
Technical Decisions
Fixed data isolation at the query layer, not the UI
Filtering in the frontend would have left the underlying API insecure and reproducible by anyone calling it directly — the fix had to live where the data was actually fetched.
Standardized POST responses to return full objects
The frontend was written to expect the created resource back immediately; returning only a status code forced unnecessary extra requests and out-of-sync UI state.
Testing Strategy
Manual testing across multiple concurrent student sessions specifically to catch cross-contamination, plus endpoint-level testing of each POST/PUT contract.
Security Considerations
Per-student query scoping doubles as an access-control boundary no student-facing route can return another student's records regardless of how the request is shaped.
Results & Outcomes
A working full-stack application with the data-isolation, response-contract, and CORS issues resolved and verified. [Placeholder: add cohort usage numbers if this is put in front of a live cohort.]
Lessons Learned
- Data isolation bugs are easy to miss in single-user manual testing they only show up under realistic concurrent use
- Frontend and backend response-contract mismatches are often mistaken for frontend bugs when the real fault is an inconsistent API
Future Improvements
- Migrate from SQLite to PostgreSQL for multi-cohort production use
- Add trainer-side analytics on progress trends across a cohort
Want to talk through how this was built, or a similar problem you’re facing?
Get in touch