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
| Layer | Technology |
|---|---|
| HTTP framework | Express v5 |
| Real-time | Socket.IO |
| Database | MongoDB (native driver — no Mongoose) |
| Cache | Redis via ioredis |
| Auth | JWT (jsonwebtoken) — access + refresh tokens |
| Validation | Joi |
| Password hashing | bcrypt |
| File uploads | multer + AWS S3 |
| Emails | Nodemailer + Handlebars templates |
| Logging | Winston (via codi-node-utils) |
| Security | helmet, 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
| Thing | Convention | Example |
|---|---|---|
| Files | kebab-case.<layer>.ts | auth.controller.ts, user-payment.service.ts |
| Factory functions | use<Domain><Layer>() | useAuthController(), useUserRepo() |
| Interfaces | I prefix | IUser, IBooking |
| Type aliases | T prefix | TUserCreate, TBookingStatus |
| Enums | PascalCase | UserType, BookingStatus |
| Enum values | SCREAMING_SNAKE_CASE | UserType.BRANCH_MANAGER |
| Resource constant | const 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'