Saltar a contenido

Arquitectura Backend — CETB

Stack Tecnológico

Componente Tecnología
Lenguaje TypeScript
Framework NestJS v11
Runtime AWS Lambda (Node.js)
Base de datos MongoDB (Mongoose)
Cola de mensajes Amazon SQS
API Gateway AWS API Gateway (REST)
Autenticación Amazon Cognito (User Pool como Authorizer)
Adaptador serverless @vendia/serverless-express

Flujo de una petición

Cliente (App/Web)
       │
       ▼
┌──────────────────────┐
│   AWS API Gateway    │
│  (REST API)          │
│                      │
│  Authorizer:         │
│  Cognito User Pool   │
│  (valida JWT token)  │
└──────────┬───────────┘
           │ evento proxy
           ▼
┌──────────────────────┐
│   AWS Lambda         │
│   (handler)          │
│                      │
│  - Extrae claims de  │
│    Cognito           │
│  - Bootstrap NestJS  │
│    (cached)          │
└──────────┬───────────┘
           │
           ▼
┌──────────────────────┐
│   NestJS App         │
│   (Express adapter)  │
│                      │
│  ValidationPipe      │
│  (whitelist,         │
│   transform)         │
└──────────┬───────────┘
           │
           ▼
┌──────────────────────┐
│   Controller         │
│   (Infraestructura)  │
└──────────┬───────────┘
           │
           ▼
┌──────────────────────┐
│   Use Case           │
│   (Aplicación)       │
└──────────┬───────────┘
           │
     ┌─────┴─────┐
     ▼           ▼
┌─────────┐  ┌─────────┐
│ MongoDB │  │   SQS   │
│(Mongoose│  │ (email/ │
│  repos) │  │   sms)  │
└─────────┘  └─────────┘

Arquitectura DDD (Domain-Driven Design)

El proyecto sigue una estructura de capas por módulo:

src/
└── <modulo>/
    ├── domain/                  ← Capa de Dominio
    │   ├── entities/            ← Entidades de negocio (POJOs puros)
    │   └── repositories/        ← Interfaces de repositorios (contratos)
    │
    ├── application/             ← Capa de Aplicación
    │   ├── use-cases/           ← Casos de uso (orquestación de lógica)
    │   └── services/            ← Servicios de aplicación (SQS, etc.)
    │
    ├── infraestructure/         ← Capa de Infraestructura
    │   ├── http/                ← Controllers (entry points HTTP)
    │   ├── dto/                 ← Data Transfer Objects (request/response)
    │   ├── moongose/models/     ← Schemas de Mongoose (persistencia)
    │   └── repositories/        ← Implementaciones concretas de repos
    │
    └── <modulo>.module.ts       ← Módulo NestJS (wiring de dependencias)

Principios aplicados

  • Inversión de dependencias: El dominio define interfaces (ITransactionRepository, ITenantRepository). La infraestructura las implementa. Se inyectan via tokens de NestJS.
  • Entidades puras: Las entidades del dominio no dependen de frameworks (Mongoose, NestJS). Son clases TypeScript planas.
  • Casos de uso: Contienen la lógica de orquestación. Reciben DTOs, consultan repositorios, ejecutan acciones (enviar email/sms).
  • DTOs con validación: Se usan class-validator y class-transformer en la capa de infraestructura para validar input antes de llegar al use case.

Autenticación y Autorización

  1. El cliente envía el JWT token (emitido por Cognito) en el header Authorization.
  2. API Gateway valida el token contra el Cognito User Pool configurado como authorizer.
  3. Si es válido, API Gateway inyecta los claims del usuario en event.requestContext.authorizer.claims.
  4. El Lambda handler extrae el username de los claims y lo pasa como header x-user-username a la app NestJS.
  5. Las peticiones que no pasen validación de Cognito reciben un 401 Unauthorized directamente desde API Gateway.

Servicios externos

Servicio Uso Cola SQS
Email Envío de comprobantes con template HTML cetb-ts-send-email
SMS Notificación de transacciones cetb-ts-send-messages

Los mensajes se publican a SQS y un consumidor separado se encarga del envío real (desacoplamiento).


Deployment

  • Build: nest build (compila TypeScript a JavaScript)
  • Entry point Lambda: dist/lambda.handler
  • Cold start optimizado: La instancia de NestJS se cachea entre invocaciones (cachedServer)
  • CORS: Configurado en el response del Lambda handler (headers Access-Control-Allow-*)