A REST API service for managing users, built with Node.js, Express, and TypeScript.
- ✅ Full CRUD operations for users
- ✅ Extended user profiles with phone number and address
- ✅ TypeScript for type safety
- ✅ Express.js web framework
- ✅ MongoDB Atlas cloud database with Mongoose ODM
- ✅ JWT-based authentication and authorization
- ✅ Role-based access control (User/Admin roles)
- ✅ Secure password hashing with bcrypt
- ✅ Input validation and data modeling
- ✅ Comprehensive error handling
- ✅ Health check endpoint
- ✅ CORS enabled
- ✅ Security headers with Helmet
- ✅ Request logging with Morgan
- ✅ Comprehensive structured logging with Winston
- ✅ Request correlation with unique request IDs
- ✅ Performance monitoring and request duration tracking
- ✅ File-based logging with rotation support
- ✅ Docker Compose for development
- ✅ MongoDB Express admin interface
- ✅ Comprehensive test suite with Vitest
- ✅ Unit tests for models, controllers, and utilities
- ✅ Integration tests for API endpoints
- ✅ Rate limiting for API endpoints and authentication
- Node.js (v16 or higher)
- npm
- MongoDB Atlas account (free tier available)
- Docker and Docker Compose (optional, for local development)
# Clone the repository
git clone https://github.com/wingedearth/users-service.git
cd users-service
# Install dependencies
npm install
# Configure your MongoDB Atlas connection (see Environment Variables below)
# Edit .env file with your Atlas connection string
# Run in development mode
npm run dev
# Or build and run in production mode
npm run build
npm startCreate a .env file in the root directory:
NODE_ENV=development
PORT=3000
MONGODB_URI=mongodb+srv://username:password@your-cluster.xxxxx.mongodb.net/users-service?retryWrites=true&w=majority
DB_NAME=users-service
JWT_SECRET=your-super-secret-jwt-key-here
JWT_EXPIRES_IN=1d
LOG_LEVEL=info
LOG_DIR=logs
To get your MongoDB Atlas connection string:
- Log into MongoDB Atlas at https://cloud.mongodb.com/
- Navigate to your cluster and click "Connect"
- Choose "Connect your application"
- Select Node.js as the driver
- Copy the connection string and replace:
<username>with your database username<password>with your database password<database>withusers-service(or your preferred database name)
Example Atlas connection string:
mongodb+srv://myuser:mypassword@users-service.abc123.mongodb.net/users-service?retryWrites=true&w=majority
For local development (alternative), you can still use Docker:
MONGODB_URI=mongodb://app-user:app-password@localhost:27017/users-service
This service is configured to use MongoDB Atlas, MongoDB's cloud database service:
Benefits:
- ✅ Cloud-hosted - No local setup required
- ✅ Automatic backups - Built-in data protection
- ✅ High availability - 99.995% uptime SLA
- ✅ Global clusters - Deploy close to your users
- ✅ Free tier - Perfect for development and small projects
- ✅ Easy scaling - Upgrade as your service grows
- ✅ Built-in security - Network isolation and encryption
Atlas Features Used:
- Connection pooling with optimized settings
- Automatic failover and replica sets
- Network-level security
- Database user authentication
- Performance monitoring and alerts
If you prefer local development, Docker Compose is still available:
# Start local MongoDB with Docker
npm run db:up
# Update your .env file to use local connection:
MONGODB_URI=mongodb://app-user:app-password@localhost:27017/users-servicehttp://localhost:3000
GET /health
Returns service health status.
Response:
{
"status": "OK",
"timestamp": "2024-07-24T03:30:00.000Z",
"service": "users-service"
}POST /api/auth/register
Content-Type: application/json
Request Body:
{
"email": "john.doe@example.com",
"password": "securePassword123",
"firstName": "John",
"lastName": "Doe",
"phoneNumber": "+1234567890",
"address": {
"street": "123 Main St",
"city": "Anytown",
"state": "CA",
"zipCode": "12345",
"country": "USA"
}
}Note: phoneNumber and address fields are optional. The address object can include any combination of street, city, state, zipCode, and country fields.
Response:
{
"success": true,
"data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": {
"id": "507f1f77bcf86cd799439011",
"email": "john.doe@example.com",
"firstName": "John",
"lastName": "Doe",
"role": "user",
"phoneNumber": "+1234567890",
"address": {
"street": "123 Main St",
"city": "Anytown",
"state": "CA",
"zipCode": "12345",
"country": "USA"
},
"createdAt": "2024-07-24T03:30:00.000Z",
"updatedAt": "2024-07-24T03:30:00.000Z"
}
}
}POST /api/auth/login
Content-Type: application/json
Request Body:
{
"email": "john.doe@example.com",
"password": "securePassword123"
}Response:
{
"success": true,
"data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": {
"id": "507f1f77bcf86cd799439011",
"email": "john.doe@example.com",
"firstName": "John",
"lastName": "Doe",
"role": "user",
"phoneNumber": "+1234567890",
"address": {
"street": "123 Main St",
"city": "Anytown",
"state": "CA",
"zipCode": "12345",
"country": "USA"
},
"createdAt": "2024-07-24T03:30:00.000Z",
"updatedAt": "2024-07-24T03:30:00.000Z"
}
}
}GET /api/auth/me
Authorization: Bearer <token>
Response:
{
"success": true,
"data": {
"id": "507f1f77bcf86cd799439011",
"email": "john.doe@example.com",
"firstName": "John",
"lastName": "Doe",
"role": "user",
"phoneNumber": "+1234567890",
"address": {
"street": "123 Main St",
"city": "Anytown",
"state": "CA",
"zipCode": "12345",
"country": "USA"
},
"createdAt": "2024-07-24T03:30:00.000Z",
"updatedAt": "2024-07-24T03:30:00.000Z"
}
}Note: All user endpoints require authentication. Include the JWT token in the Authorization header: Authorization: Bearer <token>
GET /api/users
Response:
{
"success": true,
"data": [
{
"id": 1,
"email": "john.doe@example.com",
"firstName": "John",
"lastName": "Doe",
"createdAt": "2024-07-24T03:30:00.000Z",
"updatedAt": "2024-07-24T03:30:00.000Z"
}
],
"count": 1
}GET /api/users/:id
Response:
{
"success": true,
"data": {
"id": 1,
"email": "john.doe@example.com",
"firstName": "John",
"lastName": "Doe",
"createdAt": "2024-07-24T03:30:00.000Z",
"updatedAt": "2024-07-24T03:30:00.000Z"
}
}POST /api/users
Content-Type: application/json
Request Body:
{
"email": "jane.smith@example.com",
"password": "securePassword123",
"firstName": "Jane",
"lastName": "Smith",
"phoneNumber": "+1987654321",
"address": {
"street": "456 Oak Ave",
"city": "Another City",
"state": "NY",
"zipCode": "67890",
"country": "USA"
}
}Note: password is required. phoneNumber and address fields are optional.
Response:
{
"success": true,
"data": {
"id": 2,
"email": "jane.smith@example.com",
"firstName": "Jane",
"lastName": "Smith",
"phoneNumber": "+1987654321",
"address": {
"street": "456 Oak Ave",
"city": "Another City",
"state": "NY",
"zipCode": "67890",
"country": "USA"
},
"createdAt": "2024-07-24T03:30:00.000Z",
"updatedAt": "2024-07-24T03:30:00.000Z"
}
}PUT /api/users/:id
Content-Type: application/json
Request Body:
{
"email": "jane.doe@example.com",
"firstName": "Jane",
"lastName": "Doe",
"phoneNumber": "+1555666777",
"address": {
"street": "789 Updated St",
"city": "Updated City",
"state": "TX",
"zipCode": "54321",
"country": "USA"
}
}Note: phoneNumber and address fields are optional.
Response:
{
"success": true,
"data": {
"id": 2,
"email": "jane.doe@example.com",
"firstName": "Jane",
"lastName": "Doe",
"phoneNumber": "+1555666777",
"address": {
"street": "789 Updated St",
"city": "Updated City",
"state": "TX",
"zipCode": "54321",
"country": "USA"
},
"createdAt": "2024-07-24T03:30:00.000Z",
"updatedAt": "2024-07-24T03:32:00.000Z"
}
}DELETE /api/users/:id
Response:
{
"success": true,
"message": "User deleted successfully",
"data": {
"id": 2,
"email": "jane.doe@example.com",
"firstName": "Jane",
"lastName": "Doe",
"createdAt": "2024-07-24T03:30:00.000Z",
"updatedAt": "2024-07-24T03:32:00.000Z"
}
}Note: All admin endpoints require authentication with admin role. Include the JWT token in the Authorization header: Authorization: Bearer <token>
PATCH /api/admin/:id/promote
Authorization: Bearer <admin-token>
Promotes a regular user to administrator role.
Parameters:
id- User ID to promote
Response:
{
"success": true,
"message": "User promoted to administrator successfully",
"data": {
"id": "507f1f77bcf86cd799439011",
"email": "user@example.com",
"firstName": "John",
"lastName": "Doe",
"role": "admin",
"createdAt": "2024-07-24T03:30:00.000Z",
"updatedAt": "2024-07-24T03:35:00.000Z"
}
}Error Responses:
400- User is already an administrator404- User not found403- Permission denied (not admin)
PATCH /api/admin/:id/demote
Authorization: Bearer <admin-token>
Demotes an administrator to regular user role.
Parameters:
id- Admin user ID to demote
Response:
{
"success": true,
"message": "Administrator demoted to user successfully",
"data": {
"id": "507f1f77bcf86cd799439011",
"email": "admin@example.com",
"firstName": "Jane",
"lastName": "Admin",
"role": "user",
"createdAt": "2024-07-24T03:30:00.000Z",
"updatedAt": "2024-07-24T03:40:00.000Z"
}
}Error Responses:
400- User is already a regular user or cannot demote yourself404- User not found403- Permission denied (not admin)
GET /api/admin/stats
Authorization: Bearer <admin-token>
Returns comprehensive statistics about the user base.
Response:
{
"success": true,
"data": {
"stats": {
"totalUsers": 150,
"totalAdmins": 3,
"regularUsers": 147
},
"recentUsers": [
{
"id": "507f1f77bcf86cd799439015",
"email": "newest@example.com",
"firstName": "New",
"lastName": "User",
"role": "user",
"createdAt": "2024-07-24T10:30:00.000Z",
"updatedAt": "2024-07-24T10:30:00.000Z"
}
]
}
}Error Responses:
403- Permission denied (not admin)
The service implements a two-tier role system:
Regular User (user):
- Default role for new registrations
- Can access own profile and standard user endpoints
- Cannot access admin endpoints
- Cannot modify other users' data
Administrator (admin):
- Full access to all endpoints
- Can promote users to admin
- Can demote other admins (except themselves)
- Can view system statistics
- Has audit logging for all admin actions
Role Management:
- Promote users to administrators
- Demote administrators to regular users
- Self-demotion protection (admins cannot demote themselves)
System Monitoring:
- View total user counts by role
- Access recent user registrations
- Comprehensive admin audit logging
Security Features:
- All admin actions are logged with admin identity
- Role-based middleware protection
- JWT tokens include role information
- 403 Forbidden responses for unauthorized access attempts
All endpoints return errors in the following format:
{
"success": false,
"error": "Error message describing what went wrong"
}Common HTTP status codes:
400- Bad Request (validation errors)401- Unauthorized (invalid or missing token)404- Not Found (user doesn't exist)409- Conflict (email already exists)429- Too Many Requests (rate limit exceeded)500- Internal Server Error
When rate limits are exceeded, the API returns a 429 status with additional information:
{
"error": "Too many authentication attempts from this IP, please try again after 15 minutes.",
"retryAfter": 900000
}The retryAfter field indicates the time in milliseconds until the limit resets.
Development:
npm run dev- Run in development mode with ts-nodenpm run dev:watch- Run in development mode with auto-restartnpm run build- Build TypeScript to JavaScriptnpm start- Run the compiled JavaScript
Database (Local Docker - Optional):
npm run db:up- Start local MongoDB with Docker Composenpm run db:down- Stop and remove local MongoDB containersnpm run db:logs- View local MongoDB logsnpm run db:admin- Start MongoDB Express web interface (http://localhost:8081)
Note: These scripts are only needed if using local Docker instead of MongoDB Atlas
Testing:
npm test- Run comprehensive test suite with Vitestnpm run test:watch- Run tests in watch modenpm run test:coverage- Run tests with coverage reportnpm run test:api- Run API endpoint tests with curlnpm run test:auth- Run authentication endpoint tests
Releases & Commits:
npm run commit- Interactive commit with conventional commit formatnpm run release- Generate new release with automated changelognpm run release:dry-run- Preview what would be released
src/
├── server.ts # Main server file
├── config/
│ ├── database.ts # MongoDB connection configuration
│ └── logger.ts # Winston logger configuration
├── models/
│ ├── User.ts # Mongoose User model with auth methods
│ └── User.test.ts # Unit tests for User model
├── controllers/
│ ├── index.ts # Controller exports
│ ├── authController.ts # Authentication controller logic
│ ├── authController.test.ts # Tests for auth controller
│ ├── usersController.ts # Users controller logic
│ ├── usersController.test.ts # Tests for users controller
│ └── adminController.ts # Admin role management controller
├── routes/
│ ├── users.ts # User API routes (all protected)
│ ├── auth.ts # Authentication routes
│ └── admin.ts # Admin-only routes for role management
├── middleware/
│ ├── auth.ts # JWT authentication middleware
│ ├── requireAdmin.ts # Admin role authorization middleware
│ ├── requestId.ts # Request ID generation middleware
│ ├── performance.ts # Performance monitoring middleware
│ └── rateLimiter.ts # Rate limiting middleware configurations
├── utils/
│ ├── jwt.ts # JWT token utilities
│ ├── jwt.test.ts # Tests for JWT utilities
│ └── logging.ts # Structured logging utility functions
├── test/
│ ├── setup.ts # Test environment configuration
│ ├── helpers.ts # Test helper functions
│ └── health.test.ts # Health endpoint tests
└── types/
└── user.ts # TypeScript type definitions
The service includes comprehensive structured logging with Winston:
logs/combined.log- All log messages in JSON formatlogs/error.log- Error-level messages onlylogs/exceptions.log- Uncaught exceptionslogs/rejections.log- Unhandled promise rejectionslogs/debug.log- Debug messages (development only)
- Structured JSON logging for easy parsing and aggregation
- Request correlation with unique request IDs
- Performance monitoring with request duration tracking
- Authentication event logging with detailed context
- Database operation logging with connection status
- Error tracking with stack traces and request context
- Multiple transports (console, file, error-specific files)
LOG_LEVEL- Set logging level (error, warn, info, debug)LOG_DIR- Directory for log files (default: logs)NODE_ENV- Environment affects console logging behavior
The service includes a comprehensive test suite built with Vitest:
- Unit Tests - Model methods, JWT utilities, validation logic
- Integration Tests - API endpoints with authentication
- Controller Tests - Request/response handling and error cases
- Authentication Tests - Registration, login, token validation
- Database Tests - Model validation and data persistence
# Run all tests
npm test
# Run tests in watch mode during development
npm run test:watch
# Run tests with coverage report
npm run test:coverageTests use an in-memory MongoDB instance for isolation and speed. Each test suite runs in a clean environment with automatic database cleanup.
The service implements comprehensive rate limiting to prevent abuse and ensure service availability:
| Endpoint Category | Limit | Window | Description |
|---|---|---|---|
| Authentication | 5 requests | 15 minutes | Registration, login attempts |
| User Creation | 3 requests | 1 hour | Creating new users via /api/users |
| API Users | 100 requests | 15 minutes | All /api/users/* endpoints |
| General | 1000 requests | 15 minutes | Global rate limit for all requests |
- Per-IP Tracking: Rate limits are applied per client IP address
- Request Counting: All requests count toward limits, including failed ones
- Sliding Window: Limits reset after the specified time window
- Automatic Headers: Response includes rate limit headers when available
- Logging: Rate limit violations are logged with client IP and endpoint
When rate limits are enforced, responses may include:
X-RateLimit-Limit: The rate limit ceiling for the endpointX-RateLimit-Remaining: Number of requests remaining in the windowX-RateLimit-Reset: Time when the rate limit window resetsRetry-After: Seconds until the client can retry (on 429 responses)
Use the included test script to verify rate limiting:
# Test authentication rate limiting (5 requests per 15 minutes)
./test_auth_rate_limit.shThe script makes 6 rapid registration requests. The first 5 should succeed (or fail with validation), and the 6th should return a 429 status code.
- Enhanced Validation - Add request validation with libraries like Joi or Zod
- Pagination - Add pagination for user lists
- Search & Filtering - Add user search and filtering capabilities
- Log Aggregation - Set up ELK Stack or similar for log analysis
- Docker - Add Docker support for the application itself
- CI/CD - Set up GitHub Actions for automated testing and deployment
This project follows conventional commit standards and uses automated changelog generation. See CONTRIBUTING.md for detailed guidelines on:
- Commit message format
- Development workflow
- Release process
- Code standards
This project is currently unlicensed. All rights reserved.