- Authors

- Name
- Youngju Kim
- @fjvbn20031
- 들어가며
- 여신 업무 도메인 개관
- LOS 파이프라인 — 신청부터 실행까지
- 비대면 대출의 실시간 파이프라인
- 한도 관리 시스템
- 담보 관리 시스템
- 금리 산출 — 프라이싱 구조
- 약정과 실행 — 기표와 원장 연동
- 외부 연동 맵
- 상태 머신 설계
- 재심사, 조건변경, 대환
- 시스템 설계 시 함정
- 테스트 시나리오
- 마치며
- 참고 자료
들어가며
은행 계정계 시스템에서 수신(예금)과 함께 양대 축을 이루는 것이 여신(대출)입니다. 수신이 "돈을 받아 보관하는" 비교적 단순한 원장 구조라면, 여신은 신청 접수부터 심사, 승인, 약정, 실행, 그리고 수년에 걸친 상환과 사후관리까지 이어지는 긴 라이프사이클을 가진 도메인입니다. 그만큼 시스템도 복잡합니다. 하나의 대출 건이 흘러가는 동안 신용평가 시스템(CSS), 한도 관리 시스템, 담보 관리 시스템, 금리 산출 엔진, 계정계 원장, 신용정보기관, 보증기관까지 수많은 컴포넌트가 맞물려 돌아갑니다.
이 글에서는 여신 업무 도메인의 큰 그림을 그린 뒤, 대출의 "탄생"을 책임지는 LOS(Loan Origination System)를 중심으로 신청부터 실행까지의 아키텍처를 단계별로 살펴봅니다. 비대면 대출의 실시간 심사 파이프라인, 한도/담보/금리의 각 서브시스템, 외부 기관 연동, 그리고 상태 머신 설계와 테스트 시나리오까지 실무에서 부딪히는 주제를 다룹니다.
미리 밝혀두면, 이 글은 시스템 아키텍처 관점의 기술 글이며 특정 금융상품에 대한 권유나 투자/법률 자문이 아닙니다. 규제 관련 내용은 글 작성 시점의 일반적인 이해를 바탕으로 하므로, 실제 프로젝트에서는 반드시 준법감시/법무 부서의 검토를 거치시기 바랍니다.
여신 업무 도메인 개관
여신의 분류 축
여신 상품은 보통 세 가지 축으로 분류합니다. 시스템 설계 시 이 축들이 곧 데이터 모델의 차원이 되기 때문에 정확히 이해해야 합니다.
| 분류 축 | 구분 | 시스템 관점의 차이 |
|---|---|---|
| 차주 유형 | 가계여신 / 기업여신 | 심사 모델(CSS vs 기업신용평가), 한도 체계, 필요 서류가 완전히 다름 |
| 담보 유무 | 담보대출 / 신용대출 | 담보 관리 시스템 연동 여부, LTV 검증 로직 유무 |
| 한도 방식 | 한도거래(마이너스통장 등) / 건별거래 | 원장 구조가 다름 — 한도약정과 개별 실행을 분리 관리 |
가계여신은 표준화된 상품(신용대출, 주택담보대출, 전세자금대출 등)을 대량으로 처리하므로 자동화율이 높고, 기업여신은 건당 금액이 크고 심사가 정성적이어서 워크플로 중심으로 설계합니다. 한도거래는 "약정 한도"와 "실행 잔액"을 별도 관리해야 하며, 미사용 한도도 BIS 자기자본비율 계산 시 신용환산율을 적용해 익스포저로 잡힌다는 점이 회계/리스크 관점에서 중요합니다.
여신 시스템 전체 지형도
+------------------------------------------------------------------+
| 채널 (Channel) |
| 모바일 앱 / 인터넷뱅킹 / 영업점 단말 / 상담사 / 제휴 플랫폼 |
+---------------------------+--------------------------------------+
|
v
+------------------------------------------------------------------+
| LOS (Loan Origination System) |
| 신청 접수 -> 심사 -> 승인 -> 약정 -> 실행 오케스트레이션 |
+--+----------+----------+----------+----------+-------------------+
| | | | |
v v v v v
+------+ +-------+ +-------+ +-------+ +----------+
| CSS | | 한도 | | 담보 | | 금리 | | 외부연동 |
| 신용 | | 관리 | | 관리 | | 산출 | | 게이트웨이|
| 평가 | | 시스템| | 시스템| | 엔진 | | (대외계) |
+------+ +-------+ +-------+ +-------+ +----+-----+
|
+--------------------------------------------+
| 신용정보원 / NICE / KCB / 보증기관 / 마이데이터
v
+------------------------------------------------------------------+
| 계정계 원장 (Core Banking Ledger) |
| 여신 원장 / 수신 원장 / 회계 / 일마감 배치 |
+------------------------------------------------------------------+
LOS는 "대출이 만들어지는 과정"을 오케스트레이션하는 시스템이고, 실행이 완료되면 대출 계좌는 계정계 여신 원장으로 넘어가 LMS(Loan Management System, 사후관리)의 영역이 됩니다. 이 글은 LOS 구간에 집중합니다.
LOS 파이프라인 — 신청부터 실행까지
5단계 파이프라인
[신청] [심사] [승인] [약정] [실행]
Application -> Underwriting -> Approval -> Agreement -> Disbursement
| | | | |
본인확인 신용조회 전결권자 약정서 작성 기표
상품선택 CSS 평점 승인/조건부 금리 확정 원장 계좌 생성
정보입력 한도 검증 승인/거절 담보설정 자금 이체
서류제출 담보 평가 유효기간 부여 기한/조건 확정 보증서 발급 확정
동의수집 정책 룰 체크
각 단계의 시스템 관점 핵심을 짚어보면 다음과 같습니다.
신청(Application) — 채널에서 들어온 신청을 접수하고 신청서 엔티티를 생성합니다. 핵심은 동의 관리입니다. 신용정보 조회 동의, 개인(신용)정보 수집·이용·제공 동의를 받기 전에는 신용조회를 호출할 수 없으므로, 동의 이벤트와 조회 호출 사이의 순서 보장이 감사(audit) 관점에서 중요합니다. 동의서 버전, 동의 일시, 채널을 모두 이력으로 남겨야 합니다.
심사(Underwriting) — 파이프라인의 심장입니다. 신용정보기관(CB) 조회, CSS 평점 산출, 정책 룰(연령, 연소득, DSR/DTI/LTV 규제 비율, 다중채무 여부) 체크, 한도 산출이 이 단계에서 일어납니다. 자동심사로 끝나는 건과 심사역의 수동심사로 넘어가는 건을 분기하는 라우팅 로직도 여기에 둡니다.
승인(Approval) — 심사 결과에 전결 규정을 적용합니다. 금액/등급 구간별로 자동승인, 지점장 전결, 본부 심사부 승인 등 결재선이 달라지며, 승인에는 유효기간(예: 30일)이 부여됩니다. 유효기간이 지나면 재심사가 필요하다는 점이 상태 머신 설계에 반영되어야 합니다.
약정(Agreement) — 대출 조건(금액, 금리, 기간, 상환 방식)을 확정하고 전자약정 또는 서면약정을 체결합니다. 담보대출이라면 근저당권 설정 등 담보 설정 절차가 이 단계와 실행 사이에 끼어듭니다. 약정 시점의 조건은 불변(immutable) 스냅샷으로 보존해야 하며, 이후 조건변경은 별도의 변경 약정으로 처리합니다.
실행(Disbursement) — 흔히 "기표"라고 부르는 단계입니다. 여신 원장에 대출 계좌를 생성하고, 회계 분개(대출금 계정 차변 / 고객 입금 계좌 대변)를 일으키고, 자금을 지정 계좌로 이체합니다. 실행은 반드시 트랜잭션 경계가 명확해야 하고, 부분 실패 시 보상(compensation) 처리가 설계되어 있어야 합니다.
단계 간 데이터 흐름의 원칙
실무에서 자주 강조하는 원칙이 하나 있습니다. **"심사 시점의 사실(facts)은 모두 스냅샷으로 박제하라"**입니다. CB 조회 결과, 평점, 소득 정보, 적용된 정책 룰 버전, 한도 계산 내역을 신청 건에 귀속된 불변 레코드로 저장해야, 몇 달 뒤 감사나 민원이 들어왔을 때 "그 시점에 왜 이 결정이 났는가"를 재현할 수 있습니다. 마스터 데이터를 참조 포인터로만 들고 있으면, 마스터가 갱신되는 순간 과거 의사결정의 근거가 사라집니다.
비대면 대출의 실시간 파이프라인
영업점 중심 시대의 LOS가 며칠짜리 워크플로 엔진이었다면, 비대면 신용대출의 LOS는 수십 초 안에 끝나는 실시간 파이프라인입니다. 인터넷전문은행과 핀테크 제휴 대출비교 플랫폼이 이 흐름을 주도했습니다.
고객 앱 LOS 외부 기관
| | |
|--- 한도조회 요청 -->| |
| |--- CB 조회 ---------->| NICE/KCB
| |<-- 평점/부채 정보 ----|
| |--- 소득/자산 수집 --->| 마이데이터 사업자
| |<-- 계좌/카드/대출 ----| (또는 스크래핑:
| | | 건보공단/국세청 자료)
| |-- 소득 추정 모델 -- |
| |-- CSS 평점 산출 -- |
| |-- 정책 룰 / DSR -- |
| |-- 한도/금리 산출 -- |
|<-- 가심사 결과 -----| |
| (한도/금리) | |
|--- 약정 진행 ------>| |
|<-- 전자서명/실행 ---| |
설계 포인트를 정리하면 다음과 같습니다.
- 소득 추정: 재직/소득 서류를 받는 대신, 마이데이터(본인신용정보관리업) API 또는 인증서 기반 스크래핑으로 건강보험 납부 내역, 국세청 소득금액증명 자료를 수집해 소득을 추정합니다. 추정 소득에는 보수적 할인율(haircut)을 적용하는 것이 일반적입니다.
- 가심사와 본심사의 분리: 대출비교 플랫폼의 "한도 조회"는 가심사이고, 실제 약정 직전에 본심사를 다시 수행합니다. 이때 가심사 결과의 유효기간과, 본심사에서 조건이 달라졌을 때의 고객 고지 플로우를 설계해야 합니다.
- 신용조회의 종류 구분: 한도 조회 단계에서는 신용점수에 영향을 주지 않는 조회 유형을 사용하고, 실제 신청 시점에 정식 조회를 수행하는 식으로 CB 조회 유형을 구분해 호출해야 합니다.
- 타임아웃과 폴백: 외부 기관 한 곳의 지연이 전체 파이프라인을 막지 않도록 단계별 타임아웃, 부분 실패 시 수동심사 전환(fallback to manual) 경로를 둡니다.
- 멱등성: 고객이 앱에서 재시도하면 같은 신청이 두 번 흘러갈 수 있습니다. 신청 단위의 멱등 키(idempotency key)로 중복 신청과 중복 CB 조회를 방어합니다.
한도 관리 시스템
두 층위의 한도
한도는 "이 고객에게 얼마까지"라는 고객/차주 단위 한도와, "이 상품으로 얼마까지"라는 상품/계좌 단위 한도의 두 층위로 관리합니다. 기업여신에서는 여기에 동일인/동일차주 한도라는 규제 한도가 더해집니다. 은행법상 동일한 개인·법인 및 그와 신용위험을 공유하는 자(동일차주)에 대한 신용공여는 자기자본의 일정 비율을 넘을 수 없으므로, 승인 전에 반드시 차주 그룹 전체의 익스포저를 집계해 검증해야 합니다.
익스포저 집계
익스포저 집계는 말처럼 단순하지 않습니다. 대출 잔액뿐 아니라 미사용 약정 한도, 지급보증, 파생상품 신용환산액까지 포함해야 하고, 차주 그룹(계열 관계)을 따라 합산해야 합니다.
-- 차주 그룹 단위 익스포저 집계 (개념 예시)
SELECT g.borrower_group_id,
SUM(CASE WHEN e.exposure_type = 'LOAN_BALANCE'
THEN e.amount END) AS loan_balance,
SUM(CASE WHEN e.exposure_type = 'UNDRAWN_LIMIT'
THEN e.amount * e.ccf END) AS undrawn_equiv,
SUM(CASE WHEN e.exposure_type = 'GUARANTEE'
THEN e.amount END) AS guarantee_amt,
SUM(e.amount * COALESCE(e.ccf, 1.0)) AS total_exposure
FROM exposure_snapshot e
JOIN borrower_group_map g
ON e.borrower_id = g.borrower_id
WHERE g.borrower_group_id = :group_id
AND e.base_date = :base_date
GROUP BY g.borrower_group_id;
여기서 ccf는 신용환산율(Credit Conversion Factor)입니다. 설계상 핵심 결정은 집계를 실시간으로 할 것인가, 일배치 스냅샷 기준으로 할 것인가입니다. 보통은 일마감 배치로 만든 스냅샷에 당일 승인분을 더하는 하이브리드를 씁니다. 승인 시점과 실행 시점 사이에 다른 건이 실행되어 한도를 잠식하는 경쟁 조건이 있으므로, 승인 시 한도를 **예약(soft reservation)**해 두고 실행 시 확정하는 패턴이 안전합니다.
담보 관리 시스템
감정평가와 담보 인정
담보대출에서 담보 관리 시스템은 담보물 마스터(부동산, 예금, 보증서, 동산 등), 감정평가 이력, 담보 설정(근저당권 등) 정보, 그리고 담보 인정가액 계산을 책임집니다. 부동산이라면 외부 감정평가법인의 감정가 또는 시세 자료(KB시세 등)를 기준으로 하고, 선순위 채권액과 임차보증금(방공제 등)을 차감해 유효담보가액을 산출합니다.
LTV 계산
LTV (Loan To Value) = 대출금액 / 담보가치 * 100
유효담보가액 = 담보평가액 * 담보인정비율
- 선순위 설정액
- 임차보증금 / 소액임차보증금 공제
예시:
아파트 시세 : 10억 원
규제상 LTV 상한 : 50% -> LTV 기준 한도 = 5억 원
선순위 근저당 : 1억 원
실제 대출 가능액 : 5억 원 - 1억 원 = 4억 원 (정책에 따라 상이)
LTV 규제 비율은 지역(규제지역 여부), 주택 보유 수, 상품 유형에 따라 달라지고 수시로 개정됩니다. 따라서 LTV 한도 룰은 코드에 하드코딩하지 말고 시행일자(effective date)를 가진 룰 테이블로 외부화해야 합니다. 심사 시점에 유효한 룰 버전을 찾아 적용하고, 적용된 룰 버전 ID를 심사 스냅샷에 남기는 것까지가 한 세트입니다.
또 하나, 담보 가치는 시간에 따라 변합니다. 사후관리 단계에서 주기적 재평가가 일어나고 LTV가 악화되면 추가 담보 요구나 한도 감액이 발생할 수 있으므로, 담보-여신 관계는 1:1이 아니라 N:M(공동담보, 추가담보)으로 모델링해야 합니다.
금리 산출 — 프라이싱 구조
기준금리 + 가산금리
대출 금리는 크게 "기준금리 + 가산금리 - 우대금리(감면)" 구조로 산출됩니다.
최종금리 = 기준금리 + 가산금리 - 우대금리
기준금리 (Base Rate):
COFIX(신규취급액/잔액), 금융채 금리, CD 금리 등
-> 변동금리 상품은 재산정 주기(3/6/12개월)마다 갱신
가산금리 (Spread):
+ 신용원가 : 차주 등급별 예상손실(PD x LGD) 반영
+ 자본원가 : 규제자본 비용
+ 업무원가 : 인건비/시스템 등 운영 비용
+ 유동성 프리미엄
+ 목표 마진
우대금리 (Discount):
- 급여이체, 카드 사용, 적금 보유 등 거래실적 조건부 감면
- 조건 미충족 시 감면 해제 -> 사후관리 배치에서 재판정
시스템 관점의 포인트는 세 가지입니다.
- 기준금리 마스터 관리: 기준금리는 고시일자별 이력 테이블로 관리하고, 변동금리 계좌의 금리 재산정 배치가 이를 참조합니다. "재산정일에 어느 시점 고시값을 쓰는가"(고시일 vs 적용일)는 상품설명서와 일치해야 합니다.
- 가산금리 분해 보존: 최종 금리 숫자 하나만 저장하면 안 됩니다. 금리 산정 체계의 합리성에 대한 공시·점검 요구가 있으므로, 산출 시점의 구성 요소별 분해 내역을 보존해야 합니다.
- 우대금리 사후 판정: 우대 조건 충족 여부는 매월 배치로 재판정되며, 금리 변경은 다음 이자 계산 주기부터 반영됩니다. 이 배치가 이자 계산 배치보다 먼저 돌아야 하는 선후 관계가 일마감 잡 스케줄에 반영되어야 합니다.
약정과 실행 — 기표와 원장 연동
실행(기표)은 LOS와 계정계 원장이 만나는 접점이며, 여신 시스템에서 가장 보수적으로 설계해야 하는 구간입니다.
LOS 여신 원장 회계/자금
| | |
|-- 1. 실행 요청 ------->| |
| (승인ID, 약정조건) | |
| |-- 2. 계좌 생성 |
| | (상환스케줄 생성) |
| |-- 3. 분개 전표 ----->|
| | 차) 대출금 |
| | 대) 고객 예금 |
| |<- 4. 전표 승인 ------|
|<- 5. 실행 완료 --------| |
| (계좌번호, 기표번호) | |
|-- 6. 상태 전이 | |
| APPROVED->DISBURSED | |
설계 원칙은 다음과 같습니다.
- 단일 기표 트랜잭션: 계좌 생성, 분개, 입금 처리는 원장 내에서 하나의 트랜잭션으로 묶거나, 불가능하다면 사가(Saga) 패턴으로 보상 트랜잭션을 정의합니다. "계좌는 생겼는데 입금이 안 된" 상태가 가장 위험합니다.
- 멱등 키 필수: LOS의 실행 요청에는 승인 건 기준의 고유 키를 싣고, 원장은 같은 키의 중복 기표를 거부합니다. 타임아웃 후 재시도 시 이 키가 이중 실행을 막아줍니다.
- 실행 전 최종 검증: 승인 유효기간, 한도 예약 유효성, 담보 설정 완료 여부(설정 등기 확인), 보증서 발급 상태를 실행 직전에 다시 확인합니다. 승인과 실행 사이에 며칠의 간격이 있을 수 있기 때문입니다.
- 일마감과의 관계: 일마감 진행 중 기표 차단 여부, 마감 후 익일자 기표 처리 등 영업일 전환(EOD cutover) 정책을 명확히 해야 합니다.
외부 연동 맵
여신 파이프라인은 외부 기관 연동 없이 성립하지 않습니다. 보통 대외계 게이트웨이를 통해 연동을 일원화합니다.
+--------------------+
| 대외계 게이트웨이 |
LOS / CSS <--------->| (포맷 변환, 재시도,|
| 이력, 모니터링) |
+---+----+----+----+-+
| | | |
+------------------+ | | +------------------+
v v v v
한국신용정보원 NICE평가정보 KCB 보증기관
(신용정보 집중기관) (개인CB) (개인CB) (주택금융공사, 신용보증기금,
- 대출/연체 정보 집중 - 평점/리포트 조회 기술보증기금, 지역신보 등)
- 정보 등록 의무 - 기업CB는 별도 - 보증서 발급/조회
- 보증료 정산
+---------------------+--------------------+
v v v
마이데이터 사업자 행정망 연계 금융결제원
(자산/부채 수집) (소득/재직 확인 등) (계좌 실명확인, 이체)
연동 설계에서 챙겨야 할 것들입니다.
- 조회와 등록의 양방향: CB는 조회만 하는 것이 아니라, 대출 실행/잔액/연체 정보를 신용정보 집중기관에 등록할 의무가 있습니다. 실행 후 등록 배치가 누락되면 규제 이슈가 됩니다.
- 포맷과 코드 매핑: 기관별 전문(고정길이 전문, XML, JSON)이 제각각이므로 게이트웨이에서 내부 표준 포맷으로 변환하고, 기관 코드와 내부 코드의 매핑 테이블을 관리합니다.
- 장애 격리: 기관별 서킷 브레이커와 큐 기반 재시도를 두고, 필수 연동(CB 조회)과 보강 연동(부가 정보)을 구분해 필수가 아니면 스킵 가능하게 합니다.
상태 머신 설계
신청 건의 상태 전이는 LOS의 뼈대입니다. 상태와 전이를 코드 곳곳의 if문으로 흩뿌리면 유지보수가 불가능해지므로, 명시적인 상태 머신으로 중앙화합니다.
from enum import Enum
class AppState(str, Enum):
DRAFT = "DRAFT" # 작성 중
SUBMITTED = "SUBMITTED" # 신청 완료
SCREENING = "SCREENING" # 자동심사 중
MANUAL_REVIEW = "MANUAL_REVIEW" # 수동심사 중
APPROVED = "APPROVED" # 승인 (유효기간 보유)
CONDITIONAL = "CONDITIONAL" # 조건부 승인
DECLINED = "DECLINED" # 거절
AGREED = "AGREED" # 약정 체결
DISBURSED = "DISBURSED" # 실행 완료
EXPIRED = "EXPIRED" # 승인 유효기간 만료
CANCELLED = "CANCELLED" # 고객 취소/철회
TRANSITIONS: dict[AppState, set[AppState]] = {
AppState.DRAFT: {AppState.SUBMITTED, AppState.CANCELLED},
AppState.SUBMITTED: {AppState.SCREENING, AppState.CANCELLED},
AppState.SCREENING: {AppState.APPROVED, AppState.CONDITIONAL,
AppState.DECLINED, AppState.MANUAL_REVIEW},
AppState.MANUAL_REVIEW: {AppState.APPROVED, AppState.CONDITIONAL,
AppState.DECLINED},
AppState.CONDITIONAL: {AppState.APPROVED, AppState.DECLINED,
AppState.CANCELLED},
AppState.APPROVED: {AppState.AGREED, AppState.EXPIRED,
AppState.CANCELLED},
AppState.AGREED: {AppState.DISBURSED, AppState.CANCELLED},
AppState.DISBURSED: set(), # 이후는 LMS(사후관리) 영역
AppState.DECLINED: set(),
AppState.EXPIRED: set(),
AppState.CANCELLED: set(),
}
def transit(app, to_state: AppState, actor: str, reason: str | None = None):
cur = AppState(app.state)
if to_state not in TRANSITIONS[cur]:
raise InvalidTransition(f"{cur} -> {to_state} is not allowed")
app.state = to_state
# 전이 이력은 append-only 테이블에: (app_id, from, to, actor, reason, ts)
append_history(app.id, cur, to_state, actor, reason)
실무 팁을 덧붙이면 이렇습니다.
- 전이 이력은 append-only: 현재 상태 컬럼과 별개로, 누가 언제 왜 전이시켰는지를 불변 이력으로 남깁니다. 감사와 민원 대응의 기본입니다.
- 시간 기반 전이는 배치로: APPROVED에서 EXPIRED로의 전이는 사용자 액션이 아니라 일배치가 수행합니다. 배치 누락 시 만료 승인 건으로 실행이 나가는 사고를 막으려면, 실행 시점 검증을 이중으로 둡니다.
- 거절 사유 코드화: DECLINED에는 반드시 구조화된 사유 코드를 동반시킵니다. 거절 사유 고지 의무 대응과 심사 모델 개선 데이터로 쓰입니다.
재심사, 조건변경, 대환
재심사
승인 유효기간 만료, 가심사와 본심사 사이의 정보 변경, 한도 증액 요청 등은 재심사를 유발합니다. 재심사는 기존 신청 건의 상태를 되돌리는 것이 아니라 새 심사 라운드를 생성하는 방식이 깔끔합니다. 신청(application) 아래에 심사(assessment)를 1:N으로 두고, 각 심사 라운드가 자기만의 CB 조회/평점/룰 스냅샷을 갖게 합니다.
조건변경
실행 이후의 만기 연장, 금리 조건 변경, 상환 방식 변경 등은 "변경 약정"으로 처리합니다. 원 약정을 수정하는 것이 아니라 변경 계약 레코드를 추가하고, 원장의 상환 스케줄을 변경 시점 이후 구간만 재생성합니다. 과거 구간을 건드리면 이자 계산 이력과 회계가 깨지므로 절대 소급 수정하지 않습니다.
대환
대환(refinancing)은 신규 대출 실행과 기존 대출 상환이 맞물리는 복합 트랜잭션입니다. 자행 대환은 내부 트랜잭션으로 묶을 수 있지만, 타행 대환은 신규 실행금을 타행 상환 계좌로 이체하고 상환 완료를 확인하는 비동기 플로우가 됩니다. 온라인 대환대출 인프라처럼 중계 시스템을 경유하는 경우, 상환 확인 콜백 수신까지를 하나의 사가로 설계하고, 중간 실패 시(이체는 됐는데 상환 확인이 안 오는 경우) 수동 개입 큐로 빠지는 경로를 반드시 둡니다.
시스템 설계 시 함정
실제 프로젝트에서 반복적으로 발견되는 함정들입니다.
- 승인-실행 사이의 시간 간극 무시: 승인 시점 검증만 믿고 실행 시점 재검증을 생략하면, 그 사이 다른 대출 실행으로 DSR/한도가 초과된 채 기표되는 사고가 납니다.
- 마스터 데이터 참조로 인한 근거 소실: 고객 소득, 룰 버전, 금리 구성요소를 포인터로만 들고 있다가 마스터 갱신 시 과거 심사 근거를 재현하지 못하게 됩니다. 스냅샷이 답입니다.
- 상태와 이력의 혼동: 현재 상태를 UPDATE로만 관리하고 이력을 안 남기면 감사 대응이 불가능합니다. 반대로 이력 테이블에서 현재 상태를 매번 유도하면 성능이 무너집니다. 둘 다 필요합니다.
- 동시성 미고려 한도 차감: 한도 검증과 차감 사이에 락이나 예약이 없으면 동시 신청 두 건이 모두 통과합니다. 한도 예약 레코드 + 유니크 제약으로 방어합니다.
- 외부 연동 타임아웃의 전파: CB 한 곳의 30초 지연이 스레드 풀을 고갈시켜 전 채널 장애로 번지는 패턴입니다. 연동별 풀 격리와 서킷 브레이커가 필수입니다.
- 금액 계산에 부동소수점 사용: 이자/수수료 계산에 float를 쓰면 원 단위 오차가 발생합니다. 반드시 정수(원 단위) 또는 고정소수점(decimal) 타입을 쓰고, 절사/반올림 규칙을 상품 조건으로 명시합니다.
- 테스트 환경의 외부 기관 부재: CB/보증기관 테스트망은 케이스가 제한적입니다. 연동 응답을 시나리오별로 재생할 수 있는 시뮬레이터를 초기에 만들어 두지 않으면 통합 테스트가 병목이 됩니다.
테스트 시나리오
여신 시스템의 테스트는 해피 패스보다 경계와 동시성에 집중해야 합니다. 대표 시나리오를 추려보면 다음과 같습니다.
| 영역 | 시나리오 | 기대 결과 |
|---|---|---|
| 심사 | CB 조회 타임아웃 후 재시도 | 중복 조회 없이 1회만 기록, 재시도 성공 |
| 심사 | 정책 룰 시행일 경계(개정 전일/당일 신청) | 신청일 기준 올바른 룰 버전 적용 |
| 한도 | 동일 고객 동시 신청 2건 | 한도 예약으로 1건만 통과 또는 합산 검증 |
| 승인 | 유효기간 만료 익일 실행 시도 | 실행 거부, EXPIRED 전이 확인 |
| 실행 | 기표 중 원장 응답 유실 후 재시도 | 멱등 키로 이중 기표 방지 |
| 실행 | 분개 성공, 이체 실패 | 보상 트랜잭션으로 원복, 알림 발생 |
| 대환 | 타행 상환 확인 콜백 미수신 | 수동 개입 큐 적재, 상태 보류 유지 |
| 금리 | 재산정일과 기준금리 고시일 경계 | 상품설명서와 동일한 고시값 적용 |
| 담보 | 선순위 변동 후 재평가 | 유효담보가액/LTV 재계산 정확성 |
| 일마감 | 마감 중 기표 요청 | 정책대로 차단 또는 익일자 처리 |
여기에 더해, 심사 룰 변경 배포 전에는 과거 신청 건을 새 룰로 흘려보는 백테스트(섀도 평가) 환경이 있으면 승인율/거절율 변화를 사전에 정량화할 수 있어 운영 리스크가 크게 줄어듭니다.
마치며
여신 시스템은 "대출 한 건"이라는 단순해 보이는 개념 뒤에 심사, 한도, 담보, 금리, 원장, 외부 연동이 정교하게 맞물린 도메인입니다. 이 글에서 다룬 LOS 구간의 핵심을 한 줄로 요약하면 — 모든 의사결정을 스냅샷으로 재현 가능하게 만들고, 상태 전이를 중앙화하고, 돈이 움직이는 구간은 멱등하게 설계하라는 것입니다.
다음 글에서는 심사의 두뇌에 해당하는 신용평가 시스템(CSS)의 내부 — 스코어카드, ML 모델, 의사결정 엔진 — 를 다루고, 그다음 글에서 실행 이후의 세계인 사후관리(연체, 충당금, NPL)를 살펴봅니다. 다시 한번, 본 글은 기술 아키텍처 해설이며 금융상품 권유나 법률 자문이 아님을 밝힙니다.