Commit Graph

66 Commits

Author SHA1 Message Date
GA Pro 4a7a4eeb7a chore: 검증용 토큰/임시 파일 제거 + .gitignore 보강
이전 커밋(5ee8321)에 검증 중 만든 login.json/token.txt 가 실수로 포함되어
JWT 토큰이 히스토리에 노출됨. 토큰은 이미 expired 되었지만(7200s) 즉시 제거.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 22:58:05 +09:00
GA Pro 5ee8321ef2 feat: P6 외부연동 호출 감사 이력 (V85)
펌뱅킹/SMS·카카오 어댑터 모든 호출을 external_call_log 테이블에 AOP 자동 영속화.
외부 SDK 통합 후에도 그대로 재사용. 운영 감사·장애 추적·SDK 검증 용도.

- V85: external_call_log 테이블 + 인덱스 4종 (called_at desc / type / target / failures)
       + SYSTEM_EXTERNAL_CALL 메뉴 + READ 권한 (SUPER_ADMIN/ADMIN)
- ga-core: ExternalCallLogVO/Resp/SearchParam + Mapper (insertOne / selectList / selectById)
- ga-api/aop: ExternalCallLoggingAspect — BankTransferAdapter+/MessageAdapter+
  모든 메서드 @Around 영속화. 호출자 트랜잭션과 분리(REQUIRES_NEW),
  request/response 는 PII 마스킹된 JSON 한 줄 요약(계좌·전화 뒤 4자리, 이름 첫글자만),
  영속화 자체가 실패해도 비즈니스 흐름 비차단(warn 로그만), 예외는 그대로 propagate.
- ga-api: ExternalCallLogService + Controller GET /api/external-call-logs[/{id}]
- ga-frontend: ExternalCallLogList.tsx + api/externalCallLog.ts + App.tsx 라우트
  /system/external-call-log (ProTable + Drawer 상세)

라이브 검증:
- Flyway V85 자동 적용 → 운영 DB schema v85
- 5모듈 컴파일 BUILD SUCCESSFUL + ga-frontend tsc --noEmit 통과
- 시나리오: withdraw#3 신규 → 결재 advance ×2 → 펌뱅킹 호출
  external_call_log #1: BANK/MockBankTransferAdapter/requestTransfer/
  success=true/durMs=3/target=WITHDRAW#3/accountNoMasked="****0123"

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 22:56:27 +09:00
GA Pro 0e8c563a9a feat: P6 어댑터 PoC 보강 — Resp 노출 / phone 매핑 / 재시도 배치 / SDK 분기
1. WithdrawRequestResp / VO / Mapper.xml / 화면에 transfer_tx_id/transfer_status/transfer_at 노출
2. UserMapper.selectFirstActiveContactByRoleCode — step.roleCode → user.phone 1차 매핑
   - ApprovalService.sendStepNotification 이 실제 결재자 user_id/phone 사용 (기존 0L 하드코딩 해소)
   - phone 미확보 시 SMS skip (DB 알림은 유지)
3. 펌뱅킹 재시도 — WithdrawBankRetryService + POST /api/internal/bank-retry
   - WithdrawRequestMapper.selectFailedTransfers 추가
   - @EnableScheduling + cron 옵션(기본 비활성), app.bank-retry.limit
4. 어댑터 프로파일 분기 — @ConditionalOnProperty
   - app.adapter.bank: mock(기본) | kftc → KftcBankTransferAdapter 스켈레톤
   - app.adapter.message: mock(기본) | toast → ToastMessageAdapter 스켈레톤
   - 활성화 시 UnsupportedOperationException 명시
5. V83(menu_code 오기로 0건 적용) + V84(실제 WITHDRAW 메뉴에 EXECUTE 권한 보강)
2026-05-24 02:45:13 +09:00
GA Pro b04fa79840 feat: P6 외부연동 어댑터 모듈 PoC (펌뱅킹/SMS·카카오)
신규 모듈 ga-external-adapter — 외부 SDK 의존성을 격리.
실제 SDK 통합 시 이 모듈의 구현체만 교체하면 ga-api/ga-common 무변경.

- ga-common.adapter.bank: BankTransferAdapter 인터페이스 + Request/Response/Status
- ga-common.adapter.message: MessageAdapter 인터페이스 + Channel(SMS/KAKAO)/Request/Response
- ga-external-adapter: MockBankTransferAdapter / MockMessageAdapter (로그 + 마스킹)
- V82: withdraw_request.transfer_tx_id/transfer_status/transfer_at + 부분 인덱스
- ApprovalService.handleApprovalCallback(WITHDRAW) — 최종 승인 시 펌뱅킹 어댑터 호출
  - 성공: status APPROVED → SENT 전이, transfer_tx_id 영속화
  - 실패: APPROVED 유지 + fail_reason 기록 (재시도 배치는 추후)
- ApprovalService.sendStepNotification — DB 알림 외 SMS 어댑터 호출 (non-critical)
- WithdrawRequestMapper.updateTransferResult 추가
2026-05-24 02:10:06 +09:00
GA Pro c005ad705a feat: 분급 비율 회차(월) 단위 등록 지원 (V81)
- installment_ratio.plan_month INT NULL 컬럼 추가
  - NULL = 연 단위(연차 합계, 기존 동작)
  - 1~12 = 해당 회차(월) 단위 비율
- UNIQUE 재정의: NULLS NOT DISTINCT (product_category, plan_year, plan_month, effective_from)
- InstallmentPlanGenerator: planMonth=NULL이면 1, NOT NULL이면 그대로 사용해 settle_month 계산
- 분급비율 화면: 회차(월) 컬럼·입력 추가, "(연차-1)*12+월" 통합 회차 표기
2026-05-24 01:27:47 +09:00
GA Pro 3f52596a8b fix: 전체 메뉴 점검 — 회계분개/KPI 매퍼 컬럼 오류 + 결재 mine/pending 엔드포인트
전체 화면 API 점검(85종) 중 발견한 오류 수정:

- ContractAccountingEntryMapper: ac.contract_no 미존재 -> ac.policy_no AS contract_no
  (contract 테이블 컬럼은 policy_no. 데이터 적재 후 표면화된 버그)
- KpiMapper: mv_*.refreshed_at 가 now() 기반 timestamptz 인데 VO는 LocalDateTime
  -> refreshed_at::timestamp 캐스팅 (monthly/org/cumulative/retention 4종)
- ApprovalController/Service: /requests/mine, /requests/pending 엔드포인트 부재로
  /requests/{requestId} 에 매칭돼 400 -> 두 엔드포인트 신규 추가

검증: 전체 엔드포인트 ERROR 0건. 정산 배치 데이터 + KPI MV 새로고침으로
KPI 대시보드 4화면(월별/조직별/누적/유지율) 정상 표시.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 01:41:26 +09:00
GA Pro c2a92d13cb fix: 정산 배치 파이프라인 정합 — 매퍼 NULL 파라미터 + override_settle 제약 + 정산지급 데이터
정산/지급 화면이 전부 비어있던 원인: 운영 DB에서 정산 배치가 실행된 적 없음.
MONTHLY_SETTLEMENT 배치를 돌리는 과정에서 발견한 버그 수정 + 데이터 구성.

매퍼 버그 (PG: could not determine data type of parameter):
- RegulatoryLimitMapper/ChargebackGradeMapper/InstallmentRatioMapper:
  #{productCategory} 가 IS NULL 비교에 쓰여 타입 추론 실패 -> jdbcType=VARCHAR 명시
- ForecastKpiMonthlyMapper: #{targetOrgId} 동일 -> jdbcType=BIGINT 명시

스키마 (V79):
- override_settle.settle_id NOT NULL 완화 — calcOverride(Step7)는 settle_master
  생성(Step8) 전 단계라 settle_id 를 채울 수 없음

데이터 (V80):
- 배치 실행 결과: settle_master 150 / 원장 433 / 명세서 112 / 분개 433 (2026-02~04)
- payment 는 settle_master 파생 생성, 운영성 도메인(공제/마감/세금계산서/이의신청/
  시책/정정)은 대표 샘플 시드 (멱등 NOT EXISTS)

검증: 배치 12스텝 COMPLETED, 정산/지급 10개 엔드포인트 200 OK.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 00:48:08 +09:00
GA Pro 6b44be2101 fix: 실행.bat — gradlew 경로를 .\ 명시로 수정 (실행 검증 완료)
원인: NoDefaultCurrentDirectoryInExePath 환경에서 cmd가 현재 폴더의
gradlew.bat 을 못 찾음. 백엔드 기동 라인을 'cd /d %~dp0 && .\gradlew.bat'
으로 수정. 한글/chcp 제거(UTF-8 배치 파서 깨짐 회피)해 순수 ASCII로 작성.

검증: 실행.bat 더블클릭(Start-Process) -> 백엔드(8082)+프론트(3000) 정상 기동,
localhost:3000 화면 200, 프록시 로그인 성공, /api/year-end-statements 정상.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 00:10:23 +09:00
GA Pro dd3c46a7c9 docs: 프로젝트 한 번에 실행하는 방법 (실행.bat + 실행방법.md)
비개발자도 더블클릭 한 번으로 백엔드(ga-api 8082)+프론트(ga-frontend 3000)를
동시에 띄우도록 실행.bat 추가. 실행/접속/종료/문제해결을 실행방법.md에 정리.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 22:36:13 +09:00
GA Pro 49f08f001d feat: P5-W3 본론 완료 — 회계결산/이상치예측/연말명세서 (V74~V78)
P5-W2 원천세·부가세 분기신고 미커밋분 + P5-W3 메뉴/권한 보강(V74) + P5-W3 본론(V75~V78)을 일괄 정리.

- V75 accounting_close / account_balance_snapshot (회계 결산)
- V76 retention_anomaly_alert / forecast_kpi_monthly (이상치·예측 KPI)
- V77 year_end_statement (연말 지급명세서)
- V78 P5-W3 본론 메뉴 4 + 권한 + 공통코드 7그룹 + 테스트데이터
- api: AccountingClose/YearEndStatement/ForecastKpi/RetentionAnomaly Service+Controller
- batch: BatchConfig Step 11/12 (원천세·부가세 분기) 연결
- frontend: 4화면(AccountingClose/YearEndStatement/RetentionAnomaly/ForecastKpi) + API 모듈 4 + 라우트
- frontend: usePermission/PermissionButton EXECUTE 권한 누락 보강
- fix: YearEndStatementMapper.xml 미존재 컬럼 a.agent_code 참조 제거

통합검증: Flyway V74~V78 운영DB 적용(v78), 4모듈 compileJava + 프론트 build PASS,
스모크 GET 8/8 + 쓰기 4/4 PASS, verify_v74.py 20/20 PASS.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 22:22:34 +09:00
GA Pro d5ed642c80 동기화 2026-05-15 00:25:18 +09:00
ysukkyu 88e14edffd 1 2026-05-14 18:14:49 +09:00
GA Pro c0105c6847 동기화 2026-05-14 01:22:47 +09:00
GA Pro 958fe6b980 동기화 2026-05-14 01:21:27 +09:00
GA Pro acea2afce5 docs: 세션 마무리 핸드오프 노트 — 잔여 P2/P3 작업 정리
2026-05-12 세션에서 코드 품질 5단계 + 도메인 P0/P1 완료(26 커밋).
다음 세션에서 P2 Wave 방식 진입을 위한 핸드오프 문서.

내용:
- 핸드오프 시점 상태 (마지막 커밋, 빌드 상태)
- 완료 작업 요약 (코드 품질 / P0 / P1)
- 잔여 작업 (P1 정산 통합 / P2 8항목 / P3 KPI / 마무리 통합)
- 재개 절차 (팀 재생성, 권장 시작점)
- PL 가이드 (시간차 중복 메시지 처리, 책임 경계)
- 채택한 표준 가정값 (세율/1200%/분급/차등환수)
2026-05-13 00:58:56 +09:00
GA Pro 3831eeaf89 feat(api): ChargebackCalculator + ChargebackGradeService + Controller (도메인 P1-3-c)
도메인 P1 마지막 항목 — 차등 환수 마무리.

ChargebackCalculator (pure @Component):
- calculate(contractDate, terminationDate, originalCommission, productCategory)
- monthsElapsed = ChronoUnit.MONTHS.between
- selectByMonths로 적용 비율 조회
- chargebackAmount = originalCommission × percent / 100 (HALF_UP, scale 0)
- grade 없으면 ZERO + "적용 환수 구간 없음"

ChargebackResult record:
- chargebackAmount, monthsElapsed, appliedPercent, reason

ChargebackGradeService:
- list/detail (readOnly)
- create/update (@Transactional, 중복 검증)
- deactivate (@Transactional)

ChargebackGradeController:
- GET/POST/PUT 표준 + /api/chargeback-grades/calculate (외부 호출용)
- 모든 보호 엔드포인트 @RequirePermission, CUD에 @DataChangeLog

ga-batch 정산 step 자동 통합은 마무리 통합 단계에서.
2026-05-13 00:56:24 +09:00
GA Pro 44dbbf37da feat(core): ChargebackGrade VO 세트 + Mapper (도메인 P1-3-b)
V28 chargeback_grade와 ga-core 동기화. 차등 환수 비즈니스 로직은 P1-3-c.

신규 패키지: com.ga.core.vo.chargeback, com.ga.core.mapper.chargeback

VO 세트:
- ChargebackGradeVO (BaseVO 상속, monthsFrom/monthsTo NULL=무한대)
- ChargebackGradeResp (productCategoryName + monthsRange 표시 문자열)
- ChargebackGradeSaveReq (@Valid: @Min(0) monthsFrom/percent)
- ChargebackGradeSearchParam (productCategory/monthsElapsed/effectiveDate)

ChargebackGradeMapper:
- 표준 CRUD
- selectByMonths(productCategory, monthsElapsed, baseDate)
  → 해당 경과월에 적용되는 환수 비율 1건 (months_from <= monthsElapsed
    AND (months_to IS NULL OR months_to >= monthsElapsed)) + 유효기간
    + product_category NULL 안전 비교 + LIMIT 1 최신 우선
- selectAll(baseDate) — months_from ASC + product_category NULLS FIRST
- selectByCategory(productCategory, baseDate)

XML 공통 activeCondition SQL fragment로 중복 제거.
2026-05-13 00:53:47 +09:00
GA Pro f6142a171f fix(api): RegulatoryLimitChecker TODO 해소 — 실제 누적 합산 적용 (P1 보강 후속)
P1-1-c에서 TODO로 두었던 누적 수수료 합산을 ga-core의 신규 메서드로 교체.

기존 (BigDecimal.ZERO 반환 — 모든 결과 한도 미만):
- sumPaidByContract()
- sumFirstYearPaidByContract()

교체:
- sumPaidByContract = recruit.sumByContract + maintain.sumByContract
- sumFirstYearPaidByContract = recruit.sumFirstYearByContract
  (maintain은 1차년 개념 없음)
- null-safe 헬퍼 추가

checkContractTotal / checkFirstYear가 이제 실제 누적값 기반 검증 동작.
2026-05-13 00:53:01 +09:00
GA Pro 1aa31deb77 feat(core): RecruitLedger/MaintainLedger sumByContract 메서드 추가 (P1 보강)
P1-1-c RegulatoryLimitChecker의 누적 수수료 합산용 TODO 해결.

추가 메서드:
- RecruitLedgerMapper.sumByContract(contractId)
- RecruitLedgerMapper.sumFirstYearByContract(contractId) — commission_year=1 한정
- MaintainLedgerMapper.sumByContract(contractId)

XML: COALESCE(SUM(agent_amount), 0) 패턴 (NULL 안전).
참고: V5 DDL 실제 컬럼명은 agent_amount (commission_amount 아님).

api-developer가 RegulatoryLimitChecker에서 이 메서드를 호출하면 TODO 해소.
2026-05-13 00:50:57 +09:00
GA Pro cc5d0e55f2 feat(db): V28 차등 환수 룰 (해약 경과월별 환수 비율) (도메인 P1-3-a)
도메인 P1 세번째 항목 — 차등 환수. DB 스키마/데이터만.

신규 테이블 chargeback_grade:
- (months_from, months_to) 범위형 룰
- product_category NULL=ALL (상품별 차등 가능)
- effective_from/to 개정 이력 추적
- CHECK 제약: months_from >= 0 AND months_to >= months_from

기존 V3 chargeback_rule(계약별 일반 룰)과 별개 — 단계별 환수 비율 전담.

기본 데이터 (2024-01-01, NULL=ALL, 표준 5단계):
- 1~12개월:  100% (계약 후 1년 이내 해약)
- 13~24개월: 50%
- 25~36개월: 25%
- 37~84개월: 10%
- 85개월 이상: 0% (환수 면제, 분급 7년 종료 후)

인덱스:
- (product_category, months_from, effective_from DESC) 환수율 조회
2026-05-13 00:49:30 +09:00
GA Pro 5029bc55d4 feat(core): Installment VO 세트 + Mapper + InstallmentStatus Enum (도메인 P1-2-b)
V27 분급 스키마와 ga-core 동기화. 분급 계획 생성 로직은 P1-2-c.

신규 패키지: com.ga.core.vo.installment, com.ga.core.mapper.installment

Enum:
- InstallmentStatus {SCHEDULED, PAID, DEFERRED, CANCELLED}

InstallmentRatio VO 세트 (분급 비율 마스터):
- VO/Resp/SaveReq/SearchParam 4종
- SaveReq: @Min(1)/@Max(7) planYear, @Positive ratioPercent

InstallmentPlan VO 세트 (계약별 분급):
- VO/Resp/SearchParam 3종
- Resp에 contract/product/agent 조인 표시
  (policyNo, productName, agentName, statusName)

Mapper 2종:
- InstallmentRatioMapper: selectActive(category, year, baseDate),
  selectAllActiveRatios(category, baseDate) — 1~7차년 비율 일괄 조회
- InstallmentPlanMapper: insertBatch(<foreach>), selectByContract,
  selectScheduledByMonth, updateStatus(paidAmount/paidAt/paymentId)

XML 핵심:
- 활성 비율: effective_from/to + is_active=TRUE + LIMIT 1 (최신 우선)
- selectAllActiveRatios: plan_year ASC (1~7년 순서 보장)
- selectScheduledByMonth: settle_month + status='SCHEDULED' (배치 진입점)
2026-05-13 00:45:53 +09:00
GA Pro 434e7783a9 feat(db): V27 분급 계획 + 분급 비율 마스터 (도메인 P1-2-a)
도메인 P1 두번째 항목 — 분급(installment_plan). DB 스키마/데이터만.

신규 테이블:
- installment_ratio (분급 비율 마스터, effective_from/to 이력 추적)
- installment_plan (계약별 분급 계획)

기본 비율 데이터 (2024-01-01, NULL=ALL):
- 1차년 35%, 2차년 25%, 3차년 15%, 4차년 10%,
  5차년 7%, 6차년 5%, 7차년 3% (합 100%)
- 시기/상품별 정책 변경 시 새 effective_from 추가

installment_plan 핵심:
- (contract_id, plan_year, plan_month) UNIQUE
- payment_id로 실제 지급 시 역참조
- status: SCHEDULED/PAID/DEFERRED/CANCELLED

인덱스:
- installment_plan (contract_id, plan_year, plan_month) 계약별 조회
- (settle_month, status) 월별 지급 예정 조회
- (payment_id) payment 역참조
- installment_ratio (product_category, plan_year, effective_from DESC)
2026-05-13 00:41:23 +09:00
GA Pro bba4a33143 feat(api): RegulatoryLimitChecker + Service + Controller (도메인 P1-1-c, 부분 TODO)
P1-1 마무리. 검증 인프라 + 마스터 CRUD 완성.

신규:
- service/regulatory/ViolationResult (record + ok/violated 팩토리)
- service/regulatory/RegulatoryLimitChecker (@Component)
  - checkContractTotal(contractId, additionalAmount, baseDate) — 1200% 한도
  - checkFirstYear(contractId, additionalAmount, baseDate) — 1차년 35% 한도
- service/regulatory/RegulatoryLimitService (CRUD + selectActive)
- controller/regulatory/RegulatoryLimitController
  - GET/POST /api/regulatory-limits, GET/PUT /{id}, PUT /{id}/deactivate
  - POST /check-contract (단건 검증)
- controller/regulatory/ContractLimitCheckReq

TODO (P1 마무리 단계에서 정리 예정):
- RegulatoryLimitChecker.sumPaidByContract / sumFirstYearPaidByContract
  현재 BigDecimal.ZERO 반환 (모든 결과가 한도 미만으로 나옴)
- ga-core RecruitLedgerMapper에 sumByContract / sumFirstYearByContract
  메서드 추가 후 실제 합산값으로 교체 필요
- 검증 인프라 자체는 완성, 데이터 연결만 보강 필요
2026-05-13 00:39:24 +09:00
GA Pro 11092537d7 feat(core): RegulatoryLimit VO 세트 + Mapper + Enum 3종 (도메인 P1-1-b)
V26 규제 한도 마스터와 ga-core 동기화. 검증 로직은 P1-1-c.

신규 패키지: com.ga.core.vo.regulatory

Enum 3종:
- LimitType {TOTAL_RATIO, FIRST_YEAR_RATIO, INSTALLMENT_YEARS}
- LimitUnit {PERCENT, YEAR}
- ProductCategory {ALL, LIFE, ANNUITY, SAVINGS, EXCLUDED_AUTO, EXCLUDED_HEALTH}

RegulatoryLimit VO 세트:
- RegulatoryLimitVO (BaseVO 상속)
- RegulatoryLimitResp (코드명 표시)
- RegulatoryLimitSaveReq (@Valid: limitType/unit @NotBlank, limitValue @Positive)
- RegulatoryLimitSearchParam (limitType/productCategory/effectiveDate)

RegulatoryLimitMapper (com.ga.core.mapper.regulatory):
- 표준 CRUD + 활성 한도 조회 메서드 2종:
  - selectActiveByType(limitType, productCategory, baseDate) — 특정 날짜 유효 1건
  - selectAllActive(baseDate) — 특정 날짜 유효 전체

XML:
- effective_from <= baseDate AND (effective_to IS NULL OR effective_to >= baseDate)
- is_active = TRUE
- 최신 개정본 우선 (ORDER BY effective_from DESC LIMIT 1)
- product_category NULL=ALL 처리 안전 비교
2026-05-13 00:33:25 +09:00
GA Pro 6a6ba9ff0e feat(db): V26 규제한도 마스터 + 1200%룰 기본 데이터 (도메인 P1-1-a)
도메인 P1 시작 — 1200%룰 검증의 한도 마스터. Java 동기화는 P1-1-b/c.

신규 테이블 regulatory_limit:
- 감독규정 개정 이력 추적 (effective_from/to)
- product_category NULL=ALL, 또는 LIFE/ANNUITY/SAVINGS/EXCLUDED_AUTO/EXCLUDED_HEALTH
- limit_type: TOTAL_RATIO(1200%), FIRST_YEAR_RATIO(1차년 35%), INSTALLMENT_YEARS(7년)
- is_active 부분 인덱스로 활성 한도만 빠르게 조회

기본 데이터 (2024-01-01 기준, 외부화 가능):
- TOTAL_RATIO ALL 1200% (보험업감독규정 제5-15조의5)
- FIRST_YEAR_RATIO ALL 35%
- INSTALLMENT_YEARS ALL 7년

코드그룹: LIMIT_TYPE, LIMIT_UNIT, PRODUCT_CATEGORY

인덱스:
- (limit_type, product_category, effective_from DESC) 한도 조회용
- (is_active) WHERE is_active = TRUE 부분 인덱스

ON CONFLICT DO NOTHING으로 재실행 안전.
2026-05-13 00:30:19 +09:00
GA Pro f5efcaa3ac feat(api): CommissionStatementService + ExcelStatementGenerator + Controller (도메인 P0-3-c)
도메인 P0(세무·공제·명세서) 마지막 항목. 이번 단계는 EXCEL 형식 우선,
PDF는 별도 향후 작업.

신규 도메인 클래스 (service/statement/):
- StatementSummary (record, 6필드: gross/incomeTax/localTax/vat/deduction/net)
- StatementAggregator (@Component, PaymentMapper.selectByAgentAndMonth로 집계)
- ExcelStatementGenerator (@Component, SXSSFWorkbook 직접)
- CommissionStatementService

CommissionStatementService:
- list/detail — readOnly + PageHelper
- generate(SaveReq) — @Transactional:
  1. aggregator.aggregate(agentId, settleMonth)
  2. excelGenerator.generate(agent, summary, payments) → byte[]
  3. fileService.saveBytes → fileId
  4. selectByAgentMonth → 기존 있으면 UPDATE(재발급), 없으면 INSERT
  5. issue_status=GENERATED, issued_at, issued_by 기록
- generateForMonth(settleMonth, statementType) — 월 일괄, payment의 distinct agentId 순회
- download(id) — file_path 조회 → byte[] 반환 + DOWNLOADED 전이
- cancel(id) — CANCELLED 전이

CommissionStatementController:
- GET /api/statements (페이지)
- GET /api/statements/{id}
- POST /api/statements/generate (@Valid, @DataChangeLog)
- POST /api/statements/generate-for-month (@DataChangeLog)
- GET /api/statements/{id}/download (binary 응답)
- PUT /api/statements/{id}/cancel (@DataChangeLog)

PDF 요청 시 INVALID_PARAMETER BizException — PDF는 별도 작업으로 미룸.

Mapper 추가 (ga-core):
- PaymentMapper.selectByAgentAndMonth
2026-05-13 00:28:08 +09:00
GA Pro 4f5a2f0cb9 feat(core): CommissionStatement VO 세트 + Mapper + StatementType/Status Enum (도메인 P0-3-b)
V25 명세서 스키마와 ga-core 동기화. 발급/생성 로직은 P0-3-c.

신규:
- vo/settle/StatementType {MONTHLY, ANNUAL, PROOF}
- vo/settle/StatementStatus {GENERATED, SENT, DOWNLOADED, CANCELLED}

CommissionStatement VO 세트:
- CommissionStatementVO (BaseVO 상속)
- CommissionStatementResp (agentName/statementTypeName/issueStatusName 표시)
- CommissionStatementSaveReq (@Valid: @NotNull agentId, @NotBlank settleMonth(@Size 6), statementType, fileFormat)
- CommissionStatementSearchParam (agentId/settleMonth/statementType/issueStatus + fromDate/toDate)

CommissionStatementMapper:
- selectList / selectDetailById / selectById / selectByAgentMonth /
  insert / update / updateStatus
- XML: VOMap/RespMap, STATEMENT_TYPE/STATUS 코드명 서브쿼리,
  날짜 범위 PostgreSQL 캐스트, COALESCE 기본값, <set> 동적 update
- selectByAgentMonth는 UNIQUE(agent_id, settle_month, statement_type)
  기반 — 재발급 시 기존 row 갱신 판단에 사용
2026-05-13 00:24:28 +09:00
GA Pro 930335ce3f feat(db): V25 수수료 명세서 스키마 + 코드그룹 (도메인 P0-3-a)
도메인 P0 마지막 항목 — 수수료 명세서. DB 스키마/데이터만.

신규 테이블 commission_statement:
- agent_id + settle_month + statement_type 유니크
- 발급 시점 집계 스냅샷 (gross/incomeTax/localTax/vat/deduction/net)
- 파일 경로/포맷/발급 상태
- 재발급은 PUT으로 row 갱신 (이력 분리보다 최신본 단순 관리)

코드그룹:
- STATEMENT_TYPE: MONTHLY(월별), ANNUAL(연간 누계), PROOF(소득증빙)
- STATEMENT_STATUS: GENERATED, SENT, DOWNLOADED, CANCELLED

인덱스:
- (agent_id, settle_month, statement_type DESC) 설계사 조회용
- (issued_at DESC) 최근 발급 조회용
2026-05-13 00:20:50 +09:00
GA Pro b8f33f13d1 feat(api): DeductionService + PaymentService 차감 통합 + DeductionController (도메인 P0-2-c)
P0-2 공제/차감 도메인 마무리. ga-batch 정산 step 통합은 도메인 P0 마무리에서.

DeductionService (신규):
- CRUD: list/detail/create/update/cancel
- create는 (agent_id, settle_month, deduction_type) 유니크 중복 검증
- cancel은 status를 CANCELLED로 전이
- 정산용: sumPendingByAgent, selectPendingByMonth, markAsApplied(batch)

PaymentService 확장:
- applyDeductions(paymentId, settleMonth) — 단건:
  1. PENDING 차감 조회
  2. payment_deduction_detail INSERT
  3. agent_deduction.status → APPLIED 일괄 전이
  4. payment.deduction_amount UPDATE
  5. net_amount 재계산 (newNet = currentNet - deductionTotal)
- applyDeductionsForMonth(settleMonth) — 월 일괄

net_amount 공식 갱신:
- 세금 적용(calculateTaxes): amount - incomeTax - localTax + vat
- 차감 적용(applyDeductions): currentNet - deductionTotal
- 최종: amount - incomeTax - localTax + vat - deduction

Mapper 추가 (ga-core):
- AgentDeductionMapper: selectPendingByAgent, updateStatusBatch, countByAgentMonthType
- PaymentMapper: updateDeduction

DeductionController + PaymentController 엔드포인트 추가:
- /api/deductions CRUD (5종)
- /api/payments/{id}/apply-deductions
- /api/payments/apply-deductions?settleMonth=YYYYMM
2026-05-13 00:18:53 +09:00
GA Pro a3ba7fa361 feat(core): 공제 VO 세트 + Mapper + DeductionType/Status Enum (도메인 P0-2-b)
V24 공제 스키마와 ga-core 동기화. 비즈니스 로직은 P0-2-c.

신규:
- vo/settle/DeductionType {LOAN, ADVANCE, GUARANTEE, DUES, AD, CHARGEBACK_PENDING, OTHER}
- vo/settle/DeductionStatus {PENDING, APPLIED, CANCELLED}

AgentDeduction VO 세트 (표준 5종):
- AgentDeductionVO (감사 4종 포함)
- AgentDeductionResp (agentName/deductionTypeName/statusName 조인 표시 필드)
- AgentDeductionSaveReq (@Valid)
- AgentDeductionSearchParam (settleMonth/agentId/deductionType/status)

PaymentDeductionDetailVO (이체 명세 단순 VO)

Mapper (2종 신규):
- AgentDeductionMapper: selectList/Detail/insert/update/updateStatus/
  sumPendingByAgent/selectPendingByMonth
- PaymentDeductionDetailMapper: selectByPaymentId/insert/insertBatch

PaymentVO.deductionAmount + PaymentMapper.xml VOMap 갱신.
2026-05-13 00:14:09 +09:00
GA Pro 0e73eb61a9 feat(db): V24 공제/차감 스키마 + 차감 코드그룹 (도메인 P0-2-a)
도메인 P0 두번째 항목 — 공제/차감. 본 커밋은 DB 스키마/데이터만.
ga-core/ga-api 동기화는 P0-2-b/c.

신규 테이블:
- agent_deduction (월별 차감 마스터)
  - UNIQUE (agent_id, settle_month, deduction_type)
  - PENDING/APPLIED/CANCELLED 상태
- payment_deduction_detail (이체 시 적용된 차감 명세)

payment 컬럼 추가:
- deduction_amount NUMERIC(15,2) DEFAULT 0 (차감 합계)
- net_amount 공식은 P0-2-c에서 (amount - tax - deduction + vat)로 갱신 예정

common_code 코드그룹:
- DEDUCTION_TYPE: LOAN, ADVANCE, GUARANTEE, DUES, AD,
  CHARGEBACK_PENDING, OTHER
- DEDUCTION_STATUS: PENDING, APPLIED, CANCELLED

인덱스:
- agent_deduction (settle_month, agent_id) 복합
- payment_deduction_detail (payment_id)

ON CONFLICT DO NOTHING으로 재실행 안전.
2026-05-13 00:02:05 +09:00
GA Pro f8c7d8459b feat(api): TaxCalculator 도메인 + PaymentService 세금 통합 + AgentService 세무 매핑 (도메인 P0-1-c)
P0-1 세무 처리 마무리. ga-batch 정산 step 통합은 도메인 P0 마무리 단계.

TaxCalculator (신규, ga-api/service/tax):
- @Component pure function: TaxBreakdown calculate(amount, taxType, vatType)
- record TaxBreakdown {incomeTax, localTax, vat, netAmount}
- 세율은 SystemConfigService로 외부화 (TAX_RATE_BUSINESS_INCOME 등)
- 공식:
  - incomeTax = amount × incomeRate / 100 (ROUND_HALF_UP, scale 0)
  - localTax = incomeTax × localRate / 100
  - vat = (TAXABLE) ? amount × vatRate / 100 : 0
  - netAmount = amount - incomeTax - localTax + vat

PaymentService:
- calculateTaxes(paymentId) — 단건 재계산 @Transactional
- calculateTaxesForMonth(settleMonth) — 월별 일괄 @Transactional + batch update

PaymentMapper (ga-core):
- updateTaxes / updateTaxesBatch / selectBySettleMonth 추가

AgentService.toVO():
- taxType/vatType/businessNo 매핑 + default 처리
- 사업소득자인데 businessNo 미입력 시 경고 로그

PaymentController:
- POST /api/payments/{id}/calculate-tax (@RequirePermission, @DataChangeLog)
- POST /api/payments/calculate-taxes?settleMonth=YYYYMM
2026-05-13 00:00:13 +09:00
GA Pro 92f32175ad feat(core): TaxType/VatType Enum + Agent/Payment 세무 필드 (도메인 P0-1-b)
V23 마이그레이션과 ga-core 동기화. 세금 계산 비즈니스 로직은 P0-1-c에서.

신규:
- vo/org/TaxType (BUSINESS_INCOME, OTHER_INCOME) — V23 CHECK 제약 근거
- vo/org/VatType (NONE, EXEMPT, TAXABLE) — V23 CHECK 제약 근거

AgentVO/AgentSaveReq/AgentResp 컬럼 추가:
- taxType (@NotBlank, default BUSINESS_INCOME)
- businessNo (@Size 20, 사업소득자만 필수 — 소프트 검증)
- vatType (@NotBlank, default NONE)
- AgentResp는 taxTypeName/vatTypeName 표시 필드 함께 노출

PaymentVO 컬럼 추가:
- incomeTaxAmount (원천소득세)
- localTaxAmount (지방소득세)
- vatAmount (부가세)
- netAmount (차감 후 실지급액)

Mapper XML:
- AgentMapper.xml — VOMap/agentJoinCols/insert/update 갱신, TAX_TYPE/VAT_TYPE
  코드명 스칼라 서브쿼리로 자동 매핑
- PaymentMapper.xml — VOMap에 세무 4개 컬럼 추가
2026-05-12 23:56:14 +09:00
GA Pro ad5d62ea07 feat(db): V23 세무처리 스키마 + 표준 세율 system_config (도메인 P0-1-a)
도메인 누락 P0 첫 항목 — 세무 처리. 본 커밋은 DB 스키마/데이터만.
다음 sub-step에서 ga-core VO/Enum, 그 다음 ga-api Service 통합.

agent 컬럼 추가:
- tax_type VARCHAR(20) DEFAULT 'BUSINESS_INCOME'
  (BUSINESS_INCOME 사업소득 3.3% / OTHER_INCOME 기타소득 8.8%)
- business_no VARCHAR(20) (사업자등록번호)
- vat_type VARCHAR(20) DEFAULT 'NONE'
  (NONE / EXEMPT 면세 / TAXABLE 일반과세)
- 두 컬럼 모두 CHECK 제약

payment 컬럼 추가:
- income_tax_amount (원천소득세)
- local_tax_amount (지방소득세)
- vat_amount (부가세)
- net_amount (차감 후 실지급액)

system_config 표준 세율(2024 기준, 외부화 가능):
- TAX_RATE_BUSINESS_INCOME = 3.3
- TAX_RATE_OTHER_INCOME = 8.8
- TAX_RATE_LOCAL_INCOME = 10.0
- TAX_RATE_VAT = 10.0

common_code 코드그룹 추가: TAX_TYPE, VAT_TYPE

모든 INSERT는 ON CONFLICT DO NOTHING으로 재실행 안전.
2026-05-12 23:51:57 +09:00
GA Pro b16e678e5f refactor(api): MapStruct 적용 + AgentOrgHistoryResp 적용 + PaymentService/UploadTemplateService 신설 (리뷰 5b)
코드 품질 자동 체인 마지막 단계. ga-api에 5a 산출물 적용 + 잔여 Controller
Mapper 직접 주입 제거.

MapStruct 적용 (수동 매핑 제거):
- ContractService.create/update — ContractMapStruct.toVO/updateVO
- LedgerService — ExceptionLedgerMapStruct.toVO
- UserService.create/update — UserMapStruct.toVO/updateVO

AgentOrgHistoryResp 적용:
- AgentService.history() 반환 List<AgentOrgHistoryVO> → List<AgentOrgHistoryResp>
- AgentMapper.selectHistoryResp(agentId) 사용
- AgentController history 시그니처 동반 변경 — 감사 필드 누설 + FK ID 노출 문제 해소

잔여 Controller Mapper 직접 주입 제거:
- AgentController/LedgerController — AgentService.exportCursor /
  LedgerService.exportRecruitCursor/exportMaintainCursor 위임
- PaymentService 신설 — PaymentController에서 Mapper/TransferFileService
  직접 주입 제거, PageHelper.startPage Service로 이전
- UploadTemplateService 신설 — 3개 Mapper(template/column/history) Service로 이전

PageHelper 위치 통일:
- grep -rn "startPage" controller/ → 결과 없음 (모두 Service로 이전)

남은 예외:
- BatchTriggerController.BatchJobLogMapper — 배치 트리거 특수 패턴이라 보류
- PaymentStatus Enum — 도메인 단계에서 처리 예정
2026-05-12 23:48:44 +09:00
GA Pro 4b211ecdfe feat(core): AgentOrgHistoryResp + MapStruct mapper 3종 추가 (리뷰 5a)
코드 품질 5단계 ga-core 준비물. ga-api 적용은 5b에서 진행.

AgentOrgHistoryResp 추가:
- AgentOrgHistoryVO 직접 노출 문제 해소 (감사 필드 누설 + FK ID만 노출)
- 표시용 조인 필드 포함: agentName, from/toOrgName, from/toGradeName,
  changeTypeName (CHANGE_TYPE 코드그룹 스칼라 서브쿼리)
- AgentMapper.selectHistoryResp + AgentMapper.xml 조인 쿼리 추가

MapStruct mapper 3종 (com.ga.core.mapstruct):
- ContractMapStruct (ContractSaveReq → ContractVO + update 패턴)
- ExceptionLedgerMapStruct (ExceptionLedgerSaveReq → ExceptionLedgerVO)
- UserMapStruct (UserSaveReq → UserVO)
- @Mapper(componentModel="spring"), 감사 필드 ignore
2026-05-12 23:42:58 +09:00
GA Pro 498d0d44f0 refactor(api): 동시성 정정 + UploadService/TransferFile 트랜잭션 분해 + readOnly 일괄 (리뷰 4단계)
리뷰에서 P0로 지적된 동시성/롱 트랜잭션 이슈 일괄 해소.

LookupCache (P0 데이터 정합성):
- 싱글톤 인스턴스 필드 캐시 제거 → preload()가 새 Map 반환, 호출자 보유
- TransformEngine.transform/applyTransform/applyLookup/applyCodeMap 시그니처에
  lookupData 파라미터 추가하여 명시적 전달
- 스레드 간 공유 상태 자체가 없어져 동기화 불필요

UploadService (P0 가용성):
- 신규 UploadTxHelper로 saveHistory/insertBatch/updateHistory를 REQUIRES_NEW로 분리
- UploadService에서 @Transactional 완전 제거 — 파일 파싱은 트랜잭션 밖
- 청크(1000행) 단위 커밋 → 커넥션 점유 시간 감소

TransferFileService (P0 정합성):
- 파일 생성을 트랜잭션 밖으로 분리
- markPaymentsSent() 별도 @Transactional로 payment UPDATE만 처리
- 파일 저장 실패 시 payment 상태 미변경으로 재시도 안전성 확보

조회 메서드 readOnly=true 일괄 적용 (Hibernate dirty check 비활성화 / 읽기 복제본 라우팅 준비):
- AgentService, ContractService, LedgerService, SettleService,
  OrganizationService, UserService 조회 메서드 전체
2026-05-12 23:37:27 +09:00
GA Pro af3c6b9d51 refactor(api): Map→SaveReq DTO 교체 + 입력 검증 + 잔여 Enum 적용 (리뷰 3b)
infra-reviewer가 지적한 입력 검증 누락 5건과 잔여 매직 스트링 정리.

Map<String,String> 입력 제거 — 신규 DTO 4종:
- auth/ChangePasswordReq (@NotBlank oldPassword/newPassword)
- auth/RefreshTokenReq (@NotBlank refreshToken)
- controller/settle/PaymentStatusUpdateReq (@NotBlank status)
- controller/receive/ResolveErrorReq (@NotBlank status, optional note)

검증 보강:
- PaymentController.generateTransferFile — settleMonth @Pattern("\d{6}")
- UploadController.preview — limit @Max(100)

잔여 매직 스트링 → 3a Enum 적용:
- AuthService 4곳 — UserStatus.LOCKED/RETIRED/ACTIVE
- UserService 2곳 — UserStatus.ACTIVE
- LedgerService:71 — ExceptionLedgerStatus.NEW
2026-05-12 23:28:41 +09:00
GA Pro 693275e9e0 feat(core): UserStatus + ExceptionLedgerStatus Enum 추가 (리뷰 3a)
2단계에서 매직 스트링 일부가 1단계 Enum 도메인 밖이라 미교체로 남은
두 도메인의 Enum을 추가.

- vo/user/UserStatus.java {ACTIVE, LOCKED, RETIRED}
  근거: V7 DDL users.status 주석 명시
- vo/ledger/ExceptionLedgerStatus.java {NEW, APPLIED, CANCELLED}
  근거: V5 DDL exception_ledger.status DEFAULT 'NEW'.
  현재 코드에서는 NEW만 사용. APPLIED/CANCELLED는 향후 전이 상태 추론.

approve_status(ApproveStatus)는 별개 컬럼이므로 혼동 주의.

3b 단계(api-developer)가 AuthService/UserService/LedgerService의
잔여 매직 스트링을 이 Enum으로 교체 예정.
2026-05-12 23:17:24 +09:00
GA Pro a8f0b6edf9 refactor(api): Controller→Service 분리 + 매직 스트링 Enum 교체 (리뷰 2단계)
5개 Controller가 Mapper를 직접 주입하던 패턴 제거하고 Service 레이어 신설.

신규 Service:
- InsuranceCompanyService, ProductService, RuleService, ReceiveService, RoleService
- 변경 메서드 @Transactional, 조회 @Transactional(readOnly=true) 적용

Controller 정리:
- 5개 Controller에서 Mapper 직접 주입 제거 → Service 경유
- RoleController의 Controller-level @Transactional은 Service로 이전

매직 스트링 → Enum (1단계 산출물 적용):
- AgentService/ContractService — AgentStatus, ContractStatus
- SettleService 4곳 — SettleStatus
- LedgerService 3곳 — ApproveStatus

OrganizationSaveReq 적용:
- OrganizationController create/update 입력을 OrganizationVO → OrganizationSaveReq
  로 변경, 클라이언트의 감사 필드 직접 주입 차단

원래 3단계로 분류했던 @DataChangeLog 17곳 보강도 2단계에서 함께 처리:
- ProductController DELETE
- RuleController override/chargeback/exception 8곳
- ReceiveController profiles/mapping/errors 6곳
- RoleController DELETE + savePermissions (권한 일괄변경)

미해결로 남은 매직 스트링(다음 단계):
- AuthService "LOCKED"/"RETIRED"/"ACTIVE" — UserStatus Enum 미구현
- LedgerService:71 "NEW" — LedgerStatus Enum 미구현
2026-05-12 23:13:40 +09:00
GA Pro 5e58a54128 feat(core): OrganizationSaveReq + 상태 Enum 4종 추가 (리뷰 1단계)
ga-api 코드 리뷰에서 식별된 P0 이슈 해결의 1단계.

추가:
- vo/org/OrganizationSaveReq.java — 감사필드 제외, @Valid 적용
- vo/org/AgentStatus.java {ACTIVE, LEAVE, SUSPEND}
- vo/product/ContractStatus.java {ACTIVE, LAPSE, REVIVE, TERMINATE}
- vo/settle/SettleStatus.java {CALCULATED, CONFIRMED, HOLD, PAID}
- vo/ledger/ApproveStatus.java {PENDING, APPROVED, REJECTED}

값 결정 근거: V1/V2/V5/V6 DDL 주석 + V12 공통코드 (AGENT_STATUS,
CONTRACT_STATUS, SETTLE_STATUS, APPROVE_STATUS).

다음 단계(api-developer)가 ga-api 서비스의 매직 스트링을 이 Enum으로
교체하고 OrganizationSaveReq를 사용하도록 변경 예정.
2026-05-12 22:49:38 +09:00
GA Pro 418ff7c13e chore(claude): Agent Teams 설정 및 7명 에이전트 정의 커밋
- .claude/settings.json: CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1, teammateMode=auto
- .claude/agents/*.md: ga-pro-team 7명(common/core/api/batch/frontend/dba/infra) 정의
- .gitignore: .claude/ 전부 제외 → settings.json + agents/만 공유, settings.local.json은 계속 제외
2026-05-12 22:41:44 +09:00
GA Pro a24f93a39d feat(domain): V22 비즈니스 도메인 6 카테고리 29개 + 사전 매핑 30+
신규 카테고리:

AUDIT (5) — 모든 테이블 공통 감사 컬럼
- DOM_CREATED_BY / DOM_UPDATED_BY (사용자 ID)
- DOM_IP_ADDRESS (IPv4/IPv6 통합)
- DOM_USER_AGENT (HTTP 헤더)
- DOM_VERSION (낙관적 잠금)

WORKFLOW (5) — 결재 / 승인 흐름
- DOM_APPROVE_STATUS (PENDING/APPROVED/REJECTED/CANCELLED)
- DOM_APPROVER_ID / DOM_APPROVE_COMMENT
- DOM_WORKFLOW_STAGE (DRAFT/REVIEW/APPROVED/PUBLISHED/ARCHIVED)
- DOM_PRIORITY (HIGH/MEDIUM/LOW)

SETTLEMENT_BIZ (6) — GA 정산 핵심 비즈
- DOM_RECONCILE_STATUS (대사 상태)
- DOM_RECONCILE_DIFF (보험사-시스템 차액)
- DOM_LAPSE_MONTH (실효 경과월 — 환수 규정 매칭)
- DOM_INSTALLMENT_SEQ / DOM_INSTALLMENT_TOTAL (분할 환수 회차)
- DOM_PERFORMANCE_GRADE (A/B/C/D/F)

FILE (4) — 파일 첨부
- DOM_FILE_ID (file_storage FK)
- DOM_FILE_PATH / DOM_FILE_SIZE / DOM_MIME_TYPE

TAX (4) — 세무
- DOM_TAX_INVOICE_NO (세금계산서)
- DOM_VAT (부가세 10%)
- DOM_INCOME_TAX (소득세 3%) / DOM_LOCAL_TAX (지방세)

BANKING (5) — 은행 / 결제
- DOM_TRANSFER_REF (이체 참조번호)
- DOM_TRANSFER_FEE / DOM_CURRENCY (ISO 4217)
- DOM_FX_RATE (환율 6자리) / DOM_SWIFT_CODE (BIC)

데이터 사전 매핑 30+ 추가:
- exception_ledger (8) / chargeback (7) / reconciliation (7) / batch_job_log (6)
- file_storage (6) / api_access_log (6) / data_change_log (6)
- recruit_ledger·maintain_ledger·settle_master 의 audit 컬럼

검증:
- Flyway V22 적용 35ms
- 전체 도메인 49 → 78 (16 카테고리)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 00:38:57 +09:00
GA Pro 1c74e192ec fix(upload): target_table 자유입력 → Select (whitelist) + V21 PROFILE/RESUME 도메인
[버그 fix]
- UploadTemplateManager 의 ModalForm 에서 target_table 이 ProFormText 자유입력
  이라 사용자가 잘못 입력 시 ("1" 등) 백엔드 whitelist 검증 실패
  ("허용되지 않은 target_table: 1") 발생
- ProFormSelect 로 변경 + request 로 /api/upload-templates/target-tables 호출
  → 9개 허용 테이블만 옵션 노출 (오타 / 잘못된 입력 원천 차단)

[V21__프로필_이력서_도메인.sql]
도메인 15개 추가:

PROFILE 카테고리 (8개):
- DOM_PROFILE_BIO (자기소개, TEXT)
- DOM_PROFILE_IMAGE (프로필 사진, BIGINT 파일ID)
- DOM_NICKNAME (닉네임, VARCHAR(50))
- DOM_BIRTH_DATE (생년월일, DATE)
- DOM_GENDER (성별, CHAR(1) M/F/U)
- DOM_ADDRESS (주소, VARCHAR(300))
- DOM_ZIP_CODE (우편번호, VARCHAR(10))
- DOM_NATIONALITY (국적, ISO 3166)

RESUME 카테고리 (7개):
- DOM_RESUME_FILE (이력서 파일, BIGINT)
- DOM_CAREER_HISTORY (경력 사항, JSONB 배열)
- DOM_EDUCATION (학력, JSONB 배열)
- DOM_LICENSE_LIST (자격증 목록, JSONB)
- DOM_SKILL_TAGS (스킬 태그, VARCHAR(500))
- DOM_INTRODUCTION (소개 영상 URL, VARCHAR(500))
- DOM_HIRE_TYPE (계약 형태, VARCHAR(20))

데이터 사전 매핑 28개 추가 (V20 누락 보강):
- agent: grade_id/bank_code/leave_date/created_at/updated_at
- users: 7컬럼
- organization: 6컬럼
- insurance_company: 4컬럼
- product: 5컬럼

검증:
- Flyway V21 적용 200ms
- /api/data-domains?domainCategory=PROFILE → 8건
- /api/data-domains?domainCategory=RESUME → 7건
- target-tables 9개 정상 응답
- 프론트 tsc -b 통과

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 00:34:47 +09:00
GA Pro cece084631 feat: 데이터 도메인 사전 + 데이터 사전 시스템 (V20)
3 agents 병렬 작업 (dba / api / frontend) 결과물 + SQL 버그 2건 fix.

DB (V20__데이터사전.sql):
- data_domain (domain_code PK, category, data_type, length/precision/scale,
  format_pattern, validation_regex, masking_type, encrypted, ...)
- data_dictionary (dict_id PK, table_name, column_name, domain_code FK,
  column_label, is_pk/is_fk/fk_reference, business_rule, sample_value, ...)
- VIEW v_data_dictionary_full: information_schema + pg_description +
  data_dictionary + data_domain 4-way LEFT JOIN
  → ga 스키마 모든 컬럼 자동 노출 (사전 미등록 컬럼도 회색 표시)
- 도메인 30개 초기 데이터 (IDENTIFIER 7 / PII 6 / MONEY 5 / RATE 3 /
  DATE 4 / CODE 4 / TEXT 3 / JSON 2)
- 사전 매핑 50개 (agent 10 / contract 7 / recruit_ledger 9 /
  settle_master 9 / payment 6)
- 메뉴 SYSTEM_DATA_DOMAIN, SYSTEM_DATA_DICT 등록 + 권한

Backend:
- ga-core VO 9개 + Mapper 2개 + XML 2개
- ga-api Service 2 (도메인 삭제 시 사전 참조 검증) + Controller 2
- 엔드포인트:
  · /api/data-domains (CRUD + /options)
  · /api/data-dictionary (CRUD + /tables + /full?tableName=)

Frontend:
- api/dict.ts (13 endpoints)
- pages/system/DataDomainList.tsx — 카테고리 색상 Tag, 마스킹/암호화 표시,
  ModalForm 등록/수정/삭제
- pages/system/DataDictionary.tsx — 좌(테이블 목록 + prefix 그룹핑) +
  우(v_data_dictionary_full 조회, 사전 미등록 컬럼은 회색+점선 추가 버튼)
- App.tsx + MenuIcon.tsx 매핑 추가

Bug fix:
- DataDomainMapper: WHERE is_active = true → 'Y' (CHAR vs boolean)
- DataDictionaryMapper.selectFromView: ORDER BY sort_order 제거
  (view 에 없는 컬럼)

검증:
- ./gradlew :ga-api:bootJar 통과
- Flyway V20 운영 DB 적용 (17초)
- 4 엔드포인트 모두 200 응답
- agent 테이블 15컬럼 사전 자동 노출 + 도메인 매핑 정상

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 00:29:13 +09:00
GA Pro 2136b38e1b feat(upload): 매핑 UI 4가지 보강 — 자동 채우기 + Select 옵션 + 미리보기 + 좌우 정렬
엑셀 컬럼 매핑이 더 직관적이도록:

Backend:
- TargetFieldMetaService 신규: 9개 target_table 의 사용 가능 필드 메타데이터
  (recruit_ledger 15 / maintain_ledger 11 / contract 10 / agent 10 /
   commission_rate 7 / payout_rule 7 / chargeback_rule 6 / exception_ledger 6 /
   payment 6) — field/label/type/required
- UploadService.extractHeaders(file, headerRow, sheetIndex, previewRows):
  StreamingReader 로 첫 행 헤더 + N행 미리보기 추출, A/B/C 컬럼 라벨 생성
- UploadController 에 3개 엔드포인트 추가:
  · POST /api/upload-templates/excel-headers (multipart) → ExcelHeaderResp
  · GET  /api/upload-templates/target-fields/{targetTable}
  · GET  /api/upload-templates/target-tables

Frontend:
- api/uploadTemplate.ts: extractHeaders / targetFields / targetTables 함수 추가
  + ExcelHeaderResp / TargetFieldMeta 타입
- ColumnEditor 보강:
  1) "샘플 엑셀로 자동 채우기" 버튼 — 사용자가 샘플 파일 올리면 헤더 추출 후
     sourceColumn(A,B,C) + sourceHeader(헤더명) 자동 채움 (기존 매핑 있으면
     Modal.confirm 으로 덮어쓰기 확인)
  2) 대상 필드 Input → Select (target_table 별 메타 옵션) — showSearch +
     선택 시 targetType 자동 설정 (필드 메타의 type 으로)
  3) 헤더에 target_table tag 표시 (→ recruit_ledger)
  4) 자동 채우기 후 첫 5행 샘플 데이터 테이블이 매핑 편집기 위에 표시됨

검증: tsc -b 통과, ga-api 재기동 후 /target-fields 200 (15필드 응답)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 00:14:45 +09:00
GA Pro 87e4e3d1da feat: 추천 작업 5종 일괄 진행 (4 agents 병렬)
[A] 등록 모달 7페이지 (frontend)
- CompanyList / ProductList / Commission / Payout / Override / Chargeback / ExceptionCode
- ModalForm 580px, Switch Y/N 변환, 날짜 dayjs, PermissionButton
- api/company/product/rule.ts 에 SaveReq + create/update/remove 추가

[B] BatchRun + RoleList 보강 (frontend)
- BatchRun: 정산월/보험사 선택 → 실행, antd Steps 8단계 + 5초 폴링
  (refetchInterval 자동 정지), KPI 4 카드, 최근 이력
- RoleList: 좌(역할 목록) 우(메뉴×6권한 매트릭스 체크박스),
  DIRECTORY 들여쓰기, 전체 토글, Modal.confirm 후 저장

[C] 이체파일 + 은행 어댑터 (api)
- BankTransferFileGenerator 인터페이스 + GenericCsvTransferGenerator
  (UTF-8 BOM, 표준 CSV) + KbBankTransferGenerator (088, 고정폭 + 합계)
- BankTransferFactory (Spring Map 빈)
- TransferFileService: PENDING 조회 → 파일 생성 → file_storage 적재 →
  pay_file_ref 갱신 → status=SENT
- POST /api/payments/transfer-file (DataChangeLog + EXPORT 권한)
- account_no EncryptTypeHandler 자동 복호화 후 파일에 사용
- FileService.saveBytes(byte[]) 오버로드 추가
- PaymentList: 이체파일 생성 ModalForm + 다운로드 컬럼

[D] MockMvc Controller 테스트 (api)
- AbstractControllerTest (SpringBootTest + MockMvc, JwtFilter doAnswer
  로 chain 통과 처리), TestSecurityConfig (filter 빈 override)
- 5 클래스 36 테스트: Agent/Contract/Ledger/Settle/User Controller
- happy path + validation 400 + 권한 403 + 인증 401

검증:
- ./gradlew clean build 성공
- 백엔드 단위테스트 94건 (common 33 + batch 19 + api 36 + 기타 6) 통과
- 프론트 tsc -b / vite build 통과

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 00:08:32 +09:00
GA Pro a314a95ecf feat: 엑셀 업로드 템플릿 시스템 (V19)
Agent Teams 3명 병렬 작업 (dba / api / frontend) 결과물.

DB (V19__업로드템플릿.sql):
- upload_template / upload_template_column / upload_history 3 테이블
- 인덱스 5종 (category / company_code / template_id / started_at)
- SYSTEM_UPLOAD_TEMPLATE 메뉴 + READ/CREATE/UPDATE/DELETE 권한
- 모든 역할에 권한 부여 (MANAGER 는 READ 만)

Backend:
- ga-core: VO 7개 (Template/Column/History의 VO/Resp/SaveReq/SearchParam) +
  Mapper 3개 + XML 3개 (UploadTemplate/Column/History)
- ga-api: TransformEngine (12 변환 규칙: TRIM/UPPER/LOWER/DATE/DIVIDE/MULTIPLY/
  LOOKUP/CODE_MAP/FIXED/REPLACE/SUBSTRING/CONCAT/DEFAULT) +
  LookupCache (O(1) HashMap 캐시) + UploadService (processUpload/preview) +
  LookupMapper / DynamicInsertMapper (whitelist 기반 동적 SQL)
- ga-api Controller 2개:
  · UploadTemplateController: /api/upload-templates CRUD + columns + history
  · UploadController: POST /api/upload/{templateCode}, /preview

Frontend:
- api/uploadTemplate.ts (10 endpoints)
- pages/system/UploadTemplateManager.tsx — 좌(템플릿 목록) 우(컬럼 매핑 편집기)
  + ModalForm 등록/수정 + 미리보기 Modal + 이력 Drawer
- components/common/TemplateUpload.tsx — 범용 컴포넌트 (Select 템플릿 + Dragger
  + 진행률 + 결과 Modal + 에러 파일 다운로드)
- App.tsx 라우트 추가, MenuIcon.tsx 매핑 추가

검증:
- ./gradlew :ga-api:bootJar 통과
- Flyway V19 운영 DB 적용 성공 (200ms)
- ga-api 부팅 7.8s, /api/upload-templates 200 응답
- 메뉴 트리에 SYSTEM_UPLOAD_TEMPLATE 노출 확인
- 프론트 tsc -b / vite build 통과

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 23:10:32 +09:00
GA Pro 4e008527b9 feat(frontend): 헤더 단순화 + 등록/수정 모달 도입
헤더 깨짐 수정 (MainLayout):
- logo 를 div 박스 대신 단순 img(/vite.svg) 로 (ProLayout 기본 슬롯 호환)
- avatarProps.render 의 chevron 제거 → ProLayout 기본 dom 만 Dropdown 트리거
- token.header 의 잘못된 키(colorBgRightActionsItemHover) 제거,
  heightLayoutHeader 56 으로 통일
- actionsRender 의 정산월 영역을 Space + 라벨 조합으로 정리

등록/수정 모달 (DrawerForm / ModalForm):
- AgentList: DrawerForm (680px) — 설계사명 / 사번 / 소속(Select) / 직급 /
  전화 / 이메일 / 주민번호(암호화) / 은행 / 계좌(암호화) / 입사일,
  수정 시 detail API 자동 fetch + initialValues 주입,
  액션 컬럼: 수정/퇴사 (Modal.confirm)
- ContractList: ModalForm (680px) — 증권번호 / 설계사(Select) / 상품(Select) /
  계약자 / 피보험자 / 보험료 / 납입주기 / 계약일 / 효력발생일
  toolBarRender 등록 버튼 추가
- ExceptionLedger: ModalForm (620px) — 설계사 / 정산월 / 예외코드 /
  금액 / 증권번호 / 보험사 / 내용
  toolBarRender 등록 버튼 추가, 예외코드 옵션은 ruleApi 에서 동적 로드

api/contract.ts: ContractSaveReq + create/update 추가

검증: tsc -b 통과 / dev 서버 HMR 정상 반영

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 22:43:57 +09:00
GA Pro f176b9702c feat(frontend): 누락된 메뉴 14개 페이지 일괄 구현
신규 페이지 (모두 ProTable / ProCard 패턴):
- org/OrgTree: 조직 트리 + 선택 시 우측에 소속 설계사 ProTable
- product/CompanyList: 보험사 목록
- product/ProductList: 상품 목록 (보험종 필터)
- rule/CommissionRateList: 수수료율 (보험사 통보)
- rule/PayoutRuleList: 지급율 (직급 × 보험종 × 회차)
- rule/OverrideRuleList: 오버라이드 규정 (직급 페어)
- rule/ChargebackRuleList: 환수 규정 (실효 월수 구간)
- rule/ExceptionCodeList: 예외 코드 마스터
- ledger/MaintainLedger: 유지수수료 원장
- receive/ReceiveData: 보험사 raw 수신 데이터
- receive/ReceiveMapping: 보험사 프로파일 + 필드 매핑 규칙
- system/MenuManage: 메뉴 트리 표시 (Tree)
- system/SystemConfig: 키-값 설정 (그룹별 필터)
- system/SystemLog: 로그인/API/변경 이력 3 탭

신규 API 모듈:
- api/org.ts (조직 트리)
- api/company.ts, api/product.ts
- api/rule.ts (5종 통합)
- api/receive.ts (profile/field/raw/error)
- api/config.ts, api/log.ts

App.tsx: 14 라우트 추가 (org/tree, companies, products, rules/*,
receive/*, ledger/maintain, system/menus, system/config, system/logs)

검증:
- tsc -b 통과
- 12개 백엔드 엔드포인트 200 OK 확인
- dev 서버 HMR 자동 반영

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 22:36:51 +09:00