Node / Express Guide

Folder Structure

Project layout, entry points, and environment configuration for the Express backend.

Folder Structure

src/
├── app.ts                    ← Express app setup, 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)
│   ├── auth.controller.ts
│   ├── user.controller.ts
│   └── resource.controller.ts
├── services/                 ← Business logic and orchestration
│   ├── auth.service.ts
│   ├── user.service.ts
│   └── resource.service.ts
├── repositories/             ← MongoDB + Redis data access
│   ├── base.repo.ts
│   ├── user.repo.ts
│   └── resource.repo.ts
├── models/                   ← Interfaces (IUser…) + classes (User…)
│   ├── user.model.ts
│   └── resource.model.ts
├── routes/                   ← Express Router factories
│   ├── index.ts              ← Mounts all routers under /api/
│   ├── auth.route.ts
│   ├── user.route.ts
│   └── resource.route.ts
├── middleware/               ← Tenant resolution, role guards
│   ├── tenant.middleware.ts
│   └── role-guard.middleware.ts
├── validations/              ← Joi schema definitions
│   ├── local.validation.ts
│   ├── auth.validation.ts
│   └── resource.validation.ts
├── types/                    ← Shared TypeScript types
│   └── common.types.ts
├── utils/                    ← log, pipeline, format, generate helpers
│   └── log.util.ts
├── enums/                    ← TypeScript enums
│   ├── user.enum.ts
│   └── collection.enum.ts
├── events/                   ← Socket.IO event handlers
└── cache/                    ← Cache invalidation helpers

Environment Configuration

All env vars are accessed through typed helpers in src/config.tsnever 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'

app.ts Structure

// src/app.ts
import express from 'express'
import helmet  from 'helmet'
import cors    from 'cors'
import rateLimit from 'express-rate-limit'
import { errorHandler } from '@codisolutions23/node-utils'
import routes from './routes'

const app = express()

app.use(helmet())
app.use(cors(corsOptions))
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
app.use(rateLimit({ windowMs: 15 * 60 * 1000, max: 200 }))

app.use('/api', routes)

// Error handler must be registered last
app.use(errorHandler)

export default app

server.ts Entry Point

// src/server.ts
import { useAtlas, useRedis } from '@codisolutions23/node-utils'
import { mongoUri, redisUrl, port } from './config'
import app from './app'

async function start() {
  await useAtlas().connect(mongoUri)
  await useRedis().connect(redisUrl)
  app.listen(Number(port), () => {
    console.log(`Server listening on port ${port}`)
  })
}

start()