# Architecture Negareh API is a NestJS backend built on **Fastify**, **PostgreSQL** (via MikroORM), and **Redis** (caching, OTP, queues). It powers both the customer-facing app and the admin console. ## Tech stack | Layer | Technology | |-------|------------| | Runtime | Node.js, TypeScript | | Framework | NestJS 11 | | HTTP server | Fastify (`@nestjs/platform-fastify`) | | ORM | MikroORM 6 (PostgreSQL driver) | | Auth | JWT + refresh tokens, OTP via SMS | | Cache / OTP | Redis (`@keyv/redis`, `CacheService`) | | Jobs | BullMQ (`@nestjs/bullmq`) | | Real-time | Socket.IO (notifications) | | File storage | AWS S3-compatible bucket | | Payments | Zarinpal gateway | | API docs | Swagger at `/docs` | ## High-level layout ``` src/ ├── main.ts # Bootstrap: Fastify, pipes, interceptors, CORS, Swagger ├── app.module.ts # Root module — wires all feature modules ├── config/ # MikroORM, cache, HTTP, Swagger ├── core/ # Cross-cutting: exceptions, interceptors, middlewares ├── common/ # Shared entities, decorators, enums, interfaces ├── modules/ # Feature modules (domain boundaries) └── seeders/ # Database seed data database/ └── migrations/ # Versioned schema changes (MikroORM migrations) ``` ## Feature modules Each domain lives under `src/modules//` with a consistent internal structure: ``` modules// ├── .module.ts ├── controllers/ # HTTP layer (thin) ├── providers/ # Business logic (services) ├── repositories/ # Data access (extends EntityRepository) ├── entities/ # MikroORM entities ├── dto/ # Request/response validation ├── listeners/ # Event handlers (@OnEvent) ├── events/ # Domain events (EventEmitter2) └── enum/ # Feature-specific enums ``` Current modules: - **auth** — OTP login, JWT, refresh tokens - **user** — End-user accounts and credit - **admin** — Admin accounts - **roles** — Roles and permissions (RBAC) - **product** — Products and categories - **form-builder** — Dynamic product fields and options - **request** — Customer requests / quotes - **invoice** — Invoicing - **order** — Order lifecycle - **payment** — Online payments (Zarinpal) - **print** — Print-related admin operations - **ticket** — Support tickets - **chat** — Order/chat messaging - **notification** — SMS, push, WebSocket notifications - **uploader** — File uploads to S3 - **announcements**, **learnings**, **criticisms** — Content and feedback - **util** — Shared utilities (cache, phone normalization) ## Request lifecycle 1. **Fastify** receives the HTTP request. 2. **ValidationPipe** validates and transforms DTOs (`class-validator` + `class-transformer`). 3. **Guards** enforce authentication (`AuthGuard`, `AdminAuthGuard`) and permissions (`@Permissions`). 4. **Controller** delegates to a **service**. 5. **Service** uses **repositories** and/or `EntityManager` for persistence. 6. **ResponseInterceptor** wraps successful responses in a standard envelope. 7. **HttpExceptionFilter** formats error responses. ## Cross-cutting concerns ### Response envelope Successful responses: ```json { "statusCode": 200, "success": true, "data": { } } ``` Paginated responses also include `meta`: ```json { "statusCode": 200, "success": true, "data": [], "meta": { "total": 100, "page": 1, "limit": 10, "totalPages": 10 } } ``` Errors: ```json { "statusCode": 400, "success": false, "error": { "message": ["..."] } } ``` ### Domain events Services emit events via `EventEmitter2`. Listeners in `listeners/` handle side effects (notifications, chat, payment follow-up) without bloating the main flow. ### Configuration Use `ConfigService` for all environment variables. `ConfigModule` is registered globally in `AppModule`. Never read `process.env` directly in application code. ### Rate limiting `@nestjs/throttler` is configured globally (5 requests per 60 seconds). Sensitive endpoints (OTP, refresh token) use stricter per-route limits via `@Throttle` or custom decorators. ## Design principles - **Thin controllers, fat services** — HTTP concerns stay in controllers; business rules live in services. - **Reuse before rewrite** — Search for existing services, DTOs, and repositories before adding new ones. - **Module boundaries** — Features communicate through exported services or domain events, not by reaching into another module's internals. - **No duplicated logic** — Extend existing modules rather than copying patterns. - **Transactions for multi-entity writes** — Use `em.transactional()` when several rows must commit or roll back together. ## External integrations | Integration | Purpose | |-------------|---------| | SMS.ir | OTP and transactional SMS | | Zarinpal | Payment gateway | | S3-compatible storage | File uploads | | Redis | OTP cache, general caching, BullMQ | ## Local development ```bash npm install npm run start:dev # Watch mode on APP_PORT (default 4000) ``` Swagger UI: `http://localhost:4000/docs` Database helpers (see [database.md](./database.md)): ```bash npm run migration:up # Apply pending migrations npm run db:seed # Run seeders npm run db:reset # Drop, create, migrate, seed (destructive) ```