# 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` |
