Attaching Polls to Any Resource: A Flexible, Polymorphic System
Overview
Civic platforms are incomplete without community voice. I designed a system to attach polls to any resource—leaders, parties, elections, or governments—and record structured public responses.
This post covers how I built a polymorphic poll engine that is:
- Type-safe
- Localized
- Flexible in format (radio/checkbox)
- Easily integrated across the frontend
Schema Structure
Polls use a classic polymorphic pattern:
model Poll {
id Int @id @default(autoincrement())
resourceType String // PARTY, LEADER, ELECTION, GOVERNMENT
resourceId Int
code String @unique
title String
titleLocal String
question String
questionLocal String
type String // RADIO or CHECKBOX
expiresAt DateTime?
createdAt DateTime @default(now())
}
Each poll has options
and stores responses
separately.
Poll Options
model PollOption {
id Int
pollId Int
value String
valueLocal String
linkedResourceType String?
linkedResourceId Int?
}
This allows options to optionally represent a real political entity (e.g. vote on a leader’s performance).
Poll Responses
model PollResponse {
id Int @id @default(autoincrement())
pollId Int
optionId Int
userHash String
createdAt DateTime @default(now())
}
userHash
prevents multiple voting without full auth.
UI Rendering
I created a reusable frontend component:
<SystemPoll poll={poll} onVoteSubmitted={refetch} />
It supports both RADIO
and CHECKBOX
formats and displays results immediately after voting.
Language-Aware Rendering
Every question, title, and option has an English + Nepali version. The UI auto-detects language preference:
const label = i18n.language === 'np' ? option.valueLocal : option.value;
Example Poll
{
code: 'PARTY_APPROVAL',
question: 'Do you like this party?',
questionLocal: 'के तपाईंलाई यो पार्टी मनपर्छ?',
type: 'RADIO',
options: [
{ value: 'Yes', valueLocal: 'हो' },
{ value: 'No', valueLocal: 'होइन' }
]
}
Poll Expiry and Visibility
Polls can have expiresAt
for time-limited campaigns. Inactive or expired polls are hidden automatically. Admins can view all stats and raw submissions.
Summary
This flexible polling engine now powers real-time approval ratings, debates, and issue-based questions across the entire political dataset. It supports deep linking, multilingual responses, and reuse across all modules.
Next: I’ll cover how I optimized backend performance with Redis-powered caching and TTL-based purging for high-traffic endpoints.