← ~/blog

Building a DSA Study Tracker with Per-User Progress

The problem

I decided to commit to a structured Data Structures & Algorithms study plan — 15 weeks, 5 phases, covering everything from basic arrays to advanced graph algorithms. The plan was detailed: daily blocks with specific LeetCode problems, HackerRank challenges, and learning topics. What I needed was a way to track progress without losing my place across sessions.

Spreadsheets felt wrong. Notion felt like overkill. I wanted something that lived on my site, matched its design, and did exactly one thing well: let me check off items and see how I'm tracking against the schedule.

What I built

The DSA Tracker is a Flask app that presents the entire 15-week curriculum as a navigable, interactive checklist. The course is broken down into:

  • 5 phases — from fundamentals through advanced topics
  • 14 weeks — each with a specific focus area
  • Day blocks — grouping tasks into manageable daily sessions
  • Checklist items — individual learning topics, LeetCode problems, and review tasks

Every item has a checkbox, and the whole thing saves state per-user. There's a progress bar at the top, and a timeline projection that estimates when you'll finish based on your current pace.

Opening it up

The tracker started as a single-user tool — my progress, my checkboxes, no login required. But then I thought: why not let anyone use it? The curriculum is solid, the interface works, and DSA practice is universal.

The challenge was turning a single-user app into a multi-user one without overcomplicating it. The course content (phases, weeks, problems) is shared — it's the same curriculum for everyone. Only the checked state needs to be per-user.

I added Google OAuth via Authlib, which handles the entire OAuth flow in about 20 lines of Flask code. When you sign in with Google, the app creates a user record and starts tracking your progress independently. Your start date is set to the day you first sign in, so the timeline projection is personalised.

The data model change was clean: instead of storing is_checked directly on each checklist item, I moved it to a join table — UserChecklistProgress(user_id, item_id). Same for mastery items and reflections. The course content stays global, the progress is per-user.

Anonymous browsing

If you're not signed in, you can still browse the entire curriculum — every phase, every week, every problem. The checkboxes are visible but disabled, with a prompt to sign in if you want to track progress. This way, people can evaluate the study plan before committing to it.

The timeline

Each user gets a personalised timeline based on their start date and an estimated pace of about 2 hours per day. The app tracks how many items you've checked off versus how many you should have completed by now, and projects a finish date.

If you fall behind by more than 14 days, the timeline turns yellow. More than 21 days, it goes red. It's a gentle nudge, not a punishment — you can always catch up.

Reflections

Every day block has a reflection textarea where you can write notes, record what clicked, what was confusing, or what you want to revisit. These are saved per-user too, so your notes are private to your account.

The stack

  • Flask with SQLAlchemy and PostgreSQL
  • Authlib for Google OAuth
  • Gunicorn behind Nginx on the same server as the rest of adamcoding.com
  • Server-rendered Jinja2 templates — no JavaScript framework, just vanilla JS for checkbox toggles and autosaving reflections
  • The course content is seeded from a Python script on startup, making it easy to update the curriculum

The whole thing runs as a Docker container alongside the main adamcoding.com site, sharing the same Nginx reverse proxy.

Try it

The tracker is live at adamcoding.com/tracker. Sign in with Google to start tracking your DSA progress, or browse the curriculum first to see if the study plan works for you.