Detailed Architecture
Architecture Design — Legacy Platform Modernization
Deliverable 1: Target Architecture Overview
Includes: High-level diagram, service boundaries, communication model
Approach: AI-first, Strangler Fig, 2x AI multiplier
1. Architecture Vision
1.1 Current State (Legacy Monolith)
┌─────────────────────────────────────────────────────────────────────┐
│ Legacy .NET Monolith │
│ (Single deployment unit) │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │
│ │ Travel Booking│ │ Event Mgmt │ │ Payment │ │
│ │ Controllers │ │ Controllers │ │ Controllers │ │
│ │ Services │ │ Services │ │ Services │ │
│ │ Repositories │ │ Repositories │ │ Repositories │ │
│ └───────┬───────┘ └───────┬───────┘ └───────┬───────┘ │
│ │ │ │ │
│ ┌───────┴───────┐ ┌──────┴────────┐ ┌──────┴────────┐ │
│ │ Workforce Mgmt│ │ Communications│ │ Reporting │ │
│ │ Controllers │ │ Controllers │ │ Controllers │ │
│ │ Services │ │ Services │ │ Services │ │
│ │ Repositories │ │ Repositories │ │ Repositories │ │
│ └───────────────┘ └───────────────┘ └────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Shared Data Access Layer (EF6) │ │
│ └──────────────────────────┬──────────────────────────────────┘ │
│ │ │
└──────────────────────────────┼──────────────────────────────────────┘
│
┌──────────┴──────────┐
│ │
│ Monolithic Database │
│ (Single SQL Server) │
│ │
│ ~200+ tables │
│ Cross-module FKs │
│ Shared stored procs│
│ │
└─────────────────────┘
Problems:
- Single deployment = must deploy everything for 1 bug fix
- Tight coupling via shared DB → changing 1 table impacts multiple modules
- Must scale entire monolith when only Travel Booking is under heavy load
- .NET Framework → no longer receiving security patches, outdated ecosystem
- Not event-driven → no audit trail, cannot feed AI/ML
- Hard to test → tight coupling = integration tests must run against entire system
1.2 Target State (End of 9 Months)
┌──────────────────────────────────────────────────────────────────────────┐
│ CLIENTS │
│ Web (React 18) │ Mobile │ External APIs │
└────────────────────────────────┬─────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────────────────┐
│ API GATEWAY (YARP) │
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ Strangler Fig Router │ │
│ │ ┌──────────────┐ ┌────────────────┐ ┌────────────────────────┐ │ │
│ │ │ /api/travel/* │ │ /api/payment/* │ │ /api/events/* │ │ │
│ │ │ → Travel Svc │ │ → LEGACY │ │ → Event Svc │ │ │
│ │ └──────────────┘ └────────────────┘ └────────────────────────┘ │ │
│ │ ┌──────────────┐ ┌────────────────┐ ┌────────────────────────┐ │ │
│ │ │ /api/comms/* │ │ /api/staff/* │ │ /api/reports/* │ │ │
│ │ │ → Comms Svc │ │ → Workforce Svc│ │ → Reporting Svc │ │ │
│ │ └──────────────┘ └────────────────┘ └────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
│ Cross-cutting: Rate Limiting │ Auth (JWT) │ Request Logging │ CORS │
│ AI: Smart routing │ Anomaly detection │ Traffic analysis │
└──────────────────────────────────────────────────────────────────────────┘
│ │ │ │ │ │
▼ ▼ ▼ ▼ ▼ ▼
┌──────────────────────────────────────────────────────────────────────────┐
│ MICROSERVICES LAYER │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Travel │ │ Event │ │Workforce │ │ Comms │ │Reporting │ │
│ │ Booking │ │ Mgmt │ │ Mgmt │ │ Service │ │ (CQRS) │ │
│ │ Service │ │ Service │ │ Service │ │ │ │ │ │
│ │ .NET 8 │ │ .NET 8 │ │ .NET 8 │ │ .NET 8 │ │ .NET 8 │ │
│ │ │ │ │ │ │ │ │ │ │ │
│ │ REST API │ │ REST API │ │ REST API │ │ REST API │ │ REST API │ │
│ │ Events │ │ Events │ │ Events │ │ Events │ │ Queries │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │ │ │ │
│ ┌────┴────┐ ┌────┴────┐ ┌────┴─────┐ ┌────┴─────┐ │ │
│ │Travel DB│ │Event DB │ │Workforce │ │ Comms DB │ │ │
│ │ (SQL) │ │ (SQL) │ │ DB │ │ (SQL) │ │ │
│ └─────────┘ └─────────┘ └──────────┘ └──────────┘ │ │
│ │ │
│ ┌──────────────────────────────────────────────────┐ │ │
│ │ Legacy Monolith │ │ │
│ │ ┌──────────────────────┐ │ │ │
│ │ │ Payment Module │ ◄── ACL ──────── │ ── │ ── services │
│ │ │ (FROZEN Phase 1) │ │ │ │
│ │ └──────────┬───────────┘ │ │ │
│ │ │ │ │ │
│ │ ┌──────────┴───────────┐ │ │ │
│ │ │ Monolith DB │ │ │ │
│ │ │ (Payment tables + │──── CDC ────────►│────┘ │
│ │ │ shared legacy data) │ (read sync) │ Reporting DB │
│ │ └──────────────────────┘ │ (Read replicas) │
│ └──────────────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────────────┘
│ │ │ │ │
▼ ▼ ▼ ▼ ▼
┌──────────────────────────────────────────────────────────────────────────┐
│ EVENT BUS (Azure Service Bus) │
│ │
│ Topics: │
│ ┌─────────────────┐ ┌───────────────┐ ┌──────────────────────────┐ │
│ │ travel.booking.* │ │ event.mgmt.* │ │ workforce.assignment.* │ │
│ │ .created │ │ .created │ │ .created │ │
│ │ .updated │ │ .updated │ │ .updated │ │
│ │ .cancelled │ │ .cancelled │ │ .completed │ │
│ └─────────────────┘ └───────────────┘ └──────────────────────────┘ │
│ ┌─────────────────┐ ┌───────────────┐ │
│ │ comms.notify.* │ │ payment.acl.* │ ◄── Legacy payment events │
│ │ .email │ │ .requested │ via ACL adapter │
│ │ .sms │ │ .completed │ │
│ │ .push │ │ .failed │ │
│ └─────────────────┘ └───────────────┘ │
│ │
│ Dead Letter Queue │ Retry Policies │ Event Schema Registry │
└──────────────────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────────────────┐
│ OBSERVABILITY & AI LAYER │
│ │
│ ┌──────────────┐ ┌───────────────┐ ┌─────────────┐ ┌───────────────┐ │
│ │ OpenTelemetry│ │ Serilog │ │ Health │ │ AI Anomaly │ │
│ │ Tracing │ │ Structured │ │ Checks │ │ Detection │ │
│ │ (Jaeger/ │ │ Logging │ │ /health │ │ (Azure Mon. │ │
│ │ Zipkin) │ │ (Seq/ELK) │ │ /ready │ │ + custom) │ │
│ └──────────────┘ └───────────────┘ └─────────────┘ └───────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────────────────────┐ │
│ │ AI-Ready Data Foundation │ │
│ │ Event Store (all domain events) → Future: ML training, analytics │ │
│ │ Structured logs → Future: predictive maintenance │ │
│ └────────────────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────────────────┐
│ INFRASTRUCTURE (IaC) │
│ │
│ Azure Container Apps │ Azure SQL │ Azure Service Bus │ Azure Monitor │
│ Bicep (Azure-native) │ GitHub Actions CI/CD │ Docker │ Azure Key Vault │
└──────────────────────────────────────────────────────────────────────────┘
2. Service Boundaries (Bounded Contexts)
2.1 Service Catalog
| # | Service | Bounded Context | Owns | Responsibility |
|---|---|---|---|---|
| 1 | Travel Booking Service | Travel | bookings, itineraries, suppliers, search | CRUD travel bookings, supplier integration, search, pricing rules |
| 2 | Event Management Service | Events | events, venues, schedules, attendees | Event lifecycle, scheduling, venue management, attendee registration |
| 3 | Workforce Management Service | Workforce | staff, allocations, availability, shifts | Staff assignment, availability tracking, allocation algorithms |
| 4 | Communications Service | Communications | notifications, templates, delivery logs | Email, SMS, push notifications, template management, delivery tracking |
| 5 | Reporting Service | Reporting | report definitions, cached aggregates | Read-only queries (CQRS), dashboards, data export, scheduled reports |
| 6 | Payment Module (legacy) | Payment | payments, invoices, reconciliation | Stays in monolith Phase 1. Accessed via ACL by new services |
2.2 Service Ownership & Data Boundaries
┌─────────────────────────────────────────────────────────────────┐
│ DATA OWNERSHIP MAP │
│ │
│ Travel Booking Service Event Management Service │
│ ┌─────────────────────┐ ┌────────────────────────┐ │
│ │ OWNS: │ │ OWNS: │ │
│ │ • bookings │ │ • events │ │
│ │ • itineraries │ │ • venues │ │
│ │ • travel_suppliers │ │ • event_schedules │ │
│ │ • travel_pricing │ │ • attendees │ │
│ │ • booking_status │ │ • event_categories │ │
│ │ │ │ │ │
│ │ READS (via event): │ │ READS (via event): │ │
│ │ • staff availability │ │ • staff availability │ │
│ │ │ │ │ │
│ │ CALLS (via ACL): │ │ CALLS (via ACL): │ │
│ │ • payment.process │ │ • payment.process │ │
│ └─────────────────────┘ └────────────────────────┘ │
│ │
│ Workforce Service Communications Service │
│ ┌─────────────────────┐ ┌────────────────────────┐ │
│ │ OWNS: │ │ OWNS: │ │
│ │ • staff_profiles │ │ • notification_queue │ │
│ │ • allocations │ │ • message_templates │ │
│ │ • shifts │ │ • delivery_logs │ │
│ │ • availability │ │ • channel_configs │ │
│ │ • skills_matrix │ │ │ │
│ │ │ │ SUBSCRIBES TO: │ │
│ │ PUBLISHES: │ │ • travel.booking.* │ │
│ │ • staff.assigned │ │ • event.mgmt.* │ │
│ │ • staff.available │ │ • payment.acl.* │ │
│ └─────────────────────┘ └────────────────────────┘ │
│ │
│ Reporting Service (CQRS) Payment Module (LEGACY) │
│ ┌─────────────────────┐ ┌────────────────────────┐ │
│ │ OWNS: │ │ OWNS (in monolith DB): │ │
│ │ • report_definitions │ │ • payments │ │
│ │ • cached_aggregates │ │ • invoices │ │
│ │ • export_jobs │ │ • payment_methods │ │
│ │ │ │ • reconciliation_logs │ │
│ │ READS (via CDC): │ │ │ │
│ │ • ALL domain data │ │ EXPOSED VIA ACL: │ │
│ │ (read replicas) │ │ • ProcessPayment() │ │
│ └─────────────────────┘ │ • GetPaymentStatus() │ │
│ │ • RefundPayment() │ │
│ └────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
2.3 Boundary Decision Rationale
| Boundary Decision | Rationale | Alternative Considered |
|---|---|---|
| Travel & Event = separate services | Different lifecycle, different domain experts, different scaling patterns. Travel = high-frequency CRUD, Event = complex scheduling | Merge into 1 "Operations" service → rejected because too large, hard to scale |
| Workforce = separate service | Allocation algorithms involve complex logic, independent scaling, different team ownership | Embed in Travel → rejected because workforce is used by Event as well |
| Communications = separate service | Cross-cutting concern, shared across all modules. Low coupling, easy to extract | Each service sends its own notifications → rejected due to duplicate logic, inconsistent UX |
| Reporting = CQRS read service | Read-only, different pattern (query vs command), different scaling profile (heavy reads) | Each service serves its own reports → rejected because cross-module reports need joined data |
| Payment = stay in legacy | Constraint (frozen Phase 1) + highest risk + regulatory compliance | Extract early → rejected because it violates the constraint + risk too high |
3. Communication Model
3.1 Overview
┌──────────────────────────────────────────────────────────────┐
│ COMMUNICATION PATTERNS │
│ │
│ SYNCHRONOUS (REST/gRPC) ASYNCHRONOUS (Events) │
│ ───────────────────── ──────────────────── │
│ • Client → API Gateway • Service → Event Bus │
│ • Service → ACL → Legacy • Event Bus → Subscribers │
│ • Service → Service (query only) • CDC → Reporting │
│ │
│ Rule: Commands via REST. Rule: State changes via │
│ Queries via REST. Events. │
│ Cross-service mutation Notifications via │
│ via Events ONLY. Events. │
└──────────────────────────────────────────────────────────────┘
3.2 Synchronous Communication (REST)
| From | To | Protocol | Use Case | Why Sync? |
|---|---|---|---|---|
| Client | API Gateway | HTTPS/REST | All user-facing requests | User expects immediate response |
| API Gateway | Any Service | HTTP/REST | Request routing | Strangler Fig routing pattern |
| Travel Service | Payment ACL | HTTP/REST | ProcessPayment() |
Payment needs immediate confirmation for booking |
| Event Service | Payment ACL | HTTP/REST | ProcessPayment() |
Same — registration needs payment confirmation |
| Any Service | Workforce Service | HTTP/REST | CheckAvailability() |
Real-time availability query |
API Gateway Contract:
YARP Routing Configuration:
Route: /api/travel/** → https://travel-service:8080
Route: /api/events/** → https://event-service:8080
Route: /api/workforce/** → https://workforce-service:8080
Route: /api/comms/** → https://comms-service:8080
Route: /api/reports/** → https://reporting-service:8080
Route: /api/payments/** → https://legacy-monolith:80 ← Strangler Fig
Route: /** → https://legacy-monolith:80 ← Catch-all (legacy)
Transition: Routes shift from legacy → new as services go live.
When module is fully migrated, route permanently points to new.
3.3 Asynchronous Communication (Azure Service Bus)
Event Flow:
┌──────────────┐ BookingCreated ┌──────────────┐
│ Travel │ ──────────────────► │ Azure │
│ Booking │ BookingCancelled │ Service Bus │
│ Service │ ──────────────────► │ │
└──────────────┘ │ ┌────────┐ │
│ │ Topics │ │
┌──────────────┐ EventCreated │ └────┬───┘ │
│ Event │ ──────────────────► │ │ │
│ Management │ AttendeeRegistered │ │ │
│ Service │ ──────────────────► │ │ │
└──────────────┘ │ │ │
│ │ │
┌──────────────┐ StaffAssigned │ │ │
│ Workforce │ ──────────────────► │ │ │
│ Service │ ShiftUpdated │ │ │
└──────────────┘ ──────────────────► │ │ │
└───────┼──────┘
│
┌──────────────────────────┬┘
│ │
▼ ▼
┌──────────────┐ ┌──────────────┐
│ Comms Service│ │ Reporting │
│ │ │ Service │
│ Subscribes: │ │ │
│ • booking.* │ │ Subscribes: │
│ • event.* │ │ • ALL events │
│ • payment.* │ │ (read model │
│ │ │ projection) │
│ Action: │ │ │
│ Send email/ │ │ Action: │
│ SMS/push │ │ Update read │
└──────────────┘ │ models │
└──────────────┘
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-12345",
"userId": "USR-67890",
"destination": "Tokyo",
"departureDate": "2026-06-15",
"totalAmount": 2500.00,
"currency": "USD"
},
"metadata": {
"tenantId": "tenant-001",
"region": "APAC"
}
}
Event Schema Rules:
- Versioned —
versionfield, backward compatible evolution - Immutable — events are facts, never modified
- Self-contained — consumer must NOT need to call back to producer
- Idempotent — consumers must handle duplicate delivery
- AI-ready — every event captured in Event Store for future ML/analytics
3.5 Anti-Corruption Layer (ACL) — Legacy Payment Integration
┌───────────────────┐ ┌──────────────────────┐ ┌─────────────────┐
│ New Service │ │ Anti-Corruption │ │ Legacy Monolith │
│ (Travel/Event) │ │ Layer (ACL) │ │ (Payment) │
│ │ │ │ │ │
│ PaymentRequest │ │ ┌────────────────┐ │ │ │
│ { │──────►│ │ Translator │ │ │ │
│ bookingId, │ │ │ │ │ │ LegacyPayment │
│ amount, │ │ │ New contract │ │──────►│ { │
│ currency, │ │ │ → Legacy format │ │ │ OrderId, │
│ idempotencyKey │ │ │ │ │ │ Amount, │
│ } │ │ └────────────────┘ │ │ CurrCode, │
│ │ │ │ │ RefNo │
│ │ │ ┌────────────────┐ │ │ } │
│ PaymentResult │ │ │ Error Mapper │ │ │ │
│ { │◄──────│ │ │ │◄──────│ LegacyResult │
│ success, │ │ │ Legacy errors │ │ │ { │
│ transactionId, │ │ │ → New errors │ │ │ Status, │
│ status │ │ │ │ │ │ TxnId, │
│ } │ │ └────────────────┘ │ │ ErrCode │
│ │ │ │ │ } │
│ │ │ ┌────────────────┐ │ │ │
│ │ │ │ Circuit Breaker │ │ │ │
│ │ │ │ Retry Policy │ │ │ │
│ │ │ │ Timeout (5s) │ │ │ │
│ │ │ └────────────────┘ │ │ │
└───────────────────┘ └──────────────────────┘ └─────────────────┘
Key: When Payment is modernized → change ACL target, ZERO changes to consumers.
ACL Responsibilities:
- Contract translation: New service contracts ↔ Legacy API formats
- Error mapping: Legacy error codes → standardized error responses
- Resilience: Circuit breaker, retry with backoff, timeout
- Logging: Every ACL call logged for audit trail
- Testing: Contract tests verify ACL ↔ legacy compatibility
4. Service Internal Architecture
4.1 Clean Architecture Per Service
Each microservice follows the same internal structure:
ServiceName/
├── src/
│ ├── ServiceName.API/ ← Entry point
│ │ ├── Controllers/ ← REST endpoints
│ │ ├── Middleware/ ← Auth, logging, error handling
│ │ ├── Filters/ ← Validation, exception filters
│ │ ├── Program.cs ← Host configuration
│ │ └── appsettings.json
│ │
│ ├── ServiceName.Application/ ← Business logic
│ │ ├── Commands/ ← Write operations (CQRS)
│ │ ├── Queries/ ← Read operations (CQRS)
│ │ ├── EventHandlers/ ← Handle inbound events
│ │ ├── Services/ ← Application services
│ │ ├── DTOs/ ← Data transfer objects
│ │ └── Interfaces/ ← Port definitions
│ │
│ ├── ServiceName.Domain/ ← Domain models
│ │ ├── Entities/ ← Domain entities
│ │ ├── ValueObjects/ ← Immutable value types
│ │ ├── Events/ ← Domain events
│ │ ├── Exceptions/ ← Domain-specific errors
│ │ └── Interfaces/ ← Repository contracts
│ │
│ └── ServiceName.Infrastructure/ ← External concerns
│ ├── Persistence/ ← EF Core DbContext, configs
│ ├── Messaging/ ← Azure Service Bus publishers
│ ├── ExternalServices/ ← ACL, third-party integrations
│ └── Caching/ ← Redis/in-memory cache
│
├── tests/
│ ├── ServiceName.UnitTests/
│ ├── ServiceName.IntegrationTests/
│ └── ServiceName.ContractTests/ ← Pact consumer/provider tests
│
├── Dockerfile
├── docker-compose.yml
└── README.md
4.2 Shared Patterns Across All Services
┌─────────────────────────────────────────────────────┐
│ CROSS-CUTTING CONCERNS │
│ │
│ ┌──────────────┐ Applied to ALL services: │
│ │ NuGet Package│ │
│ │ SharedKernel │ • Structured logging (Serilog) │
│ │ │ • OpenTelemetry tracing │
│ │ │ • Health check endpoints │
│ │ │ • Exception handling middleware │
│ │ │ • Correlation ID propagation │
│ │ │ • Event publishing abstractions │
│ │ │ • Base entity classes │
│ │ │ • Common value objects │
│ └──────────────┘ │
│ │
│ Published as internal NuGet package. │
│ Version-controlled. Breaking changes = major bump. │
└─────────────────────────────────────────────────────┘
5. Database Architecture
5.1 Per-Service Database Strategy
┌─────────────────────────────────────────────────────────────────┐
│ DATABASE TOPOLOGY │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌──────────────┐ │
│ │ Travel DB │ │ Event DB │ │ Workforce DB │ │
│ │ Azure SQL │ │ Azure SQL │ │ Azure SQL │ │
│ │ │ │ │ │ │ │
│ │ bookings │ │ events │ │ staff │ │
│ │ itineraries │ │ venues │ │ allocations │ │
│ │ suppliers │ │ schedules │ │ shifts │ │
│ │ pricing │ │ attendees │ │ skills │ │
│ └─────────────┘ └─────────────┘ └──────────────┘ │
│ │
│ ┌─────────────┐ ┌──────────────────────────────────────┐ │
│ │ Comms DB │ │ Reporting DB (Read-only) │ │
│ │ Azure SQL │ │ Azure SQL │ │
│ │ │ │ │ │
│ │ templates │ │ ┌──────────┐ ┌──────────┐ ┌───────┐ │ │
│ │ queue │ │ │ Travel │ │ Event │ │ Staff │ │ │
│ │ logs │ │ │ ReadModel│ │ ReadModel│ │ Read │ │ │
│ └─────────────┘ │ └──────────┘ └──────────┘ └───────┘ │ │
│ │ ┌──────────┐ ┌──────────┐ │ │
│ │ │ Payment │ │ Cross- │ │ │
│ │ │ ReadModel│ │ module │ │ │
│ │ │ (via CDC)│ │ joins │ │ │
│ │ └──────────┘ └──────────┘ │ │
│ └──────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────┐ │
│ │ Legacy Monolith DB │ │
│ │ (Payment tables + legacy data) │ │
│ │ │ │
│ │ CDC ──────────────────────► Reporting DB (read replicas) │
│ │ ACL ◄──────────────────── New services (write via ACL) │
│ └──────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
5.2 Data Sync Strategies
| Scenario | Strategy | How |
|---|---|---|
| New service → new service (read) | Events | Subscribe to domain events, maintain local projection |
| New service → legacy payment (write) | ACL (sync call) | REST call through ACL → legacy API |
| Legacy DB → Reporting (read) | CDC (Change Data Capture) | Debezium/Azure CDC → Reporting DB read models |
| Data migration (one-time) | ETL + CDC | Initial bulk load (ETL) then continuous sync (CDC) |
| Cross-service queries | API Composition at Gateway or Reporting Service | No cross-DB joins. Use Reporting for aggregated views |
5.3 Database Migration Path
Phase 0–1: Shared DB with Views
┌─────────────────────────────────────┐
│ Monolith DB │
│ ┌─────────┐ ┌─────────┐ ┌────────┐ │
│ │ Travel │ │ Event │ │ Payment│ │
│ │ tables │ │ tables │ │ tables │ │
│ └────┬────┘ └────┬────┘ └────────┘ │
│ │ │ │
│ DB Views: DB Views: │
│ Travel Svc Event Svc │
│ can ONLY can ONLY │
│ see these see these │
└─────────────────────────────────────┘
Phase 2–3: Per-Service DBs
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Travel │ │ Event │ │ Monolith │
│ DB │ │ DB │ │ DB │
│ (own) │ │ (own) │ │ (Payment)│
└──────────┘ └──────────┘ └──────────┘
Data migrated via CDC. Legacy DB shrinks as modules extract.
6. Frontend Architecture
6.1 Incremental React Migration
┌──────────────────────────────────────────────────────────────┐
│ FRONTEND ARCHITECTURE │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ App Shell (React 18) │ │
│ │ Navigation │ Auth │ Layout │ Shared Design System │ │
│ └──────────────────────────┬──────────────────────────────┘ │
│ │ │
│ ┌──────────────┬────────────┼──────────┬──────────────────┐ │
│ │ │ │ │ │ │
│ ▼ ▼ ▼ ▼ ▼ │
│ ┌────────┐ ┌────────┐ ┌────────┐ ┌──────────┐ ┌─────────┐ │
│ │ Travel │ │ Events │ │ Reports│ │ Workforce│ │ Payment │ │
│ │ Module │ │ Module │ │ Module │ │ Module │ │ Module │ │
│ │ React │ │ React │ │ React │ │ React │ │ LEGACY │ │
│ │ 18 │ │ 18 │ │ 18 │ │ 18 │ │ (iframe │ │
│ │ ✅ NEW │ │ ✅ NEW │ │ ✅ NEW │ │ ⚠️ Basic │ │ /old UI)│ │
│ └────────┘ └────────┘ └────────┘ └──────────┘ └─────────┘ │
│ │
│ Shared Design System (Storybook): │
│ Buttons │ Forms │ Tables │ Modals │ Charts │ Navigation │
└──────────────────────────────────────────────────────────────┘
Strategy:
- App Shell: React 18, contains nav + auth + layout. Deployed immediately in Phase 0–1
- Module-by-module: Each module migrates when the corresponding backend service goes live
- Legacy iframe: Payment UI embedded in React shell via iframe (Phase 1–2)
- Shared Design System: Shared components, built upfront via Storybook
- Code splitting: Each module lazy-loaded, only downloaded when user navigates to it
7. Infrastructure Architecture
7.1 Deployment Topology
┌──────────────────────────────────────────────────────────────┐
│ AZURE CLOUD │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Azure Container Apps Environment │ │
│ │ │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │ Travel │ │ Event │ │Workforce │ Auto-scale │ │
│ │ │ Service │ │ Service │ │ Service │ per service │ │
│ │ │ (2 inst) │ │ (2 inst) │ │ (1 inst) │ │ │
│ │ └──────────┘ └──────────┘ └──────────┘ │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │ Comms │ │ Reporting│ │ YARP │ │ │
│ │ │ Service │ │ Service │ │ Gateway │ │ │
│ │ │ (1 inst) │ │ (2 inst) │ │ (2 inst) │ │ │
│ │ └──────────┘ └──────────┘ └──────────┘ │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────────┐ │
│ │ Azure SQL │ │ Azure │ │ Azure Service Bus │ │
│ │ (per-service │ │ Key Vault │ │ (Standard tier) │ │
│ │ databases) │ │ (secrets) │ │ │ │
│ └──────────────┘ └──────────────┘ └──────────────────────┘ │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────────┐ │
│ │ Azure Monitor│ │ Azure CDN │ │ Azure Container │ │
│ │ + App │ │ (React SPA) │ │ Registry (ACR) │ │
│ │ Insights │ │ │ │ │ │
│ └──────────────┘ └──────────────┘ └──────────────────────┘ │
│ │
│ Legacy VM / App Service (Monolith — unchanged) │
└──────────────────────────────────────────────────────────────┘
7.2 CI/CD Pipeline
Developer Push → GitHub Actions
│
├── 1. Build (.NET 8 + React)
├── 2. Unit Tests
├── 3. Contract Tests (Pact)
├── 4. SAST Security Scan (CodeQL)
├── 5. Docker Build → Push to ACR
├── 6. Deploy to Staging (Azure Container Apps)
├── 7. Integration Tests on Staging
├── 8. Manual Approval Gate (for production)
└── 9. Deploy to Production (rolling update, zero downtime)
Branch Strategy:
main ← feature/* (PR required, CodeRabbit + human review)
main → staging (auto-deploy)
staging → production (manual approval)
8. Security Architecture
┌──────────────────────────────────────────────────────────────┐
│ SECURITY LAYERS │
│ │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ Layer 1: Edge (API Gateway) │ │
│ │ • TLS termination (HTTPS only) │ │
│ │ • JWT validation (Azure AD / Auth0) │ │
│ │ • Rate limiting (per-user, per-IP) │ │
│ │ • CORS policy enforcement │ │
│ │ • Request size limits │ │
│ └────────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ Layer 2: Service-to-Service │ │
│ │ • Managed identities (Azure AD) │ │
│ │ • mTLS between services (Container Apps built-in) │ │
│ │ • No direct DB access from other services │ │
│ │ • Service mesh networking (internal only) │ │
│ └────────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ Layer 3: Data │ │
│ │ • Encryption at rest (Azure SQL TDE) │ │
│ │ • Encryption in transit (TLS 1.3) │ │
│ │ • Secrets in Azure Key Vault (no secrets in config) │ │
│ │ • PII data masked in logs │ │
│ │ • Payment data: legacy monolith only (Phase 1) │ │
│ └────────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ Layer 4: Pipeline │ │
│ │ • SAST (CodeQL) in CI │ │
│ │ • Dependency scanning (Dependabot/Snyk) │ │
│ │ • Container image scanning │ │
│ │ • AI-generated code: same security gates as human code │ │
│ └────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
9. Observability Architecture
┌──────────────────────────────────────────────────────────────┐
│ THREE PILLARS + AI │
│ │
│ LOGS TRACES METRICS │
│ ──── ────── ─────── │
│ Serilog OpenTelemetry OpenTelemetry │
│ → Seq/ELK → Jaeger/Zipkin → Prometheus │
│ → Grafana │
│ Structured JSON Distributed trace Service health │
│ Correlation ID across services Request rate │
│ PII-masked End-to-end latency Error rate │
│ Dependency map Latency p50/p95/p99│
│ │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ AI Layer (added value) │ │
│ │ • Anomaly detection on metrics (Azure Monitor AI) │ │
│ │ • Log pattern analysis (clustering errors) │ │
│ │ • Predictive alerting (trend-based, not threshold) │ │
│ │ • Smart routing adjustment based on error rates │ │
│ └────────────────────────────────────────────────────────┘ │
│ │
│ Health Checks: │
│ /health → liveness (is process running?) │
│ /ready → readiness (can accept traffic? DB connected?) │
│ /startup → startup probe (large initialization complete?) │
└──────────────────────────────────────────────────────────────┘
10. Architecture Decision Records (ADRs)
| ADR# | Decision | Status | Rationale |
|---|---|---|---|
| ADR-001 | Use Strangler Fig Pattern for migration | Accepted | Zero downtime constraint. Only viable incremental approach |
| ADR-002 | YARP as API Gateway | Accepted | .NET-native, lightweight, supports dynamic routing for Strangler Fig |
| ADR-003 | Azure Service Bus for async messaging | Accepted | Enterprise-grade, built-in dead letter, Azure-native |
| ADR-004 | Per-service databases (eventual) | Accepted | Service autonomy. Phased: shared views first → split later |
| ADR-005 | Payment stays in monolith Phase 1 | Accepted | Constraint. ACL isolates new services from payment complexity |
| ADR-006 | Clean Architecture per service | Accepted | Testability, separation of concerns, consistent team patterns |
| ADR-007 | Contract testing with Pact | Accepted | Verify service compatibility without full E2E. Faster feedback |
| ADR-008 | CDC for legacy-to-reporting data sync | Accepted | Non-invasive (no legacy code changes), real-time, reliable |
| ADR-009 | Shared NuGet package for cross-cutting | Accepted | DRY for logging, tracing, health checks. Versioned independently |
| ADR-010 | Event schema versioning | Accepted | Backward compatibility. Consumers evolve independently |
| ADR-011 | AI-first engineering with 2x multiplier | Accepted | PhoenixDX mandate. 5 eng/9 months requires force multiplication |
| ADR-012 | AI-generated code same CI gates as human | Accepted | 60-75% code is AI-generated → must meet same quality bar |