Arquitectura Detallada - galoryzen/equipo8-pfinal GitHub Wiki
Nuestra arquitectura busca favorecer los siguientes atributos de calidad, el orden establece la importancia dentro de nuestro diseño:
- Desempeño
- Latencia
- Escalabilidad
- Seguridad
- Disponibilidad
- Modificabilidad
- Descripción de la Arquitectura — TravelHub
El diagrama de componentes muestra los componentes internos de TravelHub y cómo se comunican.

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. |

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 |

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. |
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;
Notas adicionales:
- Ningún microservicio hace JOIN de negocio fuera de su esquema; solo intercambio por API/eventos + IDs de referencia.
- Los datos de tarjeta no se almacenan en TravelHub; solo tokens y metadatos de transacción.
- Todo cambio de estado de reserva/pago/notificación genera traza auditable (
timestamp,actor,origen,resultado). - Notificaciones consumen eventos de dominio; no leen directamente tablas de Booking o Payments.
| 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%. |
| 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).
| 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).
| 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).
| 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).
| 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).
| 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 |
| 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
|
| 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 (CART → PENDING_PAYMENT → PENDING_CONFIRMATION → CONFIRMED / 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 |
SLA: ≤ 800ms (p95) Tácticas aplicadas: Cache-Aside (Redis), Database Indexing, CDN (CloudFront)
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
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
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)
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
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
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
Estados de la reserva en este flujo:
CART -> PENDING_PAYMENT -> PENDING_CONFIRMATION
(InventoryHold 15 min) (PaymentAuthorizationHold)
Manejo de fallos:
- Si expira
InventoryHoldantes de confirmar checkout, Booking cancela la reserva y Catalog libera inventario automáticamente. - Si falla autorización de pago, Booking ejecuta
releaseHoldy marca la reserva comoCANCELLED. - La confirmación definitiva ocurre en 4.3 (hotel confirma/rechaza):
confirmHold+ capture oreleaseHold+ cancelación de autorización.
Tácticas aplicadas: Authorization & Capture, Choreography-based Saga Patrón: Saga (coreografía), continuación del flujo 4.2
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
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
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
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, ejecutaconfirmHolden Catalog). -
Auto-cancel: Ejecuta
releaseHolden Catalog y publicaPaymentCancelRequestedyBookingCancelled(libera autorización).
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.
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
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
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 |
Tácticas aplicadas: Competing Consumers, Async Processing Patrón: Event-Driven, Competing Consumers
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
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
Tipos de notificación por evento:
| Evento | Destinatario | Canal | Contenido |
|---|---|---|---|
BookingConfirmed |
Viajero | Email + Push | "Tu reserva ha sido confirmada" |
BookingConfirmed |
Hotel | "Reserva #ID confirmada" | |
BookingCancelled |
Viajero | Email + Push | "Tu reserva fue cancelada. Reembolso: $X" |
BookingCancelled |
Hotel | "Reserva #ID cancelada por viajero/hotel" | |
PaymentSucceeded |
Viajero | Recibo de pago con desglose | |
PaymentFailed |
Viajero | Email + Push | "Hubo un problema con tu pago" |
PaymentAuthorized |
Hotel | "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).