feat: 테스트 데이터(V17) + 실 DB 프로파일 + 프론트 화면 확장

V17 (192.168.0.60:55432/trading_ai/ga 적용 완료):
- 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 (5상품 × 5년차 × 5보험사 = 일부)
  실제 INSERT는 상품 20개 × 1년차 + 20 × 4년차 = 100건
- payout_rule 120 (직급 6 × 보험종류 4 × 연차 5)
- override_rule 10 (FC/SFC/MGR/SMGR/DM 직급 간 오버라이드)
- chargeback_rule 4 (실효월수 구간별 환수율)

운영 DB 프로파일:
- application-trading_ai.yml (ga-api, ga-batch)
- 192.168.0.60:55432 / trading_ai / currentSchema=ga
- Flyway baseline-version=17 (수동 적용 분 인정)

DB 포트 변경 반영: 5432 → 55432 (운영 변경)

프론트 추가 화면:
- DataGrid (AG Grid Community 래퍼; 합계행/셀편집/로딩 오버레이)
- 예외원장 (ExceptionLedger): 승인/반려 액션
- 지급관리 (PaymentList)
- 정산 배치 (BatchRun): 실행 + 진행률 폴링
- 시스템관리:
  * UserList: 비밀번호 초기화 + 잠금 해제
  * RoleList: 좌측 역할 + 우측 권한 매트릭스 (메뉴 × 6권한)
  * CodeList: 좌측 그룹 + 우측 상세 코드, 시스템그룹 경고

설계사 상세/등록 폼:
- AgentDetail: 통계 카드 + 기본정보 + 수정 버튼
- AgentForm: 등록/수정 통합 (id='new' 또는 :id/edit)

라우터:
- /org/agents/{new|:id|:id/edit}
- /ledger/exception, /payments, /settle/batch
- /system/{users|roles|codes}
This commit is contained in:
GA Pro
2026-05-09 22:47:55 +09:00
parent 98eb231950
commit 92079d2385
16 changed files with 1197 additions and 4 deletions
@@ -0,0 +1,82 @@
import { useEffect, useMemo, useRef } from 'react';
import { AgGridReact } from '@ag-grid-community/react';
import { ModuleRegistry } from '@ag-grid-community/core';
import { ClientSideRowModelModule } from '@ag-grid-community/client-side-row-model';
import type { ColDef, GridReadyEvent, GridApi } from '@ag-grid-community/core';
import '@ag-grid-community/styles/ag-grid.css';
import '@ag-grid-community/styles/ag-theme-quartz.css';
ModuleRegistry.registerModules([ClientSideRowModelModule]);
interface Props<T> {
rows: T[] | undefined;
columns: ColDef<T>[];
loading?: boolean;
height?: number | string;
/** 합계행 데이터 */
pinnedBottomRow?: Partial<T>;
/** 셀 편집 가능 시 콜백 */
onCellChanged?: (row: T, field: string, newValue: unknown) => void;
rowKey?: keyof T;
}
/**
* AG Grid Community 클라이언트사이드 래퍼.
* - 100건 이상 / 셀 편집 / 합계행이 필요한 화면용
* - 서버사이드는 별도 SSRM 모듈 필요 (Community 한정 → enterprise만 지원)
* 여기서는 현실적인 절충안으로 클라이언트사이드 + 외부 페이징 사용
*/
export default function DataGrid<T extends Record<string, unknown>>({
rows,
columns,
loading,
height = 600,
pinnedBottomRow,
onCellChanged,
rowKey,
}: Props<T>) {
const apiRef = useRef<GridApi<T> | null>(null);
const defaultColDef = useMemo<ColDef>(
() => ({
sortable: true,
filter: true,
resizable: true,
suppressMovable: false,
}),
[],
);
const onGridReady = (e: GridReadyEvent<T>) => {
apiRef.current = e.api;
};
useEffect(() => {
if (apiRef.current) {
if (loading) apiRef.current.showLoadingOverlay();
else apiRef.current.hideOverlay();
}
}, [loading]);
return (
<div className="ag-theme-quartz" style={{ height, width: '100%' }}>
<AgGridReact<T>
rowData={rows}
columnDefs={columns}
defaultColDef={defaultColDef}
animateRows
rowSelection="single"
getRowId={rowKey ? (p) => String(p.data[rowKey]) : undefined}
pinnedBottomRowData={pinnedBottomRow ? [pinnedBottomRow as T] : undefined}
onCellValueChanged={(e) => {
if (onCellChanged && e.data) {
onCellChanged(e.data, String(e.colDef.field), e.newValue);
}
}}
onGridReady={onGridReady}
loadingOverlayComponent={() => <span> ...</span>}
noRowsOverlayComponent={() => <span> </span>}
/>
</div>
);
}