add docs
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user