Files
GA Pro bfc724669b feat: incar 갭 반영 수수료/운영 14개 도메인 풀스택 + 배치통합 + 신입교육자료
incar CMS(116메뉴) 벤치마킹 갭분석으로 ga-pro에 없던 14개 도메인을 풀스택 추가.

P7 수수료 계산 7종 (V88~V96):
- 수입수수료+수지차, 소개·이관수수료, 정착지원금, 인정실적+환산율,
  시상, 생보운영지원수수료, 지점장수당
- 각 rule/ledger + 공식(보험료×요율, 수입−지급 등) Service 내장

P8 운영/정산 7종 (V97~V105):
- 단계마감, 본사정산, 등급평가, 공동계약, 보증보험, 적립금, 수수료시뮬레이터
- close/reopen/apply/simulate/upsert 등 액션 + 손익·잔액·등급 산정 로직

배치 통합 (V106):
- settle_master.other_commission_total 컬럼 추가(DEFAULT 0, 백필)
- 설계사 지급성 9종 원장 aggregateByAgent → AggregateStep gross 합산
- 빈 원장 0 → 기존 정산결과·무결성 불변(비파괴적)

테스트: P7/P8 Service 공식 단위테스트 21건(ga-api:test 57건 전체 통과)
프론트: 화면 14개 + React.lazy 코드 스플리팅(단일 4MB → 130+ 청크)
문서: DOMAIN_GAP_P7/P8.md, 신입교육_보험과수수료_완전기초.md, DOMAIN_KNOWLEDGE/HANDOFF 갱신

검증: 전체 ./gradlew build(test 포함) SUCCESSFUL, Flyway V88~V106 success,
GET+액션POST smoke 5xx 0건, 9개 집계쿼리 SQL 유효성 확인, 공식 런타임 실측.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 15:45:10 +09:00

576 lines
38 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.
# Handoff Note — 최신 갱신 2026-05-29 (계약 승계 V86 §3-16) / Round 2 기준 2026-05-14
다음 세션에서 이어가기 위한 핸드오프 문서. Agent Teams 기반 자동 체인으로 진행 중인 작업의 현재 상태와 잔여 작업, 재개 절차를 기록한다.
## 1. 핸드오프 시점 상태
- **마지막 커밋**: P1-3-c (ChargebackCalculator + ChargebackGradeService + Controller)
- **빌드 상태**: `./gradlew :ga-common:compileJava :ga-core:compileJava :ga-api:compileJava` 모두 BUILD SUCCESSFUL
- **이번 세션 누적 커밋 수**: 26개 (Agent Teams 설정 1 + 코드 품질 7 + 도메인 P0 9 + 도메인 P1 11)
- **변경 사항 없음** (working tree clean)
## 2. 완료된 작업
### 2-1. 코드 품질 자동 체인 (7 커밋)
초기 ga-api 5명 리뷰 결과를 바탕으로 P0 이슈 일괄 해결.
| 단계 | 커밋 | 내용 |
|---|---|---|
| 1 | `5e58a54` | OrganizationSaveReq + 상태 Enum 4종 (Agent/Contract/Settle/Approve) |
| 2 | `a8f0b6e` | Controller→Service 분리 5개 + 매직 스트링 Enum 교체 + @DataChangeLog 17곳 |
| 3a | `693275e` | UserStatus + ExceptionLedgerStatus Enum |
| 3b | `af3c6b9` | Map→SaveReq DTO 4종 + 입력 검증 + 잔여 Enum 적용 |
| 4 | `498d0d4` | LookupCache 동시성 + UploadService/TransferFile 트랜잭션 분해 + readOnly 일괄 |
| 5a | `4b211ec` | AgentOrgHistoryResp + MapStruct mapper 3종 + AgentMapper.xml 조인 |
| 5b | `b16e678` | MapStruct 적용 + Resp 적용 + PaymentService/UploadTemplateService 신설 + PageHelper 통일 |
### 2-2. 도메인 P0 — 세무·공제·명세서 (9 커밋)
| 도메인 | a (DB) | b (core) | c (api) |
|---|---|---|---|
| P0-1 세무 | `ad5d62e` V23 | `92f3217` | `f8c7d84` TaxCalculator |
| P0-2 공제 | `0e73eb6` V24 | `a3ba7fa` | `b8f33f1` DeductionService |
| P0-3 명세서 | `930335c` V25 | `4f5a2f0` | `f5efcaa` ExcelStatementGenerator |
핵심 산출물:
- 표준 세율 system_config 외부화 (3.3%/8.8%/10%/10%)
- `agent`에 tax_type/business_no/vat_type 컬럼
- `payment`에 income_tax_amount/local_tax_amount/vat_amount/net_amount
- `agent_deduction` (월별 차감 마스터) + `payment_deduction_detail` (이체 명세)
- `commission_statement` (명세서 발급 마스터, agent+settle_month+statement_type UNIQUE)
- TaxCalculator pure 도메인 + ExcelStatementGenerator (PDF는 향후)
### 2-3. 도메인 P1 — 1200%룰·분급·차등환수 (11 커밋)
| 도메인 | a (DB) | b (core) | c (api) |
|---|---|---|---|
| P1-1 1200%룰 | `6a6ba9f` V26 | `1109253` | `bba4a33` RegulatoryLimitChecker |
| P1-2 분급 | `434e778` V27 | `5029bc5` | (P1-2-c 커밋) InstallmentPlanGenerator |
| P1-3 차등환수 | `cc5d0e5` V28 | `44dbbf3` | (P1-3-c 커밋) ChargebackCalculator |
**P1 보강 (병렬 트랙)**:
- `1aa31de` RecruitLedger/MaintainLedger sumByContract 메서드 추가
- `f6142a1` RegulatoryLimitChecker TODO 해소 (실제 누적값 사용)
핵심 산출물:
- `regulatory_limit` 마스터 (1200%/35%/7년 한도, effective_from/to 이력 추적)
- `installment_ratio` + `installment_plan` (분급 7년 비율 35/25/15/10/7/5/3)
- `chargeback_grade` (5단계: 1~12개월 100% → 85개월~ 0%)
- RegulatoryLimitChecker / InstallmentPlanGenerator / ChargebackCalculator pure 도메인
### 2-4. 병렬화 적용 (P1 후반부)
초반 직렬 a→b→c 패턴에서 후반에 도메인 간 sub-step 병렬로 전환.
- P1-2-c(api) + P1-3-a(dba) + P1 보강(core) 3명 동시 활성화
- P1-3-b(core) + P1-1-c TODO 교체(api) 2명 동시
- 모듈이 다른 사람끼리 묶어 머지 충돌 없음
## 3. Round 2 완료 사항 (2026-05-14)
### 3-1. P2 — 8 도메인 (V29~V36, ~50 VO·Mapper, 18 Service+Controller)
| # | 도메인 | 마이그레이션 | 상태 |
|---|---|---|---|
| P2-1 | 마감 (Period Close) | V29 | 완료 |
| P2-2 | 정정 (Correction) | V30 | 완료 |
| P2-3 | 이의신청 (Dispute) | V31 | 완료 |
| P2-4 | 보류사유 (Hold Reasons) | V32 | 완료 |
| P2-5 | 시책·인센티브 | V33 | 완료 |
| P2-6 | 해촉정산 (Termination) | V34 | 완료 |
| P2-7 | 세금계산서 (Tax Invoice) | V35 | 완료 |
| P2-8 | 외부회신 | V36 | 완료 |
화면: ga-frontend Wave 4 에서 P4-B 화면과 함께 작성됨.
### 3-2. P3 — KPI 대시보드 (V37~V39)
- dba: mv_monthly_summary / mv_org_summary / mv_retention_rate / mv_cumulative (V37)
- dba: 리포트 메뉴 + KPI 메뉴 INSERT (V38, V39)
- core: KpiMapper.java + XML
- api: KpiService + KpiController (`/api/kpi/*`)
- frontend: KpiMonthlySummary / KpiOrgSummary / KpiRetention / KpiCumulative (4개 화면)
### 3-3. P4-A — 수수료 종류 보강 (V40~V44, 5 도메인)
| # | 도메인 | 마이그레이션 | 상태 |
|---|---|---|---|
| P4-A-1 | commission_type 코드 + commission_master 통합 | V40 | 완료 |
| P4-A-2 | 수금수수료 (collection_commission_rule/ledger) | V41 | 완료 |
| P4-A-3 | 갱신·부활수수료 (renewal/reinstatement) | V42 | 완료 |
| P4-A-4 | 유지보수수당 (persistency_bonus_rule/bonus) | V43 | 완료 |
| P4-A-5 | 오버라이드 원장 (override_ledger/summary) | V44 | 완료 |
### 3-4. P4-B — 운영 필수 9 도메인 (V45~V53)
| # | 도메인 | 마이그레이션 | 상태 |
|---|---|---|---|
| P4-B-1 | 위촉계약 (agent_contract) | V45 | 완료 |
| P4-B-2 | 자격관리 (agent_license) | V46 | 완료 |
| P4-B-3 | 보수교육 (agent_training) | V47 | 완료 |
| P4-B-4 | 계약변경 (contract_endorsement) | V48 | 완료 |
| P4-B-5 | 민원관리 (complaint) | V49 | 완료 |
| P4-B-6 | 결재워크플로우 (approval_line/request) | V50 | 완료 |
| P4-B-7 | 공지·알림 (notice/user_notification) | V51 | 완료 |
| P4-B-8 | 첨부파일 (attachment) | V52 | 완료 |
| P4-B-9 | 출금신청 (withdraw_request) | V53 | 완료 |
### 3-5. V54~V55 + 프론트
- V54: P4 메뉴 INSERT (P4-A + P4-B 14개 메뉴)
- V55: P4 공통코드 추가 (approval_type, complaint_type, license_type, withdraw_status 등)
- 프론트: ErrorBoundary 전역 적용 + 토스 디자인 시스템 토큰 (`RADIUS`, `GRAY`, `SHADOW`) 일관 적용
- 프론트 화면 추가: AgentContracts / AgentLicenses / AgentTrainings / Complaints / ContractEndorsements / CollectionCommission / CommissionMaster / OverrideLedger / PersistencyBonus / ReinstatementCommission / RenewalCommission / WithdrawRequest / Approvals / Notices (14개)
### 3-6. P1 정산 통합 (batch-engineer 완료)
- ga-batch 8 Step에 TaxCalculator / DeductionService / RegulatoryLimitChecker / InstallmentPlanGenerator / ChargebackCalculator 통합 완료
## 3-7. P5 Wave 1 — agent + contract 회계 진입점 (V63~V66)
| 항목 | 마이그레이션 | 상태 |
|---|---|---|
| agent_annual_income 테이블 | V63 | 완료 |
| contract_accounting_entry 테이블 | V64 | 완료 |
| P5-W1 테스트 데이터 + 메뉴 INSERT (ANNUAL_INCOME / ACCOUNTING_JOURNAL) | V65 | 완료 |
| account_code 마스터 + 4건 초기 데이터 | V66 | 완료 |
| rule 감사 컬럼 보강 (commission_rate/payout_rule/override_rule 등) | V70 | 완료 |
| payment 세무 컬럼 보강 (income_tax_amount/local_tax_amount/vat_amount/net_amount) | V71 | 완료 |
핵심 산출물:
- `agent_annual_income` (agentId+settleYear 복합PK, 연도별 사업소득 집계)
- `contract_accounting_entry` (분개 엔트리, debit/credit 계정코드 + journalNo 마감)
- `account_code` 마스터 (account_type DEBIT/CREDIT/BOTH 구분, 초기 4건: 8350/2530/1130/4110)
- `AgentAnnualIncomeService` + `AgentAnnualIncomeController` (`/api/agent-annual-incomes`)
- `ContractAccountingService` + `ContractAccountingController` (`/api/accounting-entries`)
- `AccountCodeService` + `AccountCodeController` (`/api/common/account-codes`)
- `YearEndIncomeAggregateStep` (Step 10, 12월 마감 시만 실행, settleMonth.endsWith("12") 조건)
- `AccountingEntryGenerateStep` (Step 9, 매월 정산 후 분개 생성, ledger UNION 기반 contract_id 확보, journal_no=NULL 미전기)
- 프론트 화면: `AgentAnnualIncomeList` (`/commission/annual-income`) + `AccountingJournalList` (`/commission/accounting-journal`)
통합 검증 결과 (2026-05-15):
- Flyway: V63/V64/V65/V66/V70/V71 적용 확인 (현재 ga schema V71)
- GET /api/agent-annual-incomes → 200 OK
- POST /api/agent-annual-incomes/regenerate?year=2025 → 200 OK, affected=0 (payment 데이터 없음, 정상)
- GET /api/accounting-entries → 200 OK
- GET /api/common/account-codes?accountType=DEBIT → 200 OK, 2 items
보정 사항 (통합 검증 중 발견):
- App.tsx 라우트와 V65 menu_path 모두 `/commission/annual-income`, `/commission/accounting-journal`로 일치
- ANNUAL_INCOME EXECUTE 권한 누락 → DB 직접 INSERT로 보정
- payment 세무 컬럼 미적용 (V23 체크섬 충돌 이력) → V71로 idempotent 보강
운영 DB 적용: ga-api 재시작 → Flyway V18~V71 일괄 자동 적용.
## 3-8. P5 Wave 2 — 원천세/부가세 분기신고 (V67~V69)
| 항목 | 마이그레이션 | 상태 |
|---|---|---|
| withholding_tax_report 테이블 (원천세 분기신고) | V67 | 완료 |
| vat_report 테이블 (부가세 분기신고) | V68 | 완료 |
| P5-W2 테스트 데이터 + 메뉴 INSERT (WITHHOLDING_TAX / VAT_REPORT) | V69 | 완료 |
| EXECUTE 권한 보강 (WITHHOLDING_TAX / VAT_REPORT) | V73 | 완료 |
핵심 산출물:
- `withholding_tax_report` (분기별 원천세 신고 집계: settleQuarter/agentId/totalIncome/totalWithheld/totalLocalTax)
- `vat_report` (분기별 부가세 신고 집계: settleQuarter/totalSales/totalPurchase/totalVatPayable/taxInvoiceCount)
- `WithholdingTaxReportMapper` + `WithholdingTaxReportMapper.xml` (selectList/selectDetailById/upsertQuarterlyAggregate/updateFileStatusToFiled)
- `VatReportMapper` + `VatReportMapper.xml` (selectList/selectDetailById/upsertQuarterlyAggregate/updateFileStatusToFiled)
- `WithholdingTaxReportService` + `WithholdingTaxReportController` (`/api/withholding-tax-reports`)
- `VatReportService` + `VatReportController` (`/api/vat-reports`)
- `WithholdingTaxQuarterlyStep` (batch Step 11, 분기 마지막 월 실행)
- `VatReportQuarterlyStep` (batch Step 12, 분기 마지막 월 실행)
- 프론트 API 모듈: `ga-frontend/src/api/withholdingTax.ts` + `ga-frontend/src/api/vat.ts`
통합 검증 결과 (2026-05-17):
- Flyway: 운영 DB ga schema V73 (V67/V68/V69/V73 모두 적용 확인)
- GET /api/withholding-tax-reports → 200 OK, list 반환 (집계 데이터 있음)
- GET /api/withholding-tax-reports/1 → 200 OK, 단건 상세 반환
- POST /api/withholding-tax-reports/regenerate {"settleQuarter":"2025-Q4"} → 200 OK, affected=0 (이미 존재, 정상)
- PUT /api/withholding-tax-reports/complete {"ids":[1]} → 200 OK
- GET /api/vat-reports → 200 OK, list 반환
- GET /api/vat-reports/1 → 200 OK, 단건 상세 반환
- POST /api/vat-reports/regenerate {"settleQuarter":"2025-Q4"} → 200 OK, affected=1
- PUT /api/vat-reports/complete {"ids":[1]} → 200 OK
보정 사항 (통합 검증 중 발견):
- frontend build 실패: ChargebackGradeList/InstallmentRatioList/DeductionList validator 파라미터 implicit any, CommissionDispute/IncentiveProgram/TaxInvoiceList parser 반환타입 불일치 → 명시적 타입 어노테이션으로 수정 (6개 파일)
- complete 엔드포인트 요청 바디: `{"ids":[id]}` 형식 (단일 reportId 아님)
운영 DB 최신 상태: ga schema V73 적용 완료.
## 3-11. P6 PoC — 외부 연동 어댑터 모듈 (V81~V84, 2026-05-24 라이브 적용)
P6 본 작업의 PoC가 완료되어 어댑터 추상화 + Mock 구현 + SDK 분기 + 운영 잔여 기능까지 들어감.
실제 KFTC/Toast SDK 통합 시 어댑터 구현체만 바꾸면 ga-api/ga-common 무변경.
| 항목 | 마이그레이션 | 상태 |
|---|---|---|
| 분급 비율 회차(월) 단위 등록 지원 | V81 | 완료 |
| withdraw_request 펌뱅킹 추적 컬럼 (transfer_tx_id/transfer_status/transfer_at) | V82 | 완료 |
| WITHDRAW_REQUESTS EXECUTE 권한 보강 (오기 — 0건 적용) | V83 | 완료(no-op) |
| WITHDRAW 메뉴 EXECUTE 권한 (V83 보정본) | V84 | 완료 |
핵심 산출물:
- **신규 모듈 `ga-external-adapter`** — 외부 SDK 의존성 격리, settings.gradle 등록
- ga-common.adapter.bank: `BankTransferAdapter` 인터페이스 + Request/Response/Status
- ga-common.adapter.message: `MessageAdapter` 인터페이스 + Channel(SMS/KAKAO)/Request/Response
- `MockBankTransferAdapter` / `MockMessageAdapter` (로그 + 계좌·전화 마스킹, 기본 활성)
- `KftcBankTransferAdapter` / `ToastMessageAdapter` 스켈레톤 (UnsupportedOperationException, SDK 통합 시 구현)
- `@ConditionalOnProperty` 프로파일 분기: `app.adapter.bank=mock|kftc`, `app.adapter.message=mock|toast`
- `ApprovalService.handleApprovalCallback(WITHDRAW)` — 최종 승인 시 펌뱅킹 어댑터 호출 → 성공 시 APPROVED→SENT 전이 + transfer_tx_id 영속화, 실패 시 APPROVED 유지 + fail_reason 기록
- `ApprovalService.sendStepNotification` — DB 알림 외 SMS 어댑터 호출 (UserMapper.selectFirstActiveContactByRoleCode 로 실제 결재자 phone 매핑, phone 미확보 시 SMS skip)
- `WithdrawBankRetryService` + `BankRetryController` (`POST /api/internal/bank-retry`) — 실패 transfer 재시도 배치 + `@EnableScheduling` + cron 옵션(기본 비활성) + `app.bank-retry.limit`
- `WithdrawRequestMapper.selectFailedTransfers` / `updateTransferResult` 추가
- `WithdrawRequestVO/Resp` + `WithdrawRequestMapper.xml` + 화면 `WithdrawRequest.tsx` 에 transfer_tx_id/transfer_status/transfer_at 노출
설정값(application.yml):
```yaml
app:
adapter:
bank: ${ADAPTER_BANK:mock} # mock | kftc
message: ${ADAPTER_MESSAGE:mock} # mock | toast
bank-retry:
limit: ${BANK_RETRY_LIMIT:50}
cron: ${BANK_RETRY_CRON:0 0 0 1 1 ?} # 사실상 비활성. 운영 활성화 예 "0 */10 * * * *"
```
통합 검증 결과 (2026-05-24):
- 5모듈 컴파일 BUILD SUCCESSFUL (ga-common/ga-core/ga-external-adapter/ga-api/ga-batch)
- 운영 DB v82~v84 적용 완료, ga-api 8082 가동
- POST /api/auth/login → 200 OK, accessToken 발급
- GET /api/withdraw-requests → 200 OK, 2건 모두 status=SENT / transfer_status=ACCEPTED / transferTxId="MOCK-…" 영속화
- POST /api/internal/bank-retry → 200 OK, data=0 (실패 건 없음 — 정상)
- GET /api/approvals/requests/mine → 200 OK, WITHDRAW APPROVED 이력 정상
- GET /api/forecast-kpi → 200 OK
- GET /api/year-end-statements → 200 OK
보정 사항:
- V83 작성 시 menu_code 오기로 0건 적용 → V84 로 정정 보강
## 4. 잔여 작업 (P6 실연동)
P5 전체 + P6 PoC(어댑터 모듈 + Mock 구현 + SDK 분기 + 재시도 배치 + DB 추적 컬럼) 완료.
잔여는 **외부 스펙 확정 후 적용** 가능한 항목 + 모바일.
### P6 실연동
| 항목 | 설명 | 선행 조건 |
|---|---|---|
| KFTC 펌뱅킹 실 SDK 통합 | `KftcBankTransferAdapter` 본체 구현 + 인증·엔드포인트 주입 | KFTC API 키·계약·테스트망 |
| Toast(NHN) SMS 실 SDK 통합 | `ToastMessageAdapter` 본체 구현 | 계정·App Key·발신번호·템플릿 코드 |
| 카카오 알림톡 실 SDK 통합 | 동일 (채널만 KAKAO) | 비즈 채널·템플릿 승인 |
| 펌뱅킹 SETTLED 동기화 | ACCEPTED→SETTLED 폴링 스케줄 (queryStatus 사용) | 실 SDK 통합 이후 |
| 펌뱅킹/메시지 호출 감사 이력 | `external_call_log` 테이블 + 영속화 + 조회 화면 | 독립 진행 가능 |
| 모바일 셀프 조회 PWA | 설계사 전용. 정산 명세서/출금 신청/공지 등 | 화면 우선순위 협의 |
## 3-12. P6 PoC — 외부연동 호출 감사 이력 (V85, 2026-05-24 라이브 적용)
P6 PoC 의 운영성 보강. 펌뱅킹/SMS·카카오 어댑터 모든 호출이 `external_call_log` 테이블에 AOP 로 자동 영속화. 외부 SDK 통합 후에도 그대로 재사용.
| 항목 | 위치 | 상태 |
|---|---|---|
| external_call_log 테이블 + 인덱스 + SYSTEM_EXTERNAL_CALL 메뉴/권한 | V85 | 완료 |
| ExternalCallLogVO / Resp / SearchParam | ga-core | 완료 |
| ExternalCallLogMapper(.java/.xml) — insertOne + selectList + selectById | ga-core | 완료 |
| ExternalCallLogService — recordCall @Transactional(REQUIRES_NEW) | ga-api | 완료 |
| ExternalCallLogController — GET /api/external-call-logs[/{id}] | ga-api | 완료 |
| ExternalCallLoggingAspect — BankTransferAdapter+/MessageAdapter+ 모든 메서드 @Around | ga-api/aop | 완료 |
| ExternalCallLogList.tsx + api/externalCallLog.ts + App.tsx 라우트 | ga-frontend | 완료 |
핵심 동작:
- 어댑터 호출 전/후·예외 모두 `external_call_log` INSERT (호출자 트랜잭션과 분리 — REQUIRES_NEW)
- request/response 는 PII 마스킹된 JSON 한 줄로 요약 (계좌·전화 뒤 4자리, 이름 첫글자만)
- 영속화 자체가 실패해도 비즈니스 흐름은 절대 깨지 않음 (warn 로그만)
- `target_ref_type/id` 자동 추출: WITHDRAW(BankTransferRequest.withdrawRequestId), MessageRequest.refType/refId
통합 검증 결과 (2026-05-24):
- Flyway: V85 자동 적용 → 운영 DB schema **v85**
- 5모듈 컴파일 BUILD SUCCESSFUL + ga-frontend TS 타입 검증 통과
- 라이브 시나리오: 신규 withdraw#3 → 결재 1단계 + 2단계 APPROVE → 최종 승인 → 펌뱅킹 호출
- withdraw#3 status=SENT, transferTxId=MOCK-…, transferStatus=ACCEPTED
- GET /api/external-call-logs → total=1, log#1: BANK/MockBankTransferAdapter/requestTransfer/success=true/durMs=3/target=WITHDRAW#3
- 상세: requestSummary 의 accountNoMasked="****0123" — PII 마스킹 정상 (평문 비노출)
## 4. 잔여 작업 (P6 실연동)
P5 전체 + P6 PoC(어댑터 모듈 + Mock 구현 + SDK 분기 + 재시도 배치 + DB 추적 컬럼 + **호출 감사 이력**) 완료.
잔여는 **외부 스펙 확정 후 적용** 가능한 항목 + 모바일.
### P6 실연동
| 항목 | 설명 | 선행 조건 |
|---|---|---|
| KFTC 펌뱅킹 실 SDK 통합 | `KftcBankTransferAdapter` 본체 구현 + 인증·엔드포인트 주입 | KFTC API 키·계약·테스트망 |
| Toast(NHN) SMS 실 SDK 통합 | `ToastMessageAdapter` 본체 구현 | 계정·App Key·발신번호·템플릿 코드 |
| 카카오 알림톡 실 SDK 통합 | 동일 (채널만 KAKAO) | 비즈 채널·템플릿 승인 |
| 펌뱅킹 SETTLED 동기화 | ACCEPTED→SETTLED 폴링 스케줄 (queryStatus 사용) | 실 SDK 통합 이후 |
| 모바일 셀프 조회 PWA | 설계사 전용. 정산 명세서/출금 신청/공지 등 | 화면 우선순위 협의 |
## 3-13. P6 — 모바일 셀프 조회 PWA 스캐폴드 (ga-mobile-pwa, 2026-05-24)
설계사 본인 정산명세서·출금·공지를 모바일에서 조회하는 PWA 신규 모듈. 데스크탑 admin UI(`ga-frontend`)와 별도. **백엔드 무변경** — 기존 `ga-api`(8082) 그대로 재사용.
### 구성
| 항목 | 위치 | 비고 |
|---|---|---|
| 신규 모듈 | `ga-mobile-pwa/` | Vite + React 18 + TS + antd-mobile@5 |
| PWA 인프라 | `vite-plugin-pwa` | manifest + service worker autoUpdate, `/api/**` NetworkFirst(5s/5min) |
| 인증 | `src/stores/authStore.ts` (zustand persist) | 토큰 키: `mobile.accessToken` (`ga-frontend` 와 분리) |
| API 클라이언트 | `src/api/{request,auth,statement,withdraw,notice}.ts` | axios + 401 자동 리다이렉트 |
| 화면 5종 | `src/pages/{Login,Home,StatementList,WithdrawList,NoticeList}.tsx` | NavBar + List/Card + PullToRefresh + TabBar |
| 라우팅 | `src/App.tsx` + `RequireAuth` 가드 + `MobileTabBar` | `/login` 외 모두 보호 |
### 화면 ↔ 백엔드 API
| 경로 | 백엔드 |
|---|---|
| `/login` | POST `/api/auth/login` + GET `/api/auth/me` |
| `/` (홈) | 세 도메인 카운트 조회 |
| `/statement` | GET `/api/statements?agentId={me.agentId}` |
| `/withdraw` | GET `/api/withdraw-requests?agentId={me.agentId}` |
| `/notice` | GET `/api/notices/active` |
본인 데이터 필터: 클라이언트에서 `profile.agentId` 를 쿼리 파라미터로 전달. 본격 운영에는 **백엔드 `/api/mobile/me/*` 전용 endpoint** (토큰 → agentId 서버측 강제 필터) 권장 — 잔여 항목.
### 빌드 / 실행
```bash
cd ga-mobile-pwa
npm install
npm run dev # http://localhost:3001 (vite dev — /api → 8082 proxy)
npm run build # tsc --noEmit + vite build → dist/ (manifest + sw 자동 생성)
npm run preview # 3001 에서 production 번들 서빙
```
### 통합 검증 (2026-05-24)
- `npm install` 407 packages 성공
- `tsc --noEmit` PASS (`@types/node` 추가)
- `npm run build` PASS — `manifest.webmanifest` + `sw.js` + `workbox-*.js` 자동 생성, precache 8 entries (528 KiB), 번들 516KB(gzip 173KB)
- 라이브: vite dev :3001 LISTENING, ga-api :8082 정상
- API 응답 확인: `/api/statements` total=112, `/api/withdraw-requests` total=3, `/api/notices/active` 0건(정상), `/api/auth/me` 정상
### 잔여 (스캐폴드 이후)
- ~~백엔드 `/api/mobile/me/*` 전용 endpoint~~ → §3-14 에서 완료
- ~~본인 알림(`user_notification`) 표시~~ → §3-14 에서 완료
- 출금 신청 작성 폼 (현재 이력 조회만)
- 정산 명세서 상세 + PDF 다운로드
- 토큰 만료 자동 refresh
- 푸시 알림 (FCM 등) — 외부 채널 결정 후
- 실 아이콘 PNG (192/512/512 maskable)
- 번들 코드 스플리팅 (manualChunks)
## 3-14. P6 — 모바일 PWA 보안 강화: `/api/mobile/me/*` 전용 endpoint (2026-05-24)
PWA 스캐폴드에서 클라이언트가 `agentId` 를 쿼리 파라미터로 보내 본인 데이터를 필터하던 변조 가능 구조를 **서버측 강제 필터**로 교체. 토큰 → user → agentId 자동 추출.
### 백엔드 신규
| 위치 | 내용 |
|---|---|
| `ga-api/service/mobile/MobileMeService` | 토큰에서 userId 추출, `userMapper.selectById` 로 agentId 결정. 클라이언트 param 의 agentId/userId 는 **무시하고 덮어쓰기**. agentId 미연결 시 `BizException(FORBIDDEN)` |
| `ga-api/controller/mobile/MobileMeController` | `GET /api/mobile/me/{summary,statements,withdraw-requests,notifications}` + `POST /api/mobile/me/notifications/{id}/read`. 별도 메뉴 권한 없이 인증만 통과 |
### PWA 측 전환
- `src/api/statement.ts` / `withdraw.ts``/api/mobile/me/*` 호출, `agentId` 인터페이스에서 제거
- `src/api/notification.ts` 신규 — list/markRead/summary
- `Home.tsx``notificationApi.summary()` 한 번으로 3 카운트 동시 표시, 안 읽음 뱃지
- `NoticeList.tsx``Tabs``내 알림` / `공지사항` 두 탭. 알림 클릭 시 markRead + summary 무효화
- `StatementList.tsx` / `WithdrawList.tsx` — agentId 의존 제거, E403(설계사 미연결) 시 ErrorBlock 안내
### 라이브 검증 (2026-05-24)
- ga-api 컴파일 BUILD SUCCESSFUL · 재기동 OK
- PWA `tsc --noEmit` PASS · `npm run build` PASS (precache 8 entries 538 KiB, gzip 176KB)
- `GET /api/mobile/me/summary` (admin, agentId=null) → 200 OK, 세 카운트 모두 0
- `GET /api/mobile/me/statements` (admin) → **E403** 차단 (보안 강제 동작 확인)
- `GET /api/mobile/me/notifications` (admin) → 200 OK total=0
## 4. 잔여 작업 (P6 실연동)
P5 전체 + P6 PoC + **P6 후속(2026-05-27)** 완료. 잔여는 외부 SDK 차단 항목만.
### 운영 DB 마이그레이션 상태
운영 DB `192.168.0.60:55432/trading_ai/ga` 현재 **V96 적용 완료** (P7 incar 갭 반영 7도메인).
ga-api 8082 / ga-frontend 3000 / ga-mobile-pwa 3001 모두 라이브.
단위/통합 테스트: **SqlSessionFactory 환경 문제 해결 완료 (2026-05-29, §3-17)**. `./gradlew test` → 112건 전부 PASS (ga-common 57 / ga-api 36 / ga-batch 19).
## 3-15. P6 후속 (2026-05-27, 커밋 `2c9bf71` + `dfce9e5` + 후속 1)
| 영역 | 결과 |
|---|---|
| PWA 출금 신청 작성 폼 | `POST /api/mobile/me/withdraw-requests` + settle-master 드롭다운, **net_amount 잔여 한도 검증 포함** |
| PWA 명세서 상세 + 엑셀 다운로드 | `GET /api/mobile/me/statements/{id}[/download]`, 본인 검증 + 기존 download 흐름 재사용 |
| PWA 토큰 자동 refresh | 401 → `/api/auth/refresh` 단일화 재시도, refreshToken localStorage 영속 |
| 펌뱅킹 SETTLED 동기화 폴러 | `WithdrawBankSettleService` + `POST /api/internal/bank-settle`, ACCEPTED→COMPLETED/APPROVED 전이 |
| 사용자 phone 등록 (admin) | `PUT /api/system/users/{id}/phone`, UserList 인라인 Modal |
| PWA 본인 프로필 | `Profile.tsx`(phone 자기수정 + 비번변경 + 로그아웃), TabBar 5탭 |
| PWA 출금 신청 취소 | `POST /api/mobile/me/withdraw-requests/{id}/cancel`, REQUESTED 만 SwipeAction |
| SETTLED/FAILED 본인 알림 자동 발행 | `user_notification` INSERT, PWA NoticeList 내알림 탭 즉시 확인 |
| PWA 알림 모두 읽음 | `POST /api/mobile/me/notifications/read-all`, NoticeList 헤더 버튼 |
| 출금 잔여 한도 검증 | `settle_master.net_amount - sum(활성 출금합계)` 초과 시 E411 |
**e2e 검증 (2026-05-27 23:40, agent01/userId=4/agentId=1)**:
- 로그인 → AGENT role → /api/mobile/me/summary statementCount=3 / withdrawRequestCount=3
- /api/mobile/me/settle-masters → 3건 응답 (admin은 E403이었음)
- POST /api/mobile/me/withdraw-requests → 성공 (requestId=4)
- /api/mobile/me/statements/1 → 200 (본인) · /statements/2 → **E403 (타인)** ← 본인 검증 강제
- PUT /api/mobile/me/profile/phone → 200, /api/auth/me 즉시 반영
- POST /api/internal/bank-settle → SETTLED 동기화 + user_notification 자동 발행 코드 경로 검증
- POST /api/auth/refresh → 새 accessToken 발급
**잔여 — 외부 SDK 차단**:
| 항목 | 차단 사유 |
|---|---|
| KftcBankTransferAdapter 본체 | API 키·계약·테스트망 |
| ToastMessageAdapter 본체 | App Key·발신번호·템플릿 코드 |
| 카카오 알림톡 본체 | 비즈채널·템플릿 승인 |
| 푸시 알림 (FCM 등) | 외부 채널 결정 |
## 3-18. P7 — incar 갭 반영 수수료 계산 7개 도메인 풀스택 (V88~V96 — 완료, 2026-05-31 라이브 적용)
incar CMS 갭 분석 결과 GA 시스템에 없던 수수료 계산 7개 도메인을 DB→Core→API→Frontend 전 레이어로 추가. 운영 DB schema **v96**.
| 도메인 | 마이그레이션 | 테이블 | API 경로 |
|---|---|---|---|
| 수입수수료+수지차 (INCOME_COMM) | V88 | income_commission_ledger, margin_summary | `/api/income-commissions/*` |
| 소개·이관수수료 (REFERRAL_COMM) | V89 | referral_commission_rule, referral_commission_ledger | `/api/referral-commissions/*` |
| 정착지원금 (SETTLING_SUPPORT) | V90 | settling_support_rule, settling_support_ledger | `/api/settling-supports/*` |
| 인정실적+환산보험료 (RECOGNIZED_PERF) | V91 | product_conversion_rate, recognized_performance_ledger | `/api/recognized-performances/*` |
| 시상 (AWARD) | V92 | award_rule, award_ledger | `/api/awards/*` |
| 생보운영지원수수료 (LIFE_OP_SUPPORT) | V93 | life_support_rule, life_support_ledger | `/api/life-supports/*` |
| 지점장수당 (BRANCH_MGR_ALLOWANCE) | V94 | branch_mgr_allowance_rule, branch_mgr_allowance_ledger | `/api/branch-allowances/*` |
| 메뉴 7개 | V95 | — | GRP_COMMISSION 하위 sort 80~140 |
| 공통코드 5그룹 | V96 | — | INCOME_STATUS/REFERRAL_TYPE/CALC_TYPE/SUPPORT_STATUS/AWARD_TYPE |
통합 검증 (2026-05-31):
- `./gradlew build -x test` BUILD SUCCESSFUL
- Flyway V88~V96 9건 모두 success=True, 운영 DB schema v96
- 신규 14테이블 전부 존재 확인, 신규 메뉴 7건 등록 확인
- 기존 smoke_allmenus.py 67엔드포인트: PASS=66 FAIL=0 SKIP=1(settle/summary 필수파라미터, 기존 동일)
- P7 신규 8엔드포인트(인정실적은 /rates+/ledgers 분리): PASS=8 FAIL=0
- 주의: `/api/recognized-performances/rules` 는 없음. D4는 `/rates`(환산율)와 `/ledgers`(원장) 두 경로로 분리됨.
## 3-16. 계약 승계 (contract_succession, V86 — 완료, 2026-05-29 라이브 적용)
설계사 해촉/이관 시 보험계약의 **유지수수료(maintain) 귀속 설계사를 승계월 기준 후임으로 전환**.
모집수수료(1회차)는 원 모집설계사 귀속 유지 — 한국 고아계약 승계 표준. 후임 설계사는 본인 등급의 payout 비율로 수령.
| 레이어 | 산출물 |
|---|---|
| DB (V86) | `contract_succession`(contract_id/from_agent_id/to_agent_id/succession_date/reason/status) + 인덱스 3 + 메뉴 `CONTRACT_SUCCESSION`(GRP_PRD, path `/contracts/successions`) + 권한 READ/CREATE/UPDATE/DELETE + 역할부여(SUPER_ADMIN·ADMIN 전체 / MANAGER READ) + 공통코드 SUCCESSION_REASON·SUCCESSION_STATUS + 테스트데이터 1건 |
| core | `ContractSuccession` VO/Resp/SaveReq/SearchParam + Mapper(.java/.xml). 핵심 `selectEffectiveSuccessions(settleMonth)` = 계약별 최근 ACTIVE 승계 1건(DISTINCT ON, `TO_CHAR(succession_date,'YYYYMM') <= settleMonth`) |
| api | `ContractSuccessionService/Controller` (`/api/contract-successions`) CRUD + `/{id}/cancel`. from==to 가드(E411) |
| batch | `CalcMaintainStep`: effective 승계 Map 사전로드(N+1 회피) → `effectiveAgentId = getOrDefault(contractId, c.agentId)``CommissionCalculator.calcMaintainLedger(c, month, year, effectiveAgentId)` 오버로드(후임 등급 payout + `led.setAgentId(effectiveAgentId)`). **AggregateStep 무변경** — ledger의 agent_id로 집계하므로 후임 귀속 자동 전파 |
| frontend | `api/succession.ts` + `pages/contracts/ContractSuccessions.tsx` + App.tsx 라우트 `contracts/successions` |
핵심 산출물 커밋: `bd5ff4e`.
**부수 버그 수정 (커밋 `4dbc688`, 승계 무관)**:
- `AgentDeductionMapper.updateStatusBatch` 가 인터페이스 선언만 있고 XML 구문 누락 → AggregateStep(Step8) 이 PENDING 차감 일괄 APPLIED 전이 시 `Invalid bound statement (not found)` 로 aggregate 전체 FAILED 되던 잠복 버그(P0-2부터 존재). `updateStatus` 동일 패턴 + foreach IN 으로 보강. e2e 도중 발견.
통합 검증 (2026-05-29):
- 5모듈 compileJava BUILD SUCCESSFUL + ga-frontend tsc 0 오류
- Flyway V86 자동 적용 → 운영 DB schema **v86**
- API CRUD + cancel + from==to 가드(E411) 라이브 PASS
- **배치 풀잡 e2e**: ga-batch 8081 기동, `POST /internal/jobs/monthly-settlement`(JWT 필요 — ga-api admin 토큰 재사용). 테스트 승계(계약59 agent39→agent2, 2026-01-01) 등록 후 202605 정산 실행:
- maintain_ledger 계약59 = **agent2(후임)** / 5520(후임 등급 재계산, 원래 agent39/19320)
- settle_master agent2 maintain = 142700 = ledger 합 / agent39 = 191100 = ledger 합
- 무결성 **ledger 총합 == settle_master maintain 총합 = 17,556,135 정확 일치**
- (202604는 전 행 status=CONFIRMED → upsert 불변 가드 `WHERE status NOT IN ('CONFIRMED','PAID')` 로 settle_master 미갱신 = 정상 동작)
- e2e 테스트 DB 부산물(승계 레코드 / 202605 정산데이터 / 회계분개 / 차감 전이 / batch_job_log)은 단일 트랜잭션으로 전부 롤백 완료, pre-e2e 상태 복원 검증.
- **주의**: AccountingEntryGenerateStep(Step8b)은 멱등이 아님 — 동일 월 재실행 시 분개 중복 INSERT(주석상 existsByPaymentId 중복방어 언급되나 코드 미구현). 동일 월 재정산 전 기존 분개 정리 필요.
## 3-17. 테스트 환경 — SqlSessionFactory 문제 해결 (2026-05-29, 완료)
증상: `./gradlew :ga-api:test` 시 Spring 컨텍스트 로딩 실패 — `Error creating bean 'externalCallLogMapper' ... Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required`.
원인:
- `application-test.yml` 이 MybatisAutoConfiguration / DataSourceAutoConfiguration 을 제외 → 컨텍스트에 SqlSessionFactory 없음.
- 그러나 `MyBatisConfig``@MapperScan(basePackages = "com.ga")` 가 모든 @Mapper 의 MapperFactoryBean 을 생성, 이들은 SqlSessionFactory 를 요구.
- `AbstractControllerTest` 는 매퍼를 하나씩 `@MockBean` 으로 막아 회피했으나, 이후 추가된 매퍼(ExternalCallLog/Succession/AccountingEntry 등)가 목록에 누락 → 실제 MapperFactoryBean 생성 시도 → 깨짐. **매퍼 추가될 때마다 목록 갱신해야 하는 취약 구조.**
- (부수) `SettleControllerTest` 가 구버전 `hold(id, reason)` 2인자 stub 사용 → 현재 `hold(id, reason, reasonCode)` 3인자와 불일치로 testCompile 실패.
해결:
- `TestMyBatisConfig`(@TestConfiguration) 신규 — 미접속 `PGSimpleDataSource` + `SqlSessionFactory` 한 쌍 제공. 모든 MapperFactoryBean 이 생성되므로 매퍼 목록 갱신 불필요. 컨트롤러 테스트는 Service 를 mock 하므로 실제 쿼리 미실행(연결 안 함).
- `AbstractControllerTest` `@Import``TestMyBatisConfig` 추가.
- `SettleControllerTest` hold stub 3인자로 정정.
검증: `./gradlew test --rerun-tasks`**BUILD SUCCESSFUL, 112건 PASS** (ga-common 57 / ga-api 36 / ga-batch 19, 실패·에러 0). DB 무관(미접속 DataSource).
## 3-9. P5-W3 메뉴/권한 전수 정합 보강 (V74 — 완료, 2026-05-21 라이브 적용)
| 항목 | 상태 |
|---|---|
| AUDIT_P5W3.md §4 갭 리포트 작성 | 완료 (2026-05-17, infra) |
| V74 SQL 작성 | 완료 (2026-05-17, dba) |
| V74 정적검증 (PL) | 완료 (멱등·ON CONFLICT·스코프 확인) |
| 4모듈 compileJava | **PASS** (BUILD SUCCESSFUL) |
| ga-frontend npm run build | **PASS** (TS 오류 0) |
| 운영 DB 접속·Flyway V74 적용 | **완료** (2026-05-21, ga-api 재기동 시 자동 적용) |
| 스모크 검증 | **완료** (verify_v74.py 20/20 PASS) |
갭 요약 (총 27건):
- (a) menu 없음: 0건
- (b) menu_permission 없음: 3건 (NOTICE/DELETE, SYSTEM_DATA_DICT/DELETE, TERM_SETTLE/APPROVE)
- (c) grant 없음: 6건 (위 3 perm × SUPER_ADMIN+ADMIN, ADMIN/SYSTEM_* 7건은 보안상 의도적 제외)
- route/menu_path 불일치: 11건 (V74에서 UPDATE 처리)
갭 재검증 (V74 적용 후): `python verify_v74.py`**20/20 PASS** 확인 완료 (2026-05-21).
## 3-10. P5-W3 본론 — 결산 / 이상치·예측 / 연말명세서 (V75~V78, 2026-05-21 완료)
| 항목 | 마이그레이션 | 상태 |
|---|---|---|
| accounting_close + account_balance_snapshot (회계 결산) | V75 | 완료 |
| retention_anomaly_alert + forecast_kpi_monthly (이상치·예측 KPI) | V76 | 완료 |
| year_end_statement (연말 지급명세서) | V77 | 완료 |
| P5-W3 본론 메뉴 4개 + 권한 + 공통코드 7그룹 + 테스트데이터 | V78 | 완료 |
핵심 산출물:
- `AccountingCloseService/Controller` (`/api/accounting-closes`) — DRAFT 생성 / 마감 실행(분개 채번+잔액 스냅샷) / 재오픈
- `RetentionAnomalyAlertService/Controller` (`/api/retention-anomalies`) — 13M/25M 이상 탐지 / 검토 처리
- `ForecastKpiMonthlyService/Controller` (`/api/forecast-kpi`) — 이동평균(SMA3/6/NAIVE) 차월 예측
- `YearEndStatementService/Controller` (`/api/year-end-statements`) — 연 사업소득 명세서 재집계/발급/발송/엑셀
- 배치: BatchConfig 에 Step 11(WithholdingTaxQuarterly) / Step 12(VatReportQuarterly) 연결
- 프론트: `AccountingCloseList` / `YearEndStatementList` / `RetentionAnomalyList` / `ForecastKpiList` 4화면 + API 모듈 4개 + App.tsx 라우트 4개
- 공통: `usePermission`/`PermissionButton``EXECUTE` 권한 누락 보강 (canExecute)
통합 검증 (2026-05-21):
- Flyway: 운영 DB V74~V78 자동 적용 → 현재 **v78**
- 4모듈 compileJava + ga-frontend npm run build **PASS** (TS 오류 0)
- 스모크: 신규 4 + 회귀 4 = **GET 8/8 PASS**, 쓰기(regenerate/detect/draft) 4/4 PASS
- 보정: YearEndStatementMapper.xml 의 `a.agent_code` 미존재 컬럼 참조 제거 (agent 테이블에 agent_code 없음)
## 5. 재개 절차 (다음 세션)
1. **Claude Code 시작 시 cwd 확인**: `C:\Users\kyu\Desktop\ga_pro`
2. **HANDOFF.md 읽기**: 본 문서 §3-16(계약 승계) + §3-15(P6 후속) + 최근 git log
3. **운영 DB 상태**: **V96 적용 완료** (P7 incar 7도메인). ga-api 8082 가동. ga-frontend 3000 / ga-mobile-pwa 3001 은 필요 시 기동. origin/main 동기화 완료(HEAD `4dbc688`, 2026-05-29 push). P7 코드(V88~V96)는 로컬 커밋 아직 없음.
4. **재기동이 필요한 경우**:
- `cd ga-commission-system && nohup ./gradlew :ga-api:bootRun --args='--spring.profiles.active=trading_ai' > ../ga-api-bootrun.log 2>&1 & disown`
- `cd ga-commission-system/ga-frontend && npm run dev` (3000)
- `cd ga-commission-system/ga-mobile-pwa && npm run dev` (3001)
- 정산 배치: `nohup ./gradlew :ga-batch:bootRun --args='--spring.profiles.active=trading_ai' > ../ga-batch-bootrun.log 2>&1 &` (8081). 트리거 `POST :8081/internal/jobs/monthly-settlement {"settleMonth":"yyyyMM"}`**JWT 필요(ga-api `/api/auth/login` admin 토큰 재사용)**. 동기 실행.
5. **테스트 계정 / DB**: `admin`/`admin1234!`(SUPER_ADMIN), `agent01`/`agent1234!`(userId=4·agentId=1·AGENT). 로그인 필드명 `loginId`. DB: psql17 `192.168.0.60:55432/trading_ai` user `kyu`/pw `7895123`, `SET search_path TO ga`.
6. **사용자 결정 필요 항목 (외부 SDK 차단 사유)**:
- KFTC 펌뱅킹 API 계약·인증 정보 → `KftcBankTransferAdapter` 본체 구현
- NHN Toast / 카카오 비즈채널 계정 + 템플릿 코드 → `ToastMessageAdapter` 본체
- 푸시 알림 채널 (FCM 등) 결정 → PWA 통합
## 6. PL 가이드 (다음 세션 유의사항)
- **시간차 중복 메시지**: 팀원이 SendMessage로 같은 보고를 2~3번 보내는 경우 있음. 짧게 acknowledge만.
- **idle 알림**: 팀원이 작업 끝낼 때마다 idle 알림 보냄. 정상. 액션 필요 없음.
- **책임 경계**: dba=Flyway/SQL, core=VO/Mapper/Enum, api=Service/Controller. api-developer가 가끔 ga-core Mapper에 메서드 추가하는데 작은 변경이면 통과 가능, 큰 변경은 core-architect에 위임.
- **TODO 잔존**: api-developer가 부족한 ga-core 메서드 발견 시 TODO로 남기고 보고 → PL이 후속 보강 디스패치. 같은 단계에서 멈추지 말고 흐름 유지.
- **자동 정책**:
- 각 단계 완료 후 자동 커밋 (push 안 함)
- 빌드/테스트 실패 시 담당 팀원에 재지시
- 컴파일은 PL이 직접 검증. 테스트는 SqlSessionFactory 환경 문제 해결 후 `./gradlew test` 112건 PASS (§3-17)
## 7. 표준 가정 (도메인 작업 진행 시 채택한 값)
도메인 룰은 한국 보험업감독규정 표준 가정을 외부화 가능한 구조로 등록. 실제 회사 정책과 다르면 system_config / regulatory_limit / installment_ratio / chargeback_grade의 데이터만 수정하면 됨.
| 항목 | 표준값 | 근거 |
|---|---|---|
| 사업소득 원천징수 | 3.3% | 한국 표준 |
| 기타소득 원천징수 | 8.8% | 한국 표준 |
| 지방소득세 | 원천세의 10% | 한국 표준 |
| 부가세 | 10% | 한국 표준 |
| 1200% 룰 총 한도 | 1200% | 보험업감독규정 제5-15조의5 |
| 1차년 한도 | 35% | 2024년 기준 |
| 분급 연한 | 7년 | 2024년 기준 |
| 분급 비율 | 35/25/15/10/7/5/3 (합 100%) | 가정값 |
| 차등 환수 | 1~12: 100%, 13~24: 50%, 25~36: 25%, 37~84: 10%, 85~: 0% | 가정값 |
가정값과 실제가 다르면 운영 데이터 수정으로 해결 가능. 코드 변경 불필요.