A full-stack Election Management System built with React, Node.js + Express, and PostgreSQL. Admins can create polls, manage candidates, and monitor results. Voters can securely authenticate and cast their votes.
- React.js
- HTML5 / CSS3
- Tailwind CSS
- Axios
- Node.js
- Express.js
- PostgreSQL
- JWT (JSON Web Token)
- bcrypt password hashing
- Role-based access control
- Git & GitHub
- Postman (API testing)
- pgAdmin (PostgreSQL GUI)
- Create and manage election polls
- Add positions (President, Secretary, etc.)
- Add candidates for each position
- Configure voting rules
- Schedule election start and end time
- Monitor voting progress
- View election results
- Secure login and authentication
- View active elections
- Cast votes with preference voting support
- Prevent duplicate voting
- Vote confirmation
- One voter can vote only once per position (enforced at DB level)
- Password hashing with bcrypt
- Token-based authentication using JWT
- Database constraints to prevent duplicate votes
- Audit logging for transparency
Frontend (React)
|
Backend API (Node.js + Express)
|
Database (PostgreSQL)
ems/
|
+-- client/ # React Frontend
| +-- src/
| +-- components/
| +-- pages/
| +-- services/
| +-- App.js
|
+-- server/ # Node.js Backend
| +-- controllers/
| +-- routes/
| +-- models/
| +-- middleware/
| +-- server.js
| +-- .env
|
+-- database/
| +-- schema.sql # PostgreSQL schema
|
+-- README.md
Make sure the following are installed on your machine:
| Tool | Version | Download |
|---|---|---|
| Node.js | >= 18 | https://nodejs.org |
| PostgreSQL | >= 14 | https://www.postgresql.org/download |
| Git | any | https://git-scm.com |
macOS (Homebrew)
brew install node
brew install postgresql@16
brew services start postgresql@16Linux (Ubuntu / Debian)
# Node.js
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt-get install -y nodejs
# PostgreSQL
sudo apt-get install -y postgresql postgresql-contrib
sudo systemctl start postgresql
sudo systemctl enable postgresqlWindows
- Download and run the Node.js installer from https://nodejs.org
- Download and run the PostgreSQL installer from https://www.postgresql.org/download/windows
- During installation, set a password for the
postgresuser and keep port5432
- During installation, set a password for the
- Git: https://git-scm.com/download/win
git clone <your-repo-url>
cd emsCopy the example env file and fill in your values:
cp server/.env.example server/.envEdit server/.env:
PORT=5000
DB_HOST=localhost
DB_PORT=5432
DB_NAME=ems_db
DB_USER=postgres
DB_PASSWORD=your_password
JWT_SECRET=your_jwt_secret_key
NODE_ENV=development
CLIENT_URL=http://localhost:5173Never commit
.envto version control. It is already listed in.gitignore.
Open psql (the PostgreSQL shell):
psql -U postgresThen run:
CREATE DATABASE ems_db;
\qApply the SQL schema to create all tables:
psql -U postgres -d ems_db -f database/schema.sqlYou can verify the tables were created:
psql -U postgres -d ems_db -c "\dt"Expected output:
Schema | Name | Type | Owner
--------+------------+-------+----------
public | candidate | table | postgres
public | poll | table | postgres
public | position | table | postgres
public | users | table | postgres
public | vote | table | postgres
If you prefer a GUI:
- Open pgAdmin
- Connect to your PostgreSQL server
- Right-click Databases -> Create -> Database -> name it
ems_db - Open the Query Tool (Tools -> Query Tool)
- Paste the contents of
database/schema.sqland execute
# Install root dependencies
npm install
# Install server dependencies
cd server && npm install && cd ..
# Install client dependencies
cd client && npm install && cd ..Or all at once:
npm install && npm run install:all# From the root /ems directory
npm run devThis starts both the backend and the frontend:
| Service | URL |
|---|---|
| React Frontend | http://localhost:5173 |
| Express API | http://localhost:5000/api |
| Health Check | http://localhost:5000/api/health |
Stores voter and admin accounts.
CREATE TABLE users (
user_id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(150) UNIQUE NOT NULL,
password TEXT NOT NULL,
role VARCHAR(10) CHECK (role IN ('ADMIN', 'VOTER')) NOT NULL,
created_at TIMESTAMP DEFAULT NOW()
);Stores election information.
CREATE TABLE poll (
poll_id SERIAL PRIMARY KEY,
poll_name VARCHAR(200) NOT NULL,
description TEXT,
start_time TIMESTAMP NOT NULL,
end_time TIMESTAMP NOT NULL,
status VARCHAR(20) DEFAULT 'UPCOMING',
created_by INT REFERENCES users(user_id)
);Represents positions within a poll.
CREATE TABLE position (
position_id SERIAL PRIMARY KEY,
poll_id INT REFERENCES poll(poll_id) ON DELETE CASCADE,
position_name VARCHAR(100) NOT NULL,
max_selectable INT DEFAULT 1
);Candidates running for a position.
CREATE TABLE candidate (
candidate_id SERIAL PRIMARY KEY,
position_id INT REFERENCES position(position_id) ON DELETE CASCADE,
name VARCHAR(100) NOT NULL,
party VARCHAR(100),
description TEXT,
photo_url TEXT
);Stores vote records. The UNIQUE constraint prevents duplicate votes.
CREATE TABLE vote (
vote_id SERIAL PRIMARY KEY,
voter_id INT REFERENCES users(user_id),
poll_id INT REFERENCES poll(poll_id),
position_id INT REFERENCES position(position_id),
candidate_id INT REFERENCES candidate(candidate_id),
timestamp TIMESTAMP DEFAULT NOW(),
UNIQUE (voter_id, position_id)
);- Duplicate vote prevention — enforced at the database level with
UNIQUE (voter_id, position_id) - Password hashing — bcrypt with salt rounds
- JWT authentication — stateless token-based sessions
- Transaction-based vote recording — votes are committed atomically
- Role-based access control — admin and voter routes are separated
| OS | Command |
|---|---|
| macOS | brew services start postgresql@16 |
| Linux | sudo systemctl start postgresql |
| Windows | Open Services -> find PostgreSQL -> Start, or run pg_ctl start |
| OS | Fix |
|---|---|
| macOS | export PATH="/opt/homebrew/opt/postgresql@16/bin:$PATH" |
| Linux | sudo apt-get install postgresql-client |
| Windows | Add C:\Program Files\PostgreSQL\16\bin to your system PATH |
| Problem | Fix |
|---|---|
FATAL: role "postgres" does not exist |
Run createuser -s postgres (macOS/Linux) |
database "ems_db" does not exist |
Run psql -U postgres -c "CREATE DATABASE ems_db;" |
Connection refused on port 5432 |
Make sure PostgreSQL service is running (see above) |
| JWT errors | Make sure JWT_SECRET is set in server/.env |
| CORS errors | Check CLIENT_URL in server/.env matches your frontend port |
Run from the root /ems directory:
| Command | Description |
|---|---|
npm run dev |
Start both server and client |
npm run server |
Start Express server only |
npm run client |
Start React dev server only |
npm run build |
Build React for production |
- Blockchain-based vote verification
- Real-time vote analytics dashboard
- Email verification for voters
- Mobile responsive UI
- Two-factor authentication (2FA)
- Fraud detection system