Business Rules & Validations
Mandatory fields, validation logic, and exception definitions per service. These rules are enforced at the service layer before any persistence.
Customer Service
Mandatory Fields — Create Customer
| Field |
Rule |
customerId |
Non-null, unique across customer_db |
firstName |
Required, max 100 chars |
lastName |
Required, max 100 chars |
dateOfBirth |
Required, must be in the past, customer ≥ 18 years old |
mobileNumber |
Required, 10-digit numeric, unique |
address |
Required — at least permanent address sub-object |
idType + idNumber |
Required together; idType must be enum: AADHAAR, PAN, PASSPORT, VOTER_ID, DRIVING_LICENSE |
Validation Rules
- Duplicate check:
mobileNumber and idNumber must not already exist in customer_master
- Age check:
dateOfBirth → age ≥ 18 (or configurable minimum from system setup)
- PAN format: if
idType=PAN, pattern [A-Z]{5}[0-9]{4}[A-Z]
- Aadhaar format: if
idType=AADHAAR, exactly 12 digits
- Status transitions:
ACTIVE → INACTIVE → DECEASED only (no reverse from DECEASED)
- Death Marking: once
status=DECEASED, no further updates except nominee processing
- Block List: adding to block list requires supervisor-role JWT claim
Exceptions
| Exception |
HTTP |
Trigger |
CustomerNotFoundException |
404 |
custId not found in repository |
DuplicateCustomerException |
409 |
Mobile or ID number already registered |
CustomerAlreadyDeceasedException |
422 |
Attempting update on deceased customer |
InvalidIdFormatException |
400 |
PAN/Aadhaar fails regex |
AgeRestrictionException |
400 |
Customer under minimum age |
Deposit Service
Mandatory Fields — Create Term Deposit
| Field |
Rule |
customerId |
Must resolve to existing, active customer |
productCode |
Must resolve to active deposit scheme in ms-product |
principalAmount |
Required, > 0, ≤ product.maxAmount |
tenureMonths |
Required, > 0, within product.minTenure–product.maxTenure |
depositDate |
Required, ≤ today |
maturityInstructions |
Required, enum: RENEW, PAYOUT, REINVEST |
Validation Rules
- Customer validation: Feign call to
ms-customer — must return ACTIVE status
- Product validation: Feign call to
ms-product — must return active scheme; tenure must fall within scheme tenure range
- Amount limits:
principalAmount must be within product.minAmount and product.maxAmount
- Rate slab: derived from product rate table at the time of booking — stored on
term_deposit.interestRate, not re-fetched
- Deposit number: auto-generated as
TD-{branchCode}-{yyyyMMdd}-{sequence}
- Maturity date:
depositDate + tenureMonths; if falls on holiday → next working day (system-setup calendar)
- Joint holders: max 3 joint holders; each must be valid
customerId
- Nominees: max 3 nominees; nominee percentage sum must equal 100
- Authorize: only users with role
AUTHORIZER or SUPERVISOR can authorize
- TDS: if annualized interest > ₹40,000 (₹50,000 for seniors), TDS deducted at 10% (or 20% if no PAN)
- Premature closure penalty: if closed before maturity, interest reduced by
product.prematureClosurePenaltyRate
- Renewal: only
status=MATURED deposits can be renewed
Exceptions
| Exception |
HTTP |
Trigger |
DepositNotFoundException |
404 |
Deposit number not found |
InvalidDepositStatusException |
422 |
Action not permitted for current status |
CustomerValidationException |
422 |
Customer not found or inactive |
ProductValidationException |
422 |
Product not found, inactive, or tenure out of range |
AmountLimitExceededException |
400 |
Principal outside product min/max |
JointHolderLimitException |
400 |
More than 3 joint holders |
NomineePercentageMismatchException |
400 |
Nominee percentages don't sum to 100 |
UnauthorizedAuthorizerException |
403 |
Authorizer role not present in JWT |
Product Service
Mandatory Fields — Create Deposit Scheme
| Field |
Rule |
schemeCode |
Unique, non-null, alphanumeric |
schemeName |
Required, max 200 chars |
schemeType |
Enum: FIXED_DEPOSIT, RECURRING_DEPOSIT, MIS, SENIOR_CITIZEN_FD |
minAmount |
Required, > 0 |
maxAmount |
Required, > minAmount |
minTenureMonths |
Required, > 0 |
maxTenureMonths |
Required, > minTenureMonths |
interestPaymentFrequency |
Enum: MONTHLY, QUARTERLY, HALF_YEARLY, ANNUALLY, AT_MATURITY |
Validation Rules
- Rate slabs: each slab must have non-overlapping tenure ranges; rates must be > 0
- Senior citizen rate: if
schemeType=SENIOR_CITIZEN_FD, seniorCitizenRateAddOn must be present
- GL account linkage:
glAccountHead must resolve in ms-generalledger (validated via Feign)
- Scheme deactivation: a scheme with active deposits cannot be deactivated
Exceptions
| Exception |
HTTP |
Trigger |
SchemeNotFoundException |
404 |
Product code not found |
DuplicateSchemeCodeException |
409 |
Scheme code already exists |
OverlappingRateSlabException |
400 |
Rate slab tenure ranges overlap |
ActiveDepositsExistException |
422 |
Cannot deactivate scheme with live deposits |
Transaction Service
Mandatory Fields — Create Transaction
| Field |
Rule |
transactionType |
Enum: CREDIT, DEBIT, TRANSFER |
amount |
Required, > 0 |
currency |
Default INR if not supplied |
referenceAccountId |
Required |
transactionDate |
Required, ≤ today |
narration |
Required, max 500 chars |
Validation Rules
- Amount precision: max 2 decimal places
- Duplicate prevention:
(referenceAccountId, transactionDate, amount, transactionType) composite key must be unique within a 5-minute window
- TransAll:
ms-generalledger debit + credit entries must balance (sum = 0)
- Exception transactions: must carry
exceptionReason and approvedBy
Exceptions
| Exception |
HTTP |
Trigger |
TransactionNotFoundException |
404 |
Reference not found |
DuplicateTransactionException |
409 |
Same transaction within 5-minute window |
UnbalancedTransAllException |
400 |
TransAll debit ≠ credit |
InvalidAmountException |
400 |
Amount ≤ 0 or > 3 decimals |
General Ledger Service
Mandatory Fields — Create GL Entry
| Field |
Rule |
accountHead |
Must reference valid head in gl_account_head |
entryType |
Enum: DEBIT, CREDIT |
amount |
Required, > 0 |
valueDate |
Required |
narration |
Required, max 500 chars |
Validation Rules
- Balance constraint: GL account must not exceed configured debit/credit limit
- Account Head status: head must be
ACTIVE to post entries
- Branchwise GL: postings are tagged with
branchCode from JWT claims
Exceptions
| Exception |
HTTP |
Trigger |
GLAccountHeadNotFoundException |
404 |
Account head code not found |
InactiveAccountHeadException |
422 |
Head is deactivated |
GLLimitExceededException |
422 |
Posting breaches configured limit |
Share Service
Mandatory Fields — Open Share Account
| Field |
Rule |
memberId |
Must resolve to active customer |
numberOfShares |
Required, > 0, ≤ max shares per member (system config) |
shareValue |
Derived from share configuration — not user-supplied |
Validation Rules
- Member validation: Feign call to
ms-customer — must be ACTIVE
- Share limit:
numberOfShares + existing shares ≤ system max shares per member
- Admission fee: one-time fee auto-posted to GL on account opening
Exceptions
| Exception |
HTTP |
Trigger |
ShareAccountNotFoundException |
404 |
Share account not found |
ShareLimitExceededException |
400 |
Over per-member share cap |
MemberValidationException |
422 |
Customer not found or inactive |
Periodic Activity Service
Mandatory Fields — Create Interest Rate Group
| Field |
Rule |
groupCode |
Unique, non-null |
groupName |
Required |
depositType |
Enum matching deposit scheme types |
effectiveDate |
Required, cannot be in the past |
Validation Rules
- Rate slabs: tenor ranges within a group must not overlap
- Effective date: group becomes active on
effectiveDate — rate changes are prospective only
- Backward compatibility: existing deposits retain the rate at time of booking
System Setup Service
Mandatory Fields — Branch Configuration
| Field |
Rule |
branchCode |
Unique, non-null |
branchName |
Required |
ifscCode |
Required, format [A-Z]{4}0[A-Z0-9]{6} |
workingDays |
Required, bitmask or list of MON–SUN |
Validation Rules
- IFSC format: regex
[A-Z]{4}0[A-Z0-9]{6} enforced
- Working hours:
openingTime < closingTime
- Holiday calendar: holiday dates must be unique per year per branch