3센터 A-A-A RTGS 실시간총액결제 프로토타입 최초 버전관리 시작. - backend: Kotlin/Gradle 멀티모듈(sequencer, common, 채널/센터 모듈) - frontend: Vite + TS - infra: docker-compose, prometheus/grafana, ELK 네이티브 스크립트 - loadtest(k6), sim(장애/순서/정합성 시나리오), docs(PoC 보고서/복원력방안)
17 KiB
RTGS 프로토타입 로컬 테스트 시나리오
대상: 로컬(이 PC) RTGS 프로토타입 (1센터 DC1) 작성: 루비 · 사용: 양팀장님 구성: Docker 없이 네이티브 포터블(Kafka·PostgreSQL·ELK) + 6개 서비스 + React 콘솔(운영/관리자 탭) 갱신(2026-07-10): 자금이체 신청 폼, 조회 한글화·원문, 관리자(LouisVuitton) 탭 반영
0. 접속 정보 (브라우저로 여는 것)
| 화면/엔드포인트 | 주소 | 용도 |
|---|---|---|
| RTGS 콘솔(운영) | http://localhost:5174 | 자금이체 신청 폼 · 거래조회(한글·원문) · 계좌 잔액 |
| RTGS 콘솔(관리자) | http://localhost:5174 → "🛠 관리자" 탭 | DB초기화 · 코드 · 사용자권한 · 대사 대시보드 |
| Kibana(로그) | http://localhost:5601 | ☰ → Discover → RTGS Logs |
| Chanel API(접수·코어) | http://localhost:8091/pay/customer | pacs.008 전문 POST(내부 코어) |
| 조회 API | http://localhost:8091/inquiry/{BMI} , /accounts | 상태·잔액 |
| 관리자 API | http://localhost:8099/admin/* | reset·institutions·users·summary |
| Gucci 관문 API | http://localhost:8095/gucci/* | 로그인·인증 접수/조회·콜백(외부 경계) |
포트 요약: Chanel 8091 · Sequencer 8090 · Dior 8092 · Hermes 8093 · Prada 8094 · Gucci 8095 · LouisVuitton 8099 · Kafka 9092 · PostgreSQL 5433 · Elasticsearch 9200 · Logstash 5000 · Kibana 5601 · Frontend 5174
💡 가장 쉬운 테스트 경로는 브라우저(:5174) 입니다. 아래 시나리오는 화면(GUI)과 명령(curl) 두 방법을 함께 적었으니 편한 쪽을 쓰세요. curl은 자동화/부하테스트에, 화면은 눈으로 확인할 때 좋습니다.
참고: 명령은 CMD 또는 PowerShell을 열고 아래 폴더로 이동해 실행하세요.
cd C:\ai-dev\workspace\rtgs
1. 사전 확인 (헬스체크)
시작 전, 인프라·서비스가 떠 있는지 확인합니다.
rem 계좌 19개가 나오면 백엔드 정상
curl http://localhost:8091/accounts
rem Elasticsearch 상태(green/yellow면 정상)
curl http://localhost:9200/_cluster/health?pretty
- 브라우저에서 http://localhost:5174 열어 계좌 목록이 보이면 프론트도 정상.
- 안 뜨면 → 6. 기동/종료 참조.
2. 테스트용 샘플 전문 (iso20022\samples)
| 파일 | 내용 | 기대 |
|---|---|---|
pacs.008.xml |
1001→1002, 150원 | 정상 완결(ACCC) |
pacs.008-normal.xml |
1005→1010, 5,000원 | 정상 완결(ACCC) |
pacs.008-selftransfer.xml |
1007→1007 (자기이체) | 접수 반려(RJCT) |
pacs.008-unknownbank.xml |
9990(미등록)→1002 | 결제단계 반려(RJCT) |
pacs.008-badformat.xml |
ChrgBr=ZZZZ (스키마 위반) | 접수 반려(RJCT, XSD) |
전문은 정식 ISO20022 pacs.008.001.08(접수)/pacs.002.001.10(응답) 공식 XSD로 검증합니다 (2026-07-10 전환). 응답 전문은
urn:iso:std:iso:20022:tech:xsd:pacs.002.001.10네임스페이스로 옵니다.
⚠️ BMI(거래식별자)는 유일해야 합니다. 같은 파일을 두 번 보내면 두 번째는 "이미 처리됨"으로 멱등 스킵됩니다(정상 동작). 다시 테스트하려면 파일 안
<BizMsgIdr>의 뒷자리 숫자를 바꾸세요.
시나리오 A. 정상 자금이체 (기능·완결) ⭐핵심
목적: 신청→접수→청산·정산→완결(ACCC) 전 과정과 잔액 증감 확인.
A-1) 화면(폼)으로 — 권장 ✅
- 브라우저 http://localhost:5174 (운영 탭) → 자금이체 신청 폼
- 송신기관·수신기관 드롭다운 선택(서로 다르게), 금액 입력 → 신청 클릭
- 화면이 자동으로 접수(RCVD) → 조회를 폴링해 ACCC(입금처리완료)로 바뀌는 것을 표시
- 아래 계좌 테이블에서 송신기관 잔액 −금액 / 수신기관 잔액 +금액 확인
- BMI는 폼이 자동 생성(매번 유일)하므로 중복 걱정 없음
A-2) 명령(curl)으로
cd C:\ai-dev\workspace\rtgs
curl -X POST http://localhost:8091/pay/customer -H "Content-Type: application/xml" --data-binary @iso20022\samples\pacs.008-normal.xml
기대 (접수 응답, pacs.002): <TxSts>RCVD</TxSts> (접수됨)
확인 (2~3초 후)
curl http://localhost:8091/inquiry/2026070911110000000001
status= ACCC (입금처리완료)- 그 후
curl http://localhost:8091/accounts→ 1005 잔액 −5,000, 1010 잔액 +5,000 - 브라우저(5174)의 "거래 상태 조회"에 BMI
2026070911110000000001입력해도 동일 확인.
시나리오 B. 조회 (계좌·거래 · 한글화 · 원문) ⭐개선
목적: 조회 화면의 한글 항목명·상태·시각 포맷·원문 표시 확인.
화면(권장): 거래 상태 조회
- 브라우저(5174) "거래 상태 조회"에 BMI 입력 → 결과 확인:
- 항목명 한글 표시(DB 컬럼 코멘트=데이터 사전 기반), 상태 한글값(예: ACCC → 입금처리완료)
- 시각은 YYYYMMDDHH24MISS 포맷(예: 20260710153012)
- 원문 pacs.008(ISO20022 XML) 도 함께 표시 → 접수된 실제 전문 확인
- 계좌 테이블 "새로고침" → 19개 기관 당좌계좌 잔액
명령(curl)
curl http://localhost:8091/accounts rem 19개 기관 당좌계좌 잔액
curl http://localhost:8091/inquiry/{BMI} rem 특정 거래 상태(JSON)
curl http://localhost:8091/rawmessage/{BMI} rem 접수된 원문 pacs.008
curl http://localhost:8091/meta/labels rem 항목 한글 데이터사전
curl http://localhost:8091/notifications/{BMI} rem 결과통보 내역(신청/수취기관 앞 pacs.002)
curl http://localhost:8091/notifications rem 최근 결과통보 100건
결과통보(이체결과 송부): 거래가 완결(ACCC)/반려(RJCT)되면 접수센터의 Chanel이 최종 pacs.002를 생성해 신청기관(송신) 앞 결과통보(항상)와 수취기관 앞 입금통보(ACCC만)를
notification에 기록합니다. (당초 Gucci 후보 기능을 Chanel 헌장에 맞춰 이관 — 2026-07-10)
시나리오 C. 반려(RJCT) 3종
목적: 잘못된 요청이 안전하게 거절되는지(이중지급·오처리 방지) 확인.
C-1) 자기 이체 (송신=수신) → 접수 즉시 반려
curl -X POST http://localhost:8091/pay/customer -H "Content-Type: application/xml" --data-binary @iso20022\samples\pacs.008-selftransfer.xml
기대: 응답 <TxSts>RJCT</TxSts> (업무규칙 위반, 원장에 기록 안 됨)
C-2) 미등록 기관 (9990) → 접수는 되나 결제단계에서 반려
curl -X POST http://localhost:8091/pay/customer -H "Content-Type: application/xml" --data-binary @iso20022\samples\pacs.008-unknownbank.xml
기대: 응답 RCVD → 잠시 후 curl http://localhost:8091/inquiry/2026070999900000000003 → status RJCT (사유: unknown account)
C-3) 스키마 위반 (ChrgBr=ZZZZ) → 공식 XSD 검증 실패로 접수 반려
curl -X POST http://localhost:8091/pay/customer -H "Content-Type: application/xml" --data-binary @iso20022\samples\pacs.008-badformat.xml
기대: 응답 <TxSts>RJCT</TxSts> (ClrSysRef에 cvc-enumeration-valid: 'ZZZZ' ... XSD 오류 사유)
세 경우 모두 잔액은 전혀 변하지 않아야 합니다(시나리오 D로 총액 확인).
시나리오 D. 정합성 — 총액 보존 & 계층 대사 ⭐핵심
목적: 어떤 이체를 해도 19개 계좌 잔액 합계 = 190억(19,000,000,000) 이 유지되는지(돈이 생기거나 사라지지 않음 = 이중지급 0)와, 원장 각 계층이 일치하는지 확인.
"C:\ai-dev\apps\postgresql-16.4\bin\psql.exe" -h localhost -p 5433 -U rtgs -d rtgs -c "SELECT sum(balance) AS 총액, count(*) AS 계좌수 FROM account;"
"C:\ai-dev\apps\postgresql-16.4\bin\psql.exe" -h localhost -p 5433 -U rtgs -d rtgs -c "SELECT status, count(*) FROM transfer GROUP BY status ORDER BY status;"
기대: 총액 = 19000000000, 상태 분포는 대부분 ACCC(+반려테스트한 RJCT 일부).
계층 대사(원장 transfer vs 조회사본 settlement_view 일치):
"C:\ai-dev\apps\postgresql-16.4\bin\psql.exe" -h localhost -p 5433 -U rtgs -d rtgs -c "SELECT (SELECT count(*) FROM transfer WHERE status='ACCC') AS 원장ACCC, (SELECT count(*) FROM settlement_view WHERE final_status='ACCC') AS 사본ACCC;"
시나리오 E. 멱등성 (중복 전문)
목적: 같은 거래(BMI)가 두 번 들어와도 한 번만 반영(이중지급 방지).
rem 같은 파일을 연속 2회 전송
curl -X POST http://localhost:8091/pay/customer -H "Content-Type: application/xml" --data-binary @iso20022\samples\pacs.008.xml
curl -X POST http://localhost:8091/pay/customer -H "Content-Type: application/xml" --data-binary @iso20022\samples\pacs.008.xml
기대: 1001→1002 잔액 변동이 150원 한 번만 발생(2회 보내도 총액·잔액 동일). /accounts로 확인.
시나리오 F. 부하 테스트 (k6) ⭐성능
목적: 동시 다발 접수 시 처리량·응답시간·정합성 확인.
정상 부하 (초당 30건 × 15초 ≈ 450건)
cd C:\ai-dev\workspace\rtgs
"C:\ai-dev\apps\k6-0.56.0\k6.exe" run -e RATE=30 -e DURATION=15s loadtest\pacs008.k6.js
스파이크(정점) 테스트
"C:\ai-dev\apps\k6-0.56.0\k6.exe" run -e MODE=spike -e PEAK=500 loadtest\pacs008.k6.js
- 조절 옵션:
-e RATE=(초당건수)-e DURATION=(시간) / spike는-e PEAK=(정점 초당건수). - 확인: k6 요약(
http_reqs,http_req_duration), 그 후 시나리오 D로 전건 ACCC·총액 보존 확인. - 주의: 이 PC 메모리(약 16GB)에서 ELK까지 다 켠 상태면 너무 높은 PEAK는 버거울 수 있음(300~1000 권장).
시나리오 G. 로그 확인 (Kibana / ELK) ⭐로그관리
목적: 모든 서비스 로그가 중앙 수집·검색되는지 확인.
- 브라우저 http://localhost:5601 → ☰ Discover → 데이터뷰 RTGS Logs
- 검색창(KQL)에 필터 입력 예:
service : "hermes"— 결제처리 로그만service : "prada" and message : "ACCC"— 완결 로그level : "ERROR"— 오류만
- 오른쪽 위 시간범위를 "Last 1 hour"로.
- 부하테스트(F) 돌린 직후 보면 로그가 실시간으로 쌓이는 것을 확인 가능.
시나리오 H. 관리자 기능 (LouisVuitton) ⭐시스템관리
목적: 테스트 초기화·코드·사용자권한·대사 화면 동작 확인. 브라우저(5174) → "🛠 관리자" 탭.
🔐 관리자 로그인 필요(A1): 관리자 탭 진입 시 로그인 화면 → 테스트계정
a/1(ADMIN)으로 로그인. (본격 운영은 초기암호 로그인 후 변경 강제 —must_change_password.) 비ADMIN·무토큰은/admin/*401 차단. 부하테스트(k6)는 관문/인증과 무관하게 Chanel(:8091) 직접 호출로 수행.
H-1) DB 초기화 (테스트 리셋)
- 관리자 탭 → DB 초기화 버튼(확인창) → 거래/저널/조회사본/원전문 비우고 계좌 잔액 10억으로 리셋
- 초기화 후 시나리오 D로 총액 190억·거래 0건 확인. (curl:
curl -X POST http://localhost:8099/admin/reset) - 💡 반복 테스트 전에 초기화하면 상태 분포가 깔끔해집니다.
H-2) 코드 관리 (참가기관 마스터)
- 참가기관(당좌계좌) 목록 조회·추가·수정. 상태코드(RCVD~ACCC/RJCT) 데이터사전 확인.
- (curl:
curl http://localhost:8099/admin/institutions,/admin/status-codes)
H-3) 사용자·권한 관리 (관리 마스터)
- app_user 목록·추가·수정 — role ADMIN/ORG_S/ORG_R. 로그인 강제는 후속 단계(지금은 마스터 관리만).
- (curl:
curl http://localhost:8099/admin/users)
H-4) 대사 대시보드
- 상태별 건수·총액 보존 체크 + 서비스별 처리 현황(transfer/journal_log/settlement_view 건수 비교).
- 시나리오 A·F 후 열어 원장=저널=사본 건수 일치를 눈으로 확인.
- (curl:
curl http://localhost:8099/admin/summary)
시나리오 I. 복원력 검증 하니스 (sim/) ⭐자동검증
목적: 복원력방안 부록A 급소(S1 정합·S2 무손실승계·S4 순서교정)를 자동 검증. Git Bash에서 실행.
bash sim/s1_consistency.sh 30 # 정합성: 총액보존·원장=사본·이중지급 0
bash sim/s2_failover.sh 30 # 복원성: 부하중 Hermes 강제종료·재기동 → 유실 0
bash sim/s4_order.sh # 기능성: 저널 순번 역전주입 → 재정렬 완결
# 수동 대사 리포트:
"C:\ai-dev\apps\postgresql-16.4\bin\psql.exe" -h localhost -p 5433 -U rtgs -d rtgs -f sim\reconcile.sql
- 각 스크립트가
PASS/FAIL을 출력합니다. 자세한 원리는 sim/README.md. - ⚠️ S2·S4는 서비스(Hermes/Sequencer)를 죽였다 살립니다. 수동 테스트와 겹치지 않을 때 실행하세요.
시나리오 J. Gucci 관문 (인증·유량·재전송·결과송부) ⭐게이트웨이
목적: 참가기관이 Gucci(:8095) 를 통해 인증·접수하고, 결과가 콜백으로 송부되는지 확인. Git Bash 권장.
dev 계정(시크릿): kookmin_s/kookmin-secret(ORG_S,1001) · shinhan_r/shinhan-secret(ORG_R,1002) · admin/admin-secret(ADMIN)
G=http://localhost:8095
# ① 로그인 → 토큰
TOKEN=$(curl -s -X POST $G/gucci/auth/login -H "Content-Type: application/json" \
-d '{"username":"kookmin_s","secret":"kookmin-secret"}' | python -c "import sys,json;print(json.load(sys.stdin)['token'])")
# ② 인증 이체신청(토큰+nonce+timestamp). 전문 송신기관(1001)은 토큰 기관과 일치해야 함
TS=$(date +%s)
curl -s -X POST $G/gucci/pay/customer -H "Authorization: Bearer $TOKEN" \
-H "X-Nonce: n-$TS" -H "X-Timestamp: $TS" -H "Content-Type: application/xml" \
--data-binary @iso20022/samples/pacs.008-normal.xml # (송신 1005면 403 — 토큰 org와 불일치)
# ③ 인증 조회
curl -s $G/gucci/inquiry/{BMI} -H "Authorization: Bearer $TOKEN"
# ④ 헬스체크(무인증)
curl -s $G/gucci/health/centers
기대(거부 케이스): 무토큰→401 · 변조토큰→401 · 토큰org≠전문송신→403 · nonce 재사용→400 · ORG_S가 /gucci/accounts→403(ADMIN 전용) · 유량 초과→429
결과 콜백송부(G2): 완결되면 Chanel이 notification에 적재(delivered=false) → Gucci가 3초 폴링으로 기관 콜백에 pacs.002 송부 → ACK시 delivered=true.
# 콜백 레지스트리(관리자) / 송부 상태 확인
AT=$(curl -s -X POST $G/gucci/auth/login -H "Content-Type: application/json" -d '{"username":"admin","secret":"admin-secret"}' | python -c "import sys,json;print(json.load(sys.stdin)['token'])")
curl -s $G/gucci/callbacks -H "Authorization: Bearer $AT"
"C:\ai-dev\apps\postgresql-16.4\bin\psql.exe" -h localhost -p 5433 -U rtgs -d rtgs -c "SELECT bmi,to_org,delivered,attempts FROM notification ORDER BY created_at DESC LIMIT 10;"
로컬 데모는 기관 수신서버를 Gucci 자체 sink(
/gucci/sink/{org})로 모사합니다. 미등록 기관은 재시도(attempts↑)하다가 관리자가PUT /gucci/callbacks/{org}로 URL 등록하면 다음 폴링에 송부 성공합니다.
6. 기동 / 종료
전체 기동 (인프라 + 7서비스: Sequencer/Chanel/Dior/Hermes/Prada/LouisVuitton/Gucci)
C:\ai-dev\workspace\rtgs\run-dc1.cmd
ELK(로그) 기동 (선택, 메모리 여유 있을 때)
C:\ai-dev\workspace\rtgs\infra\start-elk-native.cmd
프론트엔드 기동
C:\ai-dev\workspace\rtgs\run-frontend.cmd
종료: 각 서비스/인프라 창을 닫거나 → C:\ai-dev\workspace\rtgs\stop-dc1.cmd (인프라 종료, 데이터 보존)
지금은 이미 떠 있는 상태라 바로 시나리오 A부터 하시면 됩니다.
7. 부록
유용한 psql 조회
set PSQL="C:\ai-dev\apps\postgresql-16.4\bin\psql.exe" -h localhost -p 5433 -U rtgs -d rtgs
%PSQL% -c "SELECT bmi,global_seq,status,sender_code,receiver_code,amount FROM transfer ORDER BY global_seq DESC LIMIT 10;"
%PSQL% -c "SELECT code,name,balance FROM account ORDER BY code;"
데이터 초기화(계좌 잔액 리셋 등)가 필요하면
- 가장 쉬운 방법: 콘솔(5174) "🛠 관리자" 탭 → DB 초기화 버튼 (시나리오 H-1).
- 명령으로:
curl -X POST http://localhost:8099/admin/reset - (거래/저널/사본/원전문 비우고 계좌 잔액을 10억으로 되돌림)
BMI(거래식별자) 규칙 — 직접 전문 만들 때
- 22자리 = 영업일(8, YYYYMMDD) + 기관코드(4) + 일련번호(10)
- 예:
2026070911110000000009(2026-07-09 · 기관 1111 · 일련 0000000009) - 매 요청마다 뒷자리를 다르게 하면 유일성 확보.
트러블슈팅
/accounts가 안 나옴 → 백엔드 미기동.run-dc1.cmd실행.- 접수는 되는데 계속 IN_FLIGHT → Sequencer/Hermes 창 확인(기동 여부).
- Kibana가 안 열림 → 기동에 ~1분 소요, 또는
start-elk-native.cmd로 ES/Logstash/Kibana 기동. - 포트 충돌 → acs 등 다른 프로젝트와 포트 분리돼 있으나, 8091/5433/9092 등이 이미 쓰이면 해당 프로세스 확인.
문의/이상 발견 시 루비에게 알려주시면 바로 확인하겠습니다.