# Coding Style Conventions for writing and reviewing code in Negareh API. These align with the project's Cursor rules and existing patterns. ## TypeScript - **Strict typing** — Never use `any`. Prefer `unknown` when the type is genuinely unknown, then narrow. - **Exported functions** — Add explicit return types. - **Interfaces for DTOs** — Use classes with decorators for request bodies; interfaces for internal shapes and transformers. - **Enums** — Use only when a fixed set of values is shared across layers (e.g. `PermissionEnum`, status enums). Avoid enums for one-off string unions. - **Readonly** — Prefer `readonly` on constructor-injected dependencies and immutable fields. - **Function size** — Keep functions under ~40 lines when practical; extract private methods for clarity. ## NestJS patterns ### Dependency injection - Use **constructor injection** for all dependencies. - Register providers in the feature module; export only what other modules need. - Use `forwardRef()` when circular module dependencies are unavoidable (e.g. `AuthModule` ↔ `UserModule`). ### Controllers - Keep controllers **thin** — validate input, call service, return result. - Use `@ApiTags`, `@ApiOperation`, and `@ApiBearerAuth` for Swagger. - Apply guards at method level: `@UseGuards(AuthGuard)` or `@UseGuards(AdminAuthGuard)`. - Extract identity from decorators: `@UserId()`, `@AdminId()`. ### Services - All **business logic** belongs in services (`providers/`). - Throw NestJS `HttpException` subclasses (`BadRequestException`, `NotFoundException`, etc.). - Use `ConfigService` instead of `process.env`. ### DTOs Every request body and query object must have a DTO class: ```typescript import { IsNotEmpty, IsString } from 'class-validator'; import { ApiProperty } from '@nestjs/swagger'; import { Transform } from 'class-transformer'; export class ExampleDto { @IsNotEmpty() @IsString() @ApiProperty({ example: 'value' }) @Transform(({ value }) => value?.trim()) name: string; } ``` - Use `class-validator` decorators for validation. - Use `class-transformer` (`@Transform`) for normalization (e.g. phone numbers). - Document fields with `@ApiProperty` for Swagger. ## File and naming conventions | Artifact | Convention | Example | |----------|------------|---------| | Module | `.module.ts` | `order.module.ts` | | Controller | `.controller.ts` in `controllers/` | `order.controller.ts` | | Service | `.service.ts` in `providers/` | `order.service.ts` | | Repository | `.repository.ts` in `repositories/` | `order.repository.ts` | | Entity | `.entity.ts` in `entities/` | `order.entity.ts` | | DTO | `-.dto.ts` in `dto/` | `create-order.dto.ts` | | Event | `Event` in `events/` | `OrderCreatedEvent` | | Listener | `.listeners.ts` in `listeners/` | `order.listeners.ts` | - Use **kebab-case** for file names. - Use **PascalCase** for classes, **camelCase** for methods and variables. - Folder names: `controllers`, `providers`, `repositories`, `entities`, `dto`, `listeners`, `events`, `enum`. ## MikroORM usage - Prefer **EntityRepository** subclasses over raw `EntityManager` queries in services. - Use **`populate`** instead of manual joins. - Use **`wrap(entity).assign(dto)`** for partial updates. - Use **`em.transactional()`** when updating multiple entities atomically. - Use **`Collection`** for `OneToMany` relations. - Avoid **N+1** — batch loads and selective `populate`. - Avoid **raw SQL** unless necessary (triggers, complex reports). Migrations are the exception. - Type repository injections explicitly. ## Performance - Minimize database round-trips; batch where possible. - Paginate large lists — return `PaginatedResult` with `data` and `meta`. - Select only required columns; avoid loading full entity graphs when a subset suffices. - Index foreign keys and frequently filtered columns. ## Error handling - Use specific HTTP exceptions with clear messages. - Shared user-facing messages live in `src/common/enums/message.enum.ts`. - Do not swallow errors silently; log unexpected failures with NestJS `Logger`. ## Formatting and linting ```bash npm run format # Prettier npm run lint # ESLint (with fix) npm run build # TypeScript compile check ``` Match the style of surrounding code. Do not reformat unrelated files in the same change. ## Before adding new code 1. Search for an existing implementation in `src/modules/` and `src/common/`. 2. Reuse existing services, DTOs, and repositories. 3. Follow the module's existing folder layout. 4. Extend rather than duplicate.