Backend

Overview

Stack and architecture of the booki-api backend.

booki-api is a TypeScript Express v5 backend with Socket.IO, built around a layered architecture: routes → controllers → services → repositories → MongoDB.

Stack

LayerTechnology
HTTP frameworkExpress v5
Real-timeSocket.IO
DatabaseMongoDB (native driver — no Mongoose)
CacheRedis via ioredis
AuthJWT (jsonwebtoken) — access + refresh tokens
ValidationJoi
Password hashingbcrypt
File uploadsmulter + AWS S3
EmailsNodemailer + Handlebars templates
LoggingWinston (via codi-node-utils)
Securityhelmet, express-rate-limit

Architecture Layers

HTTP Request
  │
  ▼
Route  (src/routes/)         — path + middleware composition
  │
  ▼
Middleware  (src/middleware/) — tenant, auth, role guard
  │
  ▼
Controller  (src/controllers/) — validate → delegate → respond
  │
  ▼
Service  (src/services/)      — business logic, orchestration
  │
  ▼
Repository  (src/repositories/) — MongoDB read/write + cache
  │
  ▼
MongoDB + Redis

Project Structure

src/
  app.ts              ← Express app, Socket.IO, middleware registration
  server.ts           ← Entry point: DB connect → Redis init → listen
  config.ts           ← All env vars via typed getEnv() helpers
  setup.ts            ← MongoDB index creation on startup
  controllers/        ← Request handlers (factory functions)
  services/           ← Business logic
  repositories/       ← MongoDB + Redis data access
  models/             ← Interfaces (IUser…) + classes (User…)
  routes/             ← Express Router factories
  middleware/         ← tenant, role-guard, load-organization
  validations/        ← Joi schema definitions
  types/              ← Shared TypeScript types
  utils/              ← log, pipeline, format, generate helpers
  enums/              ← TypeScript enums (UserType, BookingStatus…)
  events/             ← Socket.IO event handlers
  cache/              ← Cache invalidation helpers

Naming Conventions

ThingConventionExample
Fileskebab-case.<layer>.tsauth.controller.ts, user-payment.service.ts
Factory functionsuse<Domain><Layer>()useAuthController(), useUserRepo()
InterfacesI prefixIUser, IBooking
Type aliasesT prefixTUserCreate, TBookingStatus
EnumsPascalCaseUserType, BookingStatus
Enum valuesSCREAMING_SNAKE_CASEUserType.BRANCH_MANAGER
Resource constantconst resource = 'auth.controller'Used in log calls

Environment Configuration

All env vars are accessed through typed helpers in src/config.ts — never process.env directly in other files:

// src/config.ts
function getEnv(key: string, required = true): string {
  const value = process.env[key]
  if (required && !value) throw new Error(`Missing env var: ${key}`)
  return value ?? ''
}

export const mongoUri        = getEnv('MONGO_URI')
export const accessTokenSecret  = getEnv('ACCESS_TOKEN_SECRET')
export const refreshTokenSecret = getEnv('REFRESH_TOKEN_SECRET')
export const redisUrl        = getEnv('REDIS_URL')
export const port            = getEnv('PORT', false) || '3001'