DEV Community

Angel Umeh
Angel Umeh

Posted on

Pollux: Let's explore Nigerian political sentiment

DEV Weekend Challenge: Passion Edition Submission

This is a submission for Weekend Challenge: Passion Edition

What I Built

Pollux is an anonymous, real-time tracker of Nigerian political sentiment. Pick any of 52 politicians, national or state level, and vote support, undecided, or oppose. Leave a short comment saying why. Watch the tally move live, see how the country breaks down across all six geopolitical zones, and read a neutral, AI-generated briefing on who the person is and what's being said about them right now.

I built it because Nigerian political discourse online is loud, fast, and hard to read. Twitter tells you who's shouting. It doesn't tell you what the quiet majority actually thinks, or whether the loudest voices are representative of anything at all. Pollux is my attempt at a calmer instrument: no accounts, no follower counts, no badges, no clout scores. Just a vote, a reason, and a running tally you can watch move in real time.

The goal was never a "who's winning 2027" scoreboard. I wanted a public ledger of how much Nigerians care, one that admits what it doesn't know instead of pretending. When a politician hasn't crossed the minimum sample, Pollux withholds the number rather than inventing one.

Main features

  • Vote support, undecided, or oppose on 52 national and state-level politicians, with a 60-second cooldown and the option to retract
  • Anonymous 280-character comments, moderated by AI before anyone sees them
  • A live leaderboard, plus a Pulse page showing the top movers today, this week, and this month
  • Regional breakdowns across the six geopolitical zones covering all 36 states and the FCT
  • Per-politician detail pages with a 0 to 100 debate temperature gauge, dominant emotions, neutral supporter and critic digests, and a grounded factual briefing
  • A methodology panel on every page that reads from the same constants the code enforces
  • Shareable politician cards via the Web Share API, with a clipboard fallback

Demo

Live app: pollux-ng.vercel.app

[drop a short screen recording or a couple of screenshots here. The live tally updating and a detail page with the AI briefing and temperature gauge open make the strongest visuals]

Code

GitHub logo akcumeh / poll-ux

Poll - ux is an anonymous, real-time platform for tracking Nigerian political sentiment. Users can vote, comment, and explore public opinion on politicians across all 36 states, with live rankings, regional insights, and transparent, manipulation-resistant data.

Pollux

Anonymous, real time tracker of Nigerian political sentiment. Vote support, undecided, or oppose on politicians across all 36 states, comment, and explore live rankings and regional insight. Numbers below the minimum sample are withheld, never invented, and everything a machine wrote is labeled.

Architecture

A single Vercel deployment serves both halves:

  • src/ is a vanilla TypeScript + Vite frontend. Pages render as template strings, event handlers attach to window. No framework.
  • api/ is the backend: Vercel Node serverless functions (cast-vote, moderate-comment, ai-insights, briefing, report-comment). They hold the Supabase service role key and the Gemini key, enforce vote cooldowns and daily limits server side, and are the only thing that ever calls Gemini (gemini-2.5-flash, via @google/genai).
  • Supabase is Postgres plus realtime, nothing else. supabase/migrations holds the schema. The client only ever reads tables directly with the anon key; every write…

How I Built It

One deployment, two halves

A single Vercel project serves everything. src/ is a vanilla TypeScript + Vite frontend. No React, no Vue, no framework at all. Pages render as template strings and event handlers attach to window. I went framework-less deliberately: the app is mostly read-heavy dashboards, the bundle stays tiny, and I wanted full control over what hits the network and when. The entire project has exactly two runtime dependencies: @supabase/supabase-js and @google/genai.

api/ is a handful of Vercel Node serverless functions: cast-vote, moderate-comment, ai-insights, briefing, and report-comment. This split is the backbone of the whole trust model:

  • The browser only ever holds the Supabase anon key, and Row Level Security policies mean it can only read.
  • Every write, whether a vote, a comment, or a report, goes through api/, which holds the service-role key.
  • Rate limits (a 60-second vote cooldown, 150 actions per day, 20 reports per hour) are enforced server-side, where they can't be tampered with.

Supabase is just Postgres plus Realtime for me. Postgres triggers auto-recount the vote aggregates on every insert, update, and delete, and Realtime subscriptions push fresh tallies to every open tab. Nobody refreshes; the numbers just move.

Trust by default

This is the part I care most about, and it shaped almost every decision:

  • Minimum-sample thresholds. A politician needs 20 votes overall (and 10 per zone) before their regional breakdown shows. AI sentiment analysis won't run until at least 5 approved comments exist. Below those floors, the UI withholds the number rather than guessing.
  • One source of truth. Those thresholds live in src/lib/constants.ts, imported by both the frontend rendering and the API functions. The methodology panel I show users literally cannot drift from what the code enforces, because they read the same constants.
  • Server-side timestamps everywhere. The Pulse page's top movers are counted from server-side vote timestamps, so the rankings are identical on every device. There's no "your view" versus "my view".
  • Everything AI-generated is labeled. Briefings, the debate temperature gauge, the supporter and critic digests: each one is marked as AI-produced, with a timestamp so you know exactly how stale it is.

Google AI (Gemini) does three jobs

This is where Gemini earns its keep. I use gemini-2.5-flash via @google/genai, the only model in the stack, and it never runs in the browser. The GEMINI_API_KEY lives only in server-side env and is referenced exclusively by api/.

  1. Comment moderation. Every comment is classified clean / abusive / spam / incitement before it's stored, using structured JSON output with a strict response schema at temperature 0.2. Strong political disagreement is explicitly clean; only abuse, spam, and incitement get held for review. The moderator fails open: if Gemini errors or times out (it gets 6 seconds), the comment still posts rather than silently disappearing. Given how heated Nigerian political threads get, that was non-negotiable. One considerate detail: a held comment stays visible to its author for 60 seconds, so nobody sits there wondering whether their submission vanished.
  2. Debate insights. Once a politician has enough approved comments, Gemini produces a 0 to 100 temperature (how heated the debate is, not which side is winning), the dominant emotions, and two short neutral digests: what supporters mainly argue, and what critics mainly argue. It's prompted to stay neutral and to say plainly when a side is absent.
  3. Grounded briefings. Each politician gets a factual briefing of at most 130 words, generated with Google Search grounding, covering their current role, recent news, and the debates around them. The prompt explicitly forbids praising, condemning, predicting election outcomes, and inventing approval numbers.

All three are cached and resilient: insights live for 10 minutes (or until 5 new comments land), briefings for 24 hours, and if a regeneration call fails, the last good cached version is served rather than erroring in the user's face.

Connection to the Theme

The theme is Passion, and Pollux measures it literally. The temperature gauge on every detail page doesn't tell you who's winning; it tells you how much heat a debate is carrying. The component in my codebase is even called passionMeter.

Nigerians are among the most politically passionate people anywhere. We argue about governors in barbershops, dissect ministerial appointments in family WhatsApp groups, and turn every election season into a national obsession. What we've never really had is an honest instrument for that passion: something that captures the intensity without the noise, the shouting matches, or the bot armies. Pollux is my attempt to give that energy a place to register, one anonymous vote and one 280-character reason at a time, and to render it back as something the country can actually read.

What's Next

The anonymous model is a feature (low friction means more honest votes), but it means I lean entirely on rate limits and moderation to keep things sane. After the challenge, I want to explore:

  • more sophisticated vote-integrity signals beyond cooldowns and daily ceilings
  • a richer regional visualization, ideally an interactive map of the 36 states
  • surfacing comment trends over time, not just the current digest
  • an admin review queue for held comments, so moderation decisions are auditable

Prize Categories

Best Use of Google AI. Gemini 2.5 Flash runs three distinct, load-bearing jobs in Pollux:

  • real-time comment moderation with structured JSON classification that fails open
  • debate analysis producing a temperature score, dominant emotions, and neutral digests for both sides
  • grounded factual briefings via Google Search grounding, all behind serverless functions with caching and graceful fallback

Top comments (1)

Collapse
 
thaisavieira profile image
Thaísa Vieira

Wow! Congratulations on the project, it turned out amazing!