URL: https://lovable.dev/projects/d4e13dfb-65c9-4f92-b832-ffec1aefb18e
There are several ways of editing your application.
Use Lovable
Simply visit the Lovable Project and start prompting.
Changes made via Lovable will be committed automatically to this repo.
Use your preferred IDE
If you want to work locally using your own IDE, you can clone this repo and push changes. Pushed changes will also be reflected in Lovable.
The only requirement is having Node.js & npm installed - install with nvm
Follow these steps:
# Step 1: Clone the repository using the project's Git URL.
git clone <YOUR_GIT_URL>
# Step 2: Navigate to the project directory.
cd <YOUR_PROJECT_NAME>
# Step 3: Install the necessary dependencies.
npm i
# Step 4: Start the development server with auto-reloading and an instant preview.
npm run devEdit a file directly in GitHub
- Navigate to the desired file(s).
- Click the "Edit" button (pencil icon) at the top right of the file view.
- Make your changes and commit the changes.
Use GitHub Codespaces
- Navigate to the main page of your repository.
- Click on the "Code" button (green button) near the top right.
- Select the "Codespaces" tab.
- Click on "New codespace" to launch a new Codespace environment.
- Edit files directly within the Codespace and commit and push your changes once you're done.
This project is built with:
- Vite
- TypeScript
- React
- shadcn-ui
- Tailwind CSS
Simply open Lovable and click on Share -> Publish.
Yes, you can!
To connect a domain, navigate to Project > Settings > Domains and click Connect Domain.
Read more here: Setting up a custom domain
This document outlines the API endpoints and data structures required for the voting platform backend. The backend should be implemented using Node.js with MySQL as the database.
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
email VARCHAR(255) NOT NULL UNIQUE,
password_hash VARCHAR(255) NOT NULL,
is_admin BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_email (email)
);CREATE TABLE candidates (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
party VARCHAR(255) NOT NULL,
position VARCHAR(255) NOT NULL,
image_url TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);CREATE TABLE votes (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT NOT NULL,
candidate_id INT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id),
FOREIGN KEY (candidate_id) REFERENCES candidates(id),
UNIQUE KEY unique_user_vote (user_id),
INDEX idx_candidate (candidate_id)
);Authenticates a user and returns a JWT token.
- Request Body:
{
"email": "string",
"password": "string"
}- Response (200 OK):
{
"user": {
"id": "number",
"name": "string",
"email": "string",
"isAdmin": "boolean",
"createdAt": "string"
},
"token": "string"
}Creates a new user account.
- Request Body:
{
"name": "string",
"email": "string",
"password": "string"
}- Response: Same as login endpoint
Invalidates the current user's token.
- Request: Requires Authorization header
- Response (200 OK):
{
"success": true
}Returns the current user's information.
- Request: Requires Authorization header
- Response (200 OK): User object
Returns all candidates.
- Response (200 OK):
[
{
"id": "number",
"name": "string",
"party": "string",
"position": "string",
"imageUrl": "string",
"voteCount": "number",
"createdAt": "string",
"updatedAt": "string"
}
]Returns a specific candidate.
- Response (200 OK): Single candidate object
Creates a new candidate (Admin only).
- Request Body:
{
"name": "string",
"party": "string",
"position": "string",
"imageUrl": "string"
}- Response (201 Created): Created candidate object
Updates a candidate (Admin only).
- Request Body: Partial candidate object
- Response (200 OK): Updated candidate object
Deletes a candidate (Admin only).
- Response (204 No Content)
Casts a vote for a candidate.
- Request Body:
{
"candidateId": "number"
}- Response (201 Created):
{
"id": "number",
"userId": "number",
"candidateId": "number",
"createdAt": "string"
}Returns election results.
- Response (200 OK): Array of candidates with vote counts
Checks if the current user has voted.
- Response (200 OK):
{
"hasVoted": "boolean"
}Returns the current user's vote.
- Response (200 OK):
{
"candidateId": "number"
}-
Authentication
- Use JWT for authentication
- Implement token refresh mechanism
- Store passwords using bcrypt or argon2
- Implement role-based authorization
-
API Security
- Implement rate limiting
- Add CORS configuration
- Input validation
- SQL injection prevention
- XSS prevention
{
"dependencies": {
"express": "^4.18.2",
"mysql2": "^3.6.0",
"jsonwebtoken": "^9.0.2",
"bcrypt": "^5.1.1",
"cors": "^2.8.5",
"helmet": "^7.0.0",
"express-rate-limit": "^7.0.0",
"joi": "^17.10.1",
"winston": "^3.10.0"
}
}DATABASE_URL=mysql://user:password@localhost:3306/voting_app
JWT_SECRET=your-jwt-secret
JWT_REFRESH_SECRET=your-refresh-secret
PORT=8080
NODE_ENV=development
CORS_ORIGIN=http://localhost:5173All endpoints should return appropriate HTTP status codes:
- 200: Success
- 201: Created
- 400: Bad Request
- 401: Unauthorized
- 403: Forbidden
- 404: Not Found
- 409: Conflict
- 422: Unprocessable Entity
- 500: Internal Server Error
Error responses should follow this format:
{
"error": {
"message": "string",
"code": "string",
"details": {}
}
}Implement tests for:
- Authentication flows
- CRUD operations for candidates
- Voting mechanism
- Authorization checks
- Input validation
- Error handling
- Implement proper logging
- Add request validation middleware
- Use TypeScript for type safety
- Add API documentation using Swagger/OpenAPI
- Implement database migrations
- Add monitoring and health check endpoints