4.5 KiB
4.5 KiB
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. Preferunknownwhen 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
readonlyon 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@ApiBearerAuthfor 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
HttpExceptionsubclasses (BadRequestException,NotFoundException, etc.). - Use
ConfigServiceinstead ofprocess.env.
DTOs
Every request body and query object must have a DTO class:
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-validatordecorators for validation. - Use
class-transformer(@Transform) for normalization (e.g. phone numbers). - Document fields with
@ApiPropertyfor 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
EntityManagerqueries in services. - Use
populateinstead of manual joins. - Use
wrap(entity).assign(dto)for partial updates. - Use
em.transactional()when updating multiple entities atomically. - Use
CollectionforOneToManyrelations. - 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>withdataandmeta. - 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
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
- Search for an existing implementation in
src/modules/andsrc/common/. - Reuse existing services, DTOs, and repositories.
- Follow the module's existing folder layout.
- Extend rather than duplicate.