Backend

Middleware

Backend middleware — tenant resolution, auth, and role guards.

Tenant Middleware

Resolves organizationId from the request context and attaches it to req.organizationId. It looks in three places in order:

  1. req.user.organizationId (authenticated user)
  2. req.query.organizationId
  3. x-tenant-slug header → DB lookup
// src/middleware/tenant.middleware.ts
import { resolveOptionalTenant, resolveRequiredTenant } from '../middleware/tenant.middleware'

// Use on routes where org context is optional
router.post('/login', resolveOptionalTenant, login)

// Use on routes where org context is required
router.get('/', resolveRequiredTenant, getItems)

The resolveTenant(required: boolean) factory:

  • If required = false: continues silently if org cannot be determined.
  • If required = true: throws UnprocessableEntityError if org cannot be determined.

Auth Middleware

Comes from codi-node-utils. Validates the Authorization: Bearer <token> header and checks the JWT is not revoked:

import { authenticate } from '@codisolutions23/node-utils'
import { useRevokedTokenRepo } from '../repositories/revoked-token.repo'
import { accessTokenSecret } from '../config'

const { existsByJti } = useRevokedTokenRepo()
const authMiddleware  = authenticate(accessTokenSecret, existsByJti)

// Use per-route:
router.get('/profile', authMiddleware, getProfile)

On success, attaches req.user (decoded JWT payload) and req.token (raw token) to the request.

Role Guard Middleware

Role guards are built on requireRoles(roles[], ...) from src/middleware/role-guard.middleware.ts. Pre-composed exports:

export const requireAdmin = requireRoles([UserType.ADMIN], ...)
export const requireOwner = requireRoles([UserType.OWNER, UserType.ADMIN], ...)
export const requireBranchManagerOrAbove = requireRoles(
  [UserType.ADMIN, UserType.OWNER, UserType.BRANCH_MANAGER], ...
)

Usage:

// Route file — build middleware instances once and reuse
const authMiddleware            = authenticate(accessTokenSecret, existsByJti)
const adminMiddleware           = requireAdmin(accessTokenSecret, existsByJti)
const branchManagerMiddleware   = requireBranchManagerOrAbove(accessTokenSecret, existsByJti)

router.get('/',           authMiddleware,          getAll)
router.post('/',          branchManagerMiddleware,  create)
router.delete('/:id',     adminMiddleware,          remove)

Middleware Order in app.ts

// src/app.ts
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 }))

// Routes
app.use('/api', routes)

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

errorHandler is imported from codi-node-utils and must be registered after all routes.