# RTGS 프로토타입 워크플로우 > 로컬(1센터 DC1) RTGS 프로토타입의 전문 처리 흐름 · 서비스별 처리 · 데이터 흐름 정리 > 작성: 루비 · 담당: 양팀장님 --- ## 1. 시스템 구성도 ``` [참가기관 / 부하생성기(k6) / 조회·신청 콘솔(:5174)] │ pacs.008 (HTTP, XML) ▼ ┌──────────────────────────── 1센터 (CENTER_ID=DC1) ────────────────────────────┐ │ │ │ ① Chanel(전문송수신) :8091 │ │ XSD검증 → 경량명령문(75B)+원전문해시 → 원전문 저장 → 입구 발행 → pacs.002 응답 │ │ │ rtgs.inbound └→ raw_message(PostgreSQL) │ │ ▼ │ │ ③ Sequencer(순번기) :8090 전역순번 부여 + 결정론적값 확정 → 저널 발행 │ │ │ rtgs.journal (단일 파티션 = 전역 순서) │ │ ├───────────────┬───────────────────────────┐ │ │ ▼ ▼ ▼ │ │ Dior(접수동기화) Hermes(결제/원장엔진, cc=1) (저널 구독) │ │ PDNG 기록 순차소비→선저널→잔액이체→ACSP→결과발행 │ │ │ │ rtgs.result │ │ │ ▼ │ │ │ Prada(결과동기화) 과반확정→ACCC 최종확정 │ │ ▼ ▼ ▼ │ │ ┌──────────────── PostgreSQL(:5433, 강한 일관성 원장) ────────────────┐ │ │ │ account(잔액) · transfer(거래상태) · journal_log(선저널) · │ │ │ │ settlement_view(조회사본) · raw_message(원전문) · app_user │ │ │ └────────────────────────────────────────────────────────────────────┘ │ │ │ │ ⑥ LouisVuitton(관리자) :8099 초기화·코드·사용자·대사 (← 콘솔 관리자 탭) │ ⑦ Gucci(외부 경계 관문) :8095 로그인·API인증·유량제어·재전송차단·결과콜백송부(→참가기관) │ └────────────────────────────────────────────────────────────────────────────────┘ 로그: 각 서비스(Logback) ──TCP:5000──▶ Logstash ──▶ Elasticsearch(:9200) ──▶ Kibana(:5601) 메시지: Kafka(:9092, KRaft) 토픽: rtgs.inbound / rtgs.journal / rtgs.result / rtgs.notify ``` --- ## 2. 자금이체 처리 워크플로우 (핵심) ### 흐름 요약 ``` [신청] ORG_S가 pacs.008 전송 └▶ [접수] Chanel : XSD검증·경량화·원전문저장 → 상태 RCVD → rtgs.inbound └▶ [순번] Sequencer : 전역순번+결정론적값 → 상태 ACTC → rtgs.journal(저널) ├▶ [접수동기화] Dior : 저널 소비 → PostgreSQL 원장에 PDNG 기록 └▶ [청산·정산] Hermes : 저널 순차소비(cc=1) → gap/역전 탐지·재정렬 → 선저널(write-ahead) → 송신기관 당좌 −금액 / 수신기관 당좌 +금액 (강한 일관성 트랜잭션) → 상태 ACSP → (커밋 후) rtgs.result 발행 └▶ [결과동기화] Prada : 결과 소비 → 과반(2/3) 확정 → 상태 ACCC(입금처리완료) 최종확정 + 조회사본 기록 → (커밋 후) rtgs.notify 발행 └▶ [결과통보] Chanel(접수센터) : rtgs.notify 소비 → 최종 pacs.002 생성 → 신청기관(송신) 앞 결과통보 + 수취기관 앞 입금통보(ACCC) → notification 아웃박스 ``` ### 단계별 상세 (각 서비스가 다루는 토픽/DB) | 순서 | 서비스 | 입력 | 처리 | 출력 | 상태 | |---|---|---|---|---|---| | ① | **Chanel** | HTTP pacs.008 | XSD검증→경량명령문+원전문해시, 원전문 저장 | `raw_message` 저장, `rtgs.inbound` 발행, pacs.002 응답 | RCVD | | ② | **Sequencer** | `rtgs.inbound` | 전역순번 부여 + 결정론적값(수신시각) 확정 | `rtgs.journal` 발행(저널) | ACTC | | ③ | **Dior** | `rtgs.journal` | BMI 중복체크(upsert) | `transfer` PDNG 기록 | PDNG | | ④ | **Hermes** | `rtgs.journal`(cc=1 순차) | 순서 탐지·교정 → 선저널 → 당좌계좌 차·대변(강한 일관성) | `account`·`journal_log`·`transfer`(ACSP), `rtgs.result` 발행 | ACSP | | ⑤ | **Prada** | `rtgs.result` | 완결 규율(과반 확정) | `transfer`(ACCC)·`settlement_view`, (커밋 후) `rtgs.notify` 발행 | ACCC | | ⑥ | **Chanel**(결과통보) | `rtgs.notify` | 최종 pacs.002 생성, 접수센터만 송부 | `notification`(신청기관+수취기관) | — | > **핵심 원칙**: 어느 센터로 접수돼도 **단일 순번기**가 하나의 전역순번으로 줄 세우고, 저널(단일 파티션)을 > N센터가 **같은 순서로 결정론적 재생** → 세 센터 데이터가 항상 동일. 잔액 변경이 하나의 순번 줄로 > 직렬화되므로 "동시에 같은 계좌"가 없어 **이중지급 원천 차단**. --- ## 2.5 서비스별 처리 개념도 (참조) | 서비스 | 개념도 | |---|---| | Chanel(전문송수신) | ![Chanel](chanel.png) | | Dior(접수동기화) | ![Dior](dior.png) | | Hermes(결제/원장엔진) | ![Hermes](hermes.png) | | Prada(결과동기화) | ![Prada](prada.png) | > 전체 업무 흐름은 ![업무 흐름도](2센터흐름도.png) 참조. --- ## 3. 상태 전이도 (TxSts) ``` (접수) (승인) (대기) (예약) (완결) RCVD ──▶ ACTC ──▶ [PDNG] ──▶ ACSP ──────────▶ ACCC │Chanel │Sequencer │Dior │Hermes(이체) │Prada(과반확정) │ └─(검증실패/잔액부족/미등록기관)─▶ RJCT (반려) ``` - **RCVD** 접수 / **ACTC** 승인(순번부여) / **PDNG** 대기(원장 기록) / **ACSP** 예약(결제 반영, 결과대기) / **ACCC** 입금처리완료(최종) / **RJCT** 반려 --- ## 4. 데이터 흐름 **Kafka 토픽** (전 센터 공유 단일 클러스터 = 순서 공유) - `rtgs.inbound` : Chanel → Sequencer (접수 원시) - `rtgs.journal` : Sequencer → 전 센터(Dior/Hermes) (전역순번 저널, **단일 파티션**) - `rtgs.result` : Hermes → Prada (결제결과) - `rtgs.notify` : Prada → Chanel (완결 결과통보 트리거; 접수센터가 신청/수취기관 앞 pacs.002 송부) **PostgreSQL 테이블** (센터별 원장, 강한 일관성) - `account` 참가기관 당좌계좌 잔액 | `transfer` 거래 원장·상태 | `journal_log` 선저널 - `settlement_view` 조회 사본 | `raw_message` 원전문(pacs.008) | `notification` 결과통보 아웃박스 | `app_user` 사용자·권한 **로그(ELK)**: 서비스 Logback(JSON, service/center 필드) → Logstash(:5000) → ES `rtgs-logs-*` → Kibana --- ## 5. 관리자(LouisVuitton) 워크플로우 ``` 콘솔(:5174) "🛠 관리자" 탭 ──▶ louisvuitton(:8099) /admin/* · DB 초기화 : transfer/journal_log/settlement_view/raw_message TRUNCATE + 계좌 잔액 리셋 · 코드 관리 : 참가기관(account) 마스터 CRUD + 상태코드 데이터사전 · 사용자 권한 : app_user CRUD (ADMIN/ORG_S/ORG_R) — 로그인 강제는 후속 · 대사 대시보드 : 상태별 건수·총액 보존 체크 + 서비스별 처리 현황(transfer/journal_log/settlement_view) ``` --- ## 6. 개발 · 실행 워크플로우 **빌드** (JDK21로 — Gradle 8.10.2는 JDK26 미지원; `gradle.properties`에 고정) ``` cd C:\ai-dev\workspace\rtgs\backend gradlew build (EDR 파일락 시 재시도) ``` **기동/종료** ``` run-dc1.cmd : 네이티브 인프라(Postgres/Kafka) + 6개 서비스 infra\start-elk-native.cmd : ES/Logstash/Kibana (로그) run-frontend.cmd : 콘솔(:5174) stop-dc1.cmd : 인프라 종료(데이터 보존) ``` **접속**: 콘솔 http://localhost:5174 · Kibana http://localhost:5601 **변경→반영**: 백엔드 = 재빌드(bootJar)+해당 서비스 재기동 / 프론트 = Vite HMR(자동) --- ## 6.5 Gucci(외부 경계 관문, :8095) 워크플로우 참가기관은 코어(Chanel:8091)에 직접 붙지 않고 **Gucci 관문**을 통한다(외부↔RTGS 북-남 경계). 전역 결제순서는 **Sequencer 단독**이며 Gucci는 관문/인증/유량제어/전달보장만 담당(순서 결정 아님). ``` 참가기관 ──① 로그인(POST /gucci/auth/login, secret) ──▶ Gucci ── app_user.secret 대조 ──▶ JWT 발급 ──② 이체신청(POST /gucci/pay/customer, Bearer+X-Nonce+X-Timestamp) ──▶ Gucci 가드: [JWT검증] → [역할 ORG_S/ADMIN] → [유량제어 50/10s] → [재전송 nonce/timestamp] → [기관바인딩: 토큰 org == 전문 DbtrAgt MmbId] → (통과) Chanel /pay/customer 프록시 ◀── pacs.002(RCVD) ── [완결 후 결과 콜백송부 — G2] Prada 완결 → Chanel notification 아웃박스(delivered=false) → Gucci DeliveryService(3s 폴링) → institution_endpoint 콜백 URL로 pacs.002 POST → 2xx ACK: delivered=true / 실패: attempts++ 재시도(max 5) ``` - 감사로그(인증·허용/거부·송부)는 ELK(service=gucci)로 수집. - 헬스체크 `GET /gucci/health/centers`(관측). 다센터 정족수/펜싱·GSLB 라우팅은 G3(고사양 PC 이후). --- ## 7. 확장 워크플로우 (다센터 A-A-A, 향후) ``` ┌── DC1 (Chanel/Dior/Hermes/Prada + PostgreSQL rtgs_dc1) [단일 Sequencer] ──저널(Kafka 공유)──┼── DC2 (동일 서비스 + rtgs_dc2) └── DC3 (동일 서비스 + rtgs_dc3) · 컨슈머 그룹 센터별 분리(hermes-DC1/DC2/DC3) · 센터별 DB · 포트 오프셋 · 정족수 2/3 자동전환 · 3센터 데이터 동일성 대사로 검증(개요 "3센터 동일순서 동일업무") ``` *필요 작업·자원은 개발일지 백로그 참조. 고사양 PC 이관 후 수월.*