Getting Started¶
Audience: Developers joining the SIS backend team. Goal: Understand the project, set up locally, and start coding.
1. Prerequisites¶
Before diving into the codebase, make sure you're comfortable with the foundational topics below. You don't need to be an expert — a working understanding is enough. Each subsection explains why the topic matters here.
How the Web Works¶
Every feature in this project starts with an HTTP request and ends with an HTTP response. Understanding the client-server model, URLs, HTTP methods, status codes, headers, and the request/response cycle is essential for reasoning about anything the backend does.
Terminal / Command Line¶
The dev server, database migrations, tests, linting, and git — all run from the terminal. You'll spend significant time there, so fluency with basic shell commands, navigating directories, and reading command output is non-negotiable.
Git & Version Control¶
All code changes go through Git. We use feature branches, pull requests, and code review. You need to understand commits, branches, merges, diffs, and how to resolve conflicts.
Programming Fundamentals (OOP)¶
NestJS is built on classes, interfaces, inheritance, and dependency injection. If you don't have a solid grasp of object-oriented programming concepts — classes, constructors, access modifiers, abstract classes, interfaces — the framework code will be hard to follow.
TypeScript / JavaScript¶
The entire backend is TypeScript. You need to be comfortable with modern JavaScript (async/await, destructuring, arrow functions, Promises) and TypeScript's type system (interfaces, generics, type narrowing, union types).
SQL & Relational Databases¶
All data lives in PostgreSQL. Even though Prisma abstracts most queries, you need a mental model for tables, rows, columns, primary keys, foreign keys, JOINs, and indexes to understand what Prisma generates and to debug data issues.
Package Managers (npm)¶
npm install, npm run, and npx are used constantly. Understanding how package.json, node_modules, lock files, and scripts work will save you from common "it doesn't work on my machine" issues.
REST APIs¶
This project exposes a REST API. You need to understand REST conventions: resources, HTTP methods (GET, POST, PATCH, DELETE), status codes (200, 201, 400, 401, 404), request/response bodies in JSON, and how clients interact with APIs.
What a Web Framework Is¶
Express.js runs underneath NestJS. Understanding why web frameworks exist — routing, middleware, request parsing, error handling — helps you appreciate what NestJS adds on top (modules, DI, decorators, guards).
Backend Design Patterns¶
This codebase uses Controller-Service architecture, dependency injection, and decorator-based metadata extensively. Knowing these patterns (and why they exist) makes the code structure intuitive rather than mysterious.
Authentication & Authorization¶
The project implements JWT-based authentication and role-based authorization. Understanding the difference between authentication ("who are you?") and authorization ("what can you do?"), how tokens work, and why passwords are hashed will make the auth and permissions modules much easier to follow.
2. Tech Stack¶
| Layer | Choice |
|---|---|
| Runtime | Node.js 20+, TypeScript (ES2023 target, nodenext modules) |
| Framework | NestJS 11 |
| ORM | Prisma 7.3 with PrismaPg adapter |
| Database | PostgreSQL (UUID PKs, JSONB for custom fields) |
| Auth | Passport.js + JWT (argon2 passwords) |
| Validation | class-validator + class-transformer |
| API docs | Swagger via @nestjs/swagger |
| Testing | Jest 30 + ts-jest (ESM mode) + Supertest |
| Linting | ESLint flat config (type-checked) + Prettier |
| Deployment | Railway (BE) + Cloudflare Workers (FE) |
How a request flows through the stack¶
┌──────────────────────────────────────────────────────────────────┐
│ A request arrives at POST /api/v1/students │
│ │
│ 1. Express receives the HTTP request │
│ 2. NestJS routes it to the right controller method │
│ 3. Passport.js validates the JWT token (is this user real?) │
│ 4. ScopeGuard checks permissions (can this user do this?) │
│ 5. class-validator validates the request body (is the data ok?) │
│ 6. Service runs business logic │
│ 7. Prisma talks to PostgreSQL (reads/writes data) │
│ 8. Interceptor filters response fields (hide sensitive data) │
│ 9. Express sends the JSON response back │
└──────────────────────────────────────────────────────────────────┘
| Technology | Role | Think of it as... |
|---|---|---|
| NestJS | Web framework | The skeleton of the app. Organizes code into modules, handles routing, dependency injection. |
| TypeScript | Language | JavaScript with types. Catches bugs at compile time. |
| Prisma | ORM | Translates between TypeScript objects and SQL queries. You write prisma.student.findMany(), it runs SELECT * FROM students. |
| PostgreSQL | Database | Where all data lives. Tables, rows, relationships. |
| Passport.js | Authentication library | Handles "who are you?" — validates passwords and JWT tokens. |
| class-validator | Validation library | Handles "is this input valid?" — checks DTOs with decorators like @IsEmail(). |
| Jest | Test framework | Runs your unit and e2e tests. |
| argon2 | Password hashing | Securely hashes passwords. Never store plain text passwords. |
3. Project Structure¶
Project follows standard NestJS structure.
src/
├── main.ts # Bootstrap, global pipes/filters, Swagger
├── app.module.ts # Root module — only imports, no logic
└── generated/prisma/ # Auto-generated — never edit
├── prisma/ # PrismaModule + PrismaService wrapper
├── common/ # Shared: interfaces, filters, exceptions, decorators, DTOs, services
├── auth/ # JWT + Passport (login/refresh/logout/me), cookie delivery
├── permissions/ # Entity-Scope model (guard + interceptor + decorator + controller)
├── logger/ # Pino structured logging (nestjs-pino + CLS context)
├── health/ # GET /api/v1/health (public — no auth)
├── students/ # Student CRUD (anagraphic + sensitive scopes)
├── teachers/ # Teacher CRUD (5 scopes) + import
├── staff/ # Staff CRUD (5 scopes) + import
├── users/ # User read-only (profile + admin scopes)
├── departments/ # Department + Grade CRUD (configuration scope, nested grades sub-resource)
├── rooms/ # Room CRUD (configuration scope, canteen lunch shifts)
├── custom-fields/ # Custom field definitions CRUD + validation (service-level permission checks)
├── curriculum/ # Curricula + study plans CRUD (also used by setup wizard)
├── setup/ # Tenant setup wizard (state machine, multi-step config)
├── ... # future domain modules
Each domain module encapsulates its controller, service, DTOs, interfaces, and tests. See docs/REFERENCE.md for module patterns and docs/architecture.md for full system design.
4. Local Setup¶
Setup¶
cp .env.example .env # DATABASE_URL already points at Docker Compose Postgres
docker compose up -d # Start local Postgres
npx prisma migrate dev # Apply all migrations + generate client
npm run start:dev # Start NestJS with hot reload
What's Running¶
- Postgres 17 via Docker Compose on
localhost:5432 - NestJS natively on
localhost:8080(not containerized — avoids slow volume mounts on Windows, preserves hot reload)
Convenience Scripts¶
| Script | What it does |
|---|---|
npm run docker:up |
Start Postgres container |
npm run docker:down |
Stop Postgres container |
npm run docker:reset |
Destroy volume + restart (wipes all data) |
npm run db:setup |
Start Postgres + run migrations |
Database Reset¶
To start fresh:
This destroys the Docker volume (all data), recreates the container, and re-applies all migrations.
5. Commands¶
npm run start:dev # Dev server with hot reload
npm run build # Prisma generate + NestJS build
npm run lint # ESLint with auto-fix
npm run format # Prettier
npm test # Unit tests (Jest)
npm run test:e2e # E2E tests (Supertest)
npm run test:cov # Coverage report
npx prisma generate # Regenerate client after schema changes
npx prisma migrate dev # Create + apply migrations
npx prisma db seed # Seed data (tenant, roles, users, permissions)
npx prisma studio # GUI for DB inspection
npm run docker:up # Start PostgreSQL via Docker
npm run docker:reset # Nuke volumes + restart with migration applied
6. Prisma Basics¶
- Schema:
prisma/schema.prisma— config:prisma.config.ts - Generated client:
src/generated/prisma/— never edit this directory - Import types: always use
import typeto avoid duplicating Prisma model types:
- After schema changes: run
npx prisma generateto update the client, thennpx prisma migrate devto create and apply the migration - Raw queries: use
prisma.$queryRawwith tagged template literals to prevent SQL injection:
Full Prisma migration workflow (dev vs. deploy, migration immutability, Railway pipeline): chapter 10