For the CS50x final project, I wanted to build something that felt real — not just a project to tick a box, but an actual app people could download and use. Parsa Vault is a Flutter stock trading simulator that gives every user $10,000 of virtual cash and lets them buy and sell live stocks without risking a penny of real money. It tracks your portfolio, records every trade in your transaction history, awards XP for your activity, and ranks you against every other player on a global leaderboard. The app is live right now on Apple TestFlight for iOS and on Google Play Console for Android — built from scratch as a single Flutter codebase that compiles natively for both platforms.
This project grew directly out of my Week 9 web app, where I first built a browser-based stock trading game in Flask with an XP progression system and user login. The Week 9 version proved the idea worked, but a web app always felt like a halfway house — I wanted something you could tap open on your phone and just start using. So for the final project I took that foundation and rebuilt it properly: cloud sync with Firebase Firestore, five different sign-in methods (email, Google, Apple, Microsoft, and anonymous guest), a full ten-level progression system with named ranks from Apprentice to Vault Master, and a guest mode that lets anyone start trading in seconds without creating an account.
The most technically interesting part was the guest merge flow. When a guest eventually logs in, they might have a weeks worth of trades on their anonymous account and a whole separate portfolio on their registered account. Rather than just overwriting one with the other, the app pauses at a Two saves found screen, shows both accounts side by side with their XP, level, and cash balance, and lets the user choose which to keep. Getting this right across email login and all three SSO providers took a lot of careful sequencing — the guests Firebase UID and Firestore data have to be captured before Firebase Auth switches to the new account, otherwise the data is gone.
Beyond the merge logic, the engineering decisions that shaped the project most were the choice of Riverpod for state management and the decision to floor rather than round every cash calculation. Riverpod made it straightforward to wire up reactive dependencies across the app — the portfolio reloads automatically when the user switches accounts, the history refreshes after every trade, and the leaderboard stays in sync — all without passing state down through widget trees manually. The flooring decision came from a real bug: after a few hundred trades, floating-point arithmetic was drifting the cash balance to values like 5625.013012647001. Rounding would give the user a fraction of a cent for free on some trades; flooring ensures the house never loses. Its the kind of thing you only think about once you start writing real financial logic, and it was a genuinely satisfying problem to spot and fix.
Overall, this project taught me more about production-grade app architecture, Firebase security rules, and cross-platform mobile development than any problem set in the course — and its one of those things that will genuinely outlive CS50x.
The full source code for this week is up on GitHub — you can browse the Week 10 folder directly to see the complete Flutter project, or explore the entire CS50x repository to follow the full journey from Week 0 to the final project.