Edutrium Backend — Overview & Tech Stack
Technical overview of the Edutrium NestJS backend — architecture, modules, integrations, and AI development guidelines.
Repository Overview
Edutrium Backend is a NestJS REST API for an education platform. It uses:
- Framework: NestJS (TypeScript)
- ORM: Drizzle ORM + PostgreSQL
- Auth: BetterAuth
- File Storage: Cloudflare R2 (via AWS S3 SDK)
- Package Manager: pnpm
- Containerization: Docker / Docker Compose
- API Docs: Swagger (OpenAPI)
Modules
| Module | Description |
|---|---|
auth |
Authentication & authorization (BetterAuth, roles) |
users |
User profiles and management |
company |
Company records |
university |
University entities |
faculty |
Faculty within universities |
campus |
Campus records linked to universities |
major |
Academic majors |
degree |
Degree types |
program |
Academic programs |
program-price |
Pricing per program and academic year |
program-requirement |
Entry requirements for programs |
curriculum |
Curriculum definitions |
academic-year |
Academic year management |
semester |
Semester management |
student |
Student profiles |
student-status |
Student enrollment statuses |
student-preference |
Student preferences (hero, gallery, etc.) |
application |
Student applications to programs |
application-status |
Status tracking for applications |
application-status-type |
Lookup types for application statuses |
application-status-history |
Historical status changes per application |
field |
Fields of study |
city |
City records |
country |
Country records |
currency |
Currency records |
language |
Language records |
files |
File upload service (Cloudflare R2) |
filters |
Generic query filtering utilities |
Codebase Size
| Category | Lines |
|---|---|
TypeScript source (src/, excluding tests) |
13,684 |
| Test / spec files | 22 |
Database migration SQL (drizzle/) |
867 |
Root config files (tsconfig, eslint, drizzle.config, etc.) |
87 |
| Total tracked lines | ~14,660 |
Largest Source Files
| File | Lines |
|---|---|
src/utils/query-helpers.ts |
871 |
src/faculty/faculty.service.ts |
396 |
src/country/country.service.ts |
384 |
src/campus/campus.service.ts |
342 |
src/application/application.service.ts |
338 |
src/major/major.service.ts |
336 |
src/city/city.service.ts |
331 |
src/program/program.service.ts |
330 |
src/student/student.service.ts |
318 |
src/academic-year/academic-year.service.ts |
266 |
Integrations & Packages
Runtime Dependencies
| Package | Version | Purpose |
|---|---|---|
@nestjs/common, @nestjs/core, @nestjs/platform-express |
^11.0.1 | NestJS core framework |
@nestjs/config |
^4.0.2 | Environment configuration via .env |
@nestjs/swagger |
^11.2.4 | Auto-generated OpenAPI / Swagger UI |
drizzle-orm |
^0.45.1 | Type-safe SQL ORM |
pg |
^8.16.3 | PostgreSQL driver |
better-auth |
^1.4.18 | Authentication engine (sessions, roles, forgot-password) |
@thallesp/nestjs-better-auth |
^2.2.5 | NestJS adapter for BetterAuth |
@aws-sdk/client-s3 |
^3.995.0 | S3-compatible client for Cloudflare R2 file storage |
@aws-sdk/s3-request-presigner |
^3.995.0 | Presigned URL generation for direct browser uploads |
resend |
^6.9.2 | Transactional email delivery (e.g. forgot-password) |
class-validator |
^0.14.3 | DTO request validation decorators |
class-transformer |
^0.5.1 | Request/response payload transformation |
graphql |
^16.12.0 | GraphQL peer dependency (Swagger / NestJS schema) |
rxjs |
^7.8.1 | Reactive extensions (NestJS internals) |
reflect-metadata |
^0.2.2 | Decorator metadata reflection (required by NestJS/TypeScript) |
dotenv |
^17.2.3 | .env file loading |
pnpm |
^10.28.0 | Fast, disk-efficient package manager |
Dev / Build Dependencies
| Package | Version | Purpose |
|---|---|---|
drizzle-kit |
^0.31.8 | Schema migrations & introspection CLI |
@nestjs/cli |
^11.0.0 | NestJS project scaffolding & build |
typescript |
^5.7.3 | TypeScript compiler |
typescript-eslint |
^8.20.0 | TypeScript-aware ESLint rules |
eslint + eslint-plugin-prettier |
^9 / ^5 | Linting & style enforcement |
prettier |
^3.4.2 | Opinionated code formatter |
jest + ts-jest |
^30 / ^29 | Unit & integration testing |
supertest |
^7.0.0 | HTTP assertion library for e2e tests |
ts-node + tsconfig-paths |
^10 / ^4 | Run TypeScript directly in development |
External Services / Infrastructure
| Service | SDK / Method | Purpose |
|---|---|---|
| PostgreSQL | pg + Drizzle ORM |
Primary relational database |
| Cloudflare R2 | AWS S3 SDK (compatible API) | Object / file storage |
| Resend | resend npm package |
Transactional email |
| Docker / Docker Compose | Dockerfile + docker-compose.yml |
Containerised deployment |
AI-Assisted Development Guide
AI Can Write This Freely
These tasks are low-risk, follow a clear and repeated pattern, and are easy to review:
| Task | Rationale |
|---|---|
| New CRUD module scaffold (controller / service / module / schema / DTOs) | Every module follows the exact same pattern. AI can duplicate and rename reliably. |
OpenAPI / Swagger doc objects (docs/<module>.doc.ts) |
Purely descriptive metadata — no business logic. |
| Drizzle schema table definitions | Column declarations are declarative and uniform. |
| DTO classes with class-validator decorators | Boilerplate with known decorators. Low risk. |
| Pagination / filtering query helpers | The query-helpers.ts utility defines a consistent pattern — AI can extend by example. |
| Migration SQL generation | Drizzle Kit auto-generates migrations; AI can also write straightforward SQL. |
| Config / tooling files | Static configuration — no runtime risk. |
| Unit test stubs | Boilerplate describe/it blocks. |
AI Can Help But Needs Security Review
| Task | Security Concern | Mitigation |
|---|---|---|
| Authentication flows | Incorrect guard logic can allow privilege escalation | Review every @UseGuards, @Roles, and auth middleware change |
| Forgot-password / email flows | Token bugs can enable account takeover | Verify token entropy, expiry, and single-use |
| File upload handlers | Path traversal, MIME spoofing, unconstrained size | Validate MIME types server-side, apply size limits |
| Presigned URL generation | Overly permissive expiry leaks storage access | Confirm short expiry (≤ 5 min) scoped to a single key |
| Environment variable handling | AI may hard-code secrets | Always use process.env / ConfigModule |
| Database query construction | Injection risk with raw SQL | Use Drizzle's parameterised API — never raw string interpolation |
| CORS configuration | Too-permissive origins allow cross-origin attacks | Review allowed origins explicitly |
| Error messages to clients | Leaking stack traces aids attackers | Only generic messages reach the client |
AI Should NOT Write This (Human Only)
| Task | Reason |
|---|---|
| Initial auth architecture decisions | Long-term security implications require deliberate design |
| Role / permission model design | Business and security requirement — mistakes are hard to reverse |
| Database migration on production data | Irreversible operations must be authored by a human |
| Secrets management / key rotation | Requires verified off-channel coordination |
| Payment or financial logic | High-stakes correctness requirement |
| Legal / compliance features (GDPR, data retention) | Requires understanding of regulatory obligations |
| Third-party OAuth / SSO integration | Misconfigured OAuth flows cause account takeover |