Architecting Financial Systems: Context and Challenges
In the modern financial sector, software architecture must be both robust and transparent. A Core Banking System is the backbone of a financial institution, managing deposits, loans, transactions, and customer data with zero tolerance for ambiguity. For software architects and developers, documenting this complexity is critical. Traditional diagramming tools often lack versioning flexibility or require heavy local installations, slowing down the design phase.

Diagram-as-code offers a superior alternative. By writing diagram specifications in text, teams can maintain a living documentation source that is version-friendly, portable, and instantly renderable. Using PlantUML within VPasCode, engineers can prototype complex domain models like Core Banking without leaving the browser. This approach ensures that the visual representation of your system aligns perfectly with your codebase logic, enhancing clarity for stakeholders and developers alike.
Understanding the Model: Purpose, Scope & Problem Framing
Before diving into syntax, it is essential to understand the architectural abstraction being modeled. A Class Diagram is a static structure diagram that describes the structure of a system by showing the system’s classes, their attributes, operations (or methods), and the relationships among objects.
Diagram Abstraction & Representation
In this Core Banking System model, we are visualizing the static object-oriented structure. Classes represent real-world entities such as Account, Customer, or Transaction. Attributes define the state of these entities (e.g., balance, customerId), while Methods define behavior (e.g., deposit, withdraw). The relationships between these classes define the business rules, such as a Customer owning multiple Accounts or a Transaction belonging to a specific Account.
Target Domain Scope & Scenario
This diagram focuses on the core operational entities of a banking platform. It intentionally excludes external integrations like marketing systems or regulatory compliance engines to maintain focus on the transactional core. The scope includes:
- Account Management: Handling Savings, Checking, and Fixed Deposit accounts.
- Customer Lifecycle: Managing personal data and linking them to financial products.
- Transaction Processing: Recording financial movements and linking them to payment gateways.
- Personnel: Defining roles like Employees and Tellers who interact with the system.
Key Takeaways & Educational Insights
By constructing this model, you will gain insights into:
- How to implement inheritance hierarchies (Generalization) for account types.
- How to model cardinality (One-to-Many, Many-to-Many) between customers and accounts.
- How to distinguish between Composition (strong ownership) and Aggregation (weak ownership) in financial data structures.
Complete Diagram & Full Source Code
Below is the finished blueprint for the Core Banking System Class Diagram. You can view the rendered output directly in the VPasCode editor. The code block below is fully interactive; click the “Edit in VPasCode” button to modify and test changes instantly.

@startuml
!theme sunlust
title Core Banking System - Class Diagram
' Abstract base class
abstract class Account {
- accountNumber: String
- balance: BigDecimal
- currency: String
- openDate: Date
- status: AccountStatus
+ deposit(amount: BigDecimal): void
+ withdraw(amount: BigDecimal): void
+ getBalance(): BigDecimal
+ {abstract} calculateInterest(): BigDecimal
}
' Derived classes from Account
class SavingsAccount {
- interestRate: Double
- minimumBalance: BigDecimal
+ calculateInterest(): BigDecimal
+ applyMonthlyInterest(): void
}
class CheckingAccount {
- overdraftLimit: BigDecimal
- monthlyFee: BigDecimal
+ calculateInterest(): BigDecimal
+ processMonthlyFee(): void
}
class FixedDepositAccount {
- termMonths: Integer
- interestRate: Double
- maturityDate: Date
+ calculateInterest(): BigDecimal
+ calculateMaturityValue(): BigDecimal
}
' Customer class
class Customer {
- customerId: String
- firstName: String
- lastName: String
- dateOfBirth: Date
- email: String
- phoneNumber: String
- address: String
+ updatePersonalInfo(): void
+ getFullName(): String
}
' Transaction class
class Transaction {
- transactionId: String
- amount: BigDecimal
- transactionDate: Date
- transactionType: TransactionType
- description: String
+ processTransaction(): void
+ reverseTransaction(): void
}
' BankBranch class
class BankBranch {
- branchCode: String
- branchName: String
- address: String
- phoneNumber: String
+ openAccount(): void
+ closeAccount(): void
+ getTotalDeposits(): BigDecimal
}
' Employee class
class Employee {
- employeeId: String
- firstName: String
- lastName: String
- designation: String
- hireDate: Date
+ authorizeTransaction(): void
+ approveLoan(): void
}
' Teller class (subclass of Employee)
class Teller {
- tellerStationId: String
+ processCashTransaction(): void
+ handleCustomerService(): void
}
' Loan class
class Loan {
- loanId: String
- principalAmount: BigDecimal
- interestRate: Double
- loanTermMonths: Integer
- issueDate: Date
- dueDate: Date
+ calculateEMI(): BigDecimal
+ processPayment(): void
+ getOutstandingBalance(): BigDecimal
}
' Card class
class Card {
- cardNumber: String
- cvv: String
- expiryDate: Date
- cardType: CardType
- pinHash: String
+ authorizeTransaction(): boolean
+ blockCard(): void
+ changePin(): void
}
' PaymentGateway class
class PaymentGateway {
- gatewayId: String
- gatewayName: String
- apiKey: String
- processingFee: BigDecimal
+ processPayment(): boolean
+ refundPayment(): boolean
+ validateCard(): boolean
}
' ============ Relationships ============
' Generalization (Inheritance)
Account <|-- SavingsAccount
Account <|-- CheckingAccount
Account <|-- FixedDepositAccount
Employee <|-- Teller
' Association (Customer - Account) - One-to-Many
Customer "1" --> "0..*" Account : owns
' Association (Account - Transaction) - One-to-Many
Account "1" --> "0..*" Transaction : has
' Association (Customer - Transaction) - One-to-Many
Customer "1" --> "0..*" Transaction : performs
' Association (BankBranch - Account) - One-to-Many
BankBranch "1" --> "0..*" Account : manages
' Association (Employee - Customer) - Many-to-Many
Employee "1..*" --> "0..*" Customer : serves
' Composition (BankBranch - Employee) - Strong ownership
BankBranch *-- "1..*" Employee : employs
' Aggregation (Customer - Card) - Weak ownership
Customer o-- "0..*" Card : holds
' Association (Loan - Account) - One-to-One
Loan "1" --> "1" Account : linked_to
' Association (Transaction - PaymentGateway) - Many-to-One
Transaction "*" --> "1" PaymentGateway : processed_by
' Association (Teller - Transaction) - One-to-Many
Teller "1" --> "0..*" Transaction : processes
@enduml Step-by-Step Architectural Walkthrough
Phase 1: Canvas Configuration & Layout Directives
The first step in any PlantUML diagram is setting the global configuration. This establishes the visual theme and layout direction for the entire rendering engine. In this finance scenario, we use the sunlust theme to provide a professional, high-contrast look suitable for documentation.
We begin by declaring the start of the diagram and applying the theme:
@startuml
!theme sunlust
title Core Banking System - Class Diagram
The @startuml directive initializes the parser, while !theme sunlust loads the specific color palette and styling rules. The title directive adds a descriptive header to the rendered output, which is crucial for sharing diagrams with non-technical stakeholders.
Phase 2: Declaring Core Entities, Actors, and Boundaries
Next, we define the fundamental building blocks of the system. In Object-Oriented Design, we often start with a base class that captures common behavior. Here, Account is the cornerstone of the banking system.
We define it as an abstract class because an Account cannot exist in isolation; it must be a specific type like Savings or Checking. This enforces data integrity at the design level.
abstract class Account {
- accountNumber: String
- balance: BigDecimal
+ deposit(amount: BigDecimal): void
+ {abstract} calculateInterest(): BigDecimal
}
Notice the use of visibility modifiers. A hyphen - denotes private attributes (internal state), while a plus + denotes public methods (accessible behavior). We use BigDecimal for financial figures to ensure precision, avoiding floating-point errors common in other languages.
Phase 3: Mapping Data Flows & Key Interactions
With entities defined, we map the relationships that drive the business logic. Relationships define how objects interact. In PlantUML, these are drawn using specific arrow syntax.
- Inheritance: We use
<|--to show thatSavingsAccountextendsAccount. This means it inherits all properties and methods unless overridden. - Association: We use
-->to show a link. For example, a Customer “owns” Accounts. The cardinality"1" --> "0..*"specifies that one Customer can own zero or more Accounts.
Account <|-- SavingsAccount
Customer "1" --> "0..*" Account : owns
We also model the relationship between BankBranch and Employee using Composition (*--). This indicates strong ownership; if the Branch is deleted, the Employees associated with it are logically removed as well.
Phase 4: Grouping, Annotations & Visual Polish
The final phase involves adding advanced entities like PaymentGateway and Card to complete the ecosystem. We ensure that sensitive data like pinHash is included to reflect security requirements in the design.
We conclude by closing the diagram with @enduml. This signals the end of the PlantUML source code, allowing the renderer to process the entire model and generate the final image.
...
Teller "1" --> "0..*" Transaction : processes
@enduml
Syntax & Keyword Deep Dive
To master PlantUML Class Diagrams, you must understand the specific keywords that define structure and behavior. Below is a breakdown of the critical syntax used in this Core Banking System model.
abstract class: Defines a class that cannot be instantiated directly. It serves as a blueprint for subclasses likeSavingsAccount.<|--: Represents Generalization (Inheritance). The arrow points from the subclass to the superclass.-->: Represents a standard Association. It indicates a connection between two classes where one references the other.*--: Represents Composition. The filled diamond indicates strong ownership, meaning the child part cannot exist independently of the parent.o--: Represents Aggregation. The hollow diamond indicates weak ownership, meaning the child can exist independently of the parent."1..*"/"0..*": These are cardinality constraints.1..*means “one or more”, while0..*means “zero or more”.{abstract}: A stereotype placed inside a class block to mark a method as abstract, requiring implementation by subclasses.-/+: Visibility modifiers.-is private,+is public,#is protected, and~is package-private.
Best Practices & Pitfalls to Avoid
When modeling complex financial systems, clarity is paramount. Follow these best practices to ensure your PlantUML diagrams remain maintainable and readable.
- Keep Diagrams Modular: If your system grows too large, consider splitting the diagram into multiple files (e.g., one for Core Accounts, one for Payments) and linking them. This prevents visual clutter.
- Use Consistent Naming Conventions: Stick to PascalCase for classes (e.g.,
FixedDepositAccount) and camelCase for methods (e.g.,calculateInterest). This aligns with standard Java/C# conventions often used in banking software. - Define Cardinality Explicitly: Never leave relationship lines without cardinality labels. Ambiguity in “One-to-Many” relationships can lead to database design errors later.
- Avoid Over-Engineering: Start with the core entities. Do not add every possible attribute in the first draft. Focus on the relationships that drive business logic first.
Try It Yourself with VPasCode
Start Building PlantUML Class Diagrams Faster with VPasCode
Design professional Core Banking System models instantly in your browser with zero setup, live preview, and interactive syntax testing.