Files
2026-07-02 16:33:17 +03:30

164 lines
5.4 KiB
Markdown

# 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/<name>/` with a consistent internal structure:
```
modules/<feature>/
├── <feature>.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-form** — Print form sections and PDF generation
- **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)
```