bfc724669b
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>
256 lines
12 KiB
Markdown
256 lines
12 KiB
Markdown
# 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가 놓침) — 수정 완료:**
|
||
1. 프론트 인정실적 경로 `/rules` → 백엔드 `/rates` 불일치 → `api/commission.ts` 수정.
|
||
2. 프론트 수지차 경로 `/margin` → 백엔드 `/margins` 불일치 → 수정.
|
||
3. 수지차 recalc 3중 결함: 컨트롤러 `@RequestBody`(프론트는 쿼리파라미터)→`@RequestParam`, 서비스 `payoutTotal=0` 하드코딩 → settle_master.net_amount 실집계(`sumPayoutByMonth`)+`sumIncomeByMonth` 신규, `selectByMonthAndAgent`의 `#{agentId} IS NULL` Postgres typed-null 오류 → `<choose>`로 교체.
|