Using C4-PlantUML with Best Practices from the Bank EA Framework
In today’s complex, cloud-native enterprise landscape, architecture documentation must do more than illustrate system structureâit must enable traceability, support governance, and communicate effectively across technical and non-technical stakeholders. Yet too often, architectural diagrams become outdated silos, disconnected from implementation and business strategy.

International Hotel Management System (IHMS)Â is a cloud-native platform that enables global hotel chains to manage reservations, guest experiences, room inventory, pricing, and operations across multiple properties, currencies, and languages.
Key Capabilities:
Multi-property, multi-brand hotel management
Real-time room availability and dynamic pricing
Guest profiles with preferences and loyalty integration
Channel management (OTA, direct, corporate bookings)
Payment processing with multi-currency support
Housekeeping, maintenance, and staff scheduling
Analytics and revenue management dashboards
Shows the scope of the system and how users and external systems interact with it.

Â
@startuml
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Context.puml
LAYOUT_WITH_LEGEND()
title System Context Diagram - International Hotel Management System
' === Actors ===
Person(guest, "Hotel Guest", "A traveler booking or staying at a hotel property.")
Person(hotelStaff, "Hotel Staff", "Front desk, housekeeping, or management personnel.")
Person(revenueManager, "Revenue Manager", "Staff responsible for pricing strategy and inventory optimization.")
' === Core System ===
System(ihms, "International Hotel Management System", "Central platform for managing reservations, guest services, inventory, pricing, and operations across global hotel properties.")
' === External Systems ===
System_Ext(ota, "Online Travel Agencies (OTA)", "Expedia, Booking.com, Airbnb - external booking channels.")
System_Ext(paymentGateway, "Payment Gateway", "Stripe, Adyen, PayPal - processes guest payments and refunds.")
System_Ext(emailSystem, "Email & Notification Service", "SendGrid, AWS SES - sends booking confirmations and alerts.")
System_Ext(crm, "Customer Relationship Management", "Salesforce, HubSpot - manages guest loyalty and marketing.")
System_Ext(pms, "Legacy Property Management System", "Existing on-premise PMS at acquired hotel properties.")
' === Relationships ===
Rel(guest, ihms, "Books stays, manages reservations, checks in/out")
Rel(hotelStaff, ihms, "Manages check-ins, room assignments, guest requests")
Rel(revenueManager, ihms, "Sets pricing rules, monitors occupancy, adjusts inventory")
Rel(ihms, ota, "Syncs availability & rates, receives bookings via", "API/XML")
Rel(ihms, paymentGateway, "Processes payments and refunds via", "HTTPS/JSON")
Rel(ihms, emailSystem, "Sends confirmations and alerts via", "SMTP/API")
Rel(ihms, crm, "Syncs guest profiles and loyalty data via", "REST API")
Rel(ihms, pms, "Migrates or syncs property data during transition", "Batch/SOAP")
Rel_Back(guest, ota, "Discovers and books hotels via")
Rel_Back(guest, emailSystem, "Receives booking confirmations from")
@enduml
â Enterprise Alignment Tips:
Replace generic Person with enterprise role types: Guest, StaffRole, ManagementRole
Add Stakeholder relationships compatible with BPMN for process mapping
Link ihms to Business Capability: Reservation Management in your EA repository
Zooms into the IHMS boundary, showing high-level deployable technology components.

Â
@startuml
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml
LAYOUT_WITH_LEGEND()
title Container Diagram - International Hotel Management System
' === Actors ===
Person(guest, "Hotel Guest", "A traveler booking or staying at a hotel property.")
Person(hotelStaff, "Hotel Staff", "Front desk, housekeeping, or management personnel.")
Person(revenueManager, "Revenue Manager", "Staff responsible for pricing strategy.")
' === External Systems ===
System_Ext(ota, "Online Travel Agencies (OTA)", "Expedia, Booking.com - external booking channels.")
System_Ext(paymentGateway, "Payment Gateway", "Stripe, Adyen - processes payments.")
System_Ext(emailSystem, "Email Service", "SendGrid - sends notifications.")
System_Ext(crm, "CRM System", "Salesforce - guest loyalty and marketing.")
' === System Boundary ===
System_Boundary(ihms, "International Hotel Management System") {
Container(webPortal, "Guest Web Portal", "React/Node.js", "Responsive web app for guests to search, book, and manage stays.")
Container(mobileApp, "Mobile App", "React Native", "iOS/Android app for booking, digital key, and in-stay services.")
Container(staffPortal, "Staff Operations Portal", "Vue.js/Spring Boot", "Web interface for front desk, housekeeping, and management.")
Container(apiGateway, "API Gateway", "Kong/Node.js", "Central entry point for all client requests; handles auth, rate limiting, routing.")
Container(bookingService, "Booking Service", "Java/Spring Boot", "Manages reservation lifecycle, availability checks, and booking rules.")
Container(inventoryService, "Inventory & Pricing Service", "Java/Spring Boot", "Manages room inventory, dynamic pricing, and rate plans.")
Container(guestService, "Guest Profile Service", "Java/Spring Boot", "Manages guest identities, preferences, and loyalty data.")
Container(paymentService, "Payment Service", "Java/Spring Boot", "Orchestrates payment processing, refunds, and invoicing.")
ContainerDb(primaryDb, "Primary Database", "PostgreSQL Cluster", "Stores reservations, guest profiles, inventory, and transactions.")
ContainerDb(cacheDb, "Cache Layer", "Redis Cluster", "Caches availability, pricing, and session data for performance.")
Container(analyticsService, "Analytics & Reporting Service", "Python/Spark", "Generates occupancy reports, revenue forecasts, and KPIs.")
}
' === Guest Interactions ===
Rel(guest, webPortal, "Searches hotels, books stays, manages reservations", "HTTPS")
Rel(guest, mobileApp, "Checks in digitally, requests services, uses digital key", "HTTPS")
Rel(webPortal, apiGateway, "Makes API calls to", "JSON/HTTPS")
Rel(mobileApp, apiGateway, "Makes API calls to", "JSON/HTTPS")
' === Staff Interactions ===
Rel(hotelStaff, staffPortal, "Manages check-ins, room assignments, guest requests", "HTTPS")
Rel(revenueManager, staffPortal, "Adjusts pricing rules, monitors dashboards", "HTTPS")
Rel(staffPortal, apiGateway, "Makes API calls to", "JSON/HTTPS")
' === Internal Service Communication ===
Rel(apiGateway, bookingService, "Routes booking requests to", "gRPC/Protobuf")
Rel(apiGateway, inventoryService, "Routes availability/pricing queries to", "gRPC/Protobuf")
Rel(apiGateway, guestService, "Routes guest profile requests to", "gRPC/Protobuf")
Rel(apiGateway, paymentService, "Routes payment requests to", "gRPC/Protobuf")
Rel(bookingService, inventoryService, "Checks/updates room availability via", "gRPC")
Rel(bookingService, paymentService, "Initiates payment authorization via", "gRPC")
Rel(bookingService, guestService, "Retrieves/updates guest preferences via", "gRPC")
' === Data Persistence ===
Rel(bookingService, primaryDb, "Reads/writes reservations via", "JDBC")
Rel(inventoryService, primaryDb, "Reads/writes inventory/pricing via", "JDBC")
Rel(guestService, primaryDb, "Reads/writes guest profiles via", "JDBC")
Rel(paymentService, primaryDb, "Records transactions via", "JDBC")
Rel(bookingService, cacheDb, "Caches availability data via", "Redis Protocol")
Rel(inventoryService, cacheDb, "Caches pricing rules via", "Redis Protocol")
' === External Integrations ===
Rel(bookingService, ota, "Syncs availability and receives bookings via", "XML/HTTPS")
Rel(paymentService, paymentGateway, "Processes payments via", "REST/JSON")
Rel(bookingService, emailSystem, "Sends booking confirmations via", "SMTP/API")
Rel(guestService, crm, "Syncs guest loyalty data via", "REST API")
Rel(analyticsService, primaryDb, "Reads data for reporting via", "Read Replica JDBC")
@enduml
đ Metamodel Integration: Add Deployed on relationships to link containers to Kubernetes clusters, cloud regions, or infrastructure platforms.
Zooms into the Booking Service container to show its internal logical components.

@startuml
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Component.puml
LAYOUT_WITH_LEGEND()
title Component Diagram - Booking Service (IHMS)
' === External Dependencies ===
Container(apiGateway, "API Gateway", "Kong/Node.js", "Central entry point for all client requests.")
Container(inventoryService, "Inventory & Pricing Service", "Java/Spring Boot", "Manages room inventory and dynamic pricing.")
Container(guestService, "Guest Profile Service", "Java/Spring Boot", "Manages guest identities and preferences.")
Container(paymentService, "Payment Service", "Java/Spring Boot", "Orchestrates payment processing.")
ContainerDb(primaryDb, "Primary Database", "PostgreSQL Cluster", "Stores reservations and transactional data.")
' === Booking Service Boundary ===
Container_Boundary(bookingSvc, "Booking Service") {
Component(bookingController, "Booking Controller", "Spring MVC RestController", "Handles HTTP/gRPC requests for reservation CRUD operations.")
Component(validationComponent, "Booking Validation Engine", "Spring Bean", "Validates booking rules: dates, rates, guest eligibility, channel policies.")
Component(pricingComponent, "Pricing Calculator", "Spring Bean", "Computes final price including taxes, fees, discounts, and loyalty benefits.")
Component(availabilityChecker, "Availability Checker", "Spring Bean", "Coordinates with Inventory Service to verify room availability.")
Component(notificationComponent, "Notification Orchestrator", "Spring Bean", "Triggers confirmation emails, SMS, and CRM updates post-booking.")
Component(reservationRepository, "Reservation Repository", "Spring Data JPA", "Data access layer for reservation entities.")
Component(bookingEventPublisher, "Booking Event Publisher", "Spring Cloud Stream", "Publishes domain events: BookingCreated, BookingModified, BookingCancelled.")
}
' === Inbound Requests ===
Rel(apiGateway, bookingController, "Forwards booking requests to", "gRPC/Protobuf")
' === Controller to Internal Components ===
Rel(bookingController, validationComponent, "Validates booking request via")
Rel(bookingController, pricingComponent, "Calculates final price via")
Rel(bookingController, availabilityChecker, "Checks room availability via")
' === Component Collaborations ===
Rel(validationComponent, guestService, "Verifies guest status and loyalty tier via", "gRPC")
Rel(pricingComponent, inventoryService, "Fetches applicable rate plans via", "gRPC")
Rel(availabilityChecker, inventoryService, "Checks real-time room availability via", "gRPC")
Rel(bookingController, reservationRepository, "Persists reservation via", "JDBC")
Rel(reservationRepository, primaryDb, "Reads/writes to", "PostgreSQL Protocol")
' === Post-Booking Actions ===
Rel(bookingController, paymentService, "Initiates payment authorization via", "gRPC")
Rel(bookingController, notificationComponent, "Triggers guest notifications via")
Rel(notificationComponent, apiGateway, "Sends confirmation events to", "Async Events")
' === Event Publishing ===
Rel(bookingEventPublisher, primaryDb, "Reads reservation changes via", "CDC/Debezium")
Rel(bookingEventPublisher, apiGateway, "Publishes domain events to", "Kafka/gRPC")
@enduml
đĄ Governance Tip: Component diagrams should be owned by Tech Leads and updated during sprint planning or when modifying service boundaries.
Shows the implementation structure of the BookingController with interfaces, dependencies, and domain models.

@startuml
title Code Diagram - BookingController Dependencies (IHMS)
' === Interfaces ===
interface IBookingController {
+createBooking(request: BookingRequest): BookingResponse
+getBooking(bookingId: String): BookingDetails
+modifyBooking(bookingId: String, changes: BookingChanges): BookingResponse
+cancelBooking(bookingId: String, reason: String): CancellationResponse
}
interface IBookingValidator {
+validateDates(checkIn: LocalDate, checkOut: LocalDate): ValidationResult
+validateGuestEligibility(guestId: String, ratePlanId: String): ValidationResult
+validateChannelPolicy(channel: BookingChannel, request: BookingRequest): ValidationResult
}
interface IPricingCalculator {
+calculateTotal(roomRate: BigDecimal, nights: int, guestTier: LoyaltyTier, promoCode: String): PriceBreakdown
}
interface IAvailabilityService {
+checkAvailability(propertyId: String, roomType: String, dates: DateRange): AvailabilityResult
+reserveInventory(reservationId: String, items: List<InventoryItem>): Boolean
}
' === Core Classes ===
class BookingController {
-validator: IBookingValidator
-pricingCalculator: IPricingCalculator
-availabilityService: IAvailabilityService
-reservationRepo: IReservationRepository
-eventPublisher: IBookingEventPublisher
-logger: ILogger
+createBooking(request: BookingRequest): BookingResponse
+getBooking(bookingId: String): BookingDetails
+modifyBooking(bookingId: String, changes: BookingChanges): BookingResponse
+cancelBooking(bookingId: String, reason: String): CancellationResponse
-validateAndPrice(request: BookingRequest): PricedBooking
}
class BookingRequest {
+propertyId: String
+roomTypeId: String
+checkInDate: LocalDate
+checkOutDate: LocalDate
+guestId: String
+channel: BookingChannel
+promoCode: String
+paymentMethod: PaymentToken
}
class BookingResponse {
+bookingId: String
+confirmationNumber: String
+totalPrice: BigDecimal
+currency: Currency
+status: BookingStatus
+checkInInstructions: String
}
class Reservation {
+id: String
+propertyId: String
+roomId: String
+guestId: String
+checkIn: LocalDateTime
+checkOut: LocalDateTime
+totalAmount: BigDecimal
+currency: Currency
+status: ReservationStatus
+createdAt: Instant
+modifiedAt: Instant
}
' === Supporting Classes ===
class PriceBreakdown {
+baseRate: BigDecimal
+taxes: BigDecimal
+fees: BigDecimal
+discounts: BigDecimal
+loyaltyPointsEarned: int
+finalTotal: BigDecimal
}
class AvailabilityResult {
+isAvailable: boolean
+availableRooms: int
+alternativeDates: List<DateRange>
+ratePlanId: String
}
' === Relationships ===
IBookingController <|-- BookingController
BookingController --> IBookingValidator : uses
BookingController --> IPricingCalculator : uses
BookingController --> IAvailabilityService : uses
BookingController --> IReservationRepository : persists
BookingController --> IBookingEventPublisher : publishes
BookingController ..> BookingRequest : accepts
BookingController ..> BookingResponse : returns
BookingController ..> Reservation : maps to
IPricingCalculator ..> PriceBreakdown : returns
IAvailabilityService ..> AvailabilityResult : returns
note right of BookingController
Thread-safe, stateless controller
Uses dependency injection (Spring)
Validates input before business logic
Publishes domain events after commit
end note
@enduml
â ď¸Â Best Practice: Level 4 diagrams should only be created for complex, critical, or frequently changed components. Avoid over-diagramming to reduce maintenance overhead.
Customize your C4 diagrams with a professional light theme:
!define DEVICONS https://raw.githubusercontent.com/tupadr3/plantuml-icon-font-sprites/master/devicons
!define FONTAWESOME https://raw.githubusercontent.com/tupadr3/plantuml-icon-font-sprites/master/font-awesome-5
!include DEVICONS/react.puml
!include DEVICONS/java.puml
!include FONTAWESOME/hotel.puml
!include FONTAWESOME/database.puml
SkinParam backgroundColor #FFFFFF
SkinParam shadowing false
SkinParam defaultFontSize 13
SkinParam defaultFontName "Segoe UI"
' Professional color palette
!define PRIMARY #2563EB ' Blue
!define SECONDARY #7C3AED ' Purple
!define SUCCESS #10B981 ' Green
!define WARNING #F59E0B ' Amber
!define DANGER #EF4444 ' Red
' Apply semantic colors
skinparam rectangle {
BackgroundColor<<Person>> #FEF3C7
BackgroundColor<<System>> #DBEAFE
BackgroundColor<<Container>> #D1FAE5
BackgroundColor<<Component>> #EDE9FE
BorderColor<<External>> #9CA3AF
BorderThickness<<External>> 2
}
' Relationship styling
skinparam arrow {
Color #6B7280
Thickness 1.5
}
| Area | Action Item | Owner |
|---|---|---|
| Metamodel | Embed C4 elements into EA repository with typed relationships (Uses, Deployed on, Is part of) |
Enterprise Architect |
| Governance | Require Self-Explanatory Diagram Checklist for all Architecture Review Board submissions | Architecture Governance |
| Ownership | Assign layer owners: L1 (Business Arch), L2 (Solution Arch), L3 (Tech Lead), L4 (Senior Dev) | Delivery Leadership |
| Tooling | Standardize on C4-PlantUML + version control (Git) for diagram-as-code | Platform Engineering |
| Traceability | Link C4 elements to business capabilities, value streams, and epics in Jira/ADO | Product Management |
| Maintenance | Schedule quarterly diagram audits; tie updates to sprint retrospectives | Engineering Managers |
đĄ Final Thought: Great architecture documentation doesn’t describe what was builtâit enables what comes next. Keep it lean, keep it linked, and keep it living.
đĄÂ Pro Tip: Start with Level 1 and 2 diagrams during solution design. Add Level 3 during sprint 0 for complex services. Use Level 4 only for onboarding docs or critical component deep-dives.
This case study demonstrates how the C4 modelâwhen embedded in an enterprise metamodelâcreates traceable, maintainable, and stakeholder-aligned architecture documentation for complex global systems.