Arquitectura Detallada - galoryzen/equipo8-pfinal GitHub Wiki

Descripción de la Arquitectura — TravelHub

Nuestra arquitectura busca favorecer los siguientes atributos de calidad, el orden establece la importancia dentro de nuestro diseño:

  1. Desempeño
    • Latencia
    • Escalabilidad
  2. Seguridad
  3. Disponibilidad
  4. Modificabilidad

Tabla de Contenidos


1. Visión General

1.1 Diagrama de Componentes

El diagrama de componentes muestra los componentes internos de TravelHub y cómo se comunican.

Diagrama de Componentes

Link Diagrama

Comunicación entre servicios:

Tipo Mecanismo Uso
Sincrónica HTTP interno (ALB + Cloud Map) Cliente → Servicio y Booking → Catalog (validar/hold/release inventario)
Asíncrona EventBridge → SQS Servicio → Servicio (pagos, notificaciones, cambios de estado)
Service Discovery AWS Cloud Map (DNS) Resolución interna (booking.services.local)

Justificación de decisiones (Diagrama de Componentes):

Decisión Justificación Trade-off
5 microservicios por dominio (Auth, Catalog, Booking, Payment, Notification) Aumenta cohesión funcional y permite despliegue/escalado independiente por carga. Mayor overhead operacional (observabilidad, contratos, pruebas de integración).
HTTP síncrono para consultas y validación crítica de inventario Minimiza latencia en flujos interactivos y permite crear hold de inventario en el camino crítico de reserva. Acoplamiento temporal en rutas síncronas.
EventBridge + SQS para procesos asíncronos Evita que una falla en pagos afecte reservas y búsquedas; habilita reintentos y DLQ. Complejidad de trazabilidad y consistencia eventual.
Cloud Map para discovery interno Evita IPs fijas y facilita autoscaling en ECS/Fargate. Dependencia de DNS interno y configuración de red correcta.

1.2 Diagrama de Despliegue (AWS)

alt

Link Diagrama

Decisiones de despliegue:

Aspecto Decisión Justificación
Región us-east-1 (single region para MVP) Simplifica operación; multi-región es mejora post-MVP (No se priorizó este Atributo de Calidad)
Alta disponibilidad Multi-AZ en ECS y RDS Tolera fallo de una zona de disponibilidad completa
Red Microservicios en subredes privadas Solo el ALB es público; reduce superficie de ataque
TLS Terminación en ALB con ACM Certificados administrados, sin gestión manual
Secretos AWS Secrets Manager Las credenciales nunca están en código o variables de entorno en claro

1.3 Modelo de Dominio

alt

Link Diagrama

Esquemas de base de datos (aislamiento lógico):

Esquema Servicio Entidades principales
users User & Auth Service User, Hotel, HotelUser, Agency, AgencyUser
catalog Catalog & Availability Service Property, RoomType, Amenity, RoomTypeAmenity, RatePlan, RateCalendar, InventoryCalendar, CancellationPolicy, Review
booking Booking Service Booking, BookingItem, BookingStatusHistory
payments Payment Service Payment, Refund
notifications Notification Service Notification

Cada servicio accede exclusivamente a su propio esquema. Las referencias cruzadas se manejan mediante IDs (por ejemplo: booking.booking.user_id referencia users.user.id, y catalog.property.hotel_id referencia users.hotel.id), sin JOINs de negocio entre esquemas. Esto facilita la separación futura de bases de datos sin cambios en el código.

Justificación de decisiones (Modelo de Dominio):

Decisión Justificación Trade-off
Aislamiento lógico por esquemas Permite evolucionar de BD compartida a Database-per-Service sin reescribir lógica de negocio. Mayor disciplina de gobernanza para evitar JOINs cruzados.
BookingItem entre Booking y RoomType Soporta múltiples habitaciones por una misma reserva y cálculo granular de tarifa. Más tablas y validaciones transaccionales.
RatePlan + CancellationPolicy por tarifa Modela casos reales: misma habitación con tarifa flexible o no reembolsable. Mayor complejidad de reglas al cotizar/cancelar.
Snapshot de política en reserva Garantiza consistencia histórica para reembolsos aunque cambie la política futura. Duplicación controlada de datos.

1.4 Diagrama de Información

flowchart LR
    U[Viajero]
    H[Hotel / Agencia]
    FE[App Web / Móvil]
    ALB[ALB API Entry]

    AUTH[User & Auth Service]
    CAT[Catalog & Availability Service]
    BOOK[Booking Service]
    PAY[Payment Service]
    NOTIF[Notification Service]

    EB[EventBridge]
    SQSP[Payment Queue]
    SQSB[Booking Queue]
    SQSN[Notification Queue]

    PSTRIPE[Payment Provider<br/>Stripe / MercadoPago]
    PNOTIF[Notification Provider<br/>SES / Push]

    R_USERS[(users schema)]
    R_CATALOG[(catalog schema)]
    R_BOOKING[(booking schema)]
    R_PAY[(payments schema)]
    R_NOTIF[(notifications schema)]
    REDIS[(Redis Cache)]

    U --> FE
    H --> FE
    FE --> ALB

    ALB --> AUTH
    ALB --> CAT
    ALB --> BOOK
    ALB --> PAY

    AUTH --> R_USERS

    CAT <--> REDIS
    CAT --> R_CATALOG

    BOOK --> R_BOOKING
    BOOK -->|createHold / releaseHold| CAT

    BOOK -->|PaymentRequested| EB
    EB --> SQSP
    SQSP --> PAY

    PAY -->|token + auth/capture/cancel| PSTRIPE
    PAY --> R_PAY
    PAY -->|PaymentAuthorized / PaymentSucceeded / PaymentFailed| EB

    EB --> SQSB
    SQSB --> BOOK

    BOOK -->|BookingConfirmed / BookingCancelled| EB
    EB --> SQSN
    SQSN --> NOTIF

    NOTIF --> R_NOTIF
    NOTIF --> PNOTIF

    classDef sensitive fill:#fef3c7,stroke:#d97706,color:#111827;
    classDef restricted fill:#fee2e2,stroke:#dc2626,color:#111827;
    classDef normal fill:#dbeafe,stroke:#2563eb,color:#111827;

    class R_USERS,R_BOOKING sensitive;
    class R_PAY restricted;
    class R_CATALOG,R_NOTIF,REDIS normal;
Loading

Notas adicionales:

  1. Ningún microservicio hace JOIN de negocio fuera de su esquema; solo intercambio por API/eventos + IDs de referencia.
  2. Los datos de tarjeta no se almacenan en TravelHub; solo tokens y metadatos de transacción.
  3. Todo cambio de estado de reserva/pago/notificación genera traza auditable (timestamp, actor, origen, resultado).
  4. Notificaciones consumen eventos de dominio; no leen directamente tablas de Booking o Payments.

2. Decisiones Arquitectónicas (ADRs)

ID Decisión Justificación
ADR-001 Microservicios sobre AWS ECS Fargate. Se descompone el sistema en 5 microservicios independientes desplegados con Fargate. Permite escalar cada servicio de forma independiente (ej: más instancias de Catalog sin escalar Payment), aislar fallos (un error en pagos no afecta búsquedas) y desplegar cambios sin downtime mediante rolling updates. Fargate elimina la gestión de servidores. Se descarta Kubernetes (EKS) decisión técnica del equipo de desarrollo.
ADR-002 Comunicación asíncrona con EventBridge + SQS. Booking, Payment y Notification se comunican exclusivamente mediante eventos, sin llamadas HTTP síncronas entre ellos. El enunciado identifica como problema que el sistema de pago está acoplado al motor de reserva. Los SLAs de reserva (≤1.5s) y pago (≤3s) son independientes; si se comunican síncronamente, se suman (4.5s) y ambos se violan. Con eventos, el usuario recibe respuesta inmediata y el pago se procesa en background. Si Stripe se cae, las reservas siguen funcionando.
ADR-003 Authorization & Capture en dos fases para pagos. Al reservar se autoriza el monto (hold sin cobro). Cuando el hotel confirma se captura; si rechaza se libera. Los hoteles deben poder confirmar o rechazar reservas. Si se cobra antes de la confirmación, un rechazo implica reembolso (mala UX, costos de transacción, demora de días). Con Authorization & Capture el usuario nunca es cobrado si el hotel rechaza. Soportado nativamente por proveedores de pago ya conocidos (Stripe, Mercadopago).
ADR-004 BD compartida con aislamiento por esquemas (MVP). Una única instancia RDS PostgreSQL Multi-AZ con esquemas separados por servicio. Cada servicio accede solo a su esquema, sin JOINs cruzados. El aislamiento por esquemas mantiene la separación lógica y las referencias cruzadas usan solo IDs, por lo que el código no cambia al separar BD en el futuro (empezando por Payment para PCI-DSS).
ADR-005 Caché distribuido con Redis (ElastiCache). Cache-Aside para búsquedas (TTL 1-2 min), detalle de propiedad (TTL 15-30 min), tarifas (TTL 30-60s) y sesiones. El SLA de búsqueda es ≤800ms (p95) pero el sistema actual tarda 3-5s. La BD llegaría al 85% de CPU en picos si todas las consultas van directo a PostgreSQL. Redis reduce la latencia y el tráfico de lectura a RDS en ~60-70%.

3. Tácticas y Patrones de Arquitectura

3.1 Tácticas por Atributo de Calidad

Desempeño

Táctica Aplicación SLA que atiende
Múltiples copias de datos Redis (ElastiCache) como caché de búsquedas, tarifas y sesiones; CloudFront CDN para assets estáticos Búsqueda ≤800ms (p95), Detalle ≤500ms (p95)
Introducir concurrencia FastAPI async/await; procesamiento de pagos y notificaciones vía EventBridge+SQS sin bloquear el hilo principal Reserva ≤1.5s (p95), Pago ≤3s (p95) independientes
Múltiples copias de computación ECS auto-scaling: múltiples instancias por servicio; Competing Consumers en colas SQS Picos de hasta 800 TPM
Manejar la rata de muestreo TTL en caché Redis (1-2 min búsquedas, 30-60s tarifas): no se consulta BD en cada request Búsqueda ≤800ms (p95)
Dar prioridad a los eventos Colas SQS separadas: Payment Queue (crítico) vs Notification Queue (no crítico); flujos de pago no compiten con notificaciones Pago ≤3s (p95)
Reducir el overhead Service Discovery con DNS interno (Cloud Map); comunicación entre servicios dentro de la misma VPC sin salir a Internet Todas las operaciones internas
Limitar tiempo de ejecución Timeouts en llamadas a Stripe/MercadoPago; SQS visibility timeout libera mensaje si no se procesa a tiempo Pago ≤3s (p95)
Planificar el uso de recursos Connection Pooling a PostgreSQL; hold de 15 min que reserva inventario y libera automáticamente al expirar Operaciones de BD

Estas tácticas atienden principalmente los ASRs de rendimiento: ASR-01 (búsqueda <800ms), ASR-06 (detalle propiedad <500ms), ASR-07 (histórico reservas <1s), ASR-17 (pagos ≤3s) y ASR-59 (reserva en <1.5s).

Disponibilidad

Táctica Aplicación
Redundancia activa ECS Fargate y RDS desplegados en múltiples zonas de disponibilidad (Multi-AZ)
Monitoreo (Heartbeat) ALB verifica salud de cada servicio ECS cada 10 segundos mediante health checks
Reinicio automático ECS reinicia tareas (contenedores) que fallan automáticamente
Prevención de excepciones Servicios stateless (sesiones en Redis); cualquier instancia puede atender cualquier request sin estado local
Reintentos SQS reintenta mensajes fallidos automáticamente con backoff exponencial
Cola de mensajes fallidos (DLQ) Mensajes que fallan N veces se envían a Dead Letter Queue para análisis sin perder datos
Remoción del servicio Rolling updates en ECS: reemplaza tareas gradualmente validando health checks antes de retirar la versión anterior

Estas tácticas atienden los ASRs de disponibilidad: ASR-10 (disponibilidad ≥99.95%), ASR-08 (recuperación automática <3 min), ASR-09 (pérdida de solicitudes <0.1%) y ASR-04 (despliegues sin downtime <2 min).

Escalabilidad

Táctica Aplicación
Escalado horizontal ECS auto-scaling por CPU/memoria, independiente por servicio
Distribución de carga ALB distribuye tráfico entre instancias de cada servicio
Particionamiento de datos Esquemas separados en RDS por servicio; preparado para split físico post-MVP
Procesamiento distribuido Colas SQS permiten que múltiples instancias procesen eventos en paralelo (Competing Consumers)

Estas tácticas atienden los ASRs de escalabilidad: ASR-03 (escalado horizontal independiente por microservicio) y ASR-20 (escalado de 150 a 800 TPM en ≤5 min).

Seguridad

Táctica Aplicación
Resistir ataques: Autenticar usuarios JWT + roles (RBAC) en User & Auth Service: viajero, hotel, agencia, administrador
Resistir ataques: Autorizar usuarios Control de acceso basado en roles; cada endpoint valida permisos del rol
Resistir ataques: Mantener confidencialidad TLS 1.2+ en tránsito (ALB + ACM); AES-256 en reposo (RDS, S3); tokenización de datos de tarjeta (PCI-DSS)
Resistir ataques: Limitar acceso Microservicios en subredes privadas dentro del VPC; solo ALB es público
Detectar ataques Amazon CloudWatch con alarmas sobre patrones anómalos (picos de errores 4xx/5xx, accesos inusuales)
Recuperarse de ataques: Gestión de credenciales AWS Secrets Manager para credenciales de BD y API keys; rotación sin redespliegue

Estas tácticas atienden los ASRs de seguridad: ASR-02 (RBAC y auditoría <2s), ASR-25 (tokenización PCI-DSS, 0% datos de tarjeta en texto plano), ASR-30 (100% comunicaciones con TLS 1.2+) y ASR-28 (detección de fraude ≤2s).

Modificabilidad

Táctica Aplicación
Reducir el tamaño del módulo 5 microservicios con responsabilidades claramente delimitadas; cada uno maneja un dominio acotado
Incrementar la cohesión Cada servicio agrupa funcionalidades relacionadas (ej: todo lo de pagos en Payment Service, todo lo de búsqueda en Catalog)
Reducir el acoplamiento EventBridge + SQS desacopla Booking ↔ Payment ↔ Notification; cada servicio accede solo a su esquema de BD
Usar intermediarios EventBridge como intermediario entre productores y consumidores de eventos; ALB como intermediario entre clientes y servicios
Diferir el enlace Adapter/Strategy en Payment Service: el proveedor de pago (Stripe/MercadoPago) se selecciona en tiempo de ejecución sin cambiar código
Abstraer servicios de infraestructura Los servicios cloud se consumen a través de interfaces abstractas (Ports), no directamente con SDKs de AWS. Cambiar de proveedor cloud requiere solo reemplazar la implementación concreta del adapter
Despliegue independiente CI/CD con detección de cambios por carpeta; un servicio se despliega sin tocar los demás

Estas tácticas atienden los ASRs de modificabilidad: ASR-44 (nuevo proveedor de pago ≤40 hh), ASR-46 (cambiar política de cancelación ≤8 hh), ASR-53 (pipeline CI/CD ≤15 min) y ASR-50 (onboarding de nuevo desarrollador ≤3 días).


3.2 Patrones de Diseño

GRASP

Patrón Dónde se aplica Justificación
Information Expert Cada microservicio gestiona exclusivamente los datos de su dominio: Catalog → búsquedas e inventario, Payment → transacciones, Booking → reservas La responsabilidad se asigna al servicio que posee la información necesaria para cumplirla
Controller Endpoints FastAPI como coordinadores (ej: POST /api/bookings/checkout-confirm coordina validación, cambio de estado y publicación de evento) Componente coordinador que recibe eventos del sistema y delega a la lógica de dominio
Low Coupling EventBridge + SQS desacopla Booking ↔ Payment ↔ Notification; cada servicio accede solo a su esquema de BD; referencias cruzadas solo por IDs Minimiza dependencias directas entre servicios, reduce impacto de cambios
High Cohesion Todo lo de pagos en Payment Service, búsqueda y disponibilidad en Catalog, flujo de reservas en Booking Funcionalidades relacionadas agrupadas; cada servicio tiene un propósito claro y acotado
Pure Fabrication Notification Service no representa un concepto del dominio de reservas; existe como servicio técnico transversal Fabricación artificial para lograr bajo acoplamiento: los servicios de negocio no envían emails directamente
Indirection ALB entre clientes y servicios; EventBridge entre productores y consumidores de eventos; Redis entre Catalog Service y PostgreSQL Intermediarios que desacoplan componentes y permiten evolución independiente
Protected Variations Ports & Adapters (Hexagonal): los puertos definen interfaces estables que protegen la lógica de negocio de variaciones en proveedores externos (pago, cloud, notificaciones) Cambiar de proveedor cloud o de pago requiere solo reemplazar el adapter, sin tocar lógica de negocio

SOLID

Principio Dónde se aplica Justificación
Single Responsibility Cada microservicio tiene una sola razón para cambiar: Auth → reglas de autenticación, Catalog → lógica de búsqueda, Booking → flujo de reservas, Payment → integración de pagos, Notification → canales de comunicación Cambios en la pasarela de pago no afectan el flujo de reservas ni las notificaciones
Open/Closed Payment Service abierto a nuevos proveedores (solo implementar nuevo Adapter sin modificar lógica de autorización/captura); EventBridge permite agregar consumidores sin modificar productores Extensión por adición, no por modificación del código existente
Liskov Substitution StripeAdapter y MercadoPagoAdapter son sustituibles donde se espera PaymentProvider sin alterar el comportamiento del Payment Service Cualquier adapter cumple el contrato de la interfaz: authorize, capture, cancel, refund

GoF

Patrón Dónde se aplica Justificación
Strategy Payment Service: interfaz PaymentProvider con StripeAdapter y MercadoPagoAdapter, seleccionado en runtime según configuración Familia de algoritmos intercambiables; agregar nuevo proveedor no requiere modificar lógica existente (ASR-44: ≤40 hh)
Adapter Adapters de infraestructura cloud (AWS SES, SQS, S3 → interfaces genéricas) y adapters de pago (APIs de Stripe/MercadoPago → interfaz unificada PaymentProvider) Convierte interfaces externas incompatibles en la interfaz que el dominio espera
Observer EventBridge: los servicios publican eventos de dominio (BookingConfirmed, PaymentSucceeded) y los suscriptores reaccionan vía reglas de enrutamiento, sin acoplamiento directo Notificación automática a dependientes cuando cambia el estado de un objeto
Facade ALB como punto de entrada único con routing por path; oculta la complejidad de 5 microservicios internos detrás de un solo endpoint HTTPS Interfaz simplificada hacia un subsistema complejo
State Booking Service: la reserva cambia de comportamiento según su estado (CARTPENDING_PAYMENTPENDING_CONFIRMATIONCONFIRMED / CANCELLED / REJECTED). Las transiciones válidas y acciones permitidas dependen del estado actual Permite que un objeto altere su comportamiento cuando cambia su estado interno

4. Flujos Principales

4.1 Búsqueda de Hospedaje

SLA: ≤ 800ms (p95) Tácticas aplicadas: Cache-Aside (Redis), Database Indexing, CDN (CloudFront)

Diagrama de Componentes

flowchart LR
    FE["App Web / Móvil<br><i>Cliente</i>"]

    subgraph gw["API Gateway"]
        ALB["ALB<br>«Facade»"]
    end

    subgraph cat["Catalog Service"]
        direction TB
        API["FastAPI"]
        SEARCH["SearchService<br><small>Búsqueda + filtros</small>"]
        RANK["RankingEngine"]
        API --> SEARCH
        SEARCH --> RANK
    end

    subgraph store["Almacenamiento"]
        REDIS[("Redis")]
        PG[("PostgreSQL<br>catalog_schema")]
    end

    FE -- "HTTPS" --> ALB
    ALB -- "/api/catalog/*" --> API
    SEARCH -. "redis-py" .-> REDIS
    SEARCH -. "SQLAlchemy" .-> PG
Loading

Diagrama de Secuencia

sequenceDiagram
    actor U as Viajero
    participant FE as App Web / Móvil
    participant ALB as ALB
    participant CAT as Catalog Service
    participant REDIS as Redis
    participant DB as PostgreSQL

    U->>FE: Busca hospedaje
    FE->>ALB: GET /api/catalog/search
    ALB->>CAT: Enruta petición

    CAT->>REDIS: Consultar caché

    alt Cache HIT
        REDIS-->>CAT: Resultados
    else Cache MISS
        CAT->>DB: Buscar propiedades disponibles
        DB-->>CAT: Resultados
        CAT->>REDIS: Guardar en caché (TTL 1-2 min)
    end

    CAT->>CAT: Aplicar ranking
    CAT-->>ALB: Lista de propiedades
    ALB-->>FE: Respuesta
    FE-->>U: Muestra resultados
Loading

4.2 Creación de Reserva + Pago

SLAs: Creación de reserva ≤ 1.5s (p95), Procesamiento de pago ≤ 3s (p95) Tácticas aplicadas: Validación síncrona de inventario (Booking → Catalog), Async Processing, Choreography-based Saga, Authorization & Capture Patrón: Saga (coreografía)

Diagrama de Componentes

flowchart LR
    FE["App Web / Móvil<br><i>Viajero</i>"]

    subgraph gw["API Gateway"]
        ALB["ALB<br>«Facade»"]
    end

    subgraph book["Booking Service"]
        BAPI["FastAPI"]
        BM["BookingManager<br><small>«State»</small>"]
        BAPI --> BM
    end

    subgraph cat["Catalog Service"]
        INV["InventoryService<br><small>createHold / releaseHold</small>"]
    end

    subgraph bus["Mensajería «Observer»"]
        EB["EventBridge"]
        SQS_P[/"Payment Queue"/]
        SQS_B[/"Booking Queue"/]
        SQS_N[/"Notification Queue"/]
    end

    subgraph pay["Payment Service «Strategy»"]
        PP["PaymentProcessor"]
    end

    STRIPE["Stripe / MercadoPago"]
    NOTIF["Notification Service"]
    PG[("PostgreSQL")]

    FE -- "HTTPS" --> ALB
    ALB --> BAPI
    BM -- "createHold (síncrono)" --> INV
    BM -- "PaymentRequested" --> EB
    EB --> SQS_P & SQS_B & SQS_N
    SQS_P --> PP
    PP -. "adapter" .-> STRIPE
    SQS_B --> BM
    SQS_N --> NOTIF
    book -. "SQLAlchemy" .-> PG
    pay -. "SQLAlchemy" .-> PG
Loading

4.2A Inicio de checkout + InventoryHold (15 min)

Objetivo: bloquear inventario temporalmente mientras el usuario completa datos y pago.

sequenceDiagram
    actor U as Viajero
    participant FE as App Web / Móvil
    participant ALB as ALB
    participant BOOK as Booking Service
    participant CAT as Catalog Service

    U->>FE: Selecciona fechas, huéspedes, habitaciones
    FE->>ALB: POST /api/bookings/checkout-start
    ALB->>BOOK: Iniciar checkout

    BOOK->>CAT: createHold(15 min)
    CAT-->>BOOK: HoldCreated / HoldRejected

    alt HoldCreated
        BOOK->>BOOK: Crear Booking estado CART
        BOOK->>BOOK: Guardar inventory_hold_id y hold_expires_at
        BOOK-->>ALB: 201 booking_id
        ALB-->>FE: Checkout iniciado
        FE-->>U: Completar datos del viajero y pago
    else HoldRejected
        BOOK-->>ALB: 409 Sin disponibilidad
        ALB-->>FE: No disponible
        FE-->>U: Selecciona otra opción
    end
Loading

4.2B Confirmación de compra + PaymentAuthorizationHold

Objetivo: iniciar pago asíncrono sin bloquear la UX; si se autoriza, la reserva pasa a espera de confirmación del hotel.

sequenceDiagram
    actor U as Viajero
    participant FE as App Web / Móvil
    participant ALB as ALB
    participant BOOK as Booking Service
    participant EB as EventBridge
    participant SQS_P as Payment Queue
    participant PAY as Payment Service
    participant STRIPE as Stripe / MercadoPago
    participant SQS_B as Booking Queue
    participant SQS_N as Notification Queue
    participant NOTIF as Notification Service
    participant CAT as Catalog Service

    U->>FE: Confirma compra y envía datos de pago
    FE->>ALB: POST /api/bookings/{id}/checkout-confirm
    ALB->>BOOK: Confirmar checkout

    BOOK->>BOOK: Validar booking en CART y hold vigente
    BOOK->>BOOK: Estado -> PENDING_PAYMENT
    BOOK->>EB: PaymentRequested
    BOOK-->>ALB: 202 Pago en proceso
    ALB-->>FE: Pago en proceso
    FE-->>U: "Procesando pago..."

    EB->>SQS_P: PaymentRequested
    SQS_P->>PAY: Consume mensaje
    PAY->>STRIPE: Autorizar pago (sin cobro)

    alt Authorization OK
        STRIPE-->>PAY: PaymentAuthorized
        PAY->>EB: PaymentAuthorized
        EB->>SQS_B: PaymentAuthorized
        SQS_B->>BOOK: Consume mensaje
        BOOK->>BOOK: Estado -> PENDING_CONFIRMATION
        EB->>SQS_N: PaymentAuthorized
        SQS_N->>NOTIF: Consume mensaje
        NOTIF->>NOTIF: Email al hotel (reserva pendiente)
    else Authorization Failed
        STRIPE-->>PAY: PaymentFailed
        PAY->>EB: PaymentFailed
        EB->>SQS_B: PaymentFailed
        SQS_B->>BOOK: Consume mensaje
        BOOK->>CAT: releaseHold
        BOOK->>BOOK: Estado -> CANCELLED
        EB->>SQS_N: PaymentFailed
        SQS_N->>NOTIF: Consume mensaje
        NOTIF->>NOTIF: Notificar fallo al viajero
    end
Loading

Estados de la reserva en este flujo:

CART -> PENDING_PAYMENT -> PENDING_CONFIRMATION
(InventoryHold 15 min)   (PaymentAuthorizationHold)

Manejo de fallos:

  • Si expira InventoryHold antes de confirmar checkout, Booking cancela la reserva y Catalog libera inventario automáticamente.
  • Si falla autorización de pago, Booking ejecuta releaseHold y marca la reserva como CANCELLED.
  • La confirmación definitiva ocurre en 4.3 (hotel confirma/rechaza): confirmHold + capture o releaseHold + cancelación de autorización.

4.3 Confirmación / Rechazo por Hotel

Tácticas aplicadas: Authorization & Capture, Choreography-based Saga Patrón: Saga (coreografía), continuación del flujo 4.2

Diagrama de Componentes

flowchart LR
    H["Portal Web<br><i>Hotel</i>"]

    subgraph gw["API Gateway"]
        ALB["ALB<br>«Facade»"]
    end

    subgraph book["Booking Service"]
        BAPI["FastAPI"]
        BM["BookingManager<br><small>«State»</small>"]
        BAPI --> BM
    end

    subgraph cat["Catalog Service"]
        INV["InventoryService<br><small>confirmHold / releaseHold</small>"]
    end

    subgraph bus["Mensajería «Observer»"]
        EB["EventBridge"]
        SQS_P[/"Payment Queue"/]
        SQS_N[/"Notification Queue"/]
    end

    subgraph pay["Payment Service «Strategy»"]
        PP["PaymentProcessor"]
    end

    STRIPE["Stripe / MercadoPago"]
    NOTIF["Notification Service"]
    PG[("PostgreSQL")]

    H -- "HTTPS" --> ALB
    ALB --> BAPI
    BM -- "confirmHold / releaseHold" --> INV
    BM -- "CaptureRequested / CancelRequested" --> EB
    EB --> SQS_P & SQS_N
    SQS_P --> PP
    PP -. "capture / cancel" .-> STRIPE
    SQS_N --> NOTIF
    book -. "SQLAlchemy" .-> PG
    pay -. "SQLAlchemy" .-> PG
Loading

Flujo de Confirmación

sequenceDiagram
    actor H as Hotel
    participant FE as Portal Web
    participant ALB as ALB
    participant BOOK as Booking Service
    participant CAT as Catalog Service
    participant EB as EventBridge
    participant SQS_P as Payment Queue
    participant PAY as Payment Service
    participant STRIPE as Stripe / MercadoPago
    participant SQS_B as Booking Queue
    participant SQS_N as Notification Queue
    participant NOTIF as Notification Service

    H->>FE: Confirmar reserva pendiente
    FE->>ALB: POST /api/bookings/{id}/confirm
    ALB->>BOOK: Confirmar reserva

    BOOK->>BOOK: Validar estado PENDING_CONFIRMATION
    BOOK->>EB: PaymentCaptureRequested
    BOOK-->>ALB: 200 OK
    FE-->>H: "Confirmando..."

    EB->>SQS_P: PaymentCaptureRequested
    SQS_P->>PAY: Consume mensaje

    PAY->>STRIPE: Capturar pago autorizado
    STRIPE-->>PAY: Captura OK

    PAY->>EB: PaymentSucceeded

    par Actualizar Booking
        EB->>SQS_B: PaymentSucceeded
        SQS_B->>BOOK: Consume mensaje
        BOOK->>BOOK: Estado → CONFIRMED
        BOOK->>CAT: confirmHold (commit inventario)
        BOOK->>EB: BookingConfirmed
    and Notificar
        EB->>SQS_N: PaymentSucceeded
        SQS_N->>NOTIF: Consume mensaje
        NOTIF->>NOTIF: Email al viajero: reserva confirmada
    end
Loading

Flujo de Rechazo

sequenceDiagram
    actor H as Hotel
    participant FE as Portal Web
    participant ALB as ALB
    participant BOOK as Booking Service
    participant CAT as Catalog Service
    participant EB as EventBridge
    participant SQS_P as Payment Queue
    participant PAY as Payment Service
    participant STRIPE as Stripe / MercadoPago
    participant SQS_N as Notification Queue
    participant NOTIF as Notification Service

    H->>FE: Rechazar reserva pendiente
    FE->>ALB: POST /api/bookings/{id}/reject
    ALB->>BOOK: Rechazar reserva

    BOOK->>BOOK: Validar estado PENDING_CONFIRMATION
    BOOK->>CAT: releaseHold (liberar inventario)
    BOOK->>BOOK: Estado → REJECTED
    BOOK->>EB: PaymentCancelRequested
    BOOK->>EB: BookingCancelled
    BOOK-->>ALB: 200 OK
    FE-->>H: Reserva rechazada

    par Liberar autorización
        EB->>SQS_P: PaymentCancelRequested
        SQS_P->>PAY: Consume mensaje
        PAY->>STRIPE: Cancelar autorización
        STRIPE-->>PAY: Autorización liberada
    and Notificar
        EB->>SQS_N: BookingCancelled
        SQS_N->>NOTIF: Consume mensaje
        NOTIF->>NOTIF: Email al viajero: reserva rechazada, sin cobro
    end
Loading

Timeout automático: Si el hotel no responde dentro de 24 horas, un proceso programado (cron/scheduled task) en el Booking Service evalúa la política del hotel:

  • Auto-confirm: Publica PaymentCaptureRequested (captura el pago y, al confirmar, ejecuta confirmHold en Catalog).
  • Auto-cancel: Ejecuta releaseHold en Catalog y publica PaymentCancelRequested y BookingCancelled (libera autorización).

4.4 Cancelación + Reembolso

Tácticas aplicadas: Policy-based Processing, Async Processing Contexto: El viajero cancela una reserva que ya fue confirmada (pago ya capturado). El reembolso depende de la política de cancelación de la propiedad.

Diagrama de Componentes

flowchart LR
    FE["App Web / Móvil<br><i>Viajero</i>"]

    subgraph gw["API Gateway"]
        ALB["ALB<br>«Facade»"]
    end

    subgraph book["Booking Service"]
        BAPI["FastAPI"]
        BM["BookingManager<br><small>«State» + Política cancelación</small>"]
        BAPI --> BM
    end

    subgraph cat["Catalog Service"]
        INV["InventoryService<br><small>releaseInventory</small>"]
    end

    subgraph bus["Mensajería «Observer»"]
        EB["EventBridge"]
        SQS_P[/"Payment Queue"/]
        SQS_N[/"Notification Queue"/]
    end

    subgraph pay["Payment Service"]
        PP["PaymentProcessor<br><small>refund</small>"]
    end

    STRIPE["Stripe / MercadoPago"]
    NOTIF["Notification Service"]
    PG[("PostgreSQL")]

    FE -- "HTTPS" --> ALB
    ALB --> BAPI
    BM -- "releaseInventory" --> INV
    BM -- "BookingCancelled + RefundRequested" --> EB
    EB --> SQS_P & SQS_N
    SQS_P --> PP
    PP -. "refund" .-> STRIPE
    SQS_N --> NOTIF
    book -. "SQLAlchemy" .-> PG
    pay -. "SQLAlchemy" .-> PG
Loading

Diagrama de Secuencia

sequenceDiagram
    actor U as Viajero
    participant FE as App Web / Móvil
    participant ALB as ALB
    participant BOOK as Booking Service
    participant CAT as Catalog Service
    participant EB as EventBridge
    participant SQS_P as Payment Queue
    participant PAY as Payment Service
    participant STRIPE as Stripe / MercadoPago
    participant SQS_N as Notification Queue
    participant NOTIF as Notification Service

    U->>FE: Cancelar reserva
    FE->>ALB: POST /api/bookings/{id}/cancel
    ALB->>BOOK: Cancelar reserva

    BOOK->>BOOK: Validar estado CONFIRMED
    BOOK->>BOOK: Evaluar política de cancelación

    alt non_refundable
        BOOK->>BOOK: Reembolso = $0
    else partial
        BOOK->>BOOK: Reembolso = porcentaje según días
    else full
        BOOK->>BOOK: Reembolso = total
    end

    BOOK->>CAT: releaseInventory (reabrir cupo)
    BOOK->>BOOK: Estado → CANCELLED
    BOOK->>EB: BookingCancelled

    opt Reembolso > 0
        BOOK->>EB: RefundRequested
        EB->>SQS_P: RefundRequested
        SQS_P->>PAY: Consume mensaje
        PAY->>STRIPE: Procesar reembolso
        STRIPE-->>PAY: Reembolso OK
        PAY->>EB: RefundSucceeded
    end

    BOOK-->>ALB: 200 OK
    FE-->>U: Reserva cancelada

    EB->>SQS_N: BookingCancelled
    SQS_N->>NOTIF: Consume mensaje
    NOTIF->>NOTIF: Email al viajero y al hotel
Loading

Políticas de cancelación soportadas:

Política Comportamiento
non_refundable Sin reembolso. El pago se retiene completamente
partial Reembolso parcial si se cancela antes de X días del check-in
full Reembolso completo sin importar la fecha de cancelación

4.5 Flujo de Notificaciones

Tácticas aplicadas: Competing Consumers, Async Processing Patrón: Event-Driven, Competing Consumers

Diagrama de Componentes

flowchart LR
    subgraph bus["Mensajería"]
        EB["EventBridge"]
        SQS[/"Notification Queue"/]
        DLQ[/"Dead Letter Queue"/]
    end

    subgraph notif["Notification Service (N instancias)"]
        direction TB
        NH["NotificationHandler"]
        TR["TemplateRenderer"]
        NH --> TR
    end

    subgraph channels["Canales de Envío"]
        SES["Amazon SES<br><small>Email</small>"]
        PUSH["Push Provider<br><small>Móvil</small>"]
    end

    PG[("PostgreSQL<br><small>notification_log</small>")]

    EB --> SQS
    SQS --> NH
    SQS -. "reintentos agotados" .-> DLQ
    NH -. "boto3" .-> SES
    NH -. "SDK" .-> PUSH
    NH -. "SQLAlchemy" .-> PG
Loading

Diagrama de Secuencia

sequenceDiagram
    participant EB as EventBridge
    participant SQS_N as Notification Queue
    participant DLQ as Dead Letter Queue
    participant NOTIF as Notification Service (N instancias)
    participant SES as Amazon SES
    participant PUSH as Push Provider
    participant DB as PostgreSQL

    EB->>SQS_N: Evento de dominio

    SQS_N->>NOTIF: Consume mensaje

    NOTIF->>NOTIF: Determinar tipo y destinatario
    NOTIF->>DB: Registrar notificación

    par Email
        NOTIF->>SES: Enviar email
        SES-->>NOTIF: OK
    and Push
        NOTIF->>PUSH: Enviar push
        PUSH-->>NOTIF: OK
    end

    NOTIF->>DB: Marcar como enviada

    alt Fallo en envío
        NOTIF->>DB: Marcar como fallida
        Note over SQS_N: SQS reintenta automáticamente
        alt Reintentos agotados
            SQS_N->>DLQ: Dead Letter Queue
        end
    end
Loading

Tipos de notificación por evento:

Evento Destinatario Canal Contenido
BookingConfirmed Viajero Email + Push "Tu reserva ha sido confirmada"
BookingConfirmed Hotel Email "Reserva #ID confirmada"
BookingCancelled Viajero Email + Push "Tu reserva fue cancelada. Reembolso: $X"
BookingCancelled Hotel Email "Reserva #ID cancelada por viajero/hotel"
PaymentSucceeded Viajero Email Recibo de pago con desglose
PaymentFailed Viajero Email + Push "Hubo un problema con tu pago"
PaymentAuthorized Hotel Email "Nueva reserva pendiente de confirmación"

Competing Consumers: Si hay N instancias del Notification Service corriendo (por auto-scaling), SQS distribuye los mensajes entre ellas automáticamente. Cada mensaje es procesado por exactamente una instancia (visibilityTimeout de SQS garantiza esto).

⚠️ **GitHub.com Fallback** ⚠️