Deliverable 4.1 — Target Architecture Overview
Requirement: High-level architecture diagram, service boundaries (bounded contexts), communication model
Source: Architect.md, Architect - High Level.md, Business Domain.md, Tech Stack Analysis.md
1. High-Level Architecture Diagram
┌─────────────────────────────────────┐
│ Azure Front Door │
│ CDN + WAF + Global Load Balance │
└──────────────────┬──────────────────┘
│
┌──────────────────┴──────────────────┐
│ React 18 SPA │
│ Azure Static Web Apps │
│ Shared Design System │
└──────────────────┬──────────────────┘
│ HTTPS
┌──────────────────┴──────────────────┐
│ API Gateway (YARP) │
│ Strangler Fig weighted routing │
│ Auth (JWT) │ Rate Limit │ CORS │
└──┬──────┬──────┬──────┬──────┬──────┘
│ │ │ │ │
┌────────────┘ │ │ │ └────────────┐
▼ ▼ │ ▼ ▼
┌──────────┐ ┌──────────┐ │ ┌──────────┐ ┌──────────────┐
│ Travel │ │ Event │ │ │Workforce │ │ Reporting │
│ Booking │ │ Mgmt │ │ │ + Alloc │ │ (CQRS) │
│ .NET 8 │ │ .NET 8 │ │ │ .NET 8 │ │ .NET 8 │
└────┬─────┘ └────┬─────┘ │ └────┬─────┘ └──────┬──────┘
│ │ │ │ │
┌────┴────┐ ┌────┴────┐ │ ┌────┴─────┐ │
│Travel DB│ │Event DB │ │ │Workforce │ │
│Azure SQL│ │Azure SQL│ │ │ DB │ │
└─────────┘ └─────────┘ │ └──────────┘ │
│ │
▼ │
┌──────────┐ ┌───────┴──────┐
│ Comms │ │ Reporting DB │
│ .NET 8 │ │ (CDC reads) │
└────┬─────┘ └──────────────┘
┌────┴────┐
│Comms DB │
│Azure SQL│
└─────────┘
╔═══════════════════════════════════════════════════════════════╗
║ Legacy Monolith (Payment Module — FROZEN Phase 1) ║
║ ┌───────────────────────────┐ ║
║ │ Payment + Invoicing │◄── ACL ── New Services call ║
║ │ Legacy SQL Server │ via adapter pattern ║
║ └───────────┬───────────────┘ ║
║ │ CDC ──────────────────► Reporting DB ║
╚═══════════════════════════════════════════════════════════════╝
┌──────────────────────────────────────────────────────────────┐
│ Azure Service Bus (Event-Driven Backbone) │
│ booking.* │ event.* │ workforce.* │ comms.* │ payment.acl.* │
│ Dead Letter Queue │ Retry Policies │ Schema Registry │
└──────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────┐
│ Observability: OpenTelemetry + Serilog │
│ AI Anomaly Detection │ Distributed Tracing │
│ Correlation ID propagation across all services │
└──────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────┐
│ Infrastructure: Bicep (IaC) │ GitHub Actions (CI/CD) │
│ Azure Container Apps │ Azure Key Vault │ ACR │
└──────────────────────────────────────────────────────────────┘
2. Service Boundaries (Bounded Contexts)
2.1 Service Catalog
| # |
Service |
Bounded Context |
Type |
Owns (Data) |
Key APIs |
| 1 |
Travel Booking |
Travel |
Core |
bookings, itineraries, suppliers, pricing |
/api/travel/* |
| 2 |
Event Management |
Events |
Core |
events, venues, schedules, attendees |
/api/events/* |
| 3 |
Workforce + Allocation |
Workforce |
Supporting |
staff, allocations, shifts, skills |
/api/staff/* |
| 4 |
Communications |
Comms |
Generic |
notifications, templates, delivery logs |
/api/comms/* |
| 5 |
Reporting |
Reporting |
Supporting |
report definitions, read models, dashboards |
/api/reports/* |
| 6 |
Payment (legacy) |
Payment |
Core (frozen) |
payments, invoices, reconciliation |
/api/payments/* via ACL |
2.2 Boundary Rationale
| Decision |
Chose |
Over |
Because |
| Travel & Event = separate |
2 services |
1 "Operations" service |
Different lifecycle, different scaling pattern (Travel = high-freq CRUD, Event = complex scheduling) |
| Allocation merged into Workforce |
1 service, 2 modules |
2 separate services |
Same domain (people + allocation), same data (staff skills, availability). 2 services too small |
| Communications = separate |
Cross-cutting service |
Embed in each service |
Avoid duplicate logic (email/SMS/push). Shared across all modules |
| Reporting = CQRS read service |
Dedicated service |
Each service serves own reports |
Cross-module reports need aggregated data. Read-only = scales differently than write |
| Payment = stay in legacy |
ACL bridge |
Migrate early |
Constraint: frozen Phase 1. Highest risk (PCI, financial). ACL isolates safely |
2.3 Data Ownership
Rule: Each service OWNs its own data. NO cross-service DB access.
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│Travel DB │ │Event DB │ │WFM DB │ │Comms DB │
│ │ │ │ │ │ │ │
│bookings │ │events │ │staff │ │notif_queue│
│itineraries│ │venues │ │shifts │ │templates │
│suppliers │ │attendees │ │skills │ │del_logs │
└──────────┘ └──────────┘ └──────────┘ └──────────┘
Need data from another service? → 3 approaches:
1. API call (sync, real-time)
2. Event subscribe (async, local copy)
3. CDC → Reporting (cross-module aggregation)
3. Communication Model
3.1 Patterns
| Pattern |
When |
Examples |
Protocol |
| Sync (REST) |
User expects immediate response |
Client → Gateway → Service |
HTTPS |
| Sync (REST via ACL) |
Legacy payment processing |
Travel → ACL → Legacy Payment |
HTTP internal |
| Async (Service Bus) |
State changes, notifications |
BookingCreated → Comms sends email |
Azure Service Bus Topics |
| CDC |
Legacy → Reporting data sync |
Monolith DB → CDC stream → Reporting DB |
Debezium / SQL CDC |
3.2 Three Rules
1. CLIENT CALLS = always sync (REST via API Gateway)
2. STATE CHANGES = publish event (async via Service Bus)
3. CROSS-SERVICE WRITE = never direct DB — always API or event
3.3 Event Flow
┌──────────────┐ BookingCreated ┌───────────────┐
│ Travel │ ──────────────────► │ Service Bus │
│ │ BookingCancelled │ │
└──────────────┘ ──────────────────► │ ┌─────────┐ │
│ │ Topics │ │
┌──────────────┐ EventCreated │ └────┬────┘ │
│ Event Mgmt │ ──────────────────► │ │ │
└──────────────┘ AttendeeRegistered │ │ │
──────────────────► │ │ │
┌──────────────┐ StaffAssigned │ │ │
│ Workforce │ ──────────────────► │ │ │
└──────────────┘ └───────┼──────┘
│
┌────────────────────────┬┘
▼ ▼
┌──────────────┐ ┌──────────────┐
│ Comms │ │ Reporting │
│ Subscribes: │ │ Subscribes: │
│ • booking.* │ │ • ALL events│
│ • event.* │ │ → update │
│ • payment.* │ │ read model│
│ → send email/│ │ projection│
│ SMS/push │ └──────────────┘
└──────────────┘
3.4 Event Schema Standard
{
"eventId": "uuid-v4",
"eventType": "travel.booking.created",
"source": "travel-booking-service",
"timestamp": "2026-03-14T10:30:00Z",
"version": "1.0",
"correlationId": "uuid-v4",
"data": { "bookingId": "BK-123", "userId": "USR-456", ... },
"metadata": { "tenantId": "tenant-001", "region": "APAC" }
}
Rules: Versioned, immutable, self-contained, idempotent consumers, AI-ready (stored in Event Store).
3.5 ACL — Legacy Payment Integration
New Service ──► PaymentACL ──► Legacy Monolith
│ │
├─ Translate ├─ LegacyPayment API
│ contracts │
├─ Map errors ├─ Legacy error codes
├─ Circuit break │
├─ Retry + DLQ │
└─ Log + trace │
Interface:
ProcessPayment(bookingId, amount, currency, idempotencyKey)
GetPaymentStatus(transactionId)
RequestRefund(transactionId, amount)
Key: Khi Payment modernized → swap ACL target, ZERO changes to consumers.
4. Tech Stack Summary
| Layer |
Choice |
Why |
| Backend |
.NET 8 microservices (Clean Architecture) |
Team expertise, LTS, top performance |
| Frontend |
React 18 + Shared Design System |
Largest ecosystem, AI generation support |
| Gateway |
YARP (.NET reverse proxy) |
Strangler Fig routing, lightweight, .NET native |
| Messaging |
Azure Service Bus |
Managed, enterprise SLA, dead letter support |
| Database |
Azure SQL per-service |
Managed, familiar, independent scaling |
| IaC |
Bicep (Azure-native) |
Simpler than Terraform for 100% Azure |
| Containers |
Azure Container Apps |
Serverless, auto-scale, no K8s ops |
| Observability |
OpenTelemetry + Serilog |
Vendor-neutral tracing + structured logging |
| Testing |
Pact (contract tests) |
Verify service boundaries without full E2E |
| AI Tooling |
Cursor Pro + Claude Code + CodeRabbit |
2x engineering multiplier |
5. Key Architecture Decisions (ADRs)
| # |
Decision |
Chose |
Over |
Rationale |
| ADR-001 |
Migration pattern |
Strangler Fig |
Big bang rewrite |
Zero downtime required, 40K users |
| ADR-002 |
API Gateway |
YARP |
Azure APIM |
.NET team, lighter, Strangler Fig routing native |
| ADR-003 |
Payment approach |
ACL to legacy |
Early modernize |
Constraint: frozen Phase 1 |
| ADR-004 |
Database |
Per-service Azure SQL |
Shared DB |
Service autonomy, independent deploy |
| ADR-005 |
Messaging |
Azure Service Bus |
Kafka/RabbitMQ |
Managed (5 eng can't ops Kafka), enterprise SLA |
| ADR-006 |
Container runtime |
Container Apps |
AKS |
5 engineers, no K8s ops overhead |
| ADR-007 |
Service-to-service |
Async events (default) |
Direct REST |
Loose coupling, resilience, event store for AI |
| ADR-008 |
Frontend |
Incremental React |
Full rewrite |
5 eng can't rewrite all UI simultaneously |