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>
12 KiB
P7 — incar 갭 반영: 수수료 계산 7개 도메인
작성: PL (자율 모드), 2026-05-31 근거: incar CMS 116메뉴 vs ga-pro 96메뉴 갭 분석. 사용자 지시 "필요한 메뉴 적용 + 수수료 공식 다 적용". 범위: 🅰 수수료 계산 7개 도메인 풀스택 (DB→Core→API→Frontend→Infra).
기존 패턴 100% 준수 (template = 수금수수료 V41 / CollectionCommission*). 모든 금액 NUMERIC(15,2), 율 NUMERIC(7,4)(소수, 0~1), 반올림 HALF_UP.
Flyway: V87이 최신 → V88부터. 각 도메인은 rule(+) ledger 2테이블 패턴. 메뉴는 GRP_COMMISSION 하위.
도메인별 설계
D1. 수입수수료 + 수지차 (INCOME_COMM) — V88
보험사가 GA에 지급한 수입 측. 기존 원장(LEDGER_*)은 설계사 지급 측. 수지차 = 수입 − 지급.
income_commission_ledger (수입수수료 원장)
| 컬럼 | 타입 | 설명 |
|---|---|---|
| income_id | BIGSERIAL PK | |
| contract_id | BIGINT NN FK contract | |
| carrier_id | BIGINT NN FK insurance_company | 보험사 |
| settle_month | CHAR(6) NN | |
| premium_amount | NUMERIC(15,2) NN | 보험료 |
| company_rate | NUMERIC(7,4) NN | 보험사요율 |
| income_amount | NUMERIC(15,2) NN | = premium_amount × company_rate |
| commission_type | VARCHAR(20) NN | RECRUIT/MAINTAIN 등 |
| status | VARCHAR(20) NN DEFAULT 'CALCULATED' | CALCULATED/CONFIRMED/CANCELLED |
| created_at/updated_at | ||
| idx: (carrier_id, settle_month), (contract_id), (status, settle_month) |
margin_summary (수지차 집계 — recalc 액션으로 채움)
| 컬럼 | 타입 | 설명 |
|---|---|---|
| margin_id | BIGSERIAL PK | |
| settle_month | CHAR(6) NN | |
| agent_id | BIGINT FK agent (NULL이면 전체) | |
| income_total | NUMERIC(15,2) NN DEFAULT 0 | 수입 합 |
| payout_total | NUMERIC(15,2) NN DEFAULT 0 | 지급 합(settle_master 기준) |
| margin_amount | NUMERIC(15,2) NN DEFAULT 0 | = income_total − payout_total |
| margin_rate | NUMERIC(7,4) | = margin/income (income>0) |
| created_at | ||
| UNIQUE(settle_month, agent_id) |
공식: income_amount = premium × company_rate. margin = Σincome − Σpayout.
D2. 소개·이관수수료 (REFERRAL_COMM) — V89
계약을 소개(REFERRAL)하거나 이관(TRANSFER)한 설계사에게 주는 수수료.
referral_commission_rule
| 컬럼 | 타입 | 설명 |
|---|---|---|
| rule_id | BIGSERIAL PK | |
| referral_type | VARCHAR(20) NN | REFERRAL/TRANSFER |
| calc_type | VARCHAR(10) NN | RATE/FIXED |
| commission_rate | NUMERIC(7,4) | calc_type=RATE 일 때 |
| fixed_amount | NUMERIC(15,2) | calc_type=FIXED 일 때 |
| effective_from DATE NN / effective_to DATE | ||
| CHECK referral_type IN ('REFERRAL','TRANSFER'); CHECK calc_type IN ('RATE','FIXED') |
referral_commission_ledger
| 컬럼 | 타입 | 설명 |
|---|---|---|
| ledger_id | BIGSERIAL PK | |
| contract_id | BIGINT NN FK | |
| referrer_agent_id | BIGINT NN FK agent | 소개/이관한 설계사 |
| settle_month | CHAR(6) NN | |
| referral_type | VARCHAR(20) NN | |
| base_amount | NUMERIC(15,2) NN | 기준금액(수수료/보험료) |
| commission_rate | NUMERIC(7,4) | |
| commission_amount | NUMERIC(15,2) NN | = base×rate (RATE) 또는 fixed_amount (FIXED) |
| status | VARCHAR(20) NN DEFAULT 'CALCULATED' | |
| idx: (referrer_agent_id, settle_month),(contract_id) |
D3. 정착지원금 (SETTLING_SUPPORT) — V90
신입/경력 설계사 정착 지원금. 등급별 정액 지급 + 조기 해촉 시 환수.
settling_support_rule
| 컬럼 | 타입 | 설명 |
|---|---|---|
| rule_id BIGSERIAL PK | ||
| agent_grade | VARCHAR(20) NN | 설계사 등급 |
| support_amount | NUMERIC(15,2) NN | 월 정액 지원금 |
| duration_months | INT NN | 약정 지원 개월수 |
| clawback_months | INT NN | 이 개월 내 해촉 시 환수 대상 |
| effective_from DATE NN / effective_to DATE |
settling_support_ledger
| 컬럼 | 타입 | 설명 |
|---|---|---|
| ledger_id BIGSERIAL PK | ||
| agent_id BIGINT NN FK agent | ||
| settle_month CHAR(6) NN | ||
| support_amount NUMERIC(15,2) NN | 지급액 | |
| clawback_amount NUMERIC(15,2) NN DEFAULT 0 | 환수액 | |
| net_amount NUMERIC(15,2) NN | = support_amount − clawback_amount | |
| status VARCHAR(20) NN DEFAULT 'CALCULATED' | PAID/CLAWED_BACK 포함 | |
| idx: (agent_id, settle_month) |
공식: 지급 = 등급별 support_amount. 환수 = 조기해촉시 support_amount × (잔여약정개월/약정개월) (clawback service 계산).
D4. 인정실적 + 환산보험료 (RECOGNIZED_PERF) — V91
환산보험료 = 보험료 × 상품별환산율. 인정실적 = 환산보험료 × 인정율. 시상/등급의 기초.
product_conversion_rate (상품별 환산율)
| 컬럼 | 타입 | 설명 |
|---|---|---|
| rate_id BIGSERIAL PK | ||
| product_id BIGINT NN FK product | ||
| conversion_rate NUMERIC(7,4) NN | 환산율 (예: 0.5=50%) | |
| effective_from DATE NN / effective_to DATE | ||
| UNIQUE(product_id, effective_from) |
recognized_performance_ledger
| 컬럼 | 타입 | 설명 |
|---|---|---|
| ledger_id BIGSERIAL PK | ||
| agent_id BIGINT NN FK agent | ||
| contract_id BIGINT NN FK contract | ||
| settle_month CHAR(6) NN | ||
| premium_amount NUMERIC(15,2) NN | 보험료 | |
| conversion_rate NUMERIC(7,4) NN | 적용 환산율 | |
| converted_premium NUMERIC(15,2) NN | = premium × conversion_rate | |
| recognition_rate NUMERIC(7,4) NN | 인정율 | |
| recognized_amount NUMERIC(15,2) NN | = converted_premium × recognition_rate | |
| status VARCHAR(20) NN DEFAULT 'CALCULATED' | ||
| idx: (agent_id, settle_month),(contract_id) |
D5. 시상 (AWARD) — V92
신인도입/법인/유지율 등 시상. 조건 충족 시 정액 또는 정률.
award_rule
| 컬럼 | 타입 | 설명 |
|---|---|---|
| rule_id BIGSERIAL PK | ||
| award_type VARCHAR(20) NN | NEW_RECRUIT/CORPORATE/RETENTION/PERFORMANCE | |
| calc_type VARCHAR(10) NN | RATE/FIXED | |
| threshold_amount NUMERIC(15,2) | 충족 기준 실적(이상) | |
| award_rate NUMERIC(7,4) | RATE | |
| award_fixed NUMERIC(15,2) | FIXED | |
| effective_from DATE NN / effective_to DATE | ||
| CHECK award_type IN (...); CHECK calc_type IN ('RATE','FIXED') |
award_ledger
| 컬럼 | 타입 | 설명 |
|---|---|---|
| ledger_id BIGSERIAL PK | ||
| agent_id BIGINT NN FK agent | ||
| settle_month CHAR(6) NN | ||
| award_type VARCHAR(20) NN | ||
| base_amount NUMERIC(15,2) NN | 기준 실적 | |
| award_amount NUMERIC(15,2) NN | = base×award_rate (RATE) 또는 award_fixed (FIXED) | |
| status VARCHAR(20) NN DEFAULT 'CALCULATED' | ||
| idx: (agent_id, settle_month),(award_type, settle_month) |
D6. 생보운영지원수수료 (LIFE_OP_SUPPORT) — V93
생보 계약 운영지원 수수료. 실적 기준 지급률 + 환수.
life_support_rule
| 컬럼 | 타입 | 설명 |
|---|---|---|
| rule_id BIGSERIAL PK | ||
| agent_grade VARCHAR(20) NN | ||
| support_rate NUMERIC(7,4) NN | 지급률 | |
| effective_from DATE NN / effective_to DATE |
life_support_ledger
| 컬럼 | 타입 | 설명 |
|---|---|---|
| ledger_id BIGSERIAL PK | ||
| agent_id BIGINT NN FK agent | ||
| settle_month CHAR(6) NN | ||
| base_amount NUMERIC(15,2) NN | 생보 실적 | |
| support_rate NUMERIC(7,4) NN | ||
| support_amount NUMERIC(15,2) NN | = base × support_rate | |
| clawback_amount NUMERIC(15,2) NN DEFAULT 0 | 환수 | |
| net_amount NUMERIC(15,2) NN | = support − clawback | |
| status VARCHAR(20) NN DEFAULT 'CALCULATED' | ||
| idx: (agent_id, settle_month) |
D7. 지점장수당 (BRANCH_MGR_ALLOWANCE) — V94
지점장이 소속 조직 실적에 대해 받는 수당. cap 제한 + 환수.
branch_mgr_allowance_rule
| 컬럼 | 타입 | 설명 |
|---|---|---|
| rule_id BIGSERIAL PK | ||
| position_code VARCHAR(20) NN | 직책(지점장 등) | |
| allowance_rate NUMERIC(7,4) NN | 수당율 | |
| cap_amount NUMERIC(15,2) | 상한(NULL=무제한) | |
| effective_from DATE NN / effective_to DATE |
branch_mgr_allowance_ledger
| 컬럼 | 타입 | 설명 |
|---|---|---|
| ledger_id BIGSERIAL PK | ||
| manager_agent_id BIGINT NN FK agent | 지점장 | |
| org_id BIGINT NN FK organization | 대상 조직 | |
| settle_month CHAR(6) NN | ||
| base_amount NUMERIC(15,2) NN | 조직 실적 | |
| allowance_rate NUMERIC(7,4) NN | ||
| allowance_amount NUMERIC(15,2) NN | = LEAST(base×rate, cap) | |
| clawback_amount NUMERIC(15,2) NN DEFAULT 0 | ||
| status VARCHAR(20) NN DEFAULT 'CALCULATED' | ||
| idx: (manager_agent_id, settle_month),(org_id, settle_month) |
확정 FK (DB 실검증): contract(contract_id) · agent(agent_id) · product(product_id) · organization(org_id) · insurance_company(company_id) · settle_master. 보험사 FK는
carrier_id BIGINT REFERENCES insurance_company(company_id). 수지차 payout은 settle_master 집계로 산출(dba가 컬럼 확인).
메뉴 (V95) — GRP_COMMISSION 하위 7개 PAGE
| menu_code | menu_name | menu_path | component_path | sort |
|---|---|---|---|---|
| INCOME_COMM | 수입수수료/수지차 | /commission/income | commission/IncomeCommission | 80 |
| REFERRAL_COMM | 소개·이관수수료 | /commission/referral | commission/ReferralCommission | 90 |
| SETTLING_SUPPORT | 정착지원금 | /commission/settling-support | commission/SettlingSupport | 100 |
| RECOGNIZED_PERF | 인정실적 | /commission/recognized | commission/RecognizedPerformance | 110 |
| AWARD | 시상 | /commission/award | commission/Award | 120 |
| LIFE_OP_SUPPORT | 생보운영지원수수료 | /commission/life-support | commission/LifeSupport | 130 |
| BRANCH_MGR_ALLOWANCE | 지점장수당 | /commission/branch-allowance | commission/BranchAllowance | 140 |
권한: READ/CREATE/UPDATE/DELETE/EXPORT. 역할부여: SUPER_ADMIN/ADMIN 전체, MANAGER READ/CREATE/UPDATE/EXPORT, AGENT READ(INCOME_COMM 제외 — 본인 관련만). V54 패턴 그대로.
공통코드 (V96)
| group_code | 코드 |
|---|---|
| INCOME_STATUS | CALCULATED/CONFIRMED/CANCELLED |
| REFERRAL_TYPE | REFERRAL=소개/TRANSFER=이관 |
| CALC_TYPE | RATE=정률/FIXED=정액 |
| SUPPORT_STATUS | CALCULATED/PAID/CLAWED_BACK |
| AWARD_TYPE | NEW_RECRUIT=신인도입/CORPORATE=법인/RETENTION=유지율/PERFORMANCE=실적 |
CommissionType enum 확장: INCOME/REFERRAL/TRANSFER/SETTLING/RECOGNIZED/AWARD/LIFE_SUPPORT/BRANCH_ALLOWANCE 추가 + V40 COMMISSION_TYPE 공통코드 동기화.
Wave 실행
| Wave | 담당 | 산출물 |
|---|---|---|
| 1 | dba-architect | V88~V96 (도메인 7 + 메뉴 + 공통코드). FK 테이블명 실검증. |
| 2 | core-architect | 14테이블 VO/Resp/SaveReq/SearchParam + Mapper IF+XML + CommissionType enum 확장 |
| 3 | api-developer | 7 Service + 7 Controller (@RequirePermission/@DataChangeLog, 공식 계산 Service 내장) |
| 4 | frontend-developer | 7 페이지 + api/commission.ts 확장 + App.tsx 라우트 |
| 5 | infra-reviewer | ./gradlew build + 프론트 빌드 + smoke. README/HANDOFF/DOMAIN_KNOWLEDGE 갱신 |
완료 상태 (2026-05-31)
schema v96 적용(Flyway V88~V96 success), 전체 ./gradlew build SUCCESSFUL, 프론트 빌드 OK, ga-api 8082 라이브. P7 14개 GET + 수지차 recalc POST 전수 호출 5xx 0건. 수입수수료(보험료×요율=6,000,000)·수지차(수입−지급) 공식 런타임 실측 검증 후 테스트데이터 정리.
PL 통합검증에서 잡은 버그 3건(팀원 GET-only smoke가 놓침) — 수정 완료:
- 프론트 인정실적 경로
/rules→ 백엔드/rates불일치 →api/commission.ts수정. - 프론트 수지차 경로
/margin→ 백엔드/margins불일치 → 수정. - 수지차 recalc 3중 결함: 컨트롤러
@RequestBody(프론트는 쿼리파라미터)→@RequestParam, 서비스payoutTotal=0하드코딩 → settle_master.net_amount 실집계(sumPayoutByMonth)+sumIncomeByMonth신규,selectByMonthAndAgent의#{agentId} IS NULLPostgres typed-null 오류 →<choose>로 교체.