Uecko_ERP/docs/DTOS - GUIA DE ESTILO.md

151 lines
4.8 KiB
Markdown
Raw Normal View History

2025-06-24 18:38:57 +00:00
# Guía de estilo — DTOs y organización de carpetas
> **Objetivo:** asegurar que **todos** los equipos usen un vocabulario y una estructura de ficheros idéntica al modelar, versionar y serializar los *Data Transfer Objects* (DTO).
> Esta guía aplica a cualquier API HTTP/JSON implementada en Express + TypeScript que siga DDD, SOLID y CQRS.
---
## 1. Estructura de carpetas obligatoria
```text
src/
└─ <bounded-context>/ (ej. billing/)
└─ api/
└─ dto/
├─ common/ ← Tipos reutilizables (MoneyDTO, AddressDTO…)
├─ request/ ← Sólo comandos y queries
│ ├─ *.command.dto.ts
│ └─ *.query.dto.ts
└─ response/ ← Sólo resultados/vistas
├─ *.result.dto.ts
└─ *.view.dto.ts
```
*Alias TS recomendado*: `@<context>/dto/*``src/<context>/api/dto/*`.
---
## 2. Convención de nombres
| Categoría | Sufijo **obligatorio** | Descripción & ejemplos |
|-----------|------------------------|------------------------|
| **Comandos** (mutaciones) | `…CommandDTO` | `CreateInvoiceCommandDTO`, `UpdateInvoiceCommandDTO`, `DeleteInvoiceCommandDTO`, `ChangeInvoiceStatusCommandDTO` |
| **Queries** (lecturas con filtros) | `…QueryDTO` | `ListInvoicesQueryDTO`, `GetInvoiceByIdQueryDTO` |
| **Resultados** (respuesta de comandos) | `…ResultDTO` | `InvoiceCreationResultDTO`, `InvoiceDeletionResultDTO` |
| **Vistas** (respuesta de queries) | `…ViewDTO` | `InvoiceViewDTO`, `InvoiceSummaryViewDTO` |
| **Tipos comunes** | `…DTO` | `MoneyDTO`, `PaginationMetaDTO`, `AddressDTO` |
*Regla de oro:* **No existe ningún DTO sin sufijo, salvo los tipos comunes dentro de `common/`.**
---
## 3. Reglas de contenido
1. **Solo datos planos**: números, cadenas, literales, arrays; nada de lógica.
2. **Fechas** en ISO-8601 UTC (`yyyy-MM-dd'T'HH:mm:ss.SSS'Z'`).
3. **Enums** expuestos como _string literal_ en `snake_case` o `UPPER_SNAKE_CASE`; evita números mágicos.
4. **Moneda**
- **Siempre** con la estructura común:
```ts
export interface MoneyDTO {
amount: number | null; // unidades mínimas (ej. céntimos)
scale: number; // nº de decimales (2 = céntimos)
currency_code: string; // ISO-4217 (“EUR”)
}
```
- Se importa desde `dto/common/money.dto.ts`.
---
## 4. Guía de mapeo
| Dirección | Componente responsable | Ubicación |
|-----------|------------------------|-----------|
| **DTO → Dominio** | `…CommandMapper` / `…QueryMapper` | `src/<context>/application/mappers/` |
| **Dominio → DTO** | `…ResultMapper` / `…ViewMapper` | mismo directorio |
Cada mapper implementa **una** función pública:
```ts
interface InvoiceCreationResultMapper {
toResult(entity: Invoice): InvoiceCreationResultDTO;
}
```
---
## 5. Validación y versiones
1. **Validación de entrada**
- Usa `class-validator` o Zod en el *controller*; nunca en el dominio.
- Convierte a Value Objects una vez que el DTO pasó la validación.
2. **Versionado**
- Añade sufijos de versión en el **archivo**, no en el nombre de la interfaz:
`invoice.view.v2.dto.ts``export interface InvoiceViewV2DTO { … }`
- Mantén las versiones anteriores durante **≥1 release** o hasta que los consumidores migren.
---
## 6. Ejemplo completo (creación de factura)
```text
billing/
├─ api/
│ └─ dto/
│ ├─ input/create-invoice.command.dto.ts
│ ├─ output/invoice-creation.result.dto.ts
│ └─ common/money.dto.ts
└─ application/
└─ mappers/
└─ invoice-creation.result.mapper.ts
```
```ts
// create-invoice.command.dto.ts
export interface CreateInvoiceCommandDTO {
customerId: string;
issueDate: string;
lines: ReadonlyArray<{
description: string;
quantity: number;
unitPrice: MoneyDTO;
}>;
}
// invoice-creation.result.dto.ts
export interface InvoiceCreationResultDTO {
invoiceId: string;
number: string;
totalAmount: MoneyDTO;
createdAt: string;
}
```
---
## 7. Checklist antes de hacer *merge*
- [ ] Archivo ubicado en la carpeta correcta.
- [ ] Sufijo conforme (**CommandDTO**, **QueryDTO**, **ResultDTO**, **ViewDTO**).
- [ ] Todos los importes usan `MoneyDTO`.
- [ ] Tipos opcionales marcados con `?` y comentados.
- [ ] **Sin** lógica, constructores ni métodos.
- [ ] PR incluye al menos un test de mapper (input ⇄ dominio ⇄ output).
---
## 8. Tabla resumen
| Carpeta | Sufijo | Ejemplo clásico |
|---------|--------|-----------------|
| `dto/input/` | `CommandDTO` | `DeleteInvoiceCommandDTO` |
| `dto/input/` | `QueryDTO` | `ListInvoicesQueryDTO` |
| `dto/output/` | `ResultDTO` | `InvoiceDeletionResultDTO` |
| `dto/output/` | `ViewDTO` | `InvoiceSummaryViewDTO` |
| `dto/common/` | `DTO` | `MoneyDTO` |