A robust REST API for managing projects and tasks with user authentication, API key management, and file uploads. Built with Node.js, Express, Prisma, and PostgreSQL.
- User Authentication & Authorization - JWT-based authentication with refresh tokens
- Project Management - Create, read, update, and delete projects
- Task Management - Comprehensive task handling with status tracking and priority levels
- Collaborators & Roles - Add project collaborators with role-based permissions (OWNER/EDITOR/VIEWER)
- API Key Management - Secure API access with key-based authentication
- File Uploads - Support for task attachments using Cloudinary
- Rate Limiting - Built-in protection against abuse
- Database - PostgreSQL with Prisma ORM for type-safe database operations
- Validation - Request validation using express-validator
devBoard/
βββ src/
β βββ controllers/ # Business logic handlers
β βββ middlewares/ # Authentication, validation, file upload
β βββ routers/ # API route definitions
β βββ utils/ # Helper functions (hashing, tokens, cloudinary)
β βββ validator/ # Request validation schemas
β βββ libs/ # Database connection
β βββ app.js # Express app configuration
βββ prisma/ # Database schema and migrations
βββ public/ # Static files and uploads
- Node.js (v18 or higher)
- PostgreSQL database
- Cloudinary account (for file uploads)
-
Clone the repository
git clone <repository-url> cd devBoard
-
Install dependencies
npm install
-
Environment Setup Create a
.envfile in the root directory:PORT=8080 DATABASE_URL="postgresql://<username>:<password>@localhost:<PORT>/<DB_NAME>" JWT_SECRET="your-jwt-secret-key" JWT_REFRESH_SECRET="your-refresh-secret-key" CLOUDINARY_CLOUD_NAME="your-cloud-name" CLOUDINARY_API_KEY="your-api-key" CLOUDINARY_API_SECRET="your-api-secret"
-
Database Setup
# Generate Prisma client npx prisma generate # Run database migrations npx prisma migrate dev
-
Start the server
npm run dev
The server will start at http://localhost:8080
http://localhost:8080/api/v1
POST /auth/register
Content-Type: multipart/form-data
{
"name": "John Doe",
"email": "john@example.com",
"password": "securepassword123",
"image": [file] // optional profile image
}Response:
{
"success": true,
"message": "User registered successfully",
"data": {
"user": {
"id": "uuid",
"name": "John Doe",
"email": "john@example.com",
"image": "cloudinary-url",
"createdAt": "2024-01-01T00:00:00.000Z"
}
}
}POST /auth/login
Content-Type: application/json
{
"email": "john@example.com",
"password": "securepassword123"
}Response:
{
"success": true,
"message": "Login successful",
"data": {
"user": {
"id": "uuid",
"name": "John Doe",
"email": "john@example.com"
},
"accessToken": "jwt-token",
"refreshToken": "refresh-token"
}
}POST /auth/api-key
Authorization: Bearer <access-token>Response:
{
"success": true,
"message": "API key generated successfully",
"data": {
"apiKey": "generated-api-key-string"
}
}POST /projects
Authorization: Bearer <access-token>
X-API-Key: <api-key>
Content-Type: application/json
{
"name": "E-commerce Website",
"description": "A modern e-commerce platform with React frontend and Node.js backend"
}Response:
{
"success": true,
"message": "Project created successfully",
"data": {
"project": {
"id": "uuid",
"name": "E-commerce Website",
"description": "A modern e-commerce platform with React frontend and Node.js backend",
"createdBy": "user-uuid",
"createdAt": "2024-01-01T00:00:00.000Z",
"updatedAt": "2024-01-01T00:00:00.000Z"
}
}
}GET /projects
Authorization: Bearer <access-token>
X-API-Key: <api-key>GET /projects/:id
Authorization: Bearer <access-token>
X-API-Key: <api-key>PUT /projects/:id
Authorization: Bearer <access-token>
X-API-Key: <api-key>
Content-Type: application/json
{
"name": "Updated E-commerce Website",
"description": "Enhanced e-commerce platform with new features"
}DELETE /projects/:id
Authorization: Bearer <access-token>
X-API-Key: <api-key>GET /projects/:projectId/collaborators
Authorization: Bearer <access-token>
X-API-Key: <api-key>POST /projects/:projectId/collaborators
Authorization: Bearer <access-token>
X-API-Key: <api-key>
Content-Type: application/json
{
"userId": "user-uuid",
"role": "VIEWER" // VIEWER | EDITOR | OWNER
}PUT /projects/:projectId/collaborators/:collaboratorId
Authorization: Bearer <access-token>
X-API-Key: <api-key>
Content-Type: application/json
{
"role": "EDITOR" // VIEWER | EDITOR | OWNER
}DELETE /projects/:projectId/collaborators/:collaboratorId
Authorization: Bearer <access-token>
X-API-Key: <api-key>POST /projects/:projectId/tasks
Authorization: Bearer <access-token>
X-API-Key: <api-key>
Content-Type: multipart/form-data
{
"title": "Design User Interface",
"description": "Create wireframes and mockups for the main pages",
"assignedTo": "user-uuid",
"priority": "HIGH",
"dueAt": "2024-02-01T00:00:00.000Z",
"attachments": [file1, file2] // optional, max 3 files
}Response:
{
"success": true,
"message": "Task created successfully",
"data": {
"task": {
"id": "uuid",
"title": "Design User Interface",
"description": "Create wireframes and mockups for the main pages",
"projectId": "project-uuid",
"assignedTo": "user-uuid",
"assignedBy": "current-user-uuid",
"status": "TODO",
"priority": "HIGH",
"attachments": ["cloudinary-url1", "cloudinary-url2"],
"dueAt": "2024-02-01T00:00:00.000Z",
"createdAt": "2024-01-01T00:00:00.000Z"
}
}
}GET /projects/:projectId/tasks
Authorization: Bearer <access-token>
X-API-Key: <api-key>PUT /tasks/:id
Authorization: Bearer <access-token>
X-API-Key: <api-key>
Content-Type: application/json
{
"title": "Updated Task Title",
"status": "INPROGRESS",
"priority": "MEDIUM",
"description": "Updated task description"
}DELETE /tasks/:id
Authorization: Bearer <access-token>
X-API-Key: <api-key>- Access Token: Short-lived token for API requests
- Refresh Token: Long-lived token for getting new access tokens
- API Key: Additional security layer for sensitive operations
Authorization: Bearer <access-token>
X-API-Key: <api-key>id: Unique identifier (UUID)name: User's full nameemail: Unique email addressimage: Profile image URL (optional)password: Hashed passwordrefreshToken: JWT refresh tokencreatedAt,updatedAt: Timestamps
id: Unique identifier (UUID)name: Project namedescription: Project description (optional)createdBy: User ID who created the projectcreatedAt,updatedAt,deletedAt: Timestamps
id: Unique identifier (UUID)title: Task titledescription: Task description (optional)projectId: Associated project IDassignedTo: User ID assigned to the taskassignedBy: User ID who assigned the taskstatus: TODO, INPROGRESS, or DONEpriority: EASY, MEDIUM, or HIGHattachments: Array of file URLsdueAt: Task due date (optional)completedAt: Task completion date (optional)createdAt,updatedAt,deletedAt: Timestamps
id: Unique identifier (UUID)key: Generated API key stringcreatedBy: User ID who created the keystatus: ACTIVE or INACTIVEexpiresAt: Key expiration date (optional)createdAt,updatedAt: Timestamps
id: Unique identifier (UUID)userId: Collaborator user's IDprojectId: Associated project IDrole: VIEWER, EDITOR, OWNERcreatedAt,updatedAt,deletedAt: Timestamps
npm run dev # Start development server with nodemonnpx prisma migrate dev # Create and apply new migration
npx prisma generate # Generate Prisma client
npx prisma studio # Open Prisma Studio for database managementPORT: Server port (default: 8080)DATABASE_URL: PostgreSQL connection stringJWT_SECRET: Secret for JWT access tokensJWT_REFRESH_SECRET: Secret for JWT refresh tokensCLOUDINARY_CLOUD_NAME: Cloudinary cloud nameCLOUDINARY_API_KEY: Cloudinary API keyCLOUDINARY_API_SECRET: Cloudinary API secret
- Password Hashing: Bcrypt for secure password storage
- JWT Authentication: Secure token-based authentication
- API Key Validation: Additional security layer for sensitive operations
- Rate Limiting: Protection against API abuse
- Input Validation: Request data validation using express-validator
- File Upload Security: Secure file handling with Multer and Cloudinary
The API returns consistent error responses:
{
"success": false,
"message": "Error description",
"error": "Detailed error information"
}Common HTTP status codes:
200: Success201: Created400: Bad Request (validation errors)401: Unauthorized (authentication required)403: Forbidden (insufficient permissions)404: Not Found500: Internal Server Error
This project is licensed under the ISC License.
Made by β€οΈ Sumit Tomar