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

235 lines
22 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# RTGS 프로토타입 개발일지
> 대상: 한국은행 소액RTGS(실시간총액결제) 프로토타입 — 로컬(포터블 Windows) 자체 개발
> 목적: 클라우드 PoC(1~3차)에서 검증한 아키텍처의 **업무기능을 로컬에서 완결 개발·테스트**
> 작성: 루비 · 담당: 양팀장님(한국은행 RTGS시스템팀)
> 위치: `C:\ai-dev\workspace\rtgs`
---
## 0. 한눈에 보기
| 구분 | 내용 |
|---|---|
| 기술 스택 | Kotlin 2.0.20 · Spring Boot 3.3.4 · JDK 21(Temurin) · Gradle 8.10.2 |
| 아키텍처 | 전역 순번기(Sequencer) + 저널 순차처리 + 강한 일관성 원장(PostgreSQL) · N센터 확장형 |
| 서비스(6) | Sequencer · Chanel(전문송수신) · Dior(접수동기화) · Hermes(결제/원장엔진) · Prada(결과동기화) · LouisVuitton(관리자) |
| 인프라 | **네이티브 포터블**(Docker 아님): Kafka(KRaft) · PostgreSQL · Elasticsearch/Logstash/Kibana |
| 전문 | ISO20022 pacs.008(요청)/pacs.002(응답), BMI 22자리 식별자 |
| 상태머신 | RCVD→ACTC→PDNG→ACSP→ACCC (실패 RJCT) |
---
## 1. 일자별 상세 내역
### 📅 2026-07-08 (1일차) — 분석 · 설계 · 개발환경 · 골격 개발
**분석**
- 워크스페이스 현황 파악(acs 기존 프로젝트, rtgs는 docs만 있는 빈 폴더)
- 설계 자료 정독: PoC 1·2·3차 결과보고 PDF, "RTGS ActiveActive 복원력방안"(과제⑧ v2.0), 리뷰어/저자 의견, 프로젝트 개요
- acs와 **포트/compose 비충돌** 원칙 확인
**설계 결정**
- 언어 Kotlin, 로컬 인프라 실물 경량 스택, 센터는 1센터 시작·N센터 확장 구조
- 복원력방안 반영: **전역 순번기 / 원장=RDB(PostgreSQL) 강한 일관성 / 정족수 / 저널 결정론적 재생 / 선저널 / 완결 규율**
- 원장은 RDB, 인메모리(Hazelcast)는 코어 연산, 문서형(MongoDB)은 원전문/조회사본으로 역할 분리(설계)
**설치 (포터블, `C:\ai-dev\apps`)**
- **JDK 21 (Temurin 21.0.11)** — Gradle 8.10.2가 JDK26 미지원이라 별도 설치. `env.cmd``JDK21_HOME` 추가(전역 JAVA_HOME은 jdk-26 유지)
- **Gradle 8.10.2** — `GRADLE_HOME` 추가, 캐시는 `home\gradle`
**개발 (backend 멀티모듈)**
- Gradle Kotlin DSL 멀티모듈 구성(common/sequencer/chanel/dior/hermes/prada) + Gradle Wrapper 생성
- **common 모듈**: `TxSts`(상태머신), `CoreMessage`(경량명령문+SHA-256), `JournalEntry`(전역순번+결정론적값), `BmiGenerator`(22자리), `QuorumContext`(정족수), ISO20022 DTO(Pacs008/Pacs002)+코덱, `XmlValidator`(XSD), 토픽/맵/테이블 상수 → **빌드·단위테스트 통과**
- **5개 서비스** 구현(Sequencer 순번부여·저널발행, Chanel 접수·검증·경량화·응답, Dior 접수동기화, Hermes 순차소비·선저널·이체·결과발행, Prada 완결) → **빌드 성공**
- infra: `docker-compose.yml`(초안, Kafka/PostgreSQL/MongoDB) + `postgres-init.sql`(참가기관 19개 시드)
- loadtest: `pacs008.k6.js`(정상/스파이크), 샘플 전문
- 실행 스크립트(run-dc1/stop-dc1), React(Vite) 프론트엔드 스캐폴드
- ※ 일 사용한도 초과로 `kotlin("plugin.jpa")` 적용 직후 중단
### 📅 2026-07-09 (2일차) — 통합 · 인프라 전환 · 검증 · 고도화
**환경 이슈 해결**
- IDE(VS Code Java확장)가 JDK26으로 import 실패 → `gradle.properties``org.gradle.java.home=jdk-21` 고정, `.vscode/settings.json` 지정, wrapper 8.10.2 복원
- `kotlin("plugin.jpa")`를 common에 적용(JPA 엔티티 open/no-arg) → **전체 빌드 성공**
- 사내 EDR 파일락으로 Gradle 캐시 이동 실패 → **재시도**로 통과(Maven/git과 동일 계열)
**Docker → 네이티브 전환 (중대 전환점)**
- Docker Desktop 실행 시 **"Virtualization support not detected"** — 회사 PC의 CPU 가상화 차단(BIOS/정책). Docker(WSL2) 사용 불가 판정
- **Docker 대신 네이티브 포터블 인프라로 전환**(이 PC의 포터블 철학에 오히려 부합):
- **Kafka 3.8.1**(KRaft 단일노드, :9092) 설치·기동. Windows bat의 `wmic`(제거됨) 호출 실패 → `KAFKA_HEAP_OPTS` 사전 설정으로 우회
- **PostgreSQL 16.4**(바이너리, :5433) initdb·기동, DB `rtgs` + 스키마/시드
- **MongoDB 7.0.14** 설치했으나 **WiredTiger 체크포인트가 EDR 파일락에 걸려 반복 크래시(exit 14)** → 원전문/조회사본 저장을 **PostgreSQL로 이전**(raw_message/settlement_view). MongoDB는 미사용
**E2E 검증 성공**
- 비웹 서비스 ObjectMapper 빈 누락(spring-web 부재) 수정 → 5서비스 기동
- pacs.008 1건(1001→1002 150원): 접수 RCVD → **최종 ACCC**, 송신 150/수신 +150, transfer·journal_log·settlement_view·raw_message 전 계층 대사 일치, **19계좌 총액 190억 보존(이중지급 0)**
**ELK 로그관리 구축**
- Elasticsearch 8.15.2 설치·기동 → **EDR 환경 생존 검증 통과**(Lucene은 WiredTiger보다 견고)
- Kibana 8.15.2, Logstash 8.15.2 설치. 서비스 공통 `logback-spring.xml`(logstash-logback-encoder, TCP :5000) → Logstash → ES `rtgs-logs-*` → Kibana. 5개 서비스 로그 수집 확인
**k6 부하테스트 + 버그 2건 발견·수정**
- k6 0.56.0 설치, 30 rps×15초 부하
- **버그① ACSP 잔류 레이스**: Hermes가 결과를 트랜잭션 커밋 *전* 발행 → Prada가 커밋 전 읽음 → **커밋 후 발행(publish-after-commit)** 으로 수정
- **버그② 중복키 ERROR**: Dior/Hermes가 원장 같은 행 동시 INSERT → **원자적 upsert(ON CONFLICT)** 로 수정, 기존 ERROR 로그 정리
**프론트엔드 개선**
- **자금이체 신청 폼**(송신/수신 드롭다운·금액→RCVD→ACCC 자동조회·잔액갱신)
- 거래조회 **한글 항목명**(DB 컬럼 코멘트=데이터 사전 기반) · 상태 한글값 · 시각 `YYYYMMDDHH24MISS` · **원문 pacs.008** 표시
**관리자(LouisVuitton) 서비스 신규** (3차 PoC 미구현분)
- `louisvuitton` 서비스(:8099) + 콘솔 "🛠 관리자" 탭
- 기능: **DB 초기화**, **코드(참가기관) 관리**, **사용자 권한 관리**(app_user, ADMIN/ORG_S/ORG_R — 로그인 강제는 후속), **대사 대시보드**(서비스별 처리 현황)
**개인화**
- 어시스턴트 이름 "루비"(Louis Vuitton 줄임), 사용자 호칭 "양팀장님" — 메모리 저장
### 📅 2026-07-10 (3일차) — 세션 재개 · 문서화 · 고도화(순번영속화·정식ISO·검증하니스)
- 세션 종료 후에도 **네이티브 프로세스 전부 생존** 확인(인프라·5+1 서비스), 데이터(거래·총액 190억) 보존. **프론트엔드(Vite)만 재기동**
- 개발 문서 3종 작성: **개발일지 / 워크플로우 / 테스트 시나리오 갱신**
**고도화 ① Sequencer 전역순번 영속화 (2-1, 정합성 개선)**
- 문제: 순번기 카운터가 인메모리라 재기동 시 1로 리셋 → journal_log(global_seq PK) 충돌/스테일
- 해결: 기동 시 `@PostConstruct`에서 원장의 `MAX(global_seq)`(journal_log·transfer) 조회 → 그 다음부터 발번(high-water mark 복원). sequencer에 JDBC(:5433) 추가
- 검증: 재기동 후 실제 이체가 **globalSeq=943**(복원 max 942의 다음)으로 처리 — 리셋 없음 확인
**고도화 ② 정식 ISO20022 XSD 적용 (2-2, 실제 전문 검증)**
- iso20022.org 공식 XSD 도입: **pacs.008.001.08**(접수)·**pacs.002.001.10**(결과통보) → `common/resources/iso20022/xsd/`
- 전문 모델을 실제 구조로 전환: `Document/FIToFICstmrCdtTrf`(GrpHdr: MsgId/CreDtTm/NbOfTxs/SttlmInf=CLRG, CdtTrfTxInf: PmtId/EndToEndId·IntrBkSttlmAmt@Ccy·ChrgBr=SLEV·Dbtr/DbtrAcct/DbtrAgt(ClrSysMmbId/MmbId)·CdtrAgt·Cdtr/CdtrAcct)
- 파서를 **DOM 방식**(지역명 기준·네임스페이스 견고·XXE 차단)으로 재작성, pacs.002 응답은 정식 네임스페이스 템플릿 생성
- 샘플 5종·프론트 신청폼 XML·공통 테스트 전면 정합. 검증: 공식 XSD로 정상 4건 통과, `badformat`(ChrgBr=ZZZZ) → `cvc-enumeration-valid` 반려
- 적용: sequencer·chanel 재빌드·재기동(나머지 4서비스는 CoreMessage/JournalEntry 불변이라 무중단)
**고도화 ③ 검증 하니스 sim/ (S1/S2/S4)**
- `sim/`(Git Bash): `s1_consistency`(정합성)·`s2_failover`(무손실 승계)·`s4_order`(순서 재정렬)·`reconcile.sql`·`lib.sh`·`README.md`
- **결과 전건 PASS**: S1(20건 총액보존·원장=사본), S2(30건 투입 중 Hermes 강제종료·재기동, 유실 0), S4(seq 965→966→964 역전주입 → 964,965,966 순서기록·전건 ACCC)
**고도화 ④ 결과통보(이체결과 송부) Chanel 이관**
- Gucci 후보 기능 검토 결과, "이체신청기관앞 이체결과 송부"는 Chanel 헌장(접수+통보)에 맞아 **Chanel로 이관**
- 신규 토픽 `rtgs.notify`: **Prada**가 완결(ACCC/RJCT) 후 발행(publish-after-commit) → **Chanel**이 소비
- Chanel: 접수센터(originCenter)만 최종 pacs.002 생성 → **신청기관(송신) 결과통보**(항상)·**수취기관 입금통보**(ACCC만) → `notification` 아웃박스 기록. 조회 API `/notifications`, `/notifications/{bmi}`
- 검증: ACCC(1003→1008)=APPLICANT+BENEFICIARY 2건, RJCT(9990 미등록)=APPLICANT 1건(사유 포함) 확인
- Gucci 잔여 범위(관문/인증/헬스체크 등)는 요건 정의 후 착수
**고도화 ⑤ Gucci(외부 경계 관문) 신규 — 로컬 단계 G1·G2**
- 6개 후보 기능 검토 후 **관문 계층으로 한정**(순서결정=Sequencer, 통보=Chanel로 이미 분담). 신규 `backend/gucci`(:8095)
- **G1 인증 관문**: 로그인(app_user.secret 대조) → **JWT(HS256 자체구현)** 발급 · 인증된 리버스프록시(→Chanel) · 가드[JWT검증·역할·**기관바인딩**(토큰org=전문송신)·**유량제어**(50/10s)·**재전송차단**(nonce+timestamp)] · 감사로그(ELK) · 헬스체크
- **G2 결과 콜백송부(전달보장)**: Chanel 아웃박스(delivered=false) → Gucci `DeliveryService`(3s 폴링)가 `institution_endpoint` 콜백으로 pacs.002 POST → 2xx ACK시 확정, 실패시 재시도(max5). 데모 sink + 레지스트리 관리(admin)
- 검증: curl E2E(로그인/정상pay/무토큰401/기관불일치403/재전송400/관리자accounts/변조401) + 가드 단위테스트 통과. G2: 등록기관 즉시송부·미등록 재시도→등록→송부성공 확인
- app_user.secret·notification.attempts·institution_endpoint 스키마 추가, run-dc1.cmd에 Gucci 기동 추가 → **7개 서비스 아키텍처 완성**
- (남은 것) 프론트 Gucci 경유 로그인 UI(선택), G3(센터간 헬스/펜싱/GSLB)=다센터 단계
**보안 강화 A2 — 비밀키 BCrypt 해시**
- `app_user.secret` 평문 → **BCrypt+솔트 해시** 저장. Gucci `AuthService``PasswordEncoder.matches`로 대조
- `SecretMigrator`(ApplicationRunner): 기동 시 평문(비 BCrypt) 시크릿을 자동 해시 승격(멱등). spring-security-crypto 도입
- 검증: DB secret `$2a$10$…`(60자), 원 시크릿 로그인 200·오답 401
**A4 — Flyway 스키마 형상관리 도입**
- 수기 SQL/ALTER → **Flyway** 단일 출처. 현재 스키마를 `louisvuitton/.../db/migration/V1__baseline.sql`로 이관, LouisVuitton이 실행
- `baseline-on-migrate`**기존 운영 DB는 baseline(무변경)**, 신규 빈 DB는 V1부터 생성. 인프라 스크립트는 빈 DB만 생성(스키마는 Flyway). 구 `postgres-init.sql`은 legacy 표시
- 검증: `flyway_schema_history`에 baseline(1)+V2 기록, 운영 DB 무변경 확인
**A1 — 관리자 로그인(Gucci JWT 재사용, 옵션1)**
- LouisVuitton `/admin/**`**JWT 인터셉터**(role ADMIN 필수). Gucci 발급 토큰을 동일 서명키로 **검증만** 수행
- Gucci: 로그인 응답에 `mustChangePassword` 추가 + **비밀번호 변경 API**(`/gucci/auth/change-password`)
- **V2 마이그레이션**: `must_change_password` 컬럼 + **테스트관리자 a/1**(ADMIN)
- 프론트: 관리자 탭 **로그인 화면**(a/1) + Bearer 전송 + 초기암호변경 화면 + 로그아웃, vite proxy `/gucci`
- 검증(프론트 프록시 경유): a/1→ADMIN 로그인, `/admin/summary` 토큰有 200·無 401, ORG_S 401, 비번변경 왕복(1→12→1)
**Gucci 요건 검토(설계 방향 합의)**
- 양팀장님 제시 6개 후보 기능을 **경계 관문 계층으로 재배치**: ①헬스체크=관측만(페일오버는 정족수+펜싱) ②센터간MQ=Kafka가 이미 담당(Gucci는 외부관문) ③기관로그인=Gucci인증+LouisVuitton권한마스터 ④API인증=JWT+서명/nonce/timestamp ⑤"API순서지정"=라우팅/유량제어(전역순번은 Sequencer 단독) ⑥이체결과송부=**Chanel 이관**
- 원칙 합의: **순서=Sequencer(리더선출)/분산=GSLB·Gucci(무상태)**. 로컬 단계 G1(인증관문)/G2(콜백송부)/G3(센터간)
**작업 분담 (양팀장님 지시)**
- **ACS 프로젝트의 개선·서버배포는 Codex에게 일임**, 루비는 **RTGS 전담**. 동일 workspace 병렬작업 → 포트 이미 분리(ACS 8080/5173/5432 ↔ RTGS 8090~8095/5174/5433), 공유 `env.cmd`·Gradle 캐시는 RTGS 관련만 수정, cold 빌드 순차
**문서 산출물 관리 체계 수립**
- **아키텍처 설계서** 신규 작성(`RTGS 아키텍처 설계서.md`) — OS-WAS-DB 스택 매트릭스 포함(Win11/JDK21.0.11/SpringBoot3.3.4 내장Tomcat/PostgreSQL16.4/Kafka3.8.1/ELK8.15.2/React18+Vite5+Node26/k6). **Mermaid 다이어그램**(컴포넌트·배포·상태·시퀀스) + 팀장님 참고 PNG(2센터흐름도·서비스png) 임베드
- **문서 운영방침**(양팀장님): 개발 중 `.md` → 완성 시 **PPT/PDF**(HWP 불필요). pandoc 확인(pptx 직접·pdf는 Edge인쇄), `docs/tools/convert.cmd` 작성. 다이어그램=Mermaid+참고PNG, UML.xlsx는 필요 시 추출
- **SW 산출물 관리대장**(`SW 산출물 관리대장.md`) 신규 — 과거 PoC의 코드-문서 드리프트 재발 방지. **단일 출처 원칙**(포트=run-dc1/yml·토픽=Constants·스키마=Flyway·데이터사전=DB COMMENT·API=Controller·전문=XSD), 변경유형→갱신문서 체크리스트, 정합성 점검 항목
**개선점 진단(루비 관점) → 우선순위 논의**
- A(즉시): A1 관리자무인증·A2 평문시크릿·A3 관문우회·A4 수기스키마 / B(운영전): B1 순번기SPOF·B2 정족수하드코딩·B3 head-of-line·B4 관측성·B5 헤드리스헬스·B6 테스트자동화·B7 TLS/암호화 / C(다센터·성능)
- **A1·A2·A4 완료**(위). A3=합의(부하테스트는 Chanel 직접 유지, 운영 전 차단). B군은 아래 결정대로 진행
**B6 — 테스트 실행 화면 (완료)**
- 관리자 콘솔에 **이체 대량생성** 섹션: BMI 시작번호·건수 입력 → 송/수신기관 랜덤·금액 1,000~1,000,000 랜덤, Chanel 직접 호출(관문 우회), 20건 동시배치, 진행/접수/반려 집계. k6 대체 간이도구
- 검증: 프론트 tsc 통과. (프론트 HMR 반영)
**B1/B2/B3 — 3센터 삼중화 방향 확정(설계 논의 중, 구현 예정)**
- 양팀장님 결정: 이전 PoC는 2센터, **이제부터 3센터 기준 삼중화 구조로 전환**
- B1 순번기: **durable-before-publish**(저널을 durable 저장 후 발행, 재기동 시 미발행분 재발행=outbox) + 리더선출·펜싱(에폭)
- B2 정족수: 결정론적 재생이므로 데이터 동기화는 불필요, 단 **완결(응답) 시 과반(2/3) 확정 대기**로 1센터 손실 안전. `confirmations` 하드코딩→센터별 ack 집계로
- B3 head-of-line: 영구 gap의 원인은 B1 유실 → B1 해결 시 소멸. 방어책=gap 타임아웃 시 **journal_log(durable)에서 결번 직접 pull**(skip 아님)
**B4 관측성(메트릭) + B5 서비스 헬스 (완료)**
- **B4**: 전 서비스 Micrometer + `/actuator/prometheus` 노출. 헤드리스 4종(Sequencer/Dior/Hermes/Prada)에 starter-web 추가→예약포트(8090/8092/8093/8094)에 actuator만 노출. 업무 메트릭: `rtgs.settlements`(status)·`rtgs.settle`(Timer)·`rtgs.journal.gap`(Hermes), `rtgs.finality`(status, Prada), 접수 TPS/지연=`http_server_requests`(Chanel), Kafka lag 자동. (Prometheus 서버/Grafana는 후속)
- **B5**: `common.ops.HeartbeatAutoConfiguration`(스프링 자동설정, `@AutoConfigureAfter` DataSource) → 전 서비스가 `service_heartbeat`(Flyway V3)에 주기 기록. LouisVuitton `/admin/health` + 관리자 대시보드 **🩺 서비스 상태**(UP/STALE, 헤드리스 포함). micrometer-registry-prometheus는 common으로 전파
- 검증: 7서비스 `/actuator/prometheus` 200, 하트비트 7건, 이체1건 후 settlements/finality/http 메트릭 증가, /admin/health 7 UP
- (교훈) 자동설정 `@ConditionalOnSingleCandidate(DataSource)``@AutoConfigureAfter(DataSourceAutoConfiguration)` 없으면 순서상 미적용. 헤드리스→web 전환으로 기동 ~13s(정상)
**B4 Prometheus 서버 설치 (완료)**
- 포터블 **Prometheus 3.13.0**(`apps\prometheus-3.13.0`, 데이터 `home\prometheus-data`, :9090) 설치. `infra\prometheus.yml`(7서비스 스크랩·5s)·`infra\start-prometheus.cmd`
- 검증: **7/7 타깃 up**, PromQL `rtgs_finality_total{status="ACCC"}` 조회 성공. README apps 표 등록
- (교훈) `start "title" cmd /k ""exe" args"` 중첩따옴표는 배치에서 실패 → `start "title" "exe" args` 형태로
**B4 Grafana 시각화 (완료)**
- 포터블 **Grafana 13.1.0**(`apps\grafana-13.1.0`, 데이터 `home\grafana-data`, :3000, 익명 Admin). `infra\start-grafana.cmd` + 프로비저닝(`infra\grafana\provisioning`: Prometheus 데이터소스 rtgs-prom + "RTGS Overview" 대시보드)
- 대시보드 패널: 접수 TPS/지연(p95)·정산 처리율/지연·Kafka consumer lag·JVM heap·완결 누계. 검증: 데이터소스·대시보드 프로비저닝 확인
- **관측성(B4/B5) 완료** — 로그(ELK)+메트릭(Prometheus/Grafana)+헬스(하트비트)
- (다음) **B1/B2/B3 3센터 삼중화**(durable-before-publish·정족수·gap pull) → **B7 암복호화+TLS**. C(다센터 실측)·성능은 **7/13(월) 고사양 PC 이관 후**(터미널 3개로 DC1~DC3 병렬 실측). D: pacs.7z를 전문 보강(BAH/pacs.002 검증) 착수 시 참조
---
## 2. 주요 의사결정·전환점 요약
| 결정/전환 | 이유 |
|---|---|
| JDK21 별도 설치 | Gradle 8.10.2가 JDK26 미지원 |
| **Docker → 네이티브 포터블** | 회사 PC CPU 가상화 차단(스펙 아닌 BIOS/정책). 포터블 철학과 부합 |
| **MongoDB → PostgreSQL** | MongoDB WiredTiger가 EDR 파일락에 크래시. 문서저장을 RDB로 대체(클라우드는 문서형 유지) |
| 원장 = RDB 강한 일관성 | 복원력방안 원칙(이중지급 방지엔 단일순번+강한일관성) |
| publish-after-commit | 결과발행을 커밋 후로 → Prada 완결 레이스 제거 |
| 원자적 upsert(ON CONFLICT) | Dior/Hermes 동시삽입 중복키 제거 |
| 정식 ISO20022 공식 XSD | 실제 전문 검증(pacs.008.001.08/002.001.10) |
| 결과통보 = Chanel | Chanel 헌장(접수+통보)에 부합 |
| Gucci = 외부 경계 관문만 | 순서=Sequencer, 분산=Gucci(무상태) 역할 분리 |
| **Flyway 스키마 형상관리** | 수기 SQL 드리프트 방지(코드-문서 정합성) |
| 관리자 로그인(JWT/BCrypt) | 관리자 무인증·평문시크릿 급소 제거 |
| **ACS=Codex / RTGS=루비** | 병렬 개발 분담(양팀장님 지시) |
| 문서: md→PPT/PDF, 다이어그램 Mermaid+PNG | 개발중 관리 용이, 완성시 정식 산출물 |
| **3센터 삼중화 전환** | 이전 PoC는 2센터, 본 개발은 3센터 A-A-A 기준 |
---
## 3. 현재 산출물
- **backend/**(Gradle 멀티모듈, **7서비스**): common + sequencer/chanel/dior/hermes/prada/**gucci**/louisvuitton
- **frontend/**(React+Vite): 운영 콘솔(이체신청·조회·계좌) + 관리자 탭(로그인·대사·초기화·코드·사용자·**테스트 실행**)
- **infra/**: 네이티브 기동 스크립트(start-infra-native[빈DB만 생성]·start-elk-native), init/postgres-init.sql(**legacy**), (참고용) docker-compose
- **DB 스키마**: **Flyway** `louisvuitton/.../db/migration/`(V1__baseline, V2__admin_login)
- **loadtest/**: k6, **sim/**: S1/S2/S4 하니스, **iso20022/**: 공식 XSD·샘플 5종
- **docs/**: 개요·보고서·개발일지·워크플로우·테스트시나리오·**아키텍처 설계서**·**SW 산출물 관리대장**·참고(2센터흐름도·서비스png·UML.xlsx)·tools/convert.cmd
- 포터블 앱: `C:\ai-dev\apps`(jdk-21, gradle, kafka, postgresql, elk, k6, nodejs 등)
## 4. 남은 과제 (백로그)
**완료(2026-07-10)**: ✅순번 영속화 ✅정식 ISO20022 XSD ✅sim S1/S2/S4 ✅결과통보 Chanel이관 ✅Gucci G1/G2(인증관문·콜백) ✅A2 BCrypt ✅A4 Flyway ✅A1 관리자로그인 ✅B6 테스트화면 ✅아키텍처설계서·관리대장 ✅**B4 메트릭(Micrometer/Prometheus 노출)** ✅**B5 서비스 헬스(하트비트 대시보드)** ✅**B4 Prometheus 서버(:9090)**
**진행/예정**:
- **B1/B2/B3 3센터 삼중화** — *설계 확정 + **코드 구현·빌드·단위테스트 완료(2026-07-13, 8코어 PC)***:
- **B1**: `V4__seq_outbox.sql`(SEQUENCE `global_seq_seq` + `journal_outbox`), `SequencerService` durable-before-publish + 재발행 스케줄러(@EnableScheduling). 순번기 전역 단일 리더(그룹 `sequencer`).
- **B2**: `prada/QuorumAggregator`(신규, 단위테스트 6) — `rtgs.result`=applied-ack 재활용(별도 토픽 불필요), `processedCenter` 집계 과반(2/3) → ACCC. origin Prada만 통보.
- **B3**: `hermes/GapBuffer`(신규, 단위테스트 6) + 타임아웃 스케줄러 → 단일파티션 근거 phantom skip, `rtgs.journal.gap.timeout` 지표.
- **설정공통화**: 원장/엣지 groupId 센터접미사 파라미터화(`hermes-${center-id}`…), 순번기만 단일그룹.
- **이관 산출물**: `run-dc2/dc3.cmd`, `infra/init-3centers-db.cmd`, `run-dc1.cmd`(3센터 모드), `docs/RTGS 3센터 이관·기동 체크리스트.md`.
- **남은 것**: 전체 3센터 21 JVM 기동·재해/복구 시나리오·성능 실측 = **고사양 PC 이관 후**(팀장님 테스트).
- **B4 관측성**: Micrometer + Prometheus(TPS/지연/consumer lag)
- **B5 헤드리스 헬스**: LouisVuitton 대시보드에 서비스 하트비트(DB)
- **B7 전문 암복호화 + TLS**: 기관 수신 ISO전문 복호화→처리, 통보 암호화 송부(성능테스트에 암복호화 포함)
- **다센터(DC2/DC3) 실행·S3/S5**: 고사양 PC 이관 후
- 프론트 Gucci 경유 로그인 UI(선택), Logstash 힙 256m, PC 백업/이관 체크리스트(다음주)
*본 일지는 개발 진행에 따라 계속 갱신.*