Harshit Sharma
All work

Web AppQ4 2021Solo build

QuizTown

High-end quiz platform that saves progress and rates the user at every level.

QuizTown's nine category tiles — literature, geography, history, music, science, sport, technology and entertainment.

The build

Nine categories, ten levels each, and a rating waiting at the end of every one.

Problem

Most quiz sites forget you the moment you close the tab. That's fine for a single trivia round and useless for anything with progression: without persistence there's no reason to come back, and without a rating there's no reason to replay a level you already passed.

Constraints

  • Ninety levels of content. Nine categories, ten levels each. The data model had to make adding a level cheap, because most of the work was going to be content, not code.
  • Progress has to survive a lost session. Anonymous play with localStorage was the easy version and the wrong one.
  • Two identity providers. Facebook and Google, because the audience had one or the other, rarely both.

Approach

Levels are documents, not code. A category holds ten of them; each level holds its questions and its scoring rule. Adding content is a database write, not a deploy.

Progress is stored per account per level, so the state that matters — furthest level reached, rating achieved — is a small document rather than a recomputation over an answer log:

js
// One document per player per level. Upserted on completion.
await Progress.updateOne(
  { user: userId, category, level },
  { $max: { rating }, $set: { completedAt: new Date() } },
  { upsert: true }
);

$max is the whole replay rule: finishing a level again can raise your rating and can never lower it.

Tradeoffs

  • Storing a rating rather than the answers. Compact and fast to read, and it throws away the data that would have let me analyse which questions were badly written. A log would have been bigger and more useful later.
  • Two OAuth providers instead of one. Doubled the auth surface — two apps to register, two callback flows to keep working — for coverage of an audience that wouldn't sign up otherwise.
  • Content in the database over content in files. Adding a level got easy; version control over the questions got lost. Today I'd put them in files and validate at build, which is precisely what this portfolio does with MDX.

Outcome

The full ninety levels shipped, with progress and ratings intact across sessions and both sign-in paths working. It's the earliest project of mine that had real state to protect, and the first time getting persistence wrong would have been visible to a user rather than just to me.

Decisions

  • Accounts over anonymous play. Chosen because progression is the product, and progression without identity is a cookie waiting to be cleared. Against it: a sign-in wall before the first question is the highest-friction thing you can put in front of a casual player.
  • $max on rating over storing every attempt. Chosen for a read path that never has to aggregate. Against it: no history, so improvement over time is invisible.
  • Materialize CSS over writing my own. Chosen to spend the time on the level system instead of on components. Against it: the site looks like every other Materialize site, which is a real cost on a portfolio piece.

Stack

  • Node.js
  • Express.js
  • MongoDB
  • Passport.js
  • EJS
  • Materialize CSS
  • The Lecture Lense workspace — a lecture playing above a chaptered time rail, the corrected transcript on the left, and a chat answer on the right with a timestamp citation.

    Lecture Lense

    Turns any recording into searchable, timestamp-cited notes.

  • Chitter's landing page — headline, a Join Chitter Now button, and a phone mockup of the feed.

    Chitter

    A mini social app that lets users sign up, log in and post whatever is on their mind.

  • A live Heckfree profile — avatar and the handle meharshit above seven stacked link rows, on a peach-to-purple gradient.

    Heckfree

    Users get a public profile that showcases all of their links in one place.

esc

Pages

Home/
Work/work
Blog/blog
About/about
Uses/uses
Contact/contact
Bucket list/bucket-list
Guestbook/guestbook
Résumé/resume
Privacy/privacy
Terms/terms

Projects

Lecture LenseQ3 2026
ChitterQ1 2023
HeckfreeQ3 2022
CoscholarsQ3 2022
JsswireQ2 2022
JssconnectQ1 2022
QuizTownQ4 2021
IplheatQ2 2021
TechkartQ4 2020

Posts

Passport.js auth patterns I keep reaching for7 min read
How To Create A README For GitHub Profile3 min read
↑↓ navigate↵ openesc close