A clean, layered backend API for a Task Management app built with Node.js and TypeScript.
This repository implements a layered architecture (Controller → Service → Repository) with an Express API, Knex.js for database access, MySQL migrations & seeders, Redis caching, JWT authentication and common production-ready practices such as rate-limiting, structured logging, and centralized error handling.
- Node.js + TypeScript
- Express.js (HTTP server)
- Knex.js (query builder & migrations)
- MySQL (database)
- Redis (caching / token storage)
- JWT (jsonwebtoken)
- bcrypt (password hashing)
- Joi (validation)
- Winston (logging)
The project follows a layered / clean architecture to separate concerns and make the codebase maintainable and testable:
- Controllers — HTTP handlers (src/controllers)
- Services — Business logic & orchestration (src/services)
- Repositories — Data access via Knex (src/repository)
- Database — Migrations & seeders (src/database)
- Utilities — Logging, caching, token utilities, error classes (src/utils)
- Middlewares — Validation, rate-limiting, error handling (src/middlewares)
Request flow: Client → Controller → Service → Repository → Database
Requirements:
- Node.js 18+ (or compatible)
- pnpm
- MySQL
- Redis
- Install dependencies
pnpm install-
Copy the example env (create a
.envfile at the project root) and set the values for your environment. See theEnvironment variablessection below for required keys. -
Run migrations and seed providers
npx knex migrate:latest
npx knex seed:run- Start the development server
npm run devThe API will be available at the BASE_URL you set in .env (default in repo: http://localhost:3200/api/v1).
Create a .env file and configure the following variables. Do NOT commit secrets.
Required (used in code):
- NODE_ENV (development | production)
- PORT
- DB_HOST
- DB_PORT
- DB_USER
- DB_PASSWORD
- DB_NAME
- SALT_ROUNDS
- SECRET_KEY
- REFRESH_SECRET
- EMAIL_SECRET
- TOKEN_EXPIRY
- REFRESH_TOKEN_EXPIRY_DAYS
- RATE_LIMIT_WINDOW_MS
- RATE_LIMIT_MAX_REQUESTS
- SMTP_EMAIL
- SMTP_PASSWORD
- REDIS_URL
- BASE_URL (e.g. http://localhost:3200/api/v1)
Example (DO NOT use these keys in production):
NODE_ENV=development
PORT=3200
BASE_URL=http://localhost:3200/api/v1
REDIS_URL=redis://127.0.0.1:6379
DB_HOST=localhost
DB_PORT=3306
DB_USER=root
DB_PASSWORD=yourpassword
DB_NAME=local_todo_db
SALT_ROUNDS=12
SECRET_KEY=your_jwt_secret
REFRESH_SECRET=your_refresh_secret
EMAIL_SECRET=your_email_secret
TOKEN_EXPIRY=2h
REFRESH_TOKEN_EXPIRY_DAYS=7
RATE_LIMIT_WINDOW_MS=900000
RATE_LIMIT_MAX_REQUESTS=100
SMTP_EMAIL=your-smtp-email
SMTP_PASSWORD=your-smtp-password
You can run the following npm scripts defined in package.json:
npm run dev— start development server (nodemon + ts-node)npm run start— run compileddistserver (after build)npm run migrate— run knex migrations (via package script aliases)npm run seed— run knex seeds
Note: migrations & seed commands use the knexfile.js in repo which loads the TypeScript knex config.
Knex configuration is in src/config/knexfile.ts. Migrations are located in src/database/migrations and seeds are in src/database/seeds.
Run migrations:
npx knex migrate:latestRun seeds:
npx knex seed:runThe repo includes migrations for users, providers, auth, and tasks tables, and a seed for core providers.
Redis is used for caching and storing refresh tokens. Configure the connection with REDIS_URL in .env. The Redis client is configured in src/config/redis.ts and utilities are in src/utils/caching.ts.
Tests are written with Jest and are located inside the src/tests directory. You can run the test suite using the pnpm test command.
Base URL: {{BASE_URL}} (e.g. http://localhost:3200/api/v1)
Auth:
- POST /auth/signup — register a new user
- GET /auth/verify-email?token=... — verify email with token
- POST /auth/login — login and receive tokens
Example signup request (PowerShell curl style):
curl -X POST "http://localhost:3200/api/v1/auth/signup" -H "Content-Type: application/json" -d '{
"email": "test@example.com",
"password": "S3cure!Pass",
"confirm_password": "S3cure!Pass",
"fullname": "Test User",
"phone": "08031234567"
}'Login example:
curl -X POST "http://localhost:3200/api/v1/auth/login" -H "Content-Type: application/json" -d '{
"email": "test@example.com",
"password": "S3cure!Pass"
}'Verify email (the verification email contains a link with a token):
# GET request performed by a browser or via curl
curl "http://localhost:3200/api/v1/auth/verify-email?token=<TOKEN_HERE>"- Centralized error handler:
src/middlewares/error_handler.ts(customAppErrorsubclasses insrc/utils/errors.ts). - Logging: Winston configured in
src/utils/logger.ts(writes tologs/error.logandlogs/combined.log).
- If you see database connection problems: check
DB_*env variables and ensure MySQL is reachable. - If Redis connection fails: check
REDIS_URLand make sure Redis server is running. - For migrations, ensure
ts-nodeis available and the repo'sknexfile.jsloads the TypeScript config. - Use
npm run devto run nodemon and get live reloads for development.
Contributions are welcome. Follow the existing layered structure when adding features:
- Add new business logic in
src/services. - Add DB access code to
src/repositoryand update/create migrations. - Keep controllers thin — only handle validation and HTTP concerns.
- This repo already includes a
docs/folder with architecture notes, API docs and service responsibilities. - Be mindful of storing secrets — use environment variables or a secret manager in production.
This project has no license file in the repository. Add a LICENSE file if you plan to open-source it.