Skip to content

ndulomk/ndulojs-example

Repository files navigation

NduloJS Starter Pack

Production-ready backend starter using NduloJS + Elysia + Drizzle ORM + Valkey (Redis-compatible) + PostgreSQL.

Stack

Layer Tech
Runtime Bun
Framework NduloJS (Elysia adapter)
Database PostgreSQL 16 via Drizzle ORM
Cache / Queue Valkey 8 (Redis-compatible)
Auth JWT + refresh tokens
Validation Zod + TypeBox
Observability Pino structured logs + Prometheus metrics
API Docs Swagger via @elysiajs/swagger

Quick Start

1. Start infrastructure

cp .env.example .env
docker compose up -d

Postgres will be available on localhost:5432, Valkey on localhost:6379.

2. Install dependencies

bun install

3. Run migrations

bun run db:generate
bun run db:migrate

4. Start dev server

bun run dev

Server: http://localhost:3000
Swagger: http://localhost:3000/docs
Metrics: http://localhost:9091/metrics

Environment Variables

# App
PORT=3000
METRICS_PORT=9091
NODE_ENV=development
LOG_LEVEL=info
LOG_PRETTY=true

# Database
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/app
POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres
POSTGRES_DB=app

# Valkey / Redis
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=secret

# Auth
JWT_SECRET=change-me-in-production
JWT_EXPIRES_IN=15m
REFRESH_TOKEN_EXPIRES_IN=7d

# CORS
CORS_ORIGINS=http://localhost:5173
CORS_CREDENTIALS=true

Project Structure

src/
├── config/         # env validation
├── db/             # drizzle schema + migrations
├── middlewares/    # auth, rate-limit, metrics
├── modules/
│   └── users/
│       ├── application/   # services, ports, DTOs
│       ├── domain/        # entities
│       └── infrastructure/
│           ├── db/        # drizzle repository
│           └── http/      # controllers
└── shared/
    ├── auth/       # JWT helpers
    ├── logger/     # pino wrapper
    ├── metrics/    # prometheus
    └── upload/     # multipart parser

API Endpoints

Auth

Method Path Description
POST /users/auth/register Create account
POST /users/auth/login Login
POST /users/auth/logout Logout
POST /users/auth/refresh Refresh access token

Users

Method Path Description
GET /users/me Get current user
PATCH /users/me Update profile
POST /users/me/avatar Upload avatar
GET /users List users
DELETE /users/:id Delete user

Sessions

Method Path Description
GET /sessions List active sessions
DELETE /sessions/:id Revoke session
POST /sessions/revoke-all Revoke all sessions

System

Method Path Description
GET /health Health check
GET /ready Readiness check
GET /docs Swagger UI
GET /metrics Prometheus metrics

Scripts

bun run dev          # dev server with watch
bun run build        # production build
bun run start        # run built output
bun run typecheck    # tsc --noEmit
bun run db:generate  # generate drizzle migrations
bun run db:migrate   # run migrations
bun run db:push      # push schema (dev only)
bun run db:studio    # drizzle studio UI
bun run db:seed      # seed database
bun run test         # vitest

Result Pattern

All handlers return Ok(data) or Err(ErrorFactory.xxx(...)) — never throw. NduloJS maps these to correct HTTP status codes automatically.

import { Ok, Err, ErrorFactory } from 'ndulojs';

// 200
return Ok({ user });

// 404
return Err(ErrorFactory.notFound('User not found', 'User', userId));

// 401
return Err(ErrorFactory.unauthorized('Invalid token', 'invalid_token'));

// 409
return Err(ErrorFactory.conflict('Email already registered', 'email'));

// 422
return Err(ErrorFactory.validation('Invalid input', errors));

About

a real example on how to use ndulojs

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors