GA Pro
e407263370
fix: 회계분개 멱등성 — 동일 정산월 재실행 시 분개 중복 INSERT 방지 (V87)
...
AccountingEntryGenerateStep(Step8b)이 selectBySettleMonth 결과를 무조건 insert 하여
동일 정산월 재정산 시 분개가 누적 중복되던 버그. payment_id 가 항상 NULL(원장 기반)이라
기존 주석의 existsByPaymentId 중복방어는 불가능했음.
- V87: contract_accounting_entry.settle_month 컬럼 추가 + 기존데이터 백필(description 6자리) + 미전기 부분 인덱스
- core: VO settleMonth 필드, Mapper deleteUnpostedBySettleMonth, insertBatch/selectBySettleMonth 에 settle_month 반영
- batch: 재생성 전 deleteUnpostedBySettleMonth 호출(마감 채번분 journal_no IS NOT NULL 보존)
검증: ga-core/ga-batch/ga-api compileJava SUCCESS, Flyway v87 적용(백필 433건 NULL 0),
202605 정산 2회 실행 → 193건 유지(중복 0, 수정 전이라면 386). 멱등성 PASS. 테스트데이터 롤백 완료.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-05-29 22:58:49 +09:00
GA Pro
a5ae95e34c
docs: HANDOFF §3-16 계약 승계(V86) 추가 + 재개 절차 갱신(v86/ga-batch 트리거)
...
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-05-29 22:16:17 +09:00
GA Pro
4dbc688f79
fix: AgentDeductionMapper.updateStatusBatch XML 구문 누락 보강
...
AggregateStep(Step8) 이 차감 APPLIED 일괄 전이로 호출하는 updateStatusBatch 가
인터페이스에만 선언되고 XML 구문이 없어, PENDING 차감이 있는 정산월 집계 시
'Invalid bound statement (not found)' 로 aggregate 전체가 FAILED 되던 잠복 버그.
updateStatus 동일 패턴 + foreach IN 으로 구현. (계약승계 e2e 중 발견, 승계와 무관)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-05-29 21:44:34 +09:00
GA Pro
bd5ff4ec14
feat: 계약 승계(contract succession) — 유지수수료 귀속 후임 전환 (V86)
...
설계사 해촉/이관 시 보험계약의 유지수수료 귀속을 승계월 기준 후임 설계사로 전환.
모집수수료는 원 모집설계사 귀속 유지(고아계약 승계 표준).
- DB V86: contract_succession 테이블 + 인덱스 + 메뉴/권한(GRP_PRD) + 공통코드 2그룹 + 테스트데이터 1건
- core: ContractSuccession VO/Resp/SaveReq/SearchParam + Mapper(.java/.xml)
selectEffectiveSuccessions(settleMonth): 계약별 최근 ACTIVE 승계 1건 (DISTINCT ON)
- api: ContractSuccessionService/Controller (/api/contract-successions, CRUD+cancel)
- batch: CalcMaintainStep 이 effective 승계 사전로드(N+1 회피) 후 effectiveAgentId 결정,
CommissionCalculator.calcMaintainLedger 오버로드로 후임 등급 payout + ledger agent_id 후임 기록.
AggregateStep 은 ledger agent_id 집계라 무변경.
- frontend: api/succession.ts + ContractSuccessions.tsx + App.tsx 라우트
검증: 5모듈 compileJava SUCCESS / ga-frontend tsc 0 / Flyway v86 적용 /
API CRUD+cancel+from==to 가드(E411) 라이브 PASS / resolver 쿼리 라이브 검증(계약1→후임 agent2).
배치 풀잡 e2e 는 정산월 원장 재생성(파괴적)이라 미실행.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-05-29 21:28:00 +09:00
GA Pro
d8d64625a9
feat: P6 후속 4 — 출금 폼 잔여 한도 미리 표시
...
- 백엔드 GET /api/mobile/me/settle-masters/{id}/withdrawable-balance
· 응답 {settleId, netAmount, usedAmount, remainingAmount}
· 본인 settle_master 검증 후 net - sumActiveAmountByMaster 반환
· createWithdrawRequest 가 동일 조회 로직 재사용 (중복 제거)
- PWA WithdrawCreate: settleMaster 선택 시 잔액 카드 표시 + amount 클라이언트 사전 검증
검증: ga-api compileJava BUILD SUCCESSFUL / ga-mobile-pwa tsc --noEmit 0 오류
(라이브 e2e 는 DB/docker 미가동으로 차단 — 환경 복구 후 스모크 예정)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-05-29 20:52:17 +09:00
GA Pro
366f49c3f0
feat: P6 후속 3 — 출금 잔여한도 검증 + 알림 모두읽음 + HANDOFF 갱신
...
출금 잔여 한도 검증:
- WithdrawRequestMapper.sumActiveAmountByMaster(settleMasterId) 추가
· CANCELLED 외 모든 활성 출금의 amount SUM (COALESCE 0)
- MobileMeService.createWithdrawRequest 에 잔여 한도 가드 추가
· 1) settle_master 본인 소유 확인 (FORBIDDEN)
· 2) 잔여 = net_amount - 활성 출금합계
· 3) 요청 amount > 잔여 시 INVALID_PARAMETER(E411) 던짐
· 메시지에 잔여 금액 명시 ("출금 가능 잔액(N)을 초과합니다")
PWA 알림 모두읽음:
- POST /api/mobile/me/notifications/read-all (기존 UserNotificationMapper.markAllRead 재사용)
- NoticeList 내알림 탭 헤더에 "모두 읽음 (N)" 버튼 (안읽음 카운트 표시)
- 성공 시 invalidate notifications + summary 쿼리
검증:
- ga-api compileJava + ga-mobile-pwa tsc PASS
- e2e (agent01 / userId=4 / agentId=1):
· settle#51 net=35,079원, 기존 사용 5,000원
· amount=999,999 → E411 "출금 가능 잔액(30079.00)을 초과합니다"
· amount=100 → success, requestId=5
· markAllRead → 200, summary.unread=0
- 이전 e2e 검증 (총 9건) 모두 PASS
HANDOFF.md §3-15 갱신 (2026-05-27 P6 후속 전체 정리 + agent01 테스트 계정 명시).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-28 00:00:17 +09:00
GA Pro
dfce9e5c02
feat: P6 후속 2 — PWA 본인 프로필/출금취소 + SETTLED/FAILED 자동 알림
...
PWA 본인 프로필:
- Profile.tsx 신규 (phone 자기수정 Dialog + 비밀번호 변경 + 로그아웃)
- TabBar 에 "내정보" 탭 추가 (총 5탭)
- 백엔드 PUT /api/mobile/me/profile/phone (MobileMeService.updateMyPhone, 토큰에서 userId 강제)
- 비밀번호 변경은 기존 /api/auth/password 재사용
PWA 출금 신청 취소:
- 백엔드 POST /api/mobile/me/withdraw-requests/{id}/cancel
· 본인 agentId 검증 후 기존 WithdrawRequestService.cancel 호출
· REQUESTED 상태에서만 가능 (기존 검증 재사용)
- WithdrawList 행을 SwipeAction 으로 감싸 "취소" 액션 노출
· REQUESTED 상태 행만 SwipeAction 활성
출금 SETTLED/FAILED 본인 알림 자동 발행:
- WithdrawBankSettleService 가 SETTLED/FAILED 전이 시 user_notification INSERT
- 신청자(requestedBy) 에게 RefType=WITHDRAW, refId=requestId 로 발행
- 알림 발행 실패해도 동기화 흐름 비차단 (warn 로그만)
- PWA NoticeList 의 "내 알림" 탭에서 즉시 확인 가능
검증:
- ga-api compileJava + ga-frontend/ga-mobile-pwa tsc PASS
- PUT /api/mobile/me/profile/phone (admin) → 200, GET /api/auth/me 의 phone 변경 확인
- POST /api/mobile/me/withdraw-requests/1/cancel (admin) → E403 (agentId null 보안 강제)
- POST /api/internal/bank-settle → 200 data=0 (이번엔 ACCEPTED 잔여 없음, 알림 발행 경로 코드상 검증)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-27 23:18:39 +09:00
GA Pro
2c9bf710bc
feat: P6 후속 — PWA 출금폼/명세상세/토큰refresh + 펌뱅킹 SETTLED 동기화 + user phone UI
...
외부 SDK 차단 항목 외 P6 잔여 운영성 작업을 일괄 완료. DB 변경 없음(v85 유지).
PWA:
- 출금 신청 작성 폼 (WithdrawCreate.tsx + POST /api/mobile/me/withdraw-requests + GET /settle-masters)
· 클라이언트가 보낸 agentId/userId 무시, 토큰에서 강제 결정
- 명세서 상세 + 엑셀 다운로드 (StatementDetail.tsx + GET /api/mobile/me/statements/{id}[/download])
· 본인 agentId 검증 후 기존 CommissionStatementService.download() 재사용
- 토큰 자동 refresh (request.ts interceptor + authStore.refreshToken)
· 401 시 단일 refresh 호출로 합치고 broadcast, login/refresh 자체 401 은 무한루프 차단
펌뱅킹 SETTLED 동기화:
- WithdrawBankSettleService + POST /api/internal/bank-settle (BankSettleController)
- Mapper: selectAcceptedTransfers / markSettled / markSettleFailed
- 어댑터 queryStatus 폴링 결과로 SETTLED→COMPLETED, FAILED→APPROVED(재시도풀) 전이
- app.bank-settle.cron 옵션 (기본 비활성)
사용자 phone 등록 UI:
- PUT /api/system/users/{id}/phone — NotBlank 검증 없는 단일 패치 endpoint
- UserList 에 phone 컬럼 + "전화번호" 액션 → Antd Modal 인라인 편집
- 결재 SMS 발신 전제 충족
검증 (9/9 PASS, 라이브):
- ga-common/ga-core/ga-external-adapter/ga-api compileJava BUILD SUCCESSFUL
- ga-frontend / ga-mobile-pwa tsc --noEmit PASS
- POST /api/internal/bank-settle → data=3 (3건 COMPLETED 전이 확인)
- PUT /api/system/users/1/phone → 200, 이후 GET 으로 phone 노출 확인
- 보안 강제: admin(agentId=null)으로 /api/mobile/me/{statements,settle-masters,withdraw-requests} → E403
- POST /api/auth/refresh → 200, 새 accessToken 발급
- 3개 서비스 라이브: ga-api :8082 / ga-frontend :3000 / ga-mobile-pwa :3001
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-27 22:53:59 +09:00
GA Pro
ee3e0d40c5
feat: P6 모바일 PWA 보안 강화 — /api/mobile/me/* 서버측 본인 필터
...
스캐폴드의 클라이언트 agentId 쿼리 필터(변조 가능)를
서버측 강제 필터로 교체. 토큰 → user → agentId 자동 추출.
백엔드 (ga-api):
- MobileMeService — 클라이언트 param 의 agentId/userId 는 무시·덮어쓰기.
agentId 미연결 시 BizException(FORBIDDEN). PageHelper 로 정확한 total 산출.
- MobileMeController — GET /api/mobile/me/{summary,statements,
withdraw-requests,notifications} + POST /notifications/{id}/read.
별도 메뉴 권한 없이 인증만 통과 (PWA 사용자 전체 대상).
ga-mobile-pwa:
- api/statement.ts, api/withdraw.ts → /api/mobile/me/* 호출, agentId 제거
- api/notification.ts 신규 — list/markRead/summary
- Home.tsx — summary() 단일 호출로 3카운트 + 안 읽음 Badge
- NoticeList.tsx — Tabs(내 알림 / 공지). 알림 클릭 markRead + summary 무효화
- Statement/WithdrawList — E403(설계사 미연결) 시 ErrorBlock 안내
라이브 검증:
- ga-api 컴파일 BUILD SUCCESSFUL · 재기동 OK
- PWA tsc PASS · vite build PASS (precache 538KB, gzip 176KB)
- admin(agentId=null): /summary → 200 OK 0/0/0,
/statements → E403 차단 정상, /notifications → 200 OK total=0
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-24 23:32:19 +09:00
GA Pro
23fdd8474b
feat: P6 모바일 셀프 조회 PWA 스캐폴드 (ga-mobile-pwa)
...
설계사 본인 정산명세서/출금/공지를 모바일에서 조회하는 PWA 신규 모듈.
데스크탑 admin UI(ga-frontend)와 별도. 백엔드 무변경 — 기존 ga-api(8082)
재사용. 토큰 키도 mobile.accessToken 으로 분리.
스택:
- Vite + React 18 + TS + antd-mobile@5
- vite-plugin-pwa (manifest + service worker autoUpdate)
- React Query + Zustand (persist) + react-router-dom
- 포트 3001, /api → 8082 dev 프록시
화면 5종 (NavBar + List + PullToRefresh + TabBar):
- /login — POST /api/auth/login + GET /api/auth/me
- / — 홈 (요약 카드 + 메뉴, 로그아웃)
- /statement — GET /api/statements?agentId=… (본인 명세서)
- /withdraw — GET /api/withdraw-requests?agentId=… (본인 출금이력)
- /notice — GET /api/notices/active
PWA:
- manifest: name/icon/theme/standalone, ko, /
- /api/** NetworkFirst 5s 타임아웃 / 5분 캐시 (오프라인 시 직전 응답)
- 아이콘은 SVG placeholder (192/512) — 본 배포 시 PNG 권장
검증:
- npm install 407 packages
- tsc --noEmit PASS
- npm run build PASS — manifest.webmanifest + sw.js + workbox-*.js
자동 생성, precache 8 entries 528KB, 번들 gzip 173KB
- vite dev :3001 LISTENING + ga-api :8082 정상
- /api/statements total=112, /api/withdraw-requests total=3,
/api/notices/active 0건, /api/auth/me 정상
잔여 (스캐폴드 이후):
- 백엔드 /api/mobile/me/* 전용 endpoint (서버측 본인 필터 강제)
- 출금 신청 작성 폼, 명세서 상세, 본인 알림(user_notification)
- 토큰 만료 자동 refresh, 푸시 알림 (FCM)
- 실 아이콘 PNG, manualChunks 분리
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-24 23:22:18 +09:00
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