A production-ready REST API for a contest management platform built with Node.js, Express.js, and MongoDB.
- Authentication & Authorization: JWT-based authentication with role-based access control (admin, creator, user)
- Contest Management: Create, edit, delete, and approve contests
- Payment Integration: Stripe payment processing for contest entry fees
- Submission System: Users can join contests and submit their work
- Leaderboard: Track winners and display rankings
- Admin Panel: Admin can approve contests, manage users, and change roles
- Node.js - Runtime environment
- Express.js - Web framework
- MongoDB - Database (with Mongoose ODM)
- JWT - Authentication & authorization
- Stripe - Payment processing
- Helmet - Security middleware
- CORS - Cross-origin resource sharing
- Node.js (v14 or higher)
- MongoDB (local or MongoDB Atlas)
- Stripe account (for payment processing)
- Clone the repository:
git clone <repository-url>
cd ContestArena-Server- Install dependencies:
npm install- Create a
.envfile in the root directory:
cp .env.example .env- Update the
.envfile with your configuration:MONGODB_URI: Your MongoDB connection stringJWT_SECRET: A secure random string for JWT signingSTRIPE_SECRET_KEY: Your Stripe secret key (test mode)FRONTEND_URL: Your frontend URL for CORS
npm run devnpm startThe server will start on http://localhost:5000 (or the port specified in .env).
On first startup, the server automatically creates a default admin account:
- Email:
admin@contestarena.com - Password:
admin123
This account is created in both the Admin collection (for admin-specific authentication) and the User collection (with admin role).
-
POST /api/auth/jwt- Create or get JWT token- Body:
{ email, name, photoURL } - Returns:
{ token, user }
- Body:
-
GET /api/auth/me- Get current user profile (Protected)- Headers:
Authorization: Bearer <token>
- Headers:
-
GET /api/users- Get all users (Admin only, paginated)- Query params:
page,limit
- Query params:
-
GET /api/users/:id- Get user by ID (Authenticated) -
PATCH /api/users/:id/role- Update user role (Admin only)- Body:
{ role: 'user' | 'creator' | 'admin' }
- Body:
-
PATCH /api/users/:id- Update user profile- Body:
{ name, photoURL, bio, address }
- Body:
-
GET /api/contests- Get all contests (Public, paginated)- Query params:
status,type,search,page,limit
- Query params:
-
GET /api/contests/popular- Get popular contests (Public)- Query params:
limit
- Query params:
-
GET /api/contests/winners/recent- Get recent winners (Public)- Query params:
limit
- Query params:
-
GET /api/contests/:id- Get contest by ID (Public) -
POST /api/contests- Create contest (Creator only)- Body:
{ name, image, description, shortDescription, price, prizeMoney, taskInstructions, contestType, deadline }
- Body:
-
PUT /api/contests/:id- Update contest (Creator only, pending only) -
DELETE /api/contests/:id- Delete contest (Creator can delete own pending, Admin can delete any) -
PATCH /api/contests/:id/status- Approve contest (Admin only)- Body:
{ status: 'confirmed' }
- Body:
-
PATCH /api/contests/:id/winner- Declare winner (Creator only, after deadline)- Body:
{ winnerUserId }
- Body:
-
POST /api/participations- Join contest (User only)- Body:
{ contestId, submissionLink, paymentId }
- Body:
-
GET /api/participations/me- Get my participations (Authenticated)- Query params:
sort=deadline
- Query params:
-
GET /api/participations/contest/:contestId- Get contest submissions (Creator only) -
PATCH /api/participations/:id- Update submission (User only, before deadline)- Body:
{ submissionLink, submissionText }
- Body:
-
POST /api/payments/create-intent- Create Stripe payment intent (Authenticated)- Body:
{ price, contestId } - Returns:
{ clientSecret, paymentId }
- Body:
-
POST /api/payments/confirm- Confirm payment (Authenticated)- Body:
{ paymentId, transactionId }
- Body:
-
POST /api/payments/webhook- Stripe webhook handler -
GET /api/payments/me- Get my payment history (Authenticated)
GET /api/leaderboard- Get leaderboard (Public)- Query params:
limit
- Query params:
- users: All user data (name, email, role, winsCount, etc.)
- admin: Admin-specific authentication data
- contests: Contest information
- submissions: User submissions/participations
- payments: Payment transaction details
- JWT-based authentication
- Role-based access control (RBAC)
- Helmet.js for security headers
- CORS configuration
- Input validation
- Error handling middleware
- Password hashing (for admin accounts)
The API uses centralized error handling middleware that:
- Handles validation errors
- Handles duplicate key errors
- Handles JWT errors
- Returns appropriate HTTP status codes
- Provides meaningful error messages
Several endpoints support pagination:
- Query parameters:
page(default: 1),limit(default: 10) - Response includes:
data,total,page,pages,limit
| Variable | Description | Required |
|---|---|---|
PORT |
Server port | No (default: 5000) |
NODE_ENV |
Environment (development/production) | No |
MONGODB_URI |
MongoDB connection string | Yes |
JWT_SECRET |
Secret key for JWT signing | Yes |
JWT_EXPIRES_IN |
JWT expiration time | No (default: 7d) |
STRIPE_SECRET_KEY |
Stripe secret key | Yes |
STRIPE_WEBHOOK_SECRET |
Stripe webhook secret | No |
FRONTEND_URL |
Frontend URL for CORS | No (default: http://localhost:3000) |
src/
├── config/
│ ├── db.js # MongoDB connection
│ └── firebaseAdmin.js # Firebase admin config (if needed)
├── controllers/
│ ├── auth.controller.js
│ ├── user.controller.js
│ ├── contest.controller.js
│ ├── participation.controller.js
│ ├── payment.controller.js
│ └── leaderboard.controller.js
├── middleware/
│ ├── verifyJWT.js # JWT verification middleware
│ └── roleChecker.js # Role-based access control
├── models/
│ ├── User.model.js
│ ├── Admin.model.js
│ ├── Contest.model.js
│ ├── Submission.model.js
│ └── Payment.model.js
├── routes/
│ ├── auth.routes.js
│ ├── user.routes.js
│ ├── contest.routes.js
│ ├── participation.routes.js
│ ├── payment.routes.js
│ └── leaderboard.routes.js
├── scripts/
│ └── initializeAdmin.js # Admin initialization script
├── utils/
│ └── generateJWT.js # JWT token generation
├── app.js # Express app configuration
└── server.js # Server entry point
To test the API, you can use tools like:
- Postman
- cURL
- Thunder Client (VS Code extension)
- Insomnia
Example request to create JWT:
curl -X POST http://localhost:5000/api/auth/jwt \
-H "Content-Type: application/json" \
-d '{"email": "user@example.com", "name": "John Doe"}'ISC
For issues or questions, please contact the development team.