FileContentStoreService.upload() opened a FileOutputStream (write) and an
InputStream (post-upload MIME check) without closing either. Windows keeps
those handles open for the JVM's lifetime, so the next upsert-style
delete-then-recreate of the same file (e.g. client signature/photo
re-upload) failed with FileSystemException: "being used by another
process". Wrapped both in try-with-resources.
Also adds every distinct non-individual/constitution KYC document name
(HUF, Private/Public Ltd, LLP, Partnership, Trust, Society, Proprietorship,
Association, Govt/PSU, Cooperative) as a KYCIdProofType code value.
resolveDocumentTypeId() on the frontend matches the picked document name
against this list before creating a client_identifier; since these entity
document names had no corresponding code value, every non-individual
client's KYC document upload silently failed to persist.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Add m_client.signature_id (single-slot pointer, mirrors image_id) plus
ClientSignatureIdAdapter/EntitySignatureIdAdapter so re-uploading a signature updates the
existing m_document row in place instead of leaving duplicate rows behind that readers picked
inconsistently.
- Fix CkycBatchBuilderServiceImpl address-proof classification to read the client identifier's
actual m_code (KYCAddressProofType vs KYCIdProofType) instead of a hardcoded string set that
disagreed with the CKYC tab and silently dropped Aadhaar-as-address-proof identifiers.
- Organize the CKYC ZIP into per-artefact-type folders (PHOTO/SIGNATURE/ID_PROOF/ADDRESS_PROOF).
- Fix CkycBatchBuilderServiceImpl.createBatch() using the daily batch sequence number as the ZIP
document's parent_entity_id instead of the real m_ckyc_batch.id, which 404'd on download
whenever the two diverged (i.e. almost always).
- Add monthlyTurnover and annualIncome fields alongside the existing annualTurnover/monthlyIncome.
- Add isSeniorCitizen, isPwd, and pwdCategory (proper m_code_value-backed PwdCategory code, not a
free-text column) to m_client, following the same pattern as occupation/religion/marital status.
- Add Diploma as its own Education Level (with diploma-specific DegreeQualification values) and
Graduate as a level distinct from Undergraduate.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Login 2FA via @Primary MfaFactorBackedTwoFactorServiceImpl (replaces legacy)
- LincPay SMS OTP and SMTP email OTP with auto-promote to m_user_mfa_factor
- Reusable EmailSenderService + EmailTemplateService (CBSnexora branding)
- Admin OTP audit viewer (GET /v1/otp-logs) with paging, search, masking
- Self-service MFA factor API at /v1/mfa/factors
- READ_OTP_LOG permission + OTP Log Auditor role + bankadmin direct grant
- JsonAuthenticationEntryPoint suppresses Basic-auth popup for SPA paths
- TwoFactorAuthenticationFilter grants TWOFACTOR_AUTHENTICATED when no challenge
- Soft-delete + audit columns + deletion audit + version on client tables
- CIF number generator (TTYYYYNNNNNN format)
- DocumentNotFoundExceptionMapper to silence noisy WARN logs on missing images
- Liquibase migrations 0278-0291 (MFA, OTP log, audit/soft-delete, role wiring)
Note: application.properties intentionally not committed — contains local DB
and Gmail App Password fallbacks. Set SPRING_MAIL_PASSWORD,
FINERACT_DEFAULT_TENANTDB_PWD, FINERACT_HIKARI_PASSWORD as env vars in prod.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>