Domain / Business
Infrastructure
External Services
Events / Async
Security / Auth
Data / Storage
Domain Model
«aggregate root»Will
- willId: WillId (UUID)
- clientId: ClientId
- willjiniRef: String?
- status: DRAFT | IN_REVIEW | SIGNED | STORED | REVOKED
- content: WillContent (encrypted)
- nominees: List<Nominee>
- witnesses: List<Witness> (min 2)
- createdAt: Instant
- signedAt: Instant?
- lastReviewReminder: LocalDate?
+ draft(content): DomainEvent[WillDrafted]
+ submitForReview(): DomainEvent[WillSubmittedForReview]
+ sign(signatures): DomainEvent[WillSigned]
+ store(): DomainEvent[WillStored]
+ revoke(): DomainEvent[WillRevoked]
+ addNominee(nominee): void
+ updateContent(content): void
«entity»Nominee
- nomineeId: NomineeId
- name: String
- relation: SPOUSE | CHILD | PARENT | SIBLING | OTHER
- aadhaarHash: String (SHA-256)
- sharePercentage: BigDecimal
- assetAllocation: Map<AssetType, Percentage>
«aggregate»FamilyGroup
- groupId: FamilyGroupId
- name: String
- ownerId: ClientId
- members: Map<ClientId, FamilyRole>
- sharedPortfolios: Set<PortfolioId>
+ addMember(clientId, role): void
+ removeMember(clientId): void
+ changeRole(clientId, newRole): void
+ sharePortfolio(portfolioId): void
+ isAuthorized(clientId, action): Boolean
Willjini Will Creation Flow
MIA-guided conversational will creation → Willjini legal review → Digital signature → Secure storage
MIA Chat
MIA guides user through
asset inventory, nominees,
wishes, guardianship
Draft Will
CreateWillUseCase
assembles WillContent
from MIA conversation
Willjini Review
POST /api/v1/wills
Legal expert reviews
compliance check
Sign + Store
eSign (Aadhaar-based)
Encrypted storage
S3 + Vault
DRAFT
IN_REVIEW
SIGNED
STORED
REVOKED
«anti-corruption layer»WilljiniGatewayAdapter
implements: WillPlanningGateway (domain port)
- restClient: RestClient (API key auth)
- circuitBreaker: Resilience4j ("willjini", timeout=30s)
+ submitDraft(will): WilljiniDraftResult
+ checkReviewStatus(ref): ReviewStatus
+ downloadSignedCopy(ref): EncryptedDocument
+ scheduleReview(ref, date): void
Will Status Flow
DRAFT → IN_REVIEW (Willjini submitted)
IN_REVIEW → DRAFT (revisions needed)
IN_REVIEW → SIGNED (approved + signed)
SIGNED → STORED (encrypted + archived)
STORED → REVOKED (user revokes)
Annual reminder: "Review your will"
Security Requirements
Will content: AES-256-GCM encrypted
Key: AWS KMS (CMK per client)
Storage: S3 + cross-region replica
Access: audit log every access
Nominee Aadhaar: SHA-256 hash only
DPDP Act: consent before nominee data
MIA Will Creation Conversation (sample)
MIA: "Let's create your will. First, I'll need to understand your assets. Would you like me to pull your BYLD portfolio automatically?"
User: "Yes, include all my investments"
MIA: "I see 12.5L in mutual funds and 8.2L in equities. Who would you like as your primary nominee?"
User: "My wife Priya, 60%. Children 20% each."
MIA: "Done. I'll send this to Willjini for legal review. You'll get a notification once it's ready for your signature."
Family Office RBAC
Family Group: Sharma Family Office
👑
Rajesh Sharma
OWNER - Full control, will creator
👤
Priya Sharma
ADMIN - Manage, view, no delete
👤
Arjun Sharma
VIEWER - Read-only portfolio view
👤
Ananya Sharma
VIEWER - Read-only portfolio view
Permission Matrix
Action Owner Admin Viewer
View shared portfolio
View holdings detail SUMMARY
Place orders APPROVAL
View will
Manage nominees
Add/remove members ADD ONLY
Change roles
Export reports
RBAC Implementation
FamilyGroup.isAuthorized(clientId, action) → domain rule
JWT enriched with family roles at login (byld-identity)
Spring Security @PreAuthorize("hasRole('FAMILY_OWNER')")
Audit: every family action logged with actor + timestamp
Shared Portfolio View (Cross-Service Query)
Role-Based Field Filtering
Family Member
requests portfolio
with JWT + familyRole
byld-estate
FamilyGroup.isAuthorized
determines field mask
byld-portfolio
REST call with
X-Field-Mask header
Filtered Response
Only permitted fields
returned to client
// OWNER: full access
GET /api/v1/portfolio/{id}
Header: X-Field-Mask: *
// Returns: holdings, P&L, XIRR, transactions, cost basis
// VIEWER: summary only
GET /api/v1/portfolio/{id}
Header: X-Field-Mask: summary,allocation,total_value
// Returns: total value, asset allocation %, no individual holdings
«adapter»PortfolioQueryAdapter
implements: PortfolioQueryPort
- portfolioClient: RestClient
- fieldMaskResolver: FieldMaskResolver
+ getSharedPortfolio(portfolioId, role): FilteredPortfolio
+ getFamilyOverview(groupId): FamilyOverviewDTO
Privacy Rules (DPDP)
1. Owner must consent before sharing
2. Consent is revocable at any time
3. Viewer cannot screenshot (Kotlin CMP guard)
4. PAN/Aadhaar never shared to family
5. Transaction history: Owner/Admin only
6. Shared access logged for audit
Kafka Topics
byld.estate.events.will-drafted
byld.estate.events.will-signed
byld.estate.events.family-member-added
byld.estate.events.portfolio-shared
byld.estate.events.plan-updated
Architecture Notes
"Good fences make good neighbors."
-- Robert Frost (and also the Dependency Rule)
com.byld.estate
/domain Will, Nominee, FamilyGroup, FamilyRole, WillPlanningGateway, PortfolioQueryPort
/application CreateWillUseCase, ManageFamilyUseCase, SharePortfolioUseCase
/infrastructure WilljiniGatewayAdapter, PortfolioQueryAdapter, JpaWillRepository
/api WillController, FamilyController, NomineeController
Key Decisions:
1. Will content encrypted at rest (AES-256-GCM)
2. Willjini behind WillPlanningGateway port (swappable)
3. RBAC is a domain rule in FamilyGroup aggregate
4. Field masking via X-Field-Mask header (not separate endpoints)
5. Portfolio is read-only from estate (no write coupling)
6. Nominee data minimized (DPDP Act compliance)
Database
byld_estate (PostgreSQL)
Tables: wills (encrypted), nominees,
family_groups, family_members,
shared_portfolios, audit_log
Stability Metrics
Ca: 2 (mia, gateway)
Ce: 2 (Willjini, byld-portfolio)
Instability: 0.50 (balanced)
Abstractness: 0.5