# GA 수수료 정산 솔루션 법인보험대리점(GA) 수수료 정산 시스템 — Multi-module Spring Boot + React. ## 기술 스택 | 영역 | 기술 | |------|------| | Backend | Java 17, Spring Boot 3.2, Spring Security, Spring Batch | | ORM | MyBatis 3 + PageHelper | | DB | PostgreSQL 16 | | Cache | Redis 7 | | Build | Gradle 멀티모듈 | | Frontend | React 18 + Vite + TypeScript + Ant Design 5 + AG Grid + React Query + Zustand | | Infra | Docker Compose, Nginx | ## 모듈 구조 ``` ga-commission-system/ ├── ga-common/ # 공통 프레임워크 (인증/권한/로그/엑셀/공통코드/메뉴) ├── ga-core/ # 도메인 코어 (VO, Mapper, SQL) ├── ga-api/ # REST API (포트 8080) ├── ga-batch/ # Spring Batch (포트 8081) ├── ga-admin/ # 관리자 라이브러리 └── ga-frontend/ # React SPA (포트 3000) ``` --- ## 🚀 실행 가이드 ### 환경 요구사항 - **Java 17+** (`java -version` 확인) - **Node.js 18+** + npm - **PostgreSQL 14+** (운영: `192.168.0.60:55432/trading_ai/ga` schema) - **Redis 7+** (선택 — 공통코드/세션 캐시) - **Gradle** (또는 IDE: IntelliJ IDEA 권장 — 자동으로 Gradle wrapper 생성) ### 시나리오 A — 운영 DB(trading_ai/ga) 에 연결해서 실행 ⭐ 권장 이미 V1~V17 마이그레이션 + 테스트 데이터(보험사 5 / 상품 20 / 설계사 50 / 계약 200)가 `192.168.0.60:55432/trading_ai/ga` 스키마에 적용되어 있습니다. #### 1) Backend (ga-api) 실행 ```bash # 1-1. Gradle wrapper 가 없다면 한 번 생성 (Gradle 설치 필요) gradle wrapper --gradle-version 8.6 # 1-2. 빌드 ./gradlew :ga-api:bootJar # 1-3. 실행 (trading_ai 프로파일 — 운영 DB 연결) ./gradlew :ga-api:bootRun --args='--spring.profiles.active=trading_ai' # 또는 환경변수로 비밀번호/Redis 호스트 오버라이드 export DB_PASSWORD=your-password export REDIS_HOST=localhost java -jar ga-api/build/libs/ga-api.jar --spring.profiles.active=trading_ai ``` 확인: - API: http://localhost:8080 - Swagger: http://localhost:8080/swagger-ui.html #### 2) Backend (ga-batch) 실행 — 정산 배치 트리거 처리 ```bash ./gradlew :ga-batch:bootRun --args='--spring.profiles.active=trading_ai' # 또는 java -jar ga-batch/build/libs/ga-batch.jar --spring.profiles.active=trading_ai ``` 기본 포트 8081. ga-api 가 `/api/batch/settlement/run` 호출 시 batch_job_log 에 `REQUESTED` 상태로 기록되며, ga-batch 가 이를 폴링/직접 호출로 실행합니다. #### 3) Frontend 실행 ```bash cd ga-frontend npm install npm run dev # http://localhost:3000 (Vite dev server) ``` 기본적으로 `/api/*` 요청은 Vite 프록시로 `http://localhost:8080` 으로 전달됩니다. #### 4) 로그인 & 동작 확인 ``` URL : http://localhost:3000 ID : admin PW : admin1234! ``` 로그인 후 사이드바 메뉴 — 좌측에 동적으로 메뉴가 그려져야 합니다. 주요 화면: | 메뉴 | 경로 | 설명 | |------|------|------| | 대시보드 | `/` | 정산 요약 카드 | | 설계사 관리 | `/org/agents` | 50명 더미 + 검색/등록/수정/엑셀 | | 계약 관리 | `/contracts` | 200건 더미 + 상태/보험사 필터 | | 모집수수료 원장 | `/ledger/recruit` | AG Grid 호환 테이블 + 엑셀 다운로드 | | 예외금액 원장 | `/ledger/exception` | 승인/반려 | | 정산 결과 | `/settle` | 월 요약 + 확정/보류 | | 정산 배치 | `/settle/batch` | 배치 실행 + 진행률 폴링 | | 지급 관리 | `/payments` | 지급 상태 추적 | | 사용자 관리 | `/system/users` | 비번 초기화/잠금 해제 | | 역할/권한 | `/system/roles` | 권한 매트릭스 (메뉴 × 6권한) | | 공통코드 | `/system/codes` | 그룹별 코드 조회 | --- ### 시나리오 B — 로컬 PostgreSQL 로 처음부터 (개발용) ```bash # 1) PostgreSQL + Redis 기동 (Docker) docker compose up -d postgres redis # 2) ga-api 실행 (Flyway 가 자동으로 V1~V17 마이그레이션) ./gradlew :ga-api:bootRun # 기본 프로파일은 application.yml — localhost:5432/ga 에 연결 # 3) ga-batch 실행 ./gradlew :ga-batch:bootRun # 4) 프론트 cd ga-frontend && npm install && npm run dev ``` `application.yml` 의 기본 DB: ```yaml url: jdbc:postgresql://localhost:5432/ga username: ga password: ga ``` --- ### 시나리오 C — Docker Compose 로 전체 기동 ```bash docker compose up -d --build # postgres + redis + api + batch + frontend 모두 컨테이너로 기동 # - 프론트: http://localhost:3000 # - API: http://localhost:8080/swagger-ui.html # - Batch: http://localhost:8081 (내부 통신용) ``` `docker-compose.yml` 환경변수: - `JWT_SECRET` — JWT 서명 키 (256bit 이상) - `ENCRYPT_KEY` — AES-256 키 (32바이트) --- ### DB 마이그레이션 직접 실행 (스크립트) 저장소 루트의 `migrate.py` (이 파일은 ga-commission-system 외부에 있음) — Python + pg8000 으로 V1~V17 SQL을 임의 DB에 일괄 적용: ```bash pip install pg8000 python migrate.py # host/port/db/user/schema 는 파일 상단 상수로 수정 ``` `ga` 스키마가 이미 있으면 idempotent guard 로 멈춥니다. 완전 재설치는 `DROP SCHEMA ga CASCADE; CREATE SCHEMA ga;` 후 재실행. --- ## 🧪 데이터 확인 (운영 DB 기준) | 테이블 | 건수 | |--------|------| | insurance_company | 5 (삼성/한화/교보/디비/KB) | | product | 20 (보험사 × 4상품) | | organization | 7 (본부 1 / 지점 3 / 팀 3) | | agent | 50 (GM 3 / DM 3 / SMGR 6 / SFC 12 / FC 26) | | contract | 200 (ACTIVE 190 / LAPSE 10) | | commission_rate | 100 | | payout_rule | 120 | | override_rule | 10 | | chargeback_rule | 4 | | common_code (그룹/상세) | 18 / 42 | | menu / menu_permission | 33 / 150 | | role / role_menu_permission | 4 / 323 | --- ## 🔧 트러블슈팅 ### Q. `./gradlew` 가 없다고 함 `gradle wrapper --gradle-version 8.6` 로 한번 생성하거나, IntelliJ 로 프로젝트 열면 자동 생성. ### Q. ga-api 부팅 시 `Failed to determine a suitable driver class` JDBC URL 또는 자격증명 누락. `--spring.profiles.active=trading_ai` 가 적용됐는지 확인. ### Q. `NoSuchKey: ga` (Flyway) 운영 DB 의 `ga` 스키마를 인식하려면 `currentSchema=ga` 가 URL 에 있어야 함. `application-trading_ai.yml` 에서 이미 설정되어 있음. ### Q. 프론트에서 401 / "토큰이 만료되었습니다" `localStorage` 에 `accessToken` 이 만료됨. `/login` 으로 다시 로그인. ### Q. AG Grid 가 빈 화면으로 보임 `@ag-grid-community/styles/ag-theme-quartz.css` import 가 잘 됐는지 확인. ### Q. 비밀번호 변경 ```sql -- BCrypt 해시 생성 후 직접 UPDATE UPDATE ga.users SET password = '$2b$10$...' WHERE login_id = 'admin'; ``` 또는 사용자 관리 화면 → "비번초기화" 액션. --- ## 📋 주요 기능 ### 백엔드 - **인증/권한**: JWT (HS256), 메뉴×권한 RBAC, BCrypt 비밀번호 - **공통코드**: Redis 캐시, 시스템코드 잠금, REST CRUD - **메뉴**: 트리 구조, 사용자별 동적 메뉴 + 권한 매트릭스 - **엑셀**: SXSSF+Cursor 다운로드(100만건), SAX+배치 업로드(70만건) - **로그**: 로그인/API/데이터변경 자동 기록 (비동기) - **암호화**: AES-256 CBC (`resident_no`, `account_no` 자동) ### 도메인 - **조직**: 트리 구조, CTE 재귀, 인사 이력 - **계약**: 보험사/상품/계약 관리 - **수수료 규정**: 보험사율, 지급율, 오버라이드, 환수, 예외코드 - **원장**: 모집/유지/예외 (PageHelper + AG Grid) - **정산**: 8 Step 배치 (수신→변환→대사→모집→유지→환수/예외→오버라이드→집계) - **지급**: 이체파일 생성, 상태 추적 ### 정산 배치 8 Step 1. **receiveData** — 보험사별 DataReceiver → raw_commission_data 적재 2. **transformData** — MappingEngine 으로 raw → 표준 원장 (TRIM/UPPER/DATE/DIVIDE/CODE_MAP) 3. **reconcile** — 보험사 통보액 vs 시스템 계산액 대사 4. **calcRecruit** — 모집수수료 (계약시점 commission_rate/payout_rule 적용) 5. **calcMaintain** — 유지수수료 (납입주기 매칭, 1~5년차) 6. **chargebackException** — 실효 계약 환수 자동생성 7. **calcOverride** — 조직 트리 상향 탐색 → 상위 직급에 분배 8. **aggregate** — 설계사별 통합 집계 → settle_master UPSERT (3.3% 세금) --- ## 🛠 신입 개발자 표준 패턴 (5분 컷) ```java // 1) VO (XxxVO + XxxResp + XxxSaveReq + XxxSearchParam) @Data public class FooSearchParam extends SearchParam { } // 2) Mapper Interface + XML @Mapper public interface FooMapper { List selectList(FooSearchParam p); } // 3) Service @Service @RequiredArgsConstructor public class FooService { private final FooMapper mapper; public PageResponse list(FooSearchParam p) { p.startPage(); return PageResponse.of(mapper.selectList(p)); } } // 4) Controller @RestController @RequestMapping("/api/foos") @RequiredArgsConstructor public class FooController { private final FooService service; @GetMapping @RequirePermission(menu = "FOO", perm = "READ") public ApiResponse> list(FooSearchParam p) { return ApiResponse.ok(service.list(p)); } } ``` --- ## 🔒 보안 - JWT (HS256) — 액세스 2시간, 리프레시 7일 - AES-256 CBC 암호화 (`EncryptTypeHandler` 자동 적용) - RBAC — `role_menu_permission` 매트릭스 - `@DataChangeLog` — 데이터 변경 이력 AOP 자동 - API 접근 로그 — 비동기 저장 (`api_access_log`) --- ## 🗄 DB 마이그레이션 | 버전 | 내용 | |------|------| | V1~V8 | 도메인 스키마 + 초기 데이터 (직급, 예외코드) | | V9~V12 | 공통코드/메뉴/시스템관리 + 초기 데이터 | | V13 | 인덱스 최적화 | | V14 | 파티셔닝 helper 함수 | | V15 | 통계/리포트 뷰 (v_agent_monthly_summary 등) | | V16 | 관리자 계정 + 메뉴 상세 + 권한 매트릭스 | | V17 | 테스트 데이터 (보험사 5 / 상품 20 / 설계사 50 / 계약 200 + 수수료 규정) | --- ## ✅ 진행 상황 - [x] 1단계 — 프로젝트 뼈대 + DB (V1~V17) - [x] **ga-common** — 공통 프레임워크 일체 - [x] **ga-core** — 22개 테이블 VO/Mapper/XML - [x] **ga-api** — Auth + 14개 도메인 컨트롤러 - [x] **ga-batch** — MonthlySettlementJob 8 Step (실제 동작 로직 포함) - [x] **Docker** — docker-compose + multi-stage Dockerfile + nginx - [x] **ga-frontend** — 13개 페이지 (대시보드/설계사/계약/원장/정산/지급/배치/시스템관리) - [x] **운영 DB 적용** — 192.168.0.60:55432/trading_ai/ga (V1~V17 + 테스트 데이터) - [ ] **단위/통합 테스트** — 미작성 - [ ] **MappingEngine 정밀화** — 일부 변환 규칙은 단순화된 형태 --- ## 🔮 향후 확장 - **프론트 페이지 추가**: `menu` 테이블 등록 → React 페이지 구현 → 동적 라우팅 적용 - **신규 보험사**: `company_profile` + `company_field_mapping` 등록 + 필요 시 `DataReceiver` 구현 - **신규 정산 규정**: `commission_rate`/`payout_rule`/`override_rule`/`chargeback_rule` 에 `effective_from` 만 다른 버전으로 추가 (versioning) - **이체파일 포맷**: 은행별 EBCDIC/CSV 출력 어댑터 추가 --- ## 📡 외부 시스템 연결 정보 (요약) | 항목 | 값 | |------|-----| | 운영 DB 호스트 | `192.168.0.60` | | 운영 DB 포트 | `55432` | | 운영 DB 데이터베이스 | `trading_ai` | | 운영 DB 스키마 | `ga` | | 운영 DB 사용자 | `kyu` | | Git 원격 | https://gl.kyleyang.co.kr/kyu/ga-commission-system | | 초기 관리자 | `admin / admin1234!` |