01 Behavioral
Strategy
Define a family of algorithms, encapsulate each one, and make them interchangeable at runtime.
«interface»RiskScoringStrategy
+ score(profile): RiskScore
ConservativeScorer
+ score()
AggressiveScorer
+ score()
byld-advisory → RiskScoringStrategy
byld-mia → PersonaStrategy
Swap risk models per tier without changing use case logic
Strategy — Full Hierarchy
RiskScoringStrategy «interface»
└─ ConservativeScorer
└─ BalancedScorer
└─ AggressiveScorer
PersonaStrategy «interface»
└─ WealthPersona (warm, advisory)
└─ MarketsPersona (sharp, data)
FeeCalculationStrategy «interface»
└─ FlatFeeCalculation
└─ AumBasedFeeCalculation
└─ TieredFeeCalculation
02 Structural
Repository
Mediate between domain and data mapping layers using a collection-like interface for domain objects.
«interface»PortfolioRepository
+ findById(id): Portfolio?
+ save(p: Portfolio)
+ findByClient(c): List
JpaPortfolioRepository
- entityManager: EM
+ findById() + save()
byld-portfolio → PortfolioRepository
byld-identity → ClientRepository
Domain stays pure; JPA is a swappable plugin
Repository — Full Hierarchy
PortfolioRepository (domain.port)
└─ JpaPortfolioRepository (infra.persistence)
└─ InMemoryPortfolioRepo (test)
ClientRepository (domain.port)
└─ JpaClientRepository
GoalRepository (domain.port)
└─ JpaGoalRepository
ChatSessionRepository (domain.port)
└─ RedisSessionRepository
└─ JpaSessionRepository
03 Creational
Factory
Encapsulate complex object creation logic, ensuring aggregates are always created in a valid state.
«factory»PortfolioFactory
+ createForClient(cmd)
+ reconstitute(snapshot)
«aggregate»Portfolio
- holdings[]
- summary
«event»PortfolioCreated
clientId, tier
byld-portfolio → PortfolioFactory
byld-identity → ClientFactory
Aggregates born valid; creation rules in one place
Factory — Full Hierarchy
PortfolioFactory
└─ creates Portfolio aggregate
└─ with Holdings[], Money totalValue
└─ emits PortfolioCreated event
ClientFactory
└─ creates Client aggregate
└─ with RiskProfile, KycStatus
GoalFactory
└─ creates Goal (retirement/education/...)
└─ calculates required SIP via FV formula
04 Behavioral
Observer
Domain events notify interested parties without the aggregate knowing who listens.
«aggregate»Portfolio
+ addHolding()
→ raises HoldingAdded
«interface»EventPublisherPort
+ publish(event)
KafkaEventPublisher
+ publish(event)
All services → EventPublisherPort
byld-notification → EventConsumer
Loose coupling via domain events over Kafka
Observer — Domain Events
Portfolio raises:
HoldingAdded, TransactionRecorded
PortfolioRebalanced
Client raises:
ClientOnboarded, KycCompleted
TierUpgraded
EventPublisherPort
└─ KafkaEventPublisher
└─ InMemoryEventBus (test)
05 Architectural
Saga
Coordinate distributed transactions across microservices with compensation on failure.
«saga»MFOrderSaga
+ start(cmd)
+ onPaymentConfirmed()
+ compensate()
CreateOrder
step 1
DebitPayment
step 2
SubmitBSE
step 3
byld-distribution → MFOrderSaga
byld-payments → PaymentSaga
No 2PC; eventual consistency with compensating txns
Saga — Orchestrated Steps
MFOrderSaga
Step 1: CreateOrder in byld-distribution
Step 2: DebitPayment in byld-payments
Step 3: SubmitToBSE via MFU Central
Compensate: RefundPayment → CancelOrder
KycOnboardingSaga
Step 1: VerifyAadhaar (UIDAI)
Step 2: VerifyPAN (NSDL)
Step 3: CreateCKYC (KRA)
Compensate: RollbackKRA → NotifyClient
06 Architectural
Anti-Corruption Layer
Translate between external system models and our domain model, preventing foreign concepts from leaking in.
Our Domain
Portfolio
«ACL»MorningstarACL
+ translate(ext)
+ toFundData()
Morningstar
API Model
byld-portfolio → MorningstarACL
byld-identity → AadhaarACL, NSDLACL
External API changes never ripple into domain
ACL — Translation Boundaries
MorningstarACL
Morningstar FundDTO → FundData VO
Morningstar NAVDTO → NAV VO
AadhaarACL
UIDAI eKYC XML → AadhaarIdentity VO
FinvuACL
AA FI Data JSON → AccountAggregate VO
BSE/MFU ACL
MFU OrderResponse → OrderConfirmation
07 Structural
Decorator
Attach additional responsibilities dynamically without altering the original class.
«interface»LlmPort
+ chat(prompt): Response
CachingLlmDecorator
- cache: Redis
+ chat()
AuditingLlmDecorator
- auditLog
+ chat()
byld-mia → CachingLlmDecorator
byld-mia → AuditingLlmDecorator
Layer caching + SEBI audit without touching core LLM adapter
Decorator — Layered Wrappers
LlmPort
└─ ClaudeApiAdapter (base)
└─ CachingLlmDecorator wraps above
└─ AuditingLlmDecorator wraps above
└─ RateLimitingDecorator wraps above
Call chain:
RateLimit → Audit → Cache → Claude API
08 Behavioral
Chain of Responsibility
Pass requests along a chain of handlers; each handler decides to process or pass along.
AuthHandler
RateLimitHdlr
ComplianceHdlr
UseCase
«interface»RequestHandler
+ handle(req): Response
+ setNext(h): Handler
byld-gateway → API filter chain
byld-mia → MessageValidationChain
Security, rate-limiting, compliance checks without if-else soup
Chain of Responsibility — Pipeline
Gateway Filter Chain:
JwtAuthHandler
RateLimitHandler (tier-based)
ComplianceHandler (SEBI check)
AuditLogHandler
RouteToService
09 Architectural
CQRS
Separate read and write models to optimize each independently for scale and complexity.
«write»PortfolioAggregate
+ addHolding()
+ recordTxn()
«read»PortfolioReadModel
+ getSummary()
+ getXIRR()
Aurora PostgreSQL
(write store)
ElastiCache Redis
(materialized view)
sync
byld-portfolio → write/read split
byld-markets → quote projections
Reads scale independently; sub-100ms dashboard loads
CQRS — Separate Models
WRITE SIDE (Commands):
AddHoldingCommand → Aggregate
RecordTransactionCmd → Aggregate
Store: Aurora PostgreSQL (normalized)
READ SIDE (Queries):
GetPortfolioSummaryQuery
GetXIRRQuery
Store: Redis (denormalized projections)
Sync: Kafka event → projection handler
10 Creational
Builder
Construct complex objects step by step, separating construction from representation.
«builder»AdvisoryReportBuilder
+ withSummary(s)
+ withRiskAnalysis(r)
+ withRecommendations(r)
+ build(): Report
«value_object»AdvisoryReport
- sections: List<Section>
- generatedAt: Instant
byld-advisory → AdvisoryReportBuilder
byld-mia → PromptBuilder
Complex reports built fluently; immutable once built
Builder — Fluent Construction
AdvisoryReportBuilder
.withClientProfile(profile)
.withRiskAnalysis(analysis)
.withAssetAllocation(alloc)
.withRecommendations(recs)
.withDisclaimer(sebiDisclaimer)
.build() → AdvisoryReport (immutable)
PromptBuilder
.withSystemPrompt(persona)
.withContext(portfolio, goals)
.withHistory(messages[])
.build() → MiaPrompt
11 Behavioral
Template Method
Define the skeleton of an algorithm in a base class, deferring specific steps to subclasses.
«abstract»AbstractKycVerifier
+ verify() {template}
# extractData()
# validateRules()
# submitToKRA()
AadhaarKycVerifier
# extractData()
# validateRules()
PanKycVerifier
# extractData()
# validateRules()
byld-identity → AbstractKycVerifier
byld-advisory → AbstractRiskProfiler
KYC flow is standard; only extraction details differ per doc type
Template Method — KYC Flow
AbstractKycVerifier
1. extractData() {abstract}
2. validateRules() {abstract}
3. checkAML() {final}
4. submitToKRA() {abstract}
5. notifyClient() {final}
Implementations:
AadhaarKycVerifier (UIDAI eKYC)
PanKycVerifier (NSDL/UTI)
DigilockerKycVerifier
12 Architectural
Ports & Adapters
The application talks to the outside world through ports; adapters plug in to implement them.
DOMAIN + USE CASES
REST
Adapter
JPA
Adapter
Kafka
Adapter
Claude
Adapter
All services → Hexagonal Architecture
Domain has zero framework imports
The foundational pattern; all others compose within it
Ports & Adapters — Hexagonal
DRIVING PORTS (left side):
SendMessagePort ← REST
GetPortfolioPort ← REST
OnboardClientPort ← REST
DRIVEN PORTS (right side):
LlmPort → Claude API
PortfolioRepository → JPA
EventPublisherPort → Kafka
VectorStorePort → Pinecone