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.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'
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()