# 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 오류 → ``로 교체.