2. ARQUITECTURA GENERAL DEL SISTEMA

🎯 Enfoque Arquitectónico: Domain-Driven Design (DDD)

Este sistema está fundamentado en los principios de Domain-Driven Design (DDD) combinado con Arquitectura Hexagonal (Puertos y Adaptadores). Cada microservicio representa un Bounded Context del dominio bancario, con su propio modelo de dominio, lenguaje ubicuo y reglas de negocio encapsuladas.

Principio fundamental: El dominio de negocio está en el centro, completamente aislado de detalles técnicos de infraestructura mediante puertos y adaptadores.

2.1 Vista de Contexto

El sistema bancario BP permite a los usuarios gestionar sus finanzas mediante aplicaciones web (SPA) y móvil, con las siguientes capacidades principales:

2.2 Contextos Delimitados (Bounded Contexts) - DDD

🔷 ¿Qué es un Bounded Context?

En DDD, un Bounded Context es una frontera explícita dentro de la cual un modelo de dominio específico es válido. Cada contexto tiene su propio lenguaje ubicuo (Ubiquitous Language) y sus propias reglas de negocio.

En nuestro sistema bancario, identificamos 3 Bounded Contexts principales:

Bounded Context Responsabilidad de Dominio Entidades Principales Lenguaje Ubicuo
Context: Históricos Gestión de consultas y reportes de transacciones históricas Transaction, AccountStatement, MovementFilter Movimiento, Saldo, Período, Filtro
Context: Transferencias Ejecución de transferencias bancarias con consistencia transaccional Transfer, Account, TransferSaga, Compensation Transferencia, Débito, Crédito, Compensación
Context: Autenticación Control de acceso, identidad y autorización de usuarios User, Session, BiometricCredential, Token Usuario, Sesión, Credencial, Autenticación
Nota DDD: Cada Bounded Context se implementa como un microservicio independiente con su propia base de datos, garantizando la autonomía del dominio y evitando el acoplamiento de modelos.

2.3 Arquitectura Hexagonal (Puertos y Adaptadores)

⬡ Arquitectura Hexagonal en cada Microservicio

Cada Bounded Context (microservicio) sigue la Arquitectura Hexagonal, que separa el dominio de negocio de los detalles de infraestructura mediante:

🔹 Capa de Dominio (Core)

Responsabilidad: Lógica de negocio pura, independiente de frameworks y tecnología.

Componentes:

🔹 Puertos (Interfaces)

Responsabilidad: Contratos que definen cómo el dominio se comunica con el exterior.

Tipos de Puertos:

🔹 Adaptadores

Responsabilidad: Implementaciones concretas de los puertos, conectando el dominio con tecnologías específicas.

Tipos de Adaptadores:

✓ Beneficios de Arquitectura Hexagonal:

2.4 Diagrama de Contexto

Arquitectura de Alto Nivel (Bounded Contexts + Hexagonal)
flowchart TD
  Users["USUARIOS FINALES"]
  WebSPA["SPA Web (ReactJS)
[Adaptador: UI]"] MobileApp["App Móvil (React Native)
[Adaptador: UI]"] WAF["WAF (Cloudflare/AWS) - DDoS Protection - Bot Protection - OWASP Top 10"] Gateway["APOLLO GATEWAY
.GraphQL Federation
.Puerto de Entrada Principal
"] subgraph BC1["🔷 BOUNDED CONTEXT: HISTÓRICOS"] MS1["Microservicio Históricos [Arquitectura Hexagonal] • Dominio: Transactions • Puertos: Queries • Adaptadores: GraphQL, MongoDB"] end subgraph BC2["🔷 BOUNDED CONTEXT: TRANSFERENCIAS"] MS2["Microservicio Transferencias [Arquitectura Hexagonal] • Dominio: Transfers + SAGA • Puertos: Commands • Adaptadores: GraphQL, PostgreSQL, Kafka"] end subgraph BC3["🔷 BOUNDED CONTEXT: AUTENTICACIÓN"] MS3["Microservicio Autenticación [Arquitectura Hexagonal] • Dominio: Identity • Puertos: AuthService • Adaptadores: REST, OAuth 2.0"] end Kafka["KAFKA MESSAGE BUS [Adaptador de Comunicación] Topics: SAGA, Domain Events, Logs"] Users --> WebSPA & MobileApp WebSPA & MobileApp -->|HTTPS/TLS 1.3| WAF WAF --> Gateway Gateway --> MS1 & MS2 & MS3 MS1 & MS2 & MS3 --> Kafka classDef default fill:#f9f9f9,stroke:#333,stroke-width:2px; classDef gateway fill:#e1f3d8,stroke:#82c91e; classDef services fill:#d0ebff,stroke:#339af0; classDef messaging fill:#fff3bf,stroke:#f59f00; class WAF,Gateway gateway; class MS1,MS2,MS3 services; class Kafka messaging;

2.5 Justificación de Decisiones Arquitectónicas

1. Domain-Driven Design (DDD)

Decisión: Adoptar DDD como filosofía de diseño principal

Justificación:

2. Arquitectura Hexagonal (Puertos y Adaptadores)

Decisión: Implementar arquitectura hexagonal en cada microservicio

Justificación:

3. WAF (Web Application Firewall)

Decisión: Cloudflare WAF o AWS WAF como primera línea de defensa

Justificación:

4. Apollo Gateway con GraphQL Federation

Decisión: Punto único de entrada con GraphQL como protocolo principal (95%)

Justificación:

5. Microservicios por Bounded Context

Decisión: Cada Bounded Context es un microservicio independiente

Justificación:

2.6 Componentes Principales del Sistema

Componente Tecnología Propósito Justificación
Frontend Web React 18+ SPA Interfaz de usuario web Ecosistema maduro, reutilización de componentes con móvil
Frontend Móvil React Native 0.73+ Apps iOS/Android Compartir código con web, menor time-to-market
API Gateway Apollo Gateway Punto de entrada único GraphQL Federation, mejor que REST tradicional
Microservicios Node.js + GraphQL Lógica de negocio (Dominio DDD) Worker Threads para paralelismo, GraphQL eficiente
Message Bus Apache Kafka Comunicación asíncrona entre contexts Alta throughput, durabilidad, ideal para SAGA y Domain Events
Orquestador Kubernetes Gestión de contenedores Autoescalado, self-healing, standard de industria
Bases de Datos PostgreSQL + MongoDB Persistencia (Database per Service) CQRS: PostgreSQL para escritura, MongoDB para lectura
Caché Redis Caché + Sesiones + SAGA State Performance, estado temporal de SAGAs
Observabilidad ELK + Prometheus Logs + Métricas Stack estándar, integración con K8s

2.7 Flujo de Datos Principal

Flujo de Request Típico (Arquitectura Hexagonal)
sequenceDiagram
  actor U as Usuario (App)
  participant A as Adaptador UI
  participant W as WAF
  participant AG as Apollo Gateway (Puerto)
  participant GR as GraphQL Resolver (Adaptador Entrada)
  participant UC as Use Case (Puerto Entrada)
  participant DS as Domain Service (Dominio)
  participant RP as Repository Port (Puerto Salida)
  participant DB as DB Adapter (Adaptador Salida)
  participant Cache as Redis Cache

  U->>A: Solicita movimientos
  A->>W: GraphQL Query (HTTPS)
  Note over W: Valida seguridad
  
  W->>AG: ✓ Request limpia
  Note over AG: Puerto de entrada principal
Valida JWT AG->>GR: Enruta query Note over GR: Adaptador de entrada GraphQL GR->>UC: Ejecuta caso de uso Note over UC: Puerto de entrada
GetAccountMovements UC->>DS: Aplica lógica dominio Note over DS: DOMINIO PURO
Reglas de negocio DS->>RP: Solicita datos Note over RP: Puerto de salida
TransactionRepository interface RP->>Cache: Intenta cache Cache-->>RP: Cache miss RP->>DB: Query BD Note over DB: Adaptador MongoDB
Implementa Repository Port DB-->>RP: Retorna datos RP-->>DS: Entities de dominio DS-->>UC: Datos procesados UC-->>GR: DTO de salida GR-->>AG: GraphQL response AG-->>W: Datos optimizados W-->>A: 4 KB vs 11 KB REST A-->>U: Renderiza UI Note over U: 120ms vs 350ms latencia
Nota Arquitectónica: Observa cómo el flujo pasa por capas bien definidas:

2.8 Principios Arquitectónicos

2.8.1 Principios Fundamentales DDD

  1. Ubiquitous Language (Lenguaje Ubicuo):

    El código usa exactamente los mismos términos que los expertos del dominio. No hay traducción entre negocio y técnico: "Transfer", "Account", "Compensation" son nombres tanto en el código como en las conversaciones de negocio.

  2. Bounded Contexts Independientes:

    Cada contexto (Históricos, Transferencias, Autenticación) tiene su propio modelo y no comparte entidades con otros contextos. La comunicación es via Domain Events.

  3. Domain at the Core (Dominio en el Centro):

    La lógica de negocio está completamente aislada de frameworks, bases de datos, y APIs. El dominio no conoce GraphQL, ni PostgreSQL, ni Kafka.

  4. Agregados con Raíz:

    Conjuntos de entidades relacionadas se agrupan en Agregados con una raíz que garantiza la consistencia. Ejemplo: TransferAggregate controla Transfer + TransferLine.

  5. Domain Events:

    Los hechos importantes del dominio se modelan como eventos: TransferCompleted, AccountDebited, CompensationTriggered. Facilitan comunicación entre contextos.

2.8.2 Principios de Arquitectura Hexagonal

  1. Dependency Inversion:

    El dominio define interfaces (puertos), y la infraestructura las implementa (adaptadores). Nunca al revés. El dominio no depende de nadie.

  2. Ports and Adapters:

    Toda comunicación con el exterior se hace mediante puertos (interfaces) y adaptadores (implementaciones). Podemos cambiar de GraphQL a gRPC sin tocar el dominio.

  3. Testabilidad Total:

    El dominio se testea con mocks de puertos, sin necesidad de levantar bases de datos o servidores. Tests rápidos y confiables.

2.8.3 Otros Principios Arquitectónicos

  1. API First con GraphQL:

    Diseñar APIs antes de implementar, con GraphQL como protocolo principal para máxima eficiencia.

  2. Idempotencia:

    Todas las operaciones críticas son idempotentes (pueden ejecutarse múltiples veces sin efectos adversos).

  3. Observabilidad desde el Diseño:

    Logs estructurados, métricas y traces implementados desde el primer día.

  4. Security by Design:

    Seguridad integrada en cada capa, no agregada después.

  5. Fail Fast, Recover Faster:

    Detectar fallos rápidamente y recuperarse automáticamente.

2.8.4 Patrones Arquitectónicos Utilizados

Patrón Aplicación Beneficio
Bounded Context División del sistema en contextos Modelos de dominio independientes y mantenibles
Hexagonal Architecture Estructura interna de microservicios Dominio aislado de tecnología
CQRS Separación lectura/escritura Optimización de performance en consultas
SAGA Transacciones distribuidas Consistencia eventual con compensación
Event Sourcing Auditoría y sincronización Trazabilidad completa, replay de eventos
Domain Events Comunicación entre Bounded Contexts Desacoplamiento total entre contextos
Circuit Breaker Llamadas entre servicios Previene cascading failures
Bulkhead Aislamiento de recursos Fallo de un tipo de operación no afecta otros
API Gateway Punto de entrada único Seguridad centralizada, routing inteligente
Database per Service Cada microservicio su BD Independencia total, escalabilidad

2.9 Capas de la Arquitectura (Visión Macro)

Capa Responsabilidad Principal Tecnologías Clave Flujo / Interacciones
Capa 1: Presentación 🖼️ Interfaz con la que interactúa el usuario final (Cliente Web/Móvil). [Adaptador de UI] React, React Native, Apollo Client Envía peticiones del usuario hacia el API Gateway.
Capa 2: API Gateway 🚪 Punto de entrada único que gestiona la seguridad y el enrutamiento. [Puerto Principal] Apollo Gateway, Kong, NGINX Recibe peticiones de la Capa 1 y las dirige a los servicios correspondientes.
Capa 3: Bounded Contexts 🧠 Microservicios con arquitectura hexagonal. Contienen dominio + puertos + adaptadores. [Microservicios DDD] Microservicios en Node.js Recibe peticiones del API Gateway y utiliza las capas de Mensajería y Persistencia.
Capa 4: Mensajería 📨 Gestiona comunicación asíncrona y Domain Events entre Bounded Contexts. [Adaptador de Comunicación] Apache Kafka Es utilizada por los Bounded Contexts para publicar/consumir Domain Events.
Capa 5: Persistencia 💾 Almacenamiento y recuperación de datos. Cada contexto tiene su propia BD. [Adaptadores de BD] PostgreSQL, MongoDB, Redis Provee los datos que los Domain Services necesitan para operar.
Capa 6: Infraestructura 🏗️ Orquesta y ejecuta todos los servicios del backend en contenedores. Kubernetes, Docker Es la base sobre la que se despliegan y operan las capas 3, 4 y 5.
Capa Transversal: Observabilidad 📊 Monitorea la salud y el rendimiento de todo el sistema. Prometheus, Grafana, ELK Stack Recopila métricas y logs de todas las demás capas para análisis y alertas.

2.10 Estructura de un Microservicio (Ejemplo: Transferencias)

⬡ Anatomía de un Bounded Context con Arquitectura Hexagonal

Cada microservicio sigue esta estructura de carpetas que refleja las capas hexagonales:

ms-transferencias/
├── src/
│   ├── domain/                    # 🟦 CAPA DE DOMINIO (Centro del Hexágono)
│   │   ├── entities/              # Entidades con identidad
│   │   │   ├── Transfer.ts        # Entidad Transfer
│   │   │   ├── Account.ts         # Entidad Account
│   │   │   └── TransferLine.ts
│   │   ├── value-objects/         # Objetos de valor inmutables
│   │   │   ├── Money.ts
│   │   │   ├── AccountNumber.ts
│   │   │   └── TransferId.ts
│   │   ├── aggregates/            # Raíces de agregado
│   │   │   └── TransferAggregate.ts
│   │   ├── events/                # Domain Events
│   │   │   ├── TransferCreated.ts
│   │   │   ├── TransferCompleted.ts
│   │   │   └── CompensationTriggered.ts
│   │   ├── services/              # Domain Services
│   │   │   ├── TransferValidator.ts
│   │   │   └── CompensationService.ts
│   │   └── exceptions/            # Excepciones de dominio
│   │       └── InsufficientFundsError.ts
│   │
│   ├── application/               # 🟩 PUERTOS (Casos de Uso)
│   │   ├── ports/
│   │   │   ├── in/               # Puertos de Entrada (Driving)
│   │   │   │   ├── CreateTransferUseCase.ts
│   │   │   │   ├── CancelTransferUseCase.ts
│   │   │   │   └── GetTransferStatusUseCase.ts
│   │   │   └── out/              # Puertos de Salida (Driven)
│   │   │       ├── TransferRepository.ts      # Interface
│   │   │       ├── AccountRepository.ts       # Interface
│   │   │       ├── EventPublisher.ts          # Interface
│   │   │       └── SagaStateRepository.ts     # Interface
│   │   ├── dto/                  # 📦 DTOs (Data Transfer Objects)
│   │   │   ├── CreateTransferDto.ts          # Input DTO
│   │   │   ├── TransferResponseDto.ts        # Output DTO
│   │   │   ├── CancelTransferDto.ts
│   │   │   └── TransferStatusDto.ts
│   │   ├── mappers/              # Mappers: DTO ↔ Domain Entity
│   │   │   ├── TransferMapper.ts
│   │   │   └── AccountMapper.ts
│   │   └── usecases/             # Implementación de casos de uso
│   │       ├── CreateTransferUseCaseImpl.ts
│   │       └── CancelTransferUseCaseImpl.ts
│   │
│   ├── infrastructure/            # 🟨 ADAPTADORES
│   │   ├── adapters/
│   │   │   ├── in/               # Adaptadores de Entrada
│   │   │   │   ├── graphql/
│   │   │   │   │   ├── TransferResolver.ts
│   │   │   │   │   └── schema.graphql
│   │   │   │   └── kafka/
│   │   │   │       └── TransferEventConsumer.ts
│   │   │   └── out/              # Adaptadores de Salida
│   │   │       ├── postgres/
│   │   │       │   └── PostgresTransferRepository.ts
│   │   │       ├── kafka/
│   │   │       │   └── KafkaEventPublisher.ts
│   │   │       └── redis/
│   │   │           └── RedisSagaStateRepository.ts
│   │   ├── config/               # Configuración
│   │   │   ├── database.ts
│   │   │   └── kafka.ts
│   │   └── migrations/           # Migraciones de BD
│   │
│   └── shared/                   # Código compartido
│       ├── utils/
│       └── types/
│
├── tests/
│   ├── unit/                     # Tests del dominio (puros)
│   ├── integration/              # Tests de adaptadores
│   └── e2e/                      # Tests end-to-end
│
└── package.json
📦 Sobre los DTOs (Data Transfer Objects):

Los DTOs son objetos simples que transfieren datos entre capas. Son cruciales en arquitectura hexagonal porque:

Flujo típico: GraphQL Request → DTO → Mapper → Domain Entity → Use Case → Domain Entity → Mapper → DTO → GraphQL Response

Ejemplo práctico:

// 1. GraphQL Resolver recibe el request (Adaptador de Entrada)
async createTransfer(args: CreateTransferInput) {
  // 2. Convierte input a DTO
  const dto = new CreateTransferDto(args);
  
  // 3. Mapper convierte DTO → Domain Entity
  const transfer = TransferMapper.toDomain(dto);
  
  // 4. Ejecuta caso de uso con entidad de dominio
  const result = await createTransferUseCase.execute(transfer);
  
  // 5. Mapper convierte Domain Entity → DTO de respuesta
  const responseDto = TransferMapper.toDto(result);
  
  // 6. Retorna DTO al cliente
  return responseDto;
}
✓ Ventajas de esta estructura:

2.11 Consideraciones de Diseño

✓ Decisiones Clave Validadas:
Nota Importante sobre DDD: Esta arquitectura no es solo sobre tecnología, es sobre modelar el dominio de negocio correctamente. El código refleja exactamente cómo funciona el negocio bancario, usando el mismo lenguaje que los expertos del dominio. Los cambios en el negocio se traducen directamente a cambios en el código del dominio, sin necesidad de tocar infraestructura.
Escalabilidad: Esta arquitectura está diseñada para crecer de 50,000 usuarios iniciales hasta 10M+ usuarios sin necesidad de re-arquitectura, solo agregando más nodos horizontalmente.