A production-ready REST API built with Node.js, TypeScript and Fastify. It demonstrates backend best practices: authentication with JWT refresh-token rotation, role-based access control (RBAC), pagination/filters/sorting, rate limiting, automated tests and CI/CD.
- Authentication: register, login, logout and refresh-token rotation.
- RBAC:
userandadminroles with protected endpoints. - Tasks: full CRUD with filters, sorting and pagination.
- Security: password hashing, short-lived access tokens, Redis-backed refresh-token blacklist, rate limiting and Helmet headers.
- Database: PostgreSQL with Drizzle ORM, migrations and seed script.
- API docs: OpenAPI/Swagger UI available at
/documentation. - DevOps: Docker, Docker Compose and GitHub Actions CI.
- Testing: integration tests with Vitest, Supertest, PostgreSQL and Redis.
| Layer | Technology |
|---|---|
| Runtime | Node.js 20+ |
| Language | TypeScript 5 |
| Framework | Fastify 5 |
| ORM | Drizzle ORM |
| Database | PostgreSQL 16 |
| Cache | Redis 7 |
| Auth | JWT (access + refresh) |
| Validation | Zod |
| Logging | Pino |
| Test | Vitest + Supertest |
| CI/CD | GitHub Actions |
- Node.js 20+
- pnpm 8+
- PostgreSQL 16+ and Redis 7+ (or use Docker Compose below)
git clone https://github.com/loSpaccaBit/taskflow-api.git
cd taskflow-api
pnpm install
cp .env.example .envUpdate .env with your credentials.
cp .env.example .env
# Optional: set strong secrets in .env
docker compose up --buildThe API will be available at http://localhost:3000 and Swagger UI at http://localhost:3000/documentation.
- Start PostgreSQL and Redis.
- Apply migrations:
pnpm db:migrate- Seed the database (optional):
pnpm db:seed- Start the dev server:
pnpm dev| Method | Endpoint | Description |
|---|---|---|
| GET | /health |
Basic health check |
| GET | /health/db |
Database connectivity check |
| Method | Endpoint | Description |
|---|---|---|
| POST | /auth/register |
Register a new user |
| POST | /auth/login |
Login and receive tokens |
| POST | /auth/refresh |
Rotate refresh token |
| POST | /auth/logout |
Revoke refresh token |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | /users/me |
User | Get current profile |
| PATCH | /users/me |
User | Update current profile |
| GET | /users |
Admin | List users with pagination |
| PATCH | /users/:id/role |
Admin | Change user role |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | /tasks |
User | List tasks (filters, sort, pagination) |
| POST | /tasks |
User | Create a task |
| GET | /tasks/:id |
User | Get a task |
| PATCH | /tasks/:id |
User | Update a task |
| DELETE | /tasks/:id |
User | Delete a task |
| Variable | Description |
|---|---|
NODE_ENV |
Environment: development, test or production |
PORT |
Server port |
DATABASE_URL |
PostgreSQL connection string |
REDIS_URL |
Redis connection string |
JWT_ACCESS_SECRET |
Secret for access tokens |
JWT_REFRESH_SECRET |
Secret for refresh tokens |
JWT_ACCESS_EXPIRES_IN |
Access token TTL (e.g. 15m) |
JWT_REFRESH_EXPIRES_IN |
Refresh token TTL (e.g. 7d) |
RATE_LIMIT_MAX |
Max requests per minute per IP |
pnpm testBy default, the test suite uses PGlite (an in-memory PostgreSQL implementation) and ioredis-mock, so no Docker or local services are required. The CI pipeline runs the same tests against real PostgreSQL and Redis containers.
To run tests against real services:
export DATABASE_URL=postgresql://postgres:postgres@localhost:5432/taskflow
export REDIS_URL=redis://localhost:6379
export TEST_USE_MOCK=false
pnpm db:migrate
pnpm testpnpm dev # Start development server
pnpm build # Compile TypeScript
pnpm start # Start production server
pnpm db:migrate # Run database migrations
pnpm db:seed # Seed the database
pnpm db:studio # Open Drizzle Studio
pnpm lint # Run ESLint
pnpm type-check # Run TypeScript checks
pnpm test # Run tests
pnpm format # Format code with PrettierSee CONTRIBUTING.md.
See SECURITY.md.
MIT © Francesco Nocerino