Skip to content

Tech Stack

Backend

LayerTechnologyVersionRole
RuntimeNode.js≥ 18JavaScript runtime
FrameworkNestJS10Module-based API framework
ORMTypeORM0.3Database mapping + migrations
DatabasePostgreSQL≥ 14Primary data store
AuthPassport.jsJWT + Google OAuth strategies
Validationclass-validatorDTO input validation
DocsSwagger / OpenAPIAuto-generated at /api
Package managerpnpm≥ 8Monorepo-friendly installs

NestJS Module Pattern

Every feature is an isolated NestJS module:

src/indicators/
├── indicator.entity.ts       TypeORM entity + DB schema
├── indicator.service.ts      Business logic, orgId scoping
├── indicator.controller.ts   HTTP routes, guards, Swagger decorators
├── indicator.module.ts       Module registration
└── dto/
    ├── create-indicator.dto.ts
    └── update-indicator.dto.ts

Frontend

LayerTechnologyVersionRole
FrameworkNext.js14App Router, SSR, file-based routing
UIReact18Component model
StylingTailwind CSS3Utility-first CSS
Componentsshadcn/uiAccessible UI primitives
Data fetchingTanStack Query5Server state, caching, background refetch
HTTP clientAxiosAPI calls with interceptors
AuthCustom JWTHttpOnly cookie read by NestJS
PDFhtml2pdf.jsDOM-to-binary PDF export
ToastsSonnerNon-blocking notifications
IconsLucide ReactSVG icon library

Route Structure

/org/[orgId]/dashboard
/org/[orgId]/programs
/org/[orgId]/programs/[id]
/org/[orgId]/projects/[id]
/org/[orgId]/indicators
/org/[orgId]/reports
/org/[orgId]/reports/[id]
/org/[orgId]/data-collection
/org/[orgId]/settings
/r/[token]          ← public shareable report
/form/[token]       ← public data collection form

API Layer (lib/api/)

ts
// lib/api.ts — Axios instance with credentials
const api = axios.create({
  baseURL: process.env.NEXT_PUBLIC_API_URL,
  withCredentials: true,   // sends HttpOnly cookie
})

// lib/api-helpers.ts — orgId-scoped helpers
export const orgApi = (orgId: string) => ({
  get: (path, config?) => api.get(`/orgs/${orgId}${path}`, config),
  post: (path, data, config?) => api.post(`/orgs/${orgId}${path}`, data, config),
  // ...
})

Database

PostgreSQL 16 with:

  • UUID primary keysuuid_generate_v4() via uuid-ossp extension
  • snake_case columns — enforced via TypeORM @Column({ name: 'column_name' })
  • Soft deletesdeleted_at timestamp on sensitive entities
  • Audit timestampscreated_at, updated_at on every table via TypeORM @CreateDateColumn / @UpdateDateColumn

Migration Strategy

All schema changes are TypeORM migrations — never raw ALTER TABLE in production.

bash
# Generate a migration from entity changes
pnpm run migration:generate -- src/migrations/AddNewFeature

# Run pending migrations
pnpm run migration:run

# Revert last migration
pnpm run migration:revert

Infrastructure

ComponentDevProduction
API hostlocalhost:3001api.impactmel.com
Frontendlocalhost:3000app.impactmel.com
Databaselocal PostgreSQLManaged PostgreSQL (e.g. Neon, RDS)
Auth cookiesSameSite=LaxSameSite=None; Secure; Domain=.impactmel.com
CDNCloudflare
Process managerpnpm run start:devPM2 or systemd

ImpactMEL — Enterprise M&E Platform