A collaborative backend API for software teams to report bugs, suggest features, and coordinate resolutions. Built with Node.js, TypeScript, Express, and PostgreSQL.
https://devpulse-opal.vercel.app
- User registration and login with JWT authentication
- Role-based access control (contributor & maintainer)
- Create, read, update, and delete issues
- Filter issues by type and status
- Sort issues by newest or oldest
- Reporter details included in issue responses
- Secure password hashing with bcrypt
- Deployed on Vercel with NeonDB PostgreSQL
| Technology | Purpose |
|---|---|
| Node.js (LTS 24.x) | Runtime environment |
| TypeScript | Type-safe development |
| Express.js | Web framework |
| PostgreSQL (NeonDB) | Relational database |
| Raw SQL (pg driver) | Database queries |
| bcrypt | Password hashing |
| jsonwebtoken | JWT authentication |
| dotenv | Environment variable management |
| cors | Cross-origin resource sharing |
| http-status-codes | Consistent HTTP status codes |
devpulse/
βββ src/
β βββ config/
β β βββ db.ts # PostgreSQL connection pool
β βββ middleware/
β β βββ authenticate.ts # JWT verification middleware
β β βββ authorize.ts # Role-based access middleware
β βββ modules/
β β βββ auth/
β β β βββ auth.controller.ts
β β β βββ auth.routes.ts
β β β βββ auth.types.ts
β β βββ issues/
β β βββ issues.controller.ts
β β βββ issues.routes.ts
β β βββ issues.types.ts
β βββ utils/
β β βββ response.ts # Reusable response helpers
β β βββ validation.ts # Input validation helpers
β βββ app.ts
β βββ index.ts
βββ .env
βββ .gitignore
βββ package.json
βββ tsconfig.json
βββ vercel.json
git clone https://github.com/Sahidulislam05/DevPulse
cd devpulsenpm installDATABASE_URL=your_neondb_connection_string
JWT_SECRET=your_jwt_secret_key
PORT=3000Run the following SQL in your NeonDB SQL editor:
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL,
role VARCHAR(20) NOT NULL DEFAULT 'contributor'
CHECK (role IN ('contributor', 'maintainer')),
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE issues (
id SERIAL PRIMARY KEY,
title VARCHAR(150) NOT NULL,
description TEXT NOT NULL,
type VARCHAR(20) NOT NULL
CHECK (type IN ('bug', 'feature_request')),
status VARCHAR(20) NOT NULL DEFAULT 'open'
CHECK (status IN ('open', 'in_progress', 'resolved')),
reporter_id INTEGER NOT NULL,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);npm run devServer will run at http://localhost:3000
| Method | Endpoint | Access | Description |
|---|---|---|---|
| POST | /api/auth/signup |
Public | Register a new user |
| POST | /api/auth/login |
Public | Login and receive JWT token |
| Method | Endpoint | Access | Description |
|---|---|---|---|
| GET | /api/issues |
Public | Get all issues (supports filter & sort) |
| GET | /api/issues/:id |
Public | Get a single issue by ID |
| POST | /api/issues |
Authenticated | Create a new issue |
| PATCH | /api/issues/:id |
Authenticated | Update an issue |
| DELETE | /api/issues/:id |
Maintainer only | Delete an issue |
| Parameter | Values | Default |
|---|---|---|
sort |
newest, oldest |
newest |
type |
bug, feature_request |
β |
status |
open, in_progress, resolved |
β |
Example:
GET /api/issues?type=bug&status=open&sort=newest
Include the JWT token in the Authorization header for protected routes:
Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
| Action | Contributor | Maintainer |
|---|---|---|
| Register & Login | β | β |
| View all issues | β | β |
| Create issues | β | β |
| Update own open issues | β | β |
| Update any issue | β | β |
| Delete any issue | β | β |
| Column | Type | Constraints |
|---|---|---|
| id | SERIAL | PRIMARY KEY |
| name | VARCHAR(255) | NOT NULL |
| VARCHAR(255) | UNIQUE, NOT NULL | |
| password | VARCHAR(255) | NOT NULL |
| role | VARCHAR(20) | DEFAULT 'contributor', CHECK (contributor / maintainer) |
| created_at | TIMESTAMP | DEFAULT NOW() |
| updated_at | TIMESTAMP | DEFAULT NOW() |
| Column | Type | Constraints |
|---|---|---|
| id | SERIAL | PRIMARY KEY |
| title | VARCHAR(150) | NOT NULL |
| description | TEXT | NOT NULL, MIN 20 chars |
| type | VARCHAR(20) | CHECK (bug / feature_request) |
| status | VARCHAR(20) | DEFAULT 'open', CHECK (open / in_progress / resolved) |
| reporter_id | INTEGER | NOT NULL |
| created_at | TIMESTAMP | DEFAULT NOW() |
| updated_at | TIMESTAMP | DEFAULT NOW() |
Request:
{
"email": "john@devpulse.com",
"password": "password123"
}Response:
{
"success": true,
"message": "Login successful",
"data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": {
"id": 1,
"name": "John Doe",
"email": "john@devpulse.com",
"role": "contributor",
"created_at": "2026-05-22T09:00:00Z",
"updated_at": "2026-05-22T09:00:00Z"
}
}
}Environment variables configured in Vercel dashboard:
DATABASE_URLJWT_SECRET
Sahidul Islam
GitHub: @Sahidulislam05