- Created `/frontend/app/api/votes/check/route.ts` to handle GET requests for checking if a user has voted in a specific election. - Added error handling for unauthorized access and missing election ID. - Forwarded requests to the backend API and returned appropriate responses. - Updated `/frontend/app/api/votes/history/route.ts` to fetch user's voting history with error handling. - Ensured both endpoints utilize the authorization token for secure access.
10 KiB
10 KiB
E-Voting System - Backend & Frontend Integration Setup
This guide explains how to run both the FastAPI backend and Next.js frontend together.
System Requirements
- Python 3.12+
- Node.js 18+ (for npm)
- MySQL 8.0+ (or SQLite for development)
- Poetry (for Python dependency management)
Project Structure
e-voting-system/
├── backend/ # FastAPI application
│ ├── main.py # Entry point
│ ├── routes/ # API endpoints (auth, elections, votes)
│ ├── models.py # Database models
│ ├── schemas.py # Pydantic schemas
│ ├── config.py # Configuration
│ └── crypto/ # Cryptography modules
├── frontend/ # Next.js application
│ ├── app/ # Application pages
│ ├── components/ # React components
│ ├── lib/ # Utilities (API client, auth context)
│ └── package.json # npm dependencies
└── pyproject.toml # Python dependencies
Quick Start (Both Services)
Prerequisites Setup
- Python Environment (Backend)
# Install Poetry
curl -sSL https://install.python-poetry.org | python3 -
# Install Python dependencies
cd /home/sorti/projects/CIA/e-voting-system
poetry install
- Node.js Environment (Frontend)
cd /home/sorti/projects/CIA/e-voting-system/frontend
npm install
Database Setup
The backend uses MySQL by default. For development, you can use SQLite instead.
Option 1: Using SQLite (Easy for Development)
# Set environment variable to use SQLite
export DB_URL="sqlite:///./evoting.db"
Option 2: Using MySQL (Production-like)
# Start MySQL (if using Docker)
docker run --name mysql-evoting -e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=evoting_db -p 3306:3306 -d mysql:8.0
# Or connect to existing MySQL instance
export DB_HOST=localhost
export DB_PORT=3306
export DB_NAME=evoting_db
export DB_USER=evoting_user
export DB_PASSWORD=evoting_pass123
Running Both Services
Terminal 1: Start Backend
cd /home/sorti/projects/CIA/e-voting-system
# Activate Poetry shell or use poetry run
poetry shell
# or
poetry run uvicorn backend.main:app --reload --host 0.0.0.0 --port 8000
Backend will be available at: http://localhost:8000
- Swagger UI:
http://localhost:8000/docs - ReDoc:
http://localhost:8000/redoc
Terminal 2: Start Frontend
cd /home/sorti/projects/CIA/e-voting-system/frontend
# Create .env.local if it doesn't exist
cat > .env.local << EOF
NEXT_PUBLIC_API_URL=http://localhost:8000
EOF
# Start development server
npm run dev
Frontend will be available at: http://localhost:3000
API Endpoints
Authentication
POST /api/auth/register
Content-Type: application/json
{
"email": "user@example.com",
"password": "securepass123",
"first_name": "Jean",
"last_name": "Dupont"
}
Response 200:
{
"access_token": "eyJhbGc...",
"expires_in": 1800,
"id": 1,
"email": "user@example.com",
"first_name": "Jean",
"last_name": "Dupont"
}
POST /api/auth/login
Content-Type: application/json
{
"email": "user@example.com",
"password": "securepass123"
}
Response 200:
{
"access_token": "eyJhbGc...",
"expires_in": 1800,
"id": 1,
"email": "user@example.com",
"first_name": "Jean",
"last_name": "Dupont"
}
GET /api/auth/profile
Authorization: Bearer <token>
Response 200:
{
"id": 1,
"email": "user@example.com",
"first_name": "Jean",
"last_name": "Dupont",
"created_at": "2025-11-06T12:00:00Z"
}
Elections
GET /api/elections/active
Response 200: [Election, ...]
GET /api/elections/upcoming
Response 200: [Election, ...]
GET /api/elections/completed
Response 200: [Election, ...]
GET /api/elections/{id}
Response 200: Election
GET /api/elections/{id}/candidates
Response 200: [Candidate, ...]
GET /api/elections/{id}/results
Response 200: ElectionResultResponse
Votes
POST /api/votes
Authorization: Bearer <token>
Content-Type: application/json
{
"election_id": 1,
"choix": "Candidate Name"
}
Response 200:
{
"id": 1,
"ballot_hash": "abc123...",
"timestamp": "2025-11-06T12:00:00Z"
}
GET /api/votes/status?election_id=1
Authorization: Bearer <token>
Response 200:
{
"has_voted": false
}
GET /api/votes/history
Authorization: Bearer <token>
Response 200: [VoteHistory, ...]
Frontend Features Integrated
Pages
- ✅ Home (
/) - Landing page with call-to-action - ✅ Login (
/auth/login) - Authentication with backend - ✅ Register (
/auth/register) - User registration - ✅ Dashboard (
/dashboard) - Loads active elections from API - ✅ Active Votes (
/dashboard/votes/active) - List active elections - ✅ Upcoming Votes (
/dashboard/votes/upcoming) - Timeline of future elections - ✅ Vote History (
/dashboard/votes/history) - Past votes - ✅ Archives (
/dashboard/votes/archives) - Historical elections - ✅ Profile (
/dashboard/profile) - User profile management
Authentication Flow
- User fills login/register form
- Form data sent to backend (
/api/auth/loginor/api/auth/register) - Backend validates credentials and returns JWT token
- Frontend stores token in localStorage
- Token included in Authorization header for protected endpoints
- Dashboard pages protected with
ProtectedRoutecomponent - Non-authenticated users redirected to login
Protected Routes
- Dashboard and all sub-pages require authentication
- Automatic redirect to login if token is missing/expired
- User name displayed in dashboard header
- Logout clears token and redirects to home
Testing the Integration
Manual Testing
-
Register a new user
- Go to
http://localhost:3000/auth/register - Fill in email, name, and password
- Submit form
- Should redirect to dashboard
- Go to
-
Login
- Go to
http://localhost:3000/auth/login - Use registered email and password
- Should redirect to dashboard
- Go to
-
View Elections
- Dashboard loads active elections from backend
- See real election data with candidate counts
- Loading spinner shows while fetching data
-
Logout
- Click "Déconnexion" button in dashboard sidebar
- Should redirect to home page
- Token removed from localStorage
API Testing with curl
# Register user
curl -X POST http://localhost:8000/api/auth/register \
-H "Content-Type: application/json" \
-d '{"email":"test@example.com","password":"testpass123","first_name":"Test","last_name":"User"}'
# Login
curl -X POST http://localhost:8000/api/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"test@example.com","password":"testpass123"}'
# Get active elections (with token)
curl -X GET http://localhost:8000/api/elections/active \
-H "Authorization: Bearer YOUR_TOKEN"
# Get profile
curl -X GET http://localhost:8000/api/auth/profile \
-H "Authorization: Bearer YOUR_TOKEN"
Testing with Frontend
-
Check Network Tab (DevTools)
- Open browser DevTools (F12)
- Go to Network tab
- Try logging in
- Should see POST request to
http://localhost:8000/api/auth/login - Response includes
access_token
-
Check Console Tab
- No CORS errors should appear
- Auth context logs should show user data
-
Check Storage Tab
localStorageshould containauth_tokenafter login- Token removed after logout
Environment Variables
Backend (.env or export)
# Database
DB_HOST=localhost
DB_PORT=3306
DB_NAME=evoting_db
DB_USER=evoting_user
DB_PASSWORD=evoting_pass123
# Security
SECRET_KEY=your-secret-key-change-in-production
DEBUG=false
# Application
APP_NAME="E-Voting System API"
Frontend (.env.local)
NEXT_PUBLIC_API_URL=http://localhost:8000
Troubleshooting
"Connection refused" error on login
- Ensure backend is running on port 8000
- Check
NEXT_PUBLIC_API_URLin frontend.env.local - Verify backend is accessible:
curl http://localhost:8000/health
"CORS error" when logging in
- CORS is already enabled in backend (
allow_origins=["*"]) - Check browser console for specific CORS error
- Verify backend CORS middleware is configured
Token not persisted after page refresh
- Check localStorage in DevTools (Storage tab)
- Verify
auth_tokenkey is being set - Check browser privacy/incognito mode (may prevent localStorage)
"Unauthorized" errors on protected endpoints
- Token may have expired (30 minutes by default)
- Re-login to get new token
- Check
Authorizationheader is being sent in requests
Frontend can't find API
- Ensure backend is running:
uvicorn backend.main:app --reload - Check port: should be 8000
- Check API URL in
.env.local:http://localhost:8000 - Try health check:
curl http://localhost:8000/health
Performance Optimizations
Frontend Optimizations
- Auto-split code by routes
- Tailwind CSS: ~17 kB gzipped
- Shared JS bundle: ~102 kB
- Individual pages: 2-4 kB each
Backend Optimizations
- Use connection pooling
- Index database columns
- Cache election data
- Compress API responses
Security Considerations
Development vs Production
Development (Current)
- CORS: Allow all origins (
["*"]) - Debug mode: enabled
- Secret key: default (not secure)
- HTTPS: not required
Production (Required)
- CORS: Restrict to frontend domain
- Debug mode: disabled
- Secret key: strong, secure, environment variable
- HTTPS: required for all API calls
- Token expiration: reduce from 30 to 15 minutes
- Rate limiting: add to prevent abuse
- Hashing: use strong algorithm (bcrypt already configured)
Authentication Security
- ✅ Passwords hashed with bcrypt
- ✅ JWT tokens with expiration
- ✅ Token stored in localStorage (vulnerable to XSS)
- ⚠️ Consider HttpOnly cookies for production
- ✅ HTTPS required in production
Next Steps
- Database Population: Create test elections and candidates
- Voting Interface: Implement actual vote submission
- Results Display: Show election results with charts
- Form Validation: Add Zod validation to frontend forms
- Error Handling: Implement error boundaries
- Testing: Add unit and E2E tests
- Deployment: Deploy to production environment
Support
- Backend Docs:
http://localhost:8000/docs(Swagger) - Frontend Docs:
frontend/FRONTEND_NEXTJS_GUIDE.md - Integration Guide:
NEXT_STEPS.md
Status: Backend and frontend integrated and ready for testing Date: 2025-11-06 Branch: UI