Files
rtgs/docs/RTGS 프로토타입 로컬 테스트 시나리오.md
rtgs 58ca23b5d9 Initialize RTGS prototype repository
3센터 A-A-A RTGS 실시간총액결제 프로토타입 최초 버전관리 시작.
- backend: Kotlin/Gradle 멀티모듈(sequencer, common, 채널/센터 모듈)
- frontend: Vite + TS
- infra: docker-compose, prometheus/grafana, ELK 네이티브 스크립트
- loadtest(k6), sim(장애/순서/정합성 시나리오), docs(PoC 보고서/복원력방안)
2026-07-15 15:37:32 +09:00

17 KiB
Raw Blame History

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) 화면(폼)으로 — 권장

  1. 브라우저 http://localhost:5174 (운영 탭) → 자금이체 신청
  2. 송신기관·수신기관 드롭다운 선택(서로 다르게), 금액 입력 → 신청 클릭
  3. 화면이 자동으로 접수(RCVD) → 조회를 폴링해 ACCC(입금처리완료)로 바뀌는 것을 표시
  4. 아래 계좌 테이블에서 송신기관 잔액 −금액 / 수신기관 잔액 +금액 확인
    • 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/accounts1005 잔액 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/2026070999900000000003status 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) 로그관리

목적: 모든 서비스 로그가 중앙 수집·검색되는지 확인.

  1. 브라우저 http://localhost:5601 → ☰ Discover → 데이터뷰 RTGS Logs
  2. 검색창(KQL)에 필터 입력 예:
    • service : "hermes" — 결제처리 로그만
    • service : "prada" and message : "ACCC" — 완결 로그
    • level : "ERROR" — 오류만
  3. 오른쪽 위 시간범위를 "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 등이 이미 쓰이면 해당 프로세스 확인.

문의/이상 발견 시 루비에게 알려주시면 바로 확인하겠습니다.