A real-time live polling and audience engagement platform — create a poll, share a 5-character code, and watch votes update on every connected screen instantly, no refresh needed.
Think Slido/Mentimeter, minimal version: built to demonstrate WebSocket-based real-time architecture end-to-end, not just a CRUD app with a REST-only "refresh to see results" model.
Most portfolio full-stack projects are static request/response CRUD apps. PollPulse demonstrates:
- Real-time push architecture — votes broadcast to every connected client over WebSocket (STOMP over SockJS), not polling the server every N seconds
- Idempotency / abuse prevention — a client-side fingerprint + a unique DB constraint on
(poll_id, voter_fingerprint)stops duplicate votes without requiring login - Clean separation of concerns — Spring Boot REST + WebSocket backend, decoupled React SPA frontend, deployable independently
Browser A ---REST(create poll)---> [Spring Boot API] ---> [Postgres]
Browser B ---REST(vote)-----------> [Spring Boot API] ---> [Postgres]
|
broadcast update
v
[STOMP /topic/polls/{id}]
/ \
v v
Browser A (live) Browser B (live)
- Backend: Spring Boot REST API for poll CRUD + voting, Spring WebSocket (STOMP) for live broadcast on every vote.
- Frontend: React (Vite) SPA — create/join/vote/watch-live screens, subscribes to the poll's WebSocket topic on load.
- Database: Postgres in production, defaults to in-memory H2 for zero-config local dev.
Java 17 · Spring Boot 3 · Spring WebSocket (STOMP/SockJS) · Spring Data JPA · PostgreSQL/H2 · React 18 · Vite · React Router
git clone <your-repo-url>
cd pollpulse
docker-compose up --buildFrontend: http://localhost:5173 · Backend: http://localhost:8080
# backend (uses in-memory H2, no DB setup needed)
cd backend
./mvnw spring-boot:run
# frontend (separate terminal)
cd frontend
npm install
npm run dev| Method | Endpoint | Description |
|---|---|---|
| POST | /api/polls |
Create a poll: { "question": "...", "options": ["A","B"] } |
| GET | /api/polls/{id} |
Get poll by ID |
| GET | /api/polls/join/{code} |
Get poll by its 5-character join code |
| POST | /api/polls/{id}/vote |
Cast a vote: { "optionId": "...", "voterFingerprint": "..." } |
| POST | /api/polls/{id}/close |
Close a poll to new votes |
| WS | /ws (STOMP) |
Subscribe to /topic/polls/{id} for live updates |
This one is genuinely easy to get live for a resume link:
- Backend → Render: New Web Service, point at
/backend, Docker runtime. Add a free Render Postgres instance and setDB_URL,DB_USER,DB_PASSWORDenv vars on the service. Render gives you a public HTTPS URL automatically. - Frontend → Vercel or Netlify: point at
/frontend, build commandnpm run build, output dirdist. Set the env varVITE_API_BASE_URLto your Render backend URL. - Update the WebSocket connection — since
VITE_API_BASE_URLis reused for both REST and the/wsSockJS endpoint, no extra config needed once that env var is set correctly.
Total cost: $0 on free tiers (Render free web service + free Postgres, Vercel free hobby tier). This is the one to actually put a live demo link for on your resume/LinkedIn — it's visual, interactive, and recruiters can try it themselves in 10 seconds via the join code.
MIT — free to use as a reference or starting point.