/PROJECT 06 · LEGACY WEB2 PROJECT

Pulse Code Voting

A full-stack voting platform that replaces paper ballots at a university awards ceremony. Voters receive a printed QR ticket, cast one vote from their phone, and watch a live leaderboard; organizers manage events, print and revoke tickets, void ballots, and review insights from an admin console. Every rule that matters — the voting window, ticket state, one vote per ticket — is enforced server-side, and results are derived from votes rather than stored as counters.

BUILT BY TAIWO EMMANUEL · FULL-STACK DEVELOPER

Project screenshot: home

/GOAL

One ticket, one ballot — enforced at the data layer, not in the UI.

/STACK

Technologies used

  • React 19
  • TypeScript
  • Vite
  • TanStack Query
  • Zustand
  • Tailwind CSS v4
  • Radix UI
  • React Hook Form
  • Zod
  • Recharts
  • Express 5
  • Prisma
  • PostgreSQL / Neon
  • MongoDB-portable schema
  • JWT
  • bcrypt
  • Vitest react-qr-code
  • qr-scanner
  • React
  • Node.js
  • Express
  • PostgreSQL
  • Voting
  • Full-stack

/ARCHITECTURE

How it is built

  1. Voter and admin surfaces — React clientA mobile-first voting wizard (Ticket → Details → Choose → Review), a live results board, and an admin console for events, tickets, voters, insights and the help desk.
  2. Stateless authority — Express 5 APIPublic voting routes plus JWT-authenticated admin routes. Every rule — window, ticket state, phone uniqueness, roles — is decided here. Errors are thrown and mapped to one JSON shape with a stable code and a requestId.
  3. Facts store — Prisma + PostgreSQLBallots and votes are stored as facts. The canonical Postgres schema is the source of truth; a generated MongoDB variant allows the same code to run on either database.
  4. Views over facts — Derived resultsStandings are computed from valid votes with a 2.5-second in-memory cache that stores the in-flight promise, so a hall full of polling phones costs roughly one database query every few seconds. Casting, voiding or restoring a ballot clears the cache immediately.
  5. Time as a parameter — Pure voting statevotingState(event, now) derives DRAFT | SCHEDULED | OPEN | CLOSED | ARCHIVED on every request, so published events open and close on their own without a scheduler.

/SCOPE

What was delivered

  • Issue one vote per printed QR ticket, enforced with a conditional claim inside a transaction
  • Run a self-opening, self-closing voting window computed from event status and time
  • Show a live leaderboard with results derived from valid votes, not stored counters
  • Manage events, ballots, categories and nominees from an admin console
  • Generate, print, import, revoke and restore QR tickets in batches
  • Look up a ticket at the help desk by code or camera and show the ballot cast with it
  • Void and restore ballots with an audit trail, keeping the ticket used
  • Control public results visibility (Live / After close / Hidden)
  • Enforce Viewer / Admin / Super admin roles on the server, with token-version revocation

/NOTES

Scope boundaries

Pulse is a voting platform for a supervised, in-person event. It does not verify voter identity beyond a printed ticket and an optional phone number (no SMS confirmation), it does not connect to any external identity provider, and its live-update model is short-interval polling validated for campus-scale audiences, not large-scale real-time streaming.

/GALLERY

/WRITING_ON_THIS_STACK

Articles on the tools behind Pulse Code Voting

/MORE_WORK