A modern, real-time voting system built with Python FastAPI and React TypeScript for internal company suggestions. Features live vote updates, user authentication, and a beautiful responsive interface.
In this voting system, any authenticated user except the author of a suggestion can cast a like (upvote) or dislike (downvote) vote for a suggestion.
-
Authentication Requirement
- Only users who are logged in (i.e., have a valid JWT token) can interact with the voting API.
- Unauthenticated users cannot vote; the backend will return a 401 Unauthorized error.
-
Author Restriction
- The backend explicitly prevents the author of a suggestion from voting on their own suggestion.
- In
backend/app/api/votes.py, before allowing a vote, the code checks:if suggestion.author_id == current_user.id: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Cannot vote on your own suggestion" )
- This means: You cannot like or dislike your own suggestion.
- The frontend also disables the voting buttons for the author of the suggestion in
HomePage.tsx:const canVote = user && user.id !== suggestion.author_id;
- If you are the author, the like/dislike buttons are not clickable.
- Even if the frontend is bypassed (e.g., by using Postman), the backend will reject any vote attempt by the author.
-
One Vote Per User Per Suggestion
- Each user can only have one vote (like or dislike) per suggestion.
- If a user votes again, it updates their previous vote (switches from like to dislike or vice versa).
- If a user removes their vote, it deletes their vote record for that suggestion.
| User Type | Can Like/Dislike? | Notes |
|---|---|---|
| Not logged in | No | Must log in to vote |
| Suggestion author | No | Cannot vote on own suggestion |
| Other user | Yes | Can like/dislike once per suggestion |
- Alice creates a suggestion. She cannot vote on it.
- Bob logs in and sees Alice’s suggestion. He can like or dislike it.
- Bob can change his vote from like to dislike, or remove it.
- Charlie (another user) can also vote, but not more than once per suggestion.
In summary:
Only logged-in users who are NOT the author of a suggestion can cast a like or dislike vote for that suggestion. Each user can only vote once per suggestion, and the backend enforces all these rules for security and fairness.
This real-time voting system is built using a modern full-stack architecture with Python FastAPI as the backend API and React with TypeScript for the frontend. The system employs WebSocket connections for real-time updates, ensuring that vote counts and new suggestions are instantly reflected across all connected clients without requiring page refreshes.
- FastAPI Framework: Leverages FastAPI's automatic OpenAPI documentation, type validation, and high performance for building RESTful APIs
- WebSocket Support: Uses FastAPI's built-in WebSocket support for real-time bidirectional communication
- SQLAlchemy ORM: Implements a clean data layer with SQLAlchemy for database operations and Alembic for migrations
- SQLite for Development: Uses SQLite for easy development setup (PostgreSQL for production)
- Pydantic Models: Implements data validation and serialization using Pydantic models
- CORS Configuration: Properly configured CORS for secure cross-origin requests
- Dependency Injection: Uses FastAPI's dependency injection for clean service architecture
- React 18 with TypeScript: Modern React with strict typing for better development experience
- Vite Build Tool: Fast development server and optimized production builds
- Tailwind CSS: Utility-first CSS framework for rapid UI development
- React Query: For efficient server state management and caching
- WebSocket Client: Custom WebSocket hook for real-time updates
- Responsive Design: Mobile-first approach with modern UI/UX patterns
- WebSocket Protocol: Bidirectional communication for instant updates
- Event-Driven Architecture: Backend broadcasts events to all connected clients
- Connection Management: Proper WebSocket connection handling with reconnection logic
- State Synchronization: Frontend maintains local state that syncs with server state
- Input Validation: Comprehensive validation on both frontend and backend
- Rate Limiting: Prevents abuse with proper rate limiting
- Error Handling: Graceful error handling with user-friendly messages
- Type Safety: Full TypeScript coverage for better code quality
- Environment Configuration: Proper environment variable management
- Docker Support: Containerized deployment for easy scaling
- Single Organization: The system is designed for internal use within one organization
- Simple Authentication: Basic session-based authentication (can be extended to OAuth/JWT)
- SQLite for Development: Uses SQLite for easy development (PostgreSQL for production)
- Modern Browser Support: Targets modern browsers with WebSocket support
- Development Environment: Assumes Node.js and Python 3.8+ are available
- Network Requirements: Assumes stable network connection for WebSocket functionality
- Hot Reload: Both frontend and backend support hot reloading for rapid development
- API Documentation: Auto-generated OpenAPI docs for easy API exploration
- Type Safety: End-to-end type safety from database to frontend
- Testing Strategy: Unit tests for backend services, integration tests for API endpoints
- Deployment Ready: Docker configuration for easy deployment and scaling
This architecture ensures scalability, maintainability, and a smooth developer experience while providing a robust real-time voting platform.
- 🔐 User Authentication: Secure login/register with JWT tokens
- 💬 Real-time Updates: Live vote counts and new suggestions via WebSocket
- 🎯 Voting System: Upvote/downvote suggestions with instant feedback
- 📊 Top Suggestions: View most popular suggestions
- 🔍 Search & Filter: Find suggestions by category, status, or text
- 📱 Responsive Design: Works perfectly on desktop and mobile
- ⚡ Fast Performance: Optimized with React Query and Vite
- 🎨 Modern UI: Beautiful interface with Tailwind CSS
- Python 3.8+
- Node.js 16+
- Git
Run the setup script to automatically configure everything:
python setup.py-
Navigate to backend directory:
cd backend -
Create virtual environment:
python -m venv venv source venv/bin/activate # On Windows: venv\Scripts\activate
-
Install dependencies:
pip install -r requirements.txt
-
Start the backend server:
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
The API will be available at http://localhost:8000 with automatic documentation at http://localhost:8000/docs
-
Navigate to frontend directory:
cd frontend -
Install dependencies:
npm install
-
Start the development server:
npm run dev
The frontend will be available at http://localhost:3000
- API Documentation: Visit
http://localhost:8000/docsfor interactive API docs - Database: Uses SQLite for development (PostgreSQL for production)
- Authentication: JWT-based authentication with secure password hashing
- Real-time: WebSocket support for live updates
- Hot Reload: Vite provides instant hot module replacement
- Type Safety: Full TypeScript coverage
- State Management: React Query for server state, Context for auth
- Styling: Tailwind CSS with custom components
- All backend endpoints are covered by async tests in
backend/tests/. - Tests use
pytest,pytest-asyncio, andhttpx.AsyncClient. - Each test uses an in-memory SQLite DB for isolation.
To run all backend tests:
cd backend
pytestbackend/tests/test_auth.py: User registration and loginbackend/tests/test_suggestions.py: Suggestion CRUD (create, read, update, delete)backend/tests/test_votes.py: Voting, updating, and removing votes
- Use the FastAPI interactive docs at http://localhost:8000/docs to manually test all endpoints.
- You can also use Postman or curl for advanced/manual API testing.
Manual Testing Checklist:
- Register a new user (
POST /api/auth/register) - Login with the new user (
POST /api/auth/login) - Get current user info (
GET /api/auth/mewith Bearer token) - Create a suggestion (
POST /api/suggestions/with Bearer token) - List all suggestions (
GET /api/suggestions/with Bearer token) - Get a suggestion by ID (
GET /api/suggestions/{id}with Bearer token) - Update a suggestion (
PUT /api/suggestions/{id}with Bearer token) - Delete a suggestion (
DELETE /api/suggestions/{id}with Bearer token) - Get top suggestions (
GET /api/suggestions/topwith Bearer token) - Get suggestion categories (
GET /api/suggestions/categorieswith Bearer token) - Vote on a suggestion (
POST /api/votes/with Bearer token) - Update a vote (
POST /api/votes/with new value, same suggestion/user) - Remove a vote (
DELETE /api/votes/{suggestion_id}with Bearer token) - Get vote info (
GET /api/votes/{suggestion_id}with Bearer token) - WebSocket: Connect to
/api/wsand/api/ws/{user_id}and receive real-time updates (use a WebSocket client)
-- Users table
CREATE TABLE users (
id INTEGER PRIMARY KEY,
username VARCHAR(50) UNIQUE NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
hashed_password VARCHAR(255) NOT NULL,
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Suggestions table
CREATE TABLE suggestions (
id INTEGER PRIMARY KEY,
title VARCHAR(200) NOT NULL,
description TEXT NOT NULL,
category VARCHAR(50) NOT NULL,
status VARCHAR(20) DEFAULT 'active',
author_id INTEGER REFERENCES users(id),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP
);
-- Votes table
CREATE TABLE votes (
id INTEGER PRIMARY KEY,
user_id INTEGER REFERENCES users(id),
suggestion_id INTEGER REFERENCES suggestions(id),
is_upvote BOOLEAN NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(user_id, suggestion_id)
);POST /api/auth/register- Register new userPOST /api/auth/login- Login userGET /api/auth/me- Get current user
GET /api/suggestions- Get all suggestionsGET /api/suggestions/top- Get top suggestionsPOST /api/suggestions- Create new suggestionGET /api/suggestions/{id}- Get specific suggestionPUT /api/suggestions/{id}- Update suggestionDELETE /api/suggestions/{id}- Delete suggestion
POST /api/votes- Create/update voteDELETE /api/votes/{suggestion_id}- Remove voteGET /api/votes/{suggestion_id}- Get vote info
WS /api/ws/{user_id}- Real-time connection
-
Build and run with Docker Compose:
docker-compose up --build
-
Or build individually:
# Backend cd backend docker build -t voting-backend . docker run -p 8000:8000 voting-backend # Frontend cd frontend docker build -t voting-frontend . docker run -p 3000:3000 voting-frontend
- Use environment variables for sensitive data
- Set up proper CORS origins
- Configure database connection pooling
- Enable HTTPS in production
- Set up monitoring and logging
- Use Redis for session storage (optional)
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests if applicable
- Submit a pull request
This project is licensed under the MIT License.
For support, please open an issue on GitHub or contact the development team.
- Docker and Docker Compose installed
- Domain name (e.g., yourdomain.com)
- (Optional) SSL certificate for HTTPS (recommended for production)
Copy backend/env.example to .env.production and update values for production:
DATABASE_URL=postgresql://voting_user:voting_password@postgres/voting_system
REDIS_URL=redis://redis:6379
SECRET_KEY=your-production-secret-key
CORS_ORIGINS=https://advanced-voting-system.netlify.app
ENVIRONMENT=production
DEBUG=False
Set the following environment variable in your frontend deployment platform:
VITE_API_BASE_URL=https://voting-system-fjl8.onrender.com/api
docker-compose build
docker-compose up -d
- The frontend will be available on port 80 (http://yourdomain.com)
- The backend API will be available on port 8000 (http://yourdomain.com/api)
- The frontend Docker image uses Nginx to serve static files and proxy API requests to the backend.
- The Nginx config is in
frontend/nginx.confand is production-ready.
- PostgreSQL is used in production (see
docker-compose.yml). - Data is persisted in the
postgres_dataDocker volume.
- Set a strong
SECRET_KEYin your environment variables. - Restrict
CORS_ORIGINSto your production domain. - (Recommended) Set up HTTPS using a reverse proxy or cloud load balancer.
To update the app:
git pull
docker-compose build
docker-compose up -d
- Check logs with
docker-compose logs backendordocker-compose logs frontend. - Ensure environment variables are set correctly.
For advanced deployment (SSL, scaling, monitoring), see the comments in docker-compose.yml and frontend/nginx.conf.