Files
negareh-api/docs/coding-style.md
T
2026-07-02 15:59:46 +03:30

114 lines
4.5 KiB
Markdown

# 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 | `<feature>.module.ts` | `order.module.ts` |
| Controller | `<feature>.controller.ts` in `controllers/` | `order.controller.ts` |
| Service | `<feature>.service.ts` in `providers/` | `order.service.ts` |
| Repository | `<entity>.repository.ts` in `repositories/` | `order.repository.ts` |
| Entity | `<entity>.entity.ts` in `entities/` | `order.entity.ts` |
| DTO | `<action>-<entity>.dto.ts` in `dto/` | `create-order.dto.ts` |
| Event | `<Entity><Action>Event` in `events/` | `OrderCreatedEvent` |
| Listener | `<feature>.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<T>` 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.