---
url: /reference/ARCHITECTURE.md
---
# Arquitectura de la Aplicación Ninaku (`ARCHITECTURE.md`)

Estado: **Línea base arquitectónica normativa para ninaku-app-api**.

Este documento define la arquitectura de aplicación objetivo para Ninaku sobre **NestJS**. Conserva las fronteras de dominio y los contratos de base de datos validados en la línea base canónica de PostgreSQL, adaptando la estructura de la aplicación a TypeScript / NestJS.

El objetivo no es dividir Ninaku en microservicios, sino construir **una sola aplicación desplegable con fronteras internas fuertes**.

***

## 1. Estilo Arquitectónico

Ninaku es un **monolito modular** con Clean Architecture y DDD (Domain-Driven Design) pragmático por módulo.

* Una sola aplicación backend.
* Una sola unidad de despliegue por defecto.
* Una sola base de datos PostgreSQL de plataforma por defecto.
* Módulos de negocio explícitos con propiedad clara de datos y lógica.
* **Prohibido realizar llamadas HTTP internas** entre módulos dentro del mismo proceso.
* Sin "servicio Dios" compartido ni repositorios genéricos que abarquen todos los dominios.
* Los módulos colaboran exclusivamente a través de contratos públicos explícitos en proceso.
* Las verticales de producto componen capacidades reutilizables de la plataforma en lugar de duplicarlas.

```mermaid
flowchart TD
    R[Restaurante] --> B[Módulos compartidos]
    T[Retail] --> B
    H[Hospitalidad] --> B
    B --> C[Core de plataforma]
    B --> X[Servicios transversales]
    X --> C
    I[Integraciones opcionales] --> R
    I --> B
    I --> X
```

La dirección de dependencia es conceptual: las verticales consumen capacidades reutilizables; las capacidades reutilizables consumen el core de la plataforma y la infraestructura transversal. Una vertical nunca debe convertirse en una puerta trasera para mutar datos arbitrarios pertenecientes a otro módulo.

***

## 2. Modelo de Producto

Ninaku distingue explícitamente estos conceptos:

* **Organization**: Límite tenant / cliente.
* **Business Unit**: Subdivisión operativa y administrativa dentro de una organización.
* **Legal Entity**: Límite de propiedad legal y fiscal (RUC / RIF / NIF).
* **Brand**: Identidad comercial.
* **Site**: Grupo de ubicaciones físicas o lógicas.
* **Outlet**: Punto de venta u operación física/digital donde ocurre la actividad comercial.
* **Vertical**: Familia de capacidades funcionales de producto (Restaurante, Retail, Hospitalidad).

Una vertical **no** es un tenant, una Business Unit, una Legal Entity ni un Outlet.\
Una organización puede activar distintas verticales para diferentes Business Units. Esto es lo que permite que un grupo hotelero, por ejemplo, ejecute capacidades de hospitalidad y restaurante/alimentos en la misma plataforma Ninaku sin crear sistemas desconectados.

***

## 3. Principio Central: Un Hecho de Negocio, Un Dueño

Cada hecho de negocio relevante tiene **un único módulo propietario**:

* `sales` posee las ventas, líneas de venta, ciclo de vida de la orden y devoluciones.
* `payments` posee intenciones de pago, intentos, resultados, reversos y reembolsos.
* `cash` posee la custodia de efectivo, turnos/cajas, conteos y diferencias.
* `treasury` posee cuentas bancarias/wallets, liquidaciones, tipos de cambio y conciliación.
* `inventory` posee la custodia de mercancía, lotes, reservas, movimientos y conteos.
* `accounting` posee libros contables, solicitudes de contabilización y asientos.

Esto significa que:

* Ventas no es Pagos.
* Pagos no es Caja.
* Pagos no es Tesorería.
* Catálogo no es Inventario.
* Catálogo no es Producción.
* Impuestos no es Fiscal.
* Fiscal no es Facturación.
* Servicio de Restaurante no es Reservas Hoteleras.

Una acción del usuario puede desencadenar efectos en varios módulos, pero eso no fusiona la propiedad del dato ni rompe las fronteras de los agregados.

***

## 4. Disposición del Código Fuente en `src/`

El código fuente de la aplicación evoluciona hacia la siguiente disposición canónica de carpetas:

```text
src/
├── app/
│   └── app.module.ts
│
├── bootstrap/
│   ├── configure-http-application.ts
│   ├── create-application.ts
│   └── graceful-shutdown.ts
│
├── foundation/
│   ├── config/
│   ├── correlation/
│   ├── database/
│   ├── errors/
│   ├── events/
│   ├── http/
│   ├── idempotency/
│   ├── logging/
│   ├── tenancy/
│   ├── transactions/
│   └── validation/
│
├── modules/
│   ├── reference/
│   ├── organization/
│   ├── party/
│   ├── identity/
│   ├── platform/
│   ├── assets/
│   ├── catalog/
│   ├── pricing/
│   ├── commerce/
│   ├── sales/
│   ├── settlement/
│   ├── payments/
│   ├── inventory/
│   ├── production/
│   ├── procurement/
│   ├── crm/
│   ├── loyalty/
│   ├── receivables/
│   ├── payables/
│   ├── cash/
│   ├── treasury/
│   ├── tax/
│   ├── fiscal/
│   ├── invoicing/
│   ├── accounting/
│   ├── workforce/
│   ├── documents/
│   ├── printing/
│   ├── notifications/
│   ├── communications/
│   ├── integrations/
│   ├── events/
│   ├── sync/
│   ├── audit/
│   └── analytics/
│
├── verticals/
│   ├── restaurant/
│   │   ├── service/
│   │   └── kitchen/
│   ├── retail/
│   └── hospitality/
│
└── main.ts
```

Esta estructura representa el mapa objetivo. Una carpeta existe porque existe una responsabilidad en código, no para llenar diagramas vacíos.\
El directorio `bootstrap/` posee la secuencia de arranque: construir la aplicación NestJS, aplicar políticas HTTP y orquestar el apagado (*graceful shutdown*). `main.ts` permanece en la raíz de `src/` como el punto de entrada del proceso ejecutado por Node.js y nombrado en `package.json` y `.railway/railway.ts`.

***

## 5. Foundation contra Módulos de Negocio, y Módulos Ambient contra Capability

La carpeta `foundation/` contiene las capacidades técnicas transversales compartidas por toda la aplicación. **Nunca debe poseer conceptos de negocio** como ventas, restaurantes, inventario o contabilidad.

Las capacidades típicas de `foundation/` incluyen:

* Administrador de transacciones y contexto de tenant (`AsyncLocalStorage`).
* Conexión y ciclo de vida de la base de datos PostgreSQL.
* Traducción y catálogo de errores estandarizados (RFC 9457).
* Registro estructurado de logs y trazabilidad distribuida W3C / OpenTelemetry.
* Infraestructura de validación (Zod / Standard Schema) y filtros HTTP.
* Deduplicación e idempotencia de comandos.

### Clasificación de Módulos de Foundation

Los módulos de Foundation se dividen en dos categorías según su alcance:

1. **Módulos Ambientales (`@Global()`)**: Módulos ambientales globales que toda la aplicación requiere de fondo. Declarar una importación explícita solo reafirmaría lo que ya se asume:
   * `FoundationConfigModule`: Configuración tipada del entorno.
   * `LoggingModule`: Registro JSON estructurado y redacción de secretos.
   * `ObservabilityModule`: Correlación de peticiones y trazas.
2. **Módulos de Capacidad (`Capability Modules`, Importación Explícita)**: Módulos de infraestructura que un consumidor usa o no usa. Su inclusión debe ser visible en el arreglo `imports: [...]` de cada consumidor:
   * `DatabaseModule`: Fachadas transaccionales y salud de PostgreSQL.
   * `CollectionsModule`: Codificación y firma de cursores opacos.
   * `TelemetryModule`: Métricas HTTP.

*Razón del diseño*: La explicitud revela la propiedad. Si `DatabaseModule` fuera `@Global()`, no se podría saber qué módulos acceden a PostgreSQL leyendo sus importaciones. Las pruebas unitarias de los módulos de capacidad certifican que Nest rehusará resolver la dependencia si la importación explícita se omite.

***

## 6. Estructura Interna de un Módulo

Un módulo de negocio en `src/modules/<modulo>/` utiliza la siguiente estructura interna por capas:

```text
src/modules/identity/
├── domain/                  <-- Reglas de negocio puras y agregados
├── application/             <-- Casos de uso y puertos
│   └── ports/               <-- Interfases requeridas por la aplicación
├── infrastructure/          <-- Adaptadores de persistencia y servicios
├── presentation/            <-- Controladores HTTP, DTOs y catálogo de fallos
│   ├── controllers/
│   ├── dtos/
│   └── failures/
├── contracts/               <-- Superficie pública in-process para otros módulos
└── identity.module.ts
```

### Contenido y Responsabilidad por Carpeta:

1. **`domain/`**: Reglas puras de negocio, entidades, objetos de valor y eventos de dominio. No tiene dependencias con NestJS, HTTP, drivers de PostgreSQL, Zod u ORMs. Los nombres de carpetas y archivos responden al lenguaje ubicuo del dominio (ej. `identifier/`, `credentials/`), nunca a términos técnicos (`helpers/`, `types/`).
2. **`application/`**: Contiene los casos de uso (orquestación del workflow) y la carpeta `ports/`.
   * **`ports/`**: Define las interfaces que el módulo necesita de la infraestructura (ej. `PasswordHasherPort`, `IdentitySessionRepositoryPort`).
   * **Casos de uso**: Nombrados estrictamente con el patrón `<verb>-<subject>.use-case.ts` exponiendo un solo método `execute(...)`. Todo valor o hash requerido debe generarse antes de abrir la transacción SQL para evitar efectos secundarios ante reintentos por contención.
3. **`infrastructure/`**: Implementa los adaptadores técnicos para PostgreSQL, hashing, tokens JWT, mensajería y almacenamiento, satisfaciendo los puertos declarados en `application/ports/`.
4. **`presentation/`**: Adaptador para el protocolo HTTP.
   * **`controllers/`**: Controladores HTTP delgados. Validan la entrada con esquemas Zod, llaman a un solo caso de uso y proyectan el DTO. Cero `try/catch`.
   * **`dtos/`**: Esquemas Zod strictly configurados (`.strict()`) y tipos derivados (`z.infer`).
   * **`failures/`**: Catálogo `PublicFailure` del módulo, el mapeador `toPublicFailure` y el `NestInterceptor` que traduce las excepciones de dominio antes de que lleguen al `ProblemDetailsFilter` global. Es un interceptor y no un `ExceptionFilter` de módulo porque ese filtro sería terminal: al relanzar no alcanzaría al filtro global y todo fallo de dominio contestaría `500`.
5. **`contracts/`**: Superficie pública in-process que otros módulos pueden consumir. Define las clases abstractas e interfaces DTO del contrato.

***

## 7. Colaboración entre Módulos

Un módulo de negocio escribe y gestiona sus propios datos. Ningún módulo tiene permitido acceder directamente a los repositorios, modelos de base de datos o SQL de otro módulo.

```ts
// ❌ RECHAZADO: Acceso directo a repositorios ajenos
class ConfirmSaleUseCase {
  constructor(
    private readonly inventoryRepository: InventoryRepository,
    private readonly paymentRepository: PaymentRepository,
  ) {}
}

// ✅ PREFERIDO: Colaboración mediante Contratos Públicos
class ConfirmSaleUseCase {
  constructor(
    private readonly inventory: InventoryContract,
    private readonly payments: PaymentsContract,
  ) {}
}
```

La colaboración síncrona en proceso se realiza invocando métodos de la clase abstracta expuesta en `contracts/`. No existen llamadas HTTP internas entre módulos del mismo proceso.

***

## 8. Diseño de API

Las APIs de Ninaku se diseñan alrededor de tareas de negocio y flujos de pantalla, no reflejando tablas de base de datos.

```text
✅ Endpoints Orientados a Tareas:
POST /api/v1/sales/orders
POST /api/v1/sales/orders/{id}/confirm
POST /api/v1/inventory/transfers
POST /api/v1/inventory/transfers/{id}/dispatch
POST /api/v1/payments/intents
POST /api/v1/payments/{id}/capture
```

Se evita la creación de endpoints CRUD automáticos por tabla. Para la carga de pantallas complejas, un compositor de consultas de lectura puede combinar DTOs de lectura de múltiples contratos públicos en una sola respuesta, manteniendo las escrituras encapsuladas en casos de uso específicos.

***

## 9. Estrategia de Base de Datos

La base de datos canónica PostgreSQL bajo `database/` es un contrato de plataforma y no se regenera automáticamente desde modelos de la aplicación.

* **PostgreSQL 18** es la fuente de verdad inmutable para el esquema canónico.
* `ninaku_migrator` posee los permisos de administración para ejecutar migraciones y scripts DDL.
* `ninaku_runtime` es el rol exclusivo y restringido que utiliza la aplicación NestJS. Prohibido ejecutar la API como superusuario o propietario.
* **Row Level Security (RLS)** permanece activa en runtime para garantizar el aislamiento multi-tenant a nivel de motor SQL.
* El esquema SQL **no es propiedad de un ORM**. Las herramientas de la aplicación se adaptan al esquema PostgreSQL existente.

***

## 10. Transacciones entre Módulos

Cuando un caso de uso requiere atomicidad a través de múltiples propietarios de negocio (ej. confirmar una venta debe actualizar `sales`, reservar `inventory` e insertar en `outbox` atómicamente), la operación comparte una misma transacción PostgreSQL.

```mermaid
flowchart LR
    U[Confirm Sale Use Case] --> TX[Transacción Compartida PostgreSQL]
    TX --> S[Escrituras de Sales]
    TX --> I[Escrituras de Inventory]
    TX --> O[Escritura en Outbox]
```

### Reglas de Transacciones:

1. La transacción la abre `Foundation` mediante `TenantTransactionRunnerService`.
2. Los módulos participantes reciben un contexto de transacción opaco (`TransactionContext`).
3. Ningún contrato expone `pg.PoolClient` ni manipuladores SQL crudos hacia el caso de uso.
4. Las llamadas a red o servicios externos **nunca** se ejecutan dentro de la transacción SQL; utilizan el patrón Outbox/Inbox para garantizar reintentos e idempotencia.

***

## 11. Idempotencia y Concurrencia

La idempotencia es obligatoria en comandos donde la ejecución repetida produciría efectos duplicados (confirmar venta, cobrar, despachar stock, reconciliar pago, replay offline).

### Mecanismos de Concurrencia por Invariante:

* **ETags / `If-Match`**: Para edición concurrente de borradores y configuraciones (optimistic locking).
* **Bloqueo Pesimista (`FOR UPDATE`)**: Para reservas de stock y consumo de saldos finitos.
* **Transiciones Condicionales de Estado**: Para confirmaciones y cierres.
* **Restricciones `UNIQUE` en PostgreSQL**: Para garantizar unicidad de efectos atómicos mediante `resolveIdempotentClaim`.

Prohibido el uso de mutexes en memoria como garantía distribuida entre réplicas.

***

## 12. Comportamiento Offline-First y Sincronización

La ejecución offline y online convergen exactamente en el mismo caso de uso de la aplicación NestJS.

```mermaid
flowchart LR
    ON[Petición Online] --> UC[Caso de Uso en Application]
    OFF[Replay Offline] --> UC
    UC --> D[Reglas de Dominio]
    UC --> DB[(PostgreSQL 18)]
```

El cliente local (dispositivo móvil/escritorio) guarda atómicamente el comando y su estado local en SQLite. Al reconectar, envía el comando usando un `commandId` e `Idempotency-Key` estables. El módulo `sync` administra el transporte y el ordenamiento de mensajes, pero **no duplica ni reimplementa las reglas de negocio** de `sales`, `inventory` o `payments`.

***

## 13. Verticales

Las verticales contienen capacidades de producto específicas para una familia funcional:

* **Restaurant**: Áreas de atención, mesas, sesiones de servicio, comandas y estaciones de cocina (`kitchen`).
* **Hospitality**: Propiedades, tipos de habitación, reservas de hospedaje, estadías, folios y housekeeping.
* **Retail**: Catálogo comercial extendido, código de barras, variantes y atención directa de caja sin mesa ni cocina.

Las verticales son consumidoras de los módulos compartidos (`catalog`, `sales`, `payments`, `inventory`, `printing`). La cocina o las mesas de restaurante no son infraestructura universal del core.

***

## 14. Ejemplo de Composición Multi-Negocio

Una sola organización puede operar múltiples modelos de negocio bajo el mismo tenant:

```text
Organization (Tenant)
├── Business Unit: Hospedaje (Hospitality)
│   └── Operaciones del Hotel
└── Business Unit: Alimentos y Bebidas (Food & Beverage)
    ├── Restaurante
    ├── Bar
    └── Room Service
```

Cada Business Unit activa únicamente las verticales que requiere, compartiendo el mismo tenant, catálogo base, entidades legales y tesorería sin contaminar el código con condicionales `if (vertical === 'restaurant')`.

***

## 15. Módulos Transversales

Los módulos transversales (`events`, `sync`, `audit`, `analytics`, `printing`, `notifications`, `communications`, `integrations`) deben permanecer desacoplados.

* No convierten a todos los módulos de negocio en dependencias obligatorias.
* Utilizan adaptadores y puentes tipados cuando dos módulos necesitan colaborar (ej. un puente `restaurant-printing` que conecta eventos de cocina con el servicio de impresión).
* Prohibido crear tablas o servicios polimórficos universales que permitan mutar cualquier tabla del sistema.

***

## 16. Orden Inicial de Implementación

Antes de desarrollar funciones comerciales o de verticales, se establece la fundación de la aplicación y sus límites modulares en este orden:

1. Configuración tipada y arranque de aplicación.
2. Conexión a PostgreSQL runtime con rol `ninaku_runtime`.
3. Propagación de contexto de petición y tenant RLS (`AsyncLocalStorage`).
4. Abstracción del administrador de transacciones (`TenantTransactionRunnerService`).
5. Contrato HTTP de error RFC 9457 y filtro de excepciones.
6. Infraestructura de idempotencia (`resolveIdempotentClaim`).
7. Infraestructura de eventos de integración y Outbox.
8. Convención y reglas de linter para contratos públicos de módulo (`MODULE_CONTRACTS.md`).
9. Módulos de topología (`organization`, `platform`).
10. Módulo `identity` (autenticación, sesiones, membresías).
11. Onboarding de organizaciones.
12. Módulos comerciales compartidos (`catalog`, `pricing`, `sales`, `payments`, `inventory`).
13. Módulos de verticales (`restaurant`, `retail`, `hospitality`).

***

## 17. No-Objetivos

La arquitectura de Ninaku **NO** requiere ni busca:

* Un microservicio por cada módulo.
* Una base de datos independiente por cada módulo.
* Una aplicación NestJS independiente por vertical.
* Comunicación HTTP o RPC interna entre módulos dentro del mismo proceso.
* Un esquema de base de datos generado o administrado por un ORM.
* APIs CRUD genéricas orientadas a tablas.
* Duplicar capacidades de la plataforma dentro de cada vertical.

***

## 18. Regla Práctica de Arquitectura

Ante cualquier duda sobre la ubicación o diseño de una pieza de código, responde a estas 5 preguntas:

1. **¿Quién es el dueño inmutable de este hecho de negocio?**
2. **¿Es este concepto reutilizable entre verticales o genuinamente específico de una vertical?**
3. **¿Necesita este módulo un contrato público explícito en `contracts/`, o estoy accediendo a la infraestructura interna de otro módulo?**
4. **¿Pertenece esta regla al Dominio (`domain/`), la orquestación a Aplicación (`application/`), la traducción a Presentación (`presentation/`) o el adaptador a Infraestructura (`infrastructure/`)?**
5. **¿Preserva esta operación el aislamiento multi-tenant, la idempotencia y las garantías transaccionales?**

Si la propiedad no es clara, no la ocultes en `common/` o `shared/`. Resuelve primero la frontera del dominio.
