Skip to content

Repository files navigation

InsuHR — 보험사 통합 인사관리시스템

한국어 | English

build

임직원과 설계사(FC)를 하나의 인물 모델 위에서 통합 관리하고, 인사 기준정보의 변경을 이벤트 · Pull API · 배치 파일 3계층으로 타 시스템에 동기화하는 백엔드 시스템입니다. 설계서를 먼저 쓰고, 구현 과정의 실증으로 설계서를 교정해 가며(v1.0 → v2.3) 완성한 포트폴리오 프로젝트입니다.

Java 21 LTS · Spring Boot 4.1 · Oracle 23ai · Spring Batch 6 · Flyway V1~V17 · 테스트 168개 (실 Oracle Testcontainers) · @Disabled 0

⚠️ 포트폴리오용 가상 시스템입니다. 보수교육 주기·재정보증 금액·개인정보 보존기간 등 법령 의존 수치는 하드코딩하지 않고 정책 테이블(TB_POLICY_CONFIG)로 관리하며, 실제 적용 시 관계 법령 확인이 필요합니다.


왜 이 도메인인가

보험사의 인적 자원은 근로계약 기반의 임직원과 위촉계약 기반의 설계사로 나뉩니다. 설계사는 보험업법상 판매자격·법정교육·협회등록·재정보증 등 별도의 관리 요건이 있고, 이 요건이 하나라도 깨지면 모집이 통제되어야 합니다. 또한 인사 정보는 영업·수수료·급여·SSO 등 거의 모든 사내 시스템의 기준정보(Master Data)라서, 변경을 유실 없이 순서대로 전파하는 구조가 시스템의 절반입니다. — 이 두 가지(법적 요건의 데이터화, 기준정보 동기화)가 프로젝트의 중심 문제입니다.

핵심 기능

  • 인물–역할 모델: 주민번호(암호화+해시) 기준 인물 1건 위에 직원/설계사 역할 분리. 직원 퇴사 후 설계사 위촉 같은 실무 케이스 지원
  • 설계사 위촉 상태머신: 후보 → 협회등록 → 활동 → 정지 → 해촉 → 재위촉. 전이표(허용 7 · 금지 18)가 enum 단일 원천, 낙관적 잠금으로 동시 전이 방어, 1 전이 = 1 이력 + 1 이벤트
  • 모집자격 판정: 자격·보수교육·재정보증·제재를 종합하는 부수효과 없는 순수 함수 evaluate(agentId, asOf) + 판정 결과로만 자동 전이하는 reconciler. 자격 데이터의 모든 쓰기가 재판정을 유발
  • 임직원 발령: 기안/확정/취소 + 미래일자 예약. 스냅샷은 증분 갱신이 아니라 재계산 함수로 정의 → 배치 멱등성이 정의에서 따라 나옴
  • 3계층 동기화: Transactional Outbox → 2단계 릴레이(팬아웃/전달, 구독자별 순서 게이트, HMAC 서명 웹훅 + Kafka 프로파일) / 워터마크 지연 커서 Pull API / 체크섬 검증 스냅샷 파일
  • 개인정보 통제: AES-256-GCM 필드 암호화(키 버전), 기본 마스킹 응답, 복호화는 POST+사유+접근로그(같은 트랜잭션), 보존기간 경과 익명화 파기(파기 대장 + person.purged 전파)
  • 배치 10종: 날짜 경계 전이 포착, 만기 알림 적재(유니크 키 멱등), 정합성 점검, 스냅샷 생성, 개인정보 파기 등 — Clock 주입으로 경계일 테스트 가능

아키텍처

 insuhr-api ──┐                         ┌── 웹훅 구독자 (영업/그룹웨어)
 insuhr-batch ┼── Oracle 23ai ── insuhr-relay ──┤
              │   (HR + Outbox            └── Kafka (프로파일)
              │    + ChangeLog)
              └── Pull API /sync/changes ──── 수수료/급여 시스템
                  스냅샷 파일(일배치) ──────── DW/레거시
모듈 역할
insuhr-common 프레임워크 무관 공통 (예외·마스킹·암호화 유틸) — 의존성 0개 유지
insuhr-domain JPA 엔티티 + 도메인 서비스(상태머신·판정) + Flyway 마이그레이션 소유
insuhr-api REST API 서버 (JWT/RBAC, 조직 범위 행 수준 통제)
insuhr-batch Spring Batch 잡 10종
insuhr-relay Outbox 릴레이 (팬아웃 → 구독자별 전달, 서명·백오프·재시도)

빠른 시작 (10분 데모)

요구사항: JDK 21, Docker

docker compose up -d oracle          # Oracle 23ai Free — Flyway가 스키마 구성 (신선한 DB)

# 아래 셋은 각각 별도 터미널에서 (서버는 포그라운드로 뜬다)
./gradlew :insuhr-api:bootRun        # 8080 — API 서버
./gradlew :insuhr-relay:bootRun      # 8081 — Outbox 릴레이
./demo/receiver.sh                   # 9099 — 웹훅 수신 덤프

./demo/run.sh                        # 데모 계정 시드 → 부록 B 시나리오 자동 실행

run.sh가 밟는 흐름 (설계서 부록 B):

  1. 로그인 → 설계사 후보 등록 (주민번호 해시로 중복 인물 검사)
  2. 판매자격·등록교육·재정보증 등록
  3. 위촉 실행 → 협회 등록번호 입력 → ACTIVE + 모집가능
  4. 계좌 복호화 호출 → 원문 + 마스킹 + 접근로그 생성 확인
  5. 릴레이가 Outbox 이벤트 6건을 팬아웃 → 서명된 웹훅으로 수신 터미널에 도착 → 전 건 SENT

설계서와 개정 이력 — 이 프로젝트의 실제 산출물

전체 설계는 insuhr-design-spec.md (v2.3, 13장 + 부록) 하나로 관리했고, 구현 실증이 설계서와 충돌할 때마다 설계서를 고쳤습니다. 개정 이력에서 대표적인 것들:

개정 실증 내용
v1.1 Boot 4 자동설정 모듈화 — flyway-core만으로는 마이그레이션이 조용히 스킵(health UP, 테이블 없음). spring-boot-flyway 필수. Testcontainers 2.x 아티팩트 개명
v1.2 조직 이력 = 전체 스냅샷 전제 확정(시점 조회가 쿼리 하나로), TIMESTAMP 컬럼 UTC 규약
v1.5 Clock 파생 규칙 — 저장 시각은 Instant(UTC), 업무 날짜는 LocalDate(KST), LocalDateTime 금지 + 자정 경계 앵커 테스트
v1.7~1.8 릴레이 재설계 — 단일 STATUS로는 다중 구독자 표현 불가 → 이벤트×구독자 전달 레코드 팬아웃, (구독자, aggId) 순서 게이트
v2.0 Batch 6에서 리뷰어 지시가 틀렸음을 실증 — incrementer가 있는 잡은 start()가 업무 파라미터를 조용히 폐기. 지시 폐기, 호출자 run.id 방식으로 교정

테스트가 잡은 버그 하이라이트

순차 테스트·코드 리뷰로는 통과했을, 상태를 다시 읽어야만 보이는 버그들입니다.

  1. 롤백이 잠금 카운트를 되돌림 — 로그인 실패가 예외로 트랜잭션을 롤백시키며 실패 카운트까지 원복 → 계정이 영원히 잠기지 않음. 5회 실패 후 DB 재조회 테스트가 검출, REQUIRES_NEW 분리로 해결
  2. 유니크 제약 위반이 영속성 컨텍스트를 오염 — 제약을 방어선 삼아 위반 시 기존 인물로 전환하는 코드가 8스레드 동시 등록에서 7건 실패(rollback-only). 삽입 시도를 격리 트랜잭션에 가둠 — 같은 패턴이 Phase 6 팬아웃에서는 INSERT…WHERE NOT EXISTS 단문으로 원천 회피
  3. 프레임워크가 파라미터를 조용히 버림 — Spring Batch 6의 incrementer + 업무 파라미터 조합. 다른 테스트들은 targetDate가 "우연히 오늘"이라 통과 중이었음 → 날짜 고정 테스트가 검출

v1.1 백로그 (우선순위)

의도적으로 v1.0에서 뺀 것들 — 설계서 §13.4에 같은 순서로 근거와 함께 있습니다.

  1. 변경감사 AOP + TB_AUDIT_LOG — 설계서 §10.4에 의도적 지연으로 문서화. 구현 시 TB_PERSON 민감필드를 감사 JSON에서 소스 제외(파기 정합성 전제)
  2. PUT /auth/password + 비밀번호 이력·90일 변경 집행 (정책값은 시드 완료, 엔드포인트 미구현)
  3. Pull API 소비자 관점 계약 테스트
  4. 릴레이 스케일아웃 — aggId 해시 파티셔닝 (현재는 단일 인스턴스 가정을 §9.2에 명시)

About

보험사 통합 인사관리시스템 — 임직원·설계사 통합 관리 + Outbox 3계층 동기화. Java 21 · Spring Boot 4.1 · Oracle 23ai · 실 Oracle Testcontainers 168 tests. 포트폴리오.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages