Live Polls For Feedback is a comprehensive full-stack platform designed for real-time engagement and feedback collection. Creators can build complex polls with multiple question types, share them via secure or anonymous links, and monitor results live through a dynamic analytics dashboard. The platform ensures data integrity with atomic vote updates and provides a polished, animated user experience across all devices.
- Secure Registration: Register with email and password with mandatory verification.
- Email Verification: Token-based verification system via Resend.
- Social Login: Seamless Google OAuth integration via Passport.js.
- Session Management: JWT-based authentication using secure
httpOnlycookies. - Password Recovery: Robust forgot/reset password flow with hashed tokens.
- Session Rehydration: Automatic session recovery on page refresh via
/auth/me.
- Intuitive Creation: 3-step form with drag-and-drop question reordering.
- Flexible Configuration: Title, description, optional expiry, and privacy modes.
- Question Customization: Required/optional toggles with a minimum of 2 options per question.
- Privacy Control: Support for
ANONYMOUS(public) andAUTHENTICATED(verified users) modes. - Lifecycle Management: Polls transition through
ACTIVEβCLOSEDβPUBLISHEDstates.
- Smart Voting: Atomically increments votes and decrements previous choices to ensure accuracy.
- Duplicate Prevention: Restricted to one response per user (authenticated) or per IP (anonymous).
- Global Reach: Captures respondent metadata including User-Agent and hashed IP.
- Automatic Enforcement: Responses are blocked if the poll is expired or closed.
- Live Dashboard: Real-time stats for total responses and total views.
- Dynamic Charts: Visual breakdown of results using Recharts.
- Socket.io Integration: Instant UI updates when votes are castβno refresh required.
- Result Publishing: Snapshots final results into a dedicated collection for permanent, immutable viewing.
- Framework: Express.js + TypeScript
- Database: MongoDB with Mongoose ODM
- Authentication: Passport.js (Google Strategy) + JWT
- Communication: Socket.io (Real-time events)
- Validation: Zod (Schema-based validation)
- Email: Resend API
- Security: Bcryptjs (12 rounds), Helmet.js, express-rate-limit
- Framework: React 18 + TypeScript + Vite
- Routing: React Router v6
- Data Fetching: TanStack Query v5
- Forms: React Hook Form + Zod
- Animations: Framer Motion + GSAP (ScrollTrigger)
- UI Components: Tailwind CSS + Shadcn/ui + Lucide React
- Notifications: Sonner
The backend follows a strict Controller β Service β DB architecture to separate concerns:
- Controllers: Handle HTTP request/response logic and input parsing.
- Services: Contain business logic, database interactions, and real-time event triggers.
- Models: Define Mongoose schemas and database-level middleware.
[Register/Login] --> [Service Layer] --> [JWT Generation]
| | |
v v v
[Resend Email] [Hash Password] [Set httpOnly Cookie]
ACTIVE (Accepting votes) β CLOSED (Votes frozen) β PUBLISHED (Immutable snapshot created)
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /api/auth/register |
No | Register new user (displayName, email, password) |
| POST | /api/auth/login |
No | Login with email/password |
| POST | /api/auth/logout |
Yes | Clear auth cookies |
| GET | /api/auth/me |
Yes | Get current user profile |
| GET | /api/auth/verify-email |
No | Verify email via ?token= |
| POST | /api/auth/forgot-password |
No | Request password reset email |
| POST | /api/auth/reset-password |
No | Reset password using token |
| GET | /api/auth/google |
No | Start Google OAuth flow |
| GET | /api/auth/google/callback |
No | Google OAuth callback handler |
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /api/polls |
Yes | Create a new poll |
| GET | /api/polls |
Yes | List all polls created by user |
| GET | /api/polls/:id |
No* | Get poll details (increments views) |
| PUT | /api/polls/:id |
Yes | Update poll (ACTIVE status only) |
| DELETE | /api/polls/:id |
Yes | Cascade delete poll and data |
| POST | /api/polls/:id/response |
Opt | Submit answers (answers: [{ questionId, selectedOptionId }]) |
| GET | /api/polls/:id/responses |
Yes | Get raw response list |
| PATCH | /api/polls/:id/close |
Yes | Change status to CLOSED |
| PATCH | /api/polls/:id/publish |
Yes | Snapshot and change status to PUBLISHED |
| GET | /api/polls/:id/result |
No | Get published result snapshot |
* Authenticated if privacyMode is AUTHENTICATED
email(String, Unique)passwordHash(String, select: false)displayName(String)avatarUrl(String)isEmailVerified(Boolean)oauthProviders(Array: { provider, providerId })passwordResetToken/ExpiresemailVerificationToken/Expires
creatorId(ObjectId, Ref: User)title(String)description(String)status(Enum: ACTIVE, CLOSED, PUBLISHED)privacyMode(Enum: ANONYMOUS, AUTHENTICATED)expiresAt(Date, Optional)questions(Array: { text, required, options: [{ text, votesCount }] })totalResponses(Number)totalViews(Number)
pollId(ObjectId, Ref: Poll)respondentId(ObjectId, Optional)answers(Array: { questionId, selectedOptionId })ipHash(String)userAgent(String)country(String)submittedAt(Date)
pollId(ObjectId)publishedAt(Date)totalResponses(Number)questions(Array: Snapshot of poll questions and final counts)
- Node.js (v18+)
- MongoDB (Local or Atlas)
- Redis (for Rate Limiting)
- Resend API Key
git clone https://github.com/Asutosh-1234/Live-Polls-For-Feedback.git
cd Live-Polls-For-Feedbackcd Backend
npm install
# Create .env based on the Environment Variables section below
npm run devcd ../Frontend
npm install
# Create .env based on the Environment Variables section below
npm run dev| Variable | Description | Example |
|---|---|---|
PORT |
Server port | 5000 |
NODE_ENV |
Environment mode | development |
DATABASE_URL |
MongoDB connection URI | mongodb://localhost:27017/livepoll |
JWT_SECRET |
Secret for signing tokens | super-secret-key |
JWT_EXPIRES_IN |
Token lifespan | 7d |
GOOGLE_CLIENT_ID |
Google OAuth Client ID | your-id.apps.googleusercontent.com |
GOOGLE_CLIENT_SECRET |
Google OAuth Secret | GOCSPX-... |
BASE_URL |
Backend base URL | http://localhost:5000 |
FRONTEND_URL |
Frontend base URL | http://localhost:5173 |
RESEND_API_KEY |
Resend email service key | re_123... |
SESSION_SECRET |
Express session secret | session-secret |
| Variable | Description | Example |
|---|---|---|
VITE_API_URL |
Backend API root | http://localhost:5000/api |
VITE_SOCKET_URL |
Socket.io server URL | http://localhost:5000 |
- HttpOnly Cookies: All JWT tokens are stored in
httpOnly,secure, andsameSitecookies to prevent XSS. - Token Hashing: Reset and verification tokens are hashed with SHA-256 before being stored in the database.
- Sensitive Data Protection:
passwordHashis excluded from all API responses via Mongooseselect: false. - Strong Hashing: Passwords use
bcryptjswith 12 salt rounds. - Security Headers:
Helmet.jsimplementation for protection against common web vulnerabilities. - Rate Limiting: Applied to authentication routes to prevent brute-force attacks.
- CORS Policy: Restricted to the specific frontend origin only.
- Auth Privacy: Password login is blocked for users who registered via Google OAuth.
Clients join this room when viewing a specific poll page.
Emitted by the server on every successful vote submission. Payload Shape:
{
"totalResponses": 42,
"questions": [
{
"questionId": "65b...",
"options": [
{ "optionId": "65c...", "votesCount": 12 }
]
}
]
}Live-Polls-For-Feedback/
βββ Backend/
β βββ src/
β β βββ controllers/ # Route handlers
β β βββ services/ # Business logic
β β βββ schemas/ # Mongoose models
β β βββ routers/ # Express routes
β β βββ middlewares/ # Auth & Rate limiting
β β βββ utility/ # Helpers & Configs
β β βββ types/ # TypeScript definitions
β βββ package.json
βββ Frontend/
βββ src/
β βββ @/ # UI components & Shadcn
β βββ components/ # Layout & Shared components
β βββ pages/ # View components
β βββ services/ # API integration
β βββ hooks/ # Custom React hooks
β βββ App.tsx # Routing & Main logic
βββ package.json