A secure, transaction-based voter identification + booth verification system designed to enforce one-person-one-vote using QR identity tokens.
This repo is split into:
- backend/: Bun + Express + PostgreSQL (Drizzle ORM) API
- frontend/: React + Vite UI (QR generation + booth scanner)
- Registration / Identity issuance: the system creates a voter record and issues a unique QR token.
- Booth verification: a polling-booth UI scans the QR code and submits the token for verification.
- Atomic update (transactional): verification is all-or-nothing so a voter can’t be partially verified.
- Double-vote prevention: once a token/voter is verified, subsequent attempts are rejected.
- Auditability: verification attempts (success/failure) are recorded for traceability.
- Single-use verification (prevents double voting)
- Token validity periods / expiry
- Server-side validation using schema validation (Zod)
- Runtime: Bun
- API: Express
- DB/ORM: PostgreSQL + Drizzle
- Other:
dotenv,cors,zod,firebase-admin
- React + Vite
- QR:
react-qr-code(render QR)html5-qrcode/react-qr-reader(scan QR)
- HTTP:
axios - Firebase client:
firebase
- Bun (recommended) or Node.js (Bun scripts are used in this repo)
- PostgreSQL running locally or remotely
cd backend
bun installCreate a backend/.env (or update the existing one) and set:
DATABASE_URL=postgres://postgres:postgres@localhost:5432/voting_dbNote: an
.env.exampleis not currently included in the repo.
bun run generate
bun run migratebun run devThe backend will start on the port defined in the backend source (see backend/src/index.ts).
cd frontend
bun install
bun devOpen:
- Open the frontend at
http://localhost:5173. - Click Generate Demo Identity to create a voter + QR token (stored in the database).
- Open the booth screen at
http://localhost:5173/booth. - Scan the QR code with a webcam (or copy/paste the token if the UI supports manual entry).
Expected behavior:
- First scan → ✅ Verified
- Second scan → ❌ Denied (already verified)
.
├── backend/
│ ├── package.json
│ └── src/
├── frontend/
│ ├── package.json
│ └── src/
└── README.md
bun run dev— start dev server (watch mode)bun run start— start serverbun run generate— generate Drizzle migrationsbun run migrate— run migrations
bun dev— start Vite dev serverbun run build— typecheck + buildbun run preview— preview production build
- Add
.env.examplefiles for backend + frontend. - Document API endpoints and expected request/response payloads.
- Add Docker Compose for Postgres + app services for one-command local setup.
If you changed the “full system” recently (new routes, new DB schema, auth model, or new deployment steps), tell me what changed and I’ll revise this README to match it precisely.