94 lines
5.3 KiB
Markdown
94 lines
5.3 KiB
Markdown
📌 CONTEXTO DEL PROYECTO:
|
|
Estoy desarrollando una API en **Node.js** con **TypeScript**, **Express.js**, **Sequelize**, y **Arquitectura Hexagonal (Ports & Adapters)** bajo los principios de **DDD (Domain-Driven Design)** y **SOLID**.
|
|
Este módulo es para **facturas de cliente (Customer Invoices)** y debe cumplir con los estándares definidos previamente para el contexto de autenticación, adaptados a los datos, reglas y operaciones de las facturas.
|
|
|
|
📌 PRINCIPIOS Y PATRONES A APLICAR:
|
|
✅ **DDD (Domain-Driven Design)**
|
|
- Las **facturas** serán agregados raíz (`CustomerInvoice`) con propiedades como `id`, `customerId`, `invoiceNumber`, `date`, `lines`, `totals`, etc.
|
|
- Las **líneas de factura** (`InvoiceLine`) se modelan como entidades o value objects dentro del agregado.
|
|
- Se usará un `Mapper` para convertir entre dominio y persistencia.
|
|
- Repositorios (`ICustomerInvoiceRepository`) solo manejan agregados.
|
|
- Operaciones como `createInvoice`, `updateInvoice`, `getInvoiceById` serán gestionadas en `CustomerInvoiceApplicationService`.
|
|
|
|
✅ **SOLID**
|
|
- Usar SRP: cada clase con una responsabilidad clara.
|
|
- Usar interfaces como `ICustomerInvoiceRepository`, `ITransactionManager`, `IInvoicePresenter`.
|
|
- Evitar acoplamientos entre capa de aplicación y capa de infraestructura.
|
|
- Controladores deben transformar los datos en DTOs antes de enviarlos.
|
|
|
|
📌 ESTRUCTURA DE DATOS:
|
|
|
|
La entidad `CustomerInvoice` tendrá:
|
|
- `id`: UUID (ValueObject `UniqueID`)
|
|
- `status`: string (ValueObject) (`Draft`, `Issued`, `Sent`, `Rejected`)
|
|
- `invoiceNumber`: string (ValueObject )
|
|
- `invoiceSeries`: string (ValueObject )
|
|
- `customerId`: UUID (ValueObject)
|
|
- `issueDate`: UtcDate (ValueObject)
|
|
- `operationDate`: UtcDate (ValueObject)
|
|
- `lines`: array de `InvoiceLine`, cada una con:
|
|
- `productId`: (Optional) UUID (ValueObject `UniqueID`)
|
|
- `description`: string (ValueObject)
|
|
- `quantity`: Amount (number) and scale (number) (ValueObject Quantity)
|
|
- `unitPrice`: Amount (number), scale (number) and currency (string) (ValueObject MoneyValue)
|
|
- `totalLineAmount`: Amount (number), scale (number) and currency (string) (ValueObject MoneyValue)
|
|
- `subtotalPrice`: Amount (number), scale (number) and currency (string) (ValueObject MoneyValue)
|
|
- `discount`: Amount (number) and scale (number) (ValueObject Percentage)
|
|
- `tax`: Amount (number) and scale (number) (ValueObject Percentage)
|
|
- `totalAmount`: Amount (number), scale (number) and currency (string) (ValueObject MoneyValue)
|
|
|
|
|
|
📌 OPERACIONES PRINCIPALES:
|
|
- `createInvoice(data: CreateCustomerInvoiceDTO)`
|
|
- `getInvoiceById(id: string)`
|
|
- `updateInvoice(id: string, changes: UpdateCustomerInvoiceDTO)`
|
|
- `listInvoices(filter?)`
|
|
- `deleteInvoice(id: string)`
|
|
- `markAsPaid(id: string)`
|
|
|
|
📌 VALIDACIONES:
|
|
✅ Usar `Zod` para validaciones en Value Objects (`InvoiceNumber`, `InvoiceDate`, `InvoiceLine`).
|
|
✅ No se deben lanzar excepciones para errores de validación. Usar `Result<T, E>` como en autenticación.
|
|
|
|
📌 PRESENTACIÓN:
|
|
✅ Los controladores convierten el agregado `CustomerInvoice` a `CustomerInvoiceDTO`.
|
|
✅ Se usan `Presenters` (`CustomerInvoicePresenter`) para construir los DTOs.
|
|
✅ DTOs solo exponen campos necesarios: nada sensible, nada interno.
|
|
✅ Se puede extender con `CsvInvoicePresenter`, `PdfInvoicePresenter`, etc.
|
|
|
|
📌 AUTORIZACIÓN Y ACCESO:
|
|
✅ Se protegerán rutas con middleware JWT (`authenticateJWT`).
|
|
✅ Se validará que el usuario autenticado pueda acceder/modificar la factura (p. ej. pertenece a su empresa).
|
|
|
|
📌 PERSISTENCIA:
|
|
✅ `SequelizeCustomerInvoiceRepository` no accede directamente al modelo de Sequelize, lo hace a través de `Mapper`.
|
|
✅ La clase `CustomerInvoiceMapper` mapea de/agregado <-> persistencia.
|
|
✅ Soporta transacciones Sequelize (`TransactionManager.complete(...)`).
|
|
✅ Los nombres de los campos y las tablas en la base de datos seguirán la notación "snake_case".
|
|
✅ Los nombres de los campos en los modelos Sequelize seguirán la notación "snake_case".
|
|
✅ Los modelos Sequelize de los agregados tienen campos 'timestamp' con los nombres "created_at", "updated_at" y "deleted_at".
|
|
|
|
|
|
📌 ERRORES:
|
|
✅ Usar `ApiError` para errores en la API.
|
|
✅ Los repositorios deben capturar errores de Sequelize (`UniqueConstraintError`, etc.) y convertirlos a errores de dominio con mensajes claros y específicos (mediante `errorMapper`).
|
|
|
|
📌 TESTING:
|
|
✅ Los servicios (`CustomerInvoiceApplicationService`) serán testeados con mocks de repositorio.
|
|
✅ Las rutas serán testeadas con `supertest`.
|
|
✅ Las validaciones de ValueObjects tendrán pruebas unitarias.
|
|
|
|
📌 NOMENCLATURA:
|
|
- Agregado: `CustomerInvoice`
|
|
- Línea: `CustomerInvoiceLine`
|
|
- DTOs: `CustomerInvoiceDTO`, `InvoiceLineDTO`
|
|
- Presentadores: `CustomerInvoicePresenter`
|
|
- Repositorio: `ICustomerInvoiceRepository`, `SequelizeCustomerInvoiceRepository`
|
|
- ValueObjects: `CustomerInvoiceNumber`, `CustomerInvoiceDate`, `CustomerInvoiceTotal`, `CustomerInvoiceItemQuantity`, etc.
|
|
|
|
⚠️ IMPORTANTE:
|
|
- NO incluir `passwords`, `tokens`, o datos sensibles en respuestas.
|
|
- NO usar Sequelize directamente en servicios ni controladores.
|
|
- NO devolver el agregado como respuesta bruta. Usar DTOs.
|
|
- TODO debe estar tipado, incluso los métodos de los servicios (`Promise<Result<T, Error>>`).
|