RESTful API built with Express.js featuring JWT authentication, MongoDB integration, and comprehensive user management.Bas### Security Features
- β Password Hashing: bcrypt with automatic salt generation (12 rounds)
- β JWT Tokens: HS256 algorithm with 24-hour expiration
- β Account Lockout: Account locked for 60 minutes after 5 failed login attempts
- β Role-Based Access Control: Different permissions for Admin and User roles
- β Password Requirements: Minimum 8 characters
- β Unique Email Constraint: Enforced at database level
- β Secure Responses: Password hashes never exposed in API responses
-
Node.js >= 18- Node.js >= 18
-
MongoDB (local or MongoDB Atlas)
```bashnpm install
npm install```
Copy .env.example to .env and adjust the values.
Copy .env.example to .env and adjust the values:
```bashcp .env.example .env
cp .env.example .env```
npm run dev: start the server with auto-reload (nodemon)
```bash- npm start: start in production mode
MONGO_URI=mongodb://localhost:27017 # or MongoDB Atlas URI- npm run lint:fix: auto-fix ESLint issues
MONGO_DB_NAME=checkibot_db- npm run format: format code with Prettier
npm run format:check: check formatting without writing changes
ADMIN_EMAIL=admin@checkibot.com## Code style and quality
ADMIN_PASSWORD=your_secure_admin_password
JWT_SECRET=your_secret_jwt_key_change_in_production- ESLint (Flat Config) configured for Node ESM
- Prettier as the code formatter
PORT=3000- Husky + lint-staged run checks on each commit
NODE_ENV=development
```When you run npm install, Husky initializes automatically via the `prepare` script.
β οΈ SECURITY NOTE: Always use strong passwords and change theJWT_SECRETin production!### Git hooks
Generate a strong JWT secret:- pre-commit: runs lint-staged to lint/format staged files.
node -e "console.log(require('crypto').randomBytes(64).toString('hex'))"If youβre on CI or Docker and donβt want to install hooks, you can disable Husky with `HUSKY=0`.
- `npm run dev`: start the server with auto-reload (nodemon)src/
- `npm start`: start in production mode app.js
- `npm test`: run tests with Jest server.js
- `npm run test:watch`: run tests in watch mode config/
- `npm run test:coverage`: run tests with coverage report index.js
- `npm run lint`: run ESLint routes/
- `npm run lint:fix`: auto-fix ESLint issues index.js
- `npm run format`: format code with Prettier health.js
- `npm run format:check`: check formatting without writing changes middleware/
errorHandler.js
## Getting Started```
1. Install dependencies:## Health endpoint
```bash
npm installGET `/api/health`
Sample response:
- Configure environment variables in
.env
3. Start the server:{
```bash "status": "ok",
npm run dev "service": "data-feeder-server",
``` "timestamp": "2025-09-16T12:34:56.000Z",
"env": "development"
4. The admin user will be created automatically on first startup}
-
Test the health endpoint:
curl http://localhost:3000/api/health ```In VS Code, enable format on save and ESLint fixes:
{
The API uses JWT (JSON Web Tokens) for authentication with bcrypt password hashing and account lockout protection. "editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"source.fixAll.eslint": true,
-
Admin: Full access - can create, deactivate, activate, and delete user accounts "source.organizeImports": true,
-
User: Standard access - can register, login, and use protected endpoints },
}
- β Password Hashing: bcrypt with automatic salt generation (12 rounds)
- β JWT Tokens: 24-hour expiration
- β Account Lockout: Account locked for 60 minutes after 5 failed login attempts
- β Role-Based Access Control: Different permissions for Admin and User roles
- β Password Requirements: Minimum 8 characters
- β Unique Email Constraint: Enforced at database level
- β Secure Responses: Password hashes never exposed in API responses
Check if the server is running.
Response:
{
"status": "ok",
"service": "data-feeder-server",
"timestamp": "2025-10-13T12:34:56.000Z",
"env": "development"
}POST /api/auth/register
Register a new user account. Default role is User.
Request Body:
{
"email": "user@example.com",
"password": "securepass123",
"role": "User"
}Response (201 Created):
{
"email": "user@example.com",
"role": "User",
"is_active": true,
"created_at": "2025-10-13T20:00:00.000Z"
}Example with curl:
curl -X POST http://localhost:3000/api/auth/register \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"password": "securepass123",
"role": "User"
}'POST /api/auth/login
Authenticate with email and password to receive a JWT token.
Request Body:
{
"email": "user@example.com",
"password": "securepass123"
}Response (200 OK):
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "bearer"
}Failed Attempts:
- After 1-4 failed attempts: Returns remaining attempts
- After 5 failed attempts: Account locked for 60 minutes
Example with curl:
curl -X POST http://localhost:3000/api/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"password": "securepass123"
}'GET /api/auth/me
Get the profile of the currently authenticated user.
Headers:
Authorization: Bearer YOUR_TOKEN_HERE
Response (200 OK):
{
"email": "user@example.com",
"role": "User",
"is_active": true,
"created_at": "2025-10-13T20:00:00.000Z"
}Example with curl:
curl -X GET http://localhost:3000/api/auth/me \
-H "Authorization: Bearer YOUR_TOKEN_HERE"These endpoints require Admin role and valid JWT token.
GET /api/auth/users
List all registered users (Admin only).
Headers:
Authorization: Bearer ADMIN_TOKEN_HERE
Response (200 OK):
{
"users": [
{
"email": "admin@example.com",
"role": "Admin",
"is_active": true,
"created_at": "2025-10-13T20:00:00.000Z"
},
{
"email": "user@example.com",
"role": "User",
"is_active": true,
"created_at": "2025-10-13T20:01:00.000Z"
}
],
"count": 2
}Example with curl:
curl -X GET http://localhost:3000/api/auth/users \
-H "Authorization: Bearer ADMIN_TOKEN_HERE"PATCH /api/auth/users/:email/deactivate
Deactivate a user account. User will not be able to login until reactivated (Admin only).
Headers:
Authorization: Bearer ADMIN_TOKEN_HERE
Response (200 OK):
{
"message": "User user@example.com has been deactivated"
}Example with curl:
curl -X PATCH http://localhost:3000/api/auth/users/user@example.com/deactivate \
-H "Authorization: Bearer ADMIN_TOKEN_HERE"PATCH /api/auth/users/:email/activate
Activate a previously deactivated user account (Admin only).
Headers:
Authorization: Bearer ADMIN_TOKEN_HERE
Response (200 OK):
{
"message": "User user@example.com has been activated"
}Example with curl:
curl -X PATCH http://localhost:3000/api/auth/users/user@example.com/activate \
-H "Authorization: Bearer ADMIN_TOKEN_HERE"DELETE /api/auth/users/:email
Permanently delete a user account. This action cannot be undone (Admin only).
Headers:
Authorization: Bearer ADMIN_TOKEN_HERE
Response (200 OK):
{
"message": "User user@example.com has been deleted permanently"
}Example with curl:
curl -X DELETE http://localhost:3000/api/auth/users/user@example.com \
-H "Authorization: Bearer ADMIN_TOKEN_HERE"The project includes comprehensive tests using Jest and Supertest with an in-memory MongoDB.
# Run all tests
npm test
# Run tests in watch mode
npm run test:watch
# Run tests with coverage report
npm run test:coverageThe test suite includes 20+ tests covering:
- β User registration (success, duplicate email, validation)
- β User login (success, invalid credentials, deactivated account)
- β Account lockout (5 failed attempts, auto-unlock)
- β JWT authentication (valid token, expired token, missing token)
- β Protected routes (authorization, role-based access)
- β Admin operations (activate, deactivate, delete users)
- β Permission checks (non-admin cannot perform admin actions)
-
First 4 attempts: User receives remaining attempts count
{ "message": "Invalid credentials. 3 attempts remaining." } -
5th failed attempt: Account is locked for 60 minutes
{ "message": "Account locked due to too many failed attempts. Try again in 60 minutes." } -
During lockout: Shows remaining time in Bolivia timezone (UTC-4)
{ "message": "Account locked due to too many failed attempts. Try again in 45 minutes (unlocks at 15:30:00)" } -
Auto-unlock: After 60 minutes, lockout automatically expires
-
Successful login: Resets failed attempts counter to 0
The project follows a modular architecture for better scalability:
src/
βββ app.js # Express app setup
βββ server.js # Server startup & DB initialization
βββ config/
β βββ index.js # Environment configuration
β βββ database.js # MongoDB connection & setup
β βββ server.routes.js # Centralized route registration
βββ modules/ # β Feature-based modules
β βββ auth/ # Authentication module
β β βββ auth.controller.js # Request handlers
β β βββ auth.service.js # Business logic
β β βββ auth.routes.js # Route definitions
β β βββ user.model.js # Data models
β βββ health/ # Health check module
β βββ health.controller.js
β βββ health.routes.js
βββ middleware/ # Shared middleware
β βββ errorHandler.js # Error handling
β βββ auth.js # JWT authentication
βββ validators/ # Shared validators
β βββ auth.js # Request validation schemas
βββ utils/ # Shared utilities
β βββ auth.js # Password hashing & JWT utilities
βββ tests/
βββ auth.test.js # Integration tests
π Learn More: See ARCHITECTURE.md for detailed information about the modular architecture, how to add new modules, and best practices.
- Never commit
.envfile - It contains sensitive credentials - Use strong passwords - Minimum 8 characters (enforced)
- Rotate JWT secrets regularly - Especially in production
- Use HTTPS in production - Protect tokens in transit
- Monitor failed login attempts - Watch for brute force attacks
- Keep dependencies updated - Run
npm auditregularly
- ESLint (Flat Config) configured for Node ESM
- Prettier as the code formatter
- ESLint + Prettier integration to avoid conflicts
- Husky + lint-staged run checks on each commit
When you run npm install, Husky initializes automatically via the prepare script.
pre-commit: runslint-stagedto lint/format staged files
If you're on CI or Docker and don't want to install hooks, you can disable Husky with HUSKY=0.
In VS Code, enable format on save and ESLint fixes:
Make sure to set these in your production environment:
NODE_ENV=production
JWT_SECRET=<generate-a-strong-secret>
MONGO_URI=<your-production-mongodb-uri>
ADMIN_EMAIL=<your-admin-email>
ADMIN_PASSWORD=<strong-admin-password>A Dockerfile will be added for containerized deployments.
This project is private and proprietary.
Contact the development team for contribution guidelines.
For issues or questions, contact the CheckiBot development team.
{ "editor.formatOnSave": true, "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.codeActionsOnSave": { "source.fixAll.eslint": true, "source.organizeImports": true, }, }