From d4433a8e46a2879b72cff25107e160502dfc9741 Mon Sep 17 00:00:00 2001 From: GA Pro Date: Sat, 9 May 2026 22:21:45 +0900 Subject: [PATCH] fix: critical bugs + admin account (V16) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bugs: - MyBatisConfig: @MapperScan basePackages corrected to scan all com.ga.* by @Mapper annotation (was missing common.code/menu/system/file/notification) - CalcRecruitStep: endDate was first day of month (only contracts on day 1 were picked); now full month range via DateUtil.getMonthRange - EncryptTypeHandler: removed @MappedTypes(String.class) to prevent encrypting all String columns; now requires explicit per-column typeHandler - mybatis-config.xml: removed redundant javaType for JsonTypeHandler (uses @MappedTypes) V16 admin initial data: - Child menus (24): ORG_TREE, ORG_AGENT, CONTRACT_LIST, COMPANY, PRODUCT, RULE_*, RECEIVE_*, LEDGER_*, SETTLE_LIST, BATCH_RUN, PAYMENT, SYSTEM_* - Permissions for each PAGE menu × {READ,CREATE,UPDATE,DELETE,APPROVE,EXPORT} - SUPER_ADMIN: full grants - ADMIN: all except SYSTEM - MANAGER: READ/CREATE/UPDATE/EXPORT except SYSTEM - AGENT: READ on LEDGER_*, SETTLE_LIST - admin user (login_id=admin, pw=admin1234!) mapped to SUPER_ADMIN --- .../settlement/step/CalcRecruitStep.java | 19 +-- .../com/ga/common/config/MyBatisConfig.java | 7 +- .../ga/common/mybatis/EncryptTypeHandler.java | 8 +- .../db/migration/V16__관리자_초기데이터.sql | 112 ++++++++++++++++++ .../main/resources/mybatis/mybatis-config.xml | 6 +- 5 files changed, 130 insertions(+), 22 deletions(-) create mode 100644 ga-common/src/main/resources/db/migration/V16__관리자_초기데이터.sql diff --git a/ga-batch/src/main/java/com/ga/batch/settlement/step/CalcRecruitStep.java b/ga-batch/src/main/java/com/ga/batch/settlement/step/CalcRecruitStep.java index fc714af..52262a6 100644 --- a/ga-batch/src/main/java/com/ga/batch/settlement/step/CalcRecruitStep.java +++ b/ga-batch/src/main/java/com/ga/batch/settlement/step/CalcRecruitStep.java @@ -2,6 +2,7 @@ package com.ga.batch.settlement.step; import com.ga.batch.settlement.SettlementContext; import com.ga.batch.settlement.calc.CommissionCalculator; +import com.ga.common.util.DateUtil; import com.ga.common.util.MoneyUtil; import com.ga.core.mapper.ledger.RecruitLedgerMapper; import com.ga.core.mapper.product.ContractMapper; @@ -17,7 +18,6 @@ import org.springframework.batch.core.step.tasklet.Tasklet; import org.springframework.batch.repeat.RepeatStatus; import org.springframework.stereotype.Component; -import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; @@ -44,9 +44,10 @@ public class CalcRecruitStep implements Tasklet { log.info("[Step4 calcRecruit] settleMonth={}", ctx.getSettleMonth()); // 모집수수료 대상: 계약일이 정산월에 해당하는 계약 + String[] range = DateUtil.getMonthRange(ctx.getSettleMonth()); ContractSearchParam param = new ContractSearchParam(); - param.setStartDate(ctx.getSettleMonth().substring(0, 4) + "-" + ctx.getSettleMonth().substring(4) + "-01"); - param.setEndDate(param.getStartDate()); + param.setStartDate(range[0]); + param.setEndDate(range[1]); param.setPageSize(Integer.MAX_VALUE); List contracts = contractMapper.selectList(param); @@ -74,16 +75,4 @@ public class CalcRecruitStep implements Tasklet { log.info("[Step4] recruit ledger inserted: {}", total); return RepeatStatus.FINISHED; } - - /** 정산월의 첫날 / 마지막날 — calcRecruit 대상 기간 */ - private static String[] monthRange(String yyyymm) { - int year = Integer.parseInt(yyyymm.substring(0, 4)); - int month = Integer.parseInt(yyyymm.substring(4)); - java.time.YearMonth ym = java.time.YearMonth.of(year, month); - return new String[]{ym.atDay(1).toString(), ym.atEndOfMonth().toString()}; - } - - /** 외부에서 사용할 수도 있는 헬퍼 */ - @SuppressWarnings("unused") - private BigDecimal premiumOrZero(ContractResp c) { return MoneyUtil.zero(c.getPremium()); } } diff --git a/ga-common/src/main/java/com/ga/common/config/MyBatisConfig.java b/ga-common/src/main/java/com/ga/common/config/MyBatisConfig.java index 092918a..2bddcfd 100644 --- a/ga-common/src/main/java/com/ga/common/config/MyBatisConfig.java +++ b/ga-common/src/main/java/com/ga/common/config/MyBatisConfig.java @@ -1,12 +1,17 @@ package com.ga.common.config; import com.ga.common.mybatis.AuditInterceptor; +import org.apache.ibatis.annotations.Mapper; import org.mybatis.spring.annotation.MapperScan; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +/** + * 모든 com.ga 패키지 하위에서 @Mapper 가 붙은 인터페이스만 스캔. + * (common.code / common.menu / common.system / common.notification / common.file / core.mapper.*) + */ @Configuration -@MapperScan(basePackages = {"com.ga.common.mapper", "com.ga.core.mapper"}) +@MapperScan(basePackages = "com.ga", annotationClass = Mapper.class) public class MyBatisConfig { @Bean diff --git a/ga-common/src/main/java/com/ga/common/mybatis/EncryptTypeHandler.java b/ga-common/src/main/java/com/ga/common/mybatis/EncryptTypeHandler.java index a6b7b00..b59e563 100644 --- a/ga-common/src/main/java/com/ga/common/mybatis/EncryptTypeHandler.java +++ b/ga-common/src/main/java/com/ga/common/mybatis/EncryptTypeHandler.java @@ -3,7 +3,6 @@ package com.ga.common.mybatis; import com.ga.common.util.EncryptUtil; import org.apache.ibatis.type.BaseTypeHandler; import org.apache.ibatis.type.JdbcType; -import org.apache.ibatis.type.MappedTypes; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; @@ -16,10 +15,13 @@ import java.sql.SQLException; /** * AES 암호화 컬럼용 TypeHandler. - * Mapper XML 에서 typeHandler="com.ga.common.mybatis.EncryptTypeHandler" 지정. + * + * @MappedTypes 를 의도적으로 빼서 String 전체 자동 적용을 막는다. + * 사용 시 컬럼별로 명시: + * */ @Component -@MappedTypes(String.class) public class EncryptTypeHandler extends BaseTypeHandler implements ApplicationContextAware { private static EncryptUtil encryptUtil; diff --git a/ga-common/src/main/resources/db/migration/V16__관리자_초기데이터.sql b/ga-common/src/main/resources/db/migration/V16__관리자_초기데이터.sql new file mode 100644 index 0000000..70f4b67 --- /dev/null +++ b/ga-common/src/main/resources/db/migration/V16__관리자_초기데이터.sql @@ -0,0 +1,112 @@ +-- V16: 관리자 계정 + 메뉴 상세 + 권한 매트릭스 초기화 +-- admin 계정 비밀번호: admin1234! (BCrypt $2b$10) + +-- 1. 자식 메뉴 (V10에서 정의된 menu_code 와 컨트롤러 @RequirePermission 매칭) +WITH parent AS ( + SELECT menu_id, menu_code FROM menu WHERE menu_level = 1 +) +INSERT INTO menu (parent_menu_id, menu_code, menu_name, menu_type, menu_path, component_path, menu_level, sort_order) +SELECT p.menu_id, x.code, x.name, 'PAGE', x.path, x.cmpt, 2, x.sort +FROM parent p +JOIN (VALUES + -- 조직 + ('ORG', 'ORG_TREE', '조직 트리', '/org/tree', 'org/OrgTree', 10), + ('ORG', 'ORG_AGENT', '설계사 관리', '/org/agents', 'org/AgentList', 20), + -- 계약 + ('CONTRACT', 'CONTRACT_LIST', '계약 목록', '/contracts', 'product/ContractList', 10), + ('CONTRACT', 'COMPANY', '보험사 관리', '/companies', 'product/CompanyList', 20), + ('CONTRACT', 'PRODUCT', '상품 관리', '/products', 'product/ProductList', 30), + -- 수수료 규정 + ('RULE', 'RULE_COMMISSION', '보험사 수수료율', '/rules/commission', 'rule/CommissionRate', 10), + ('RULE', 'RULE_PAYOUT', '지급율 관리', '/rules/payout', 'rule/PayoutRule', 20), + ('RULE', 'RULE_OVERRIDE', '오버라이드 규정', '/rules/override', 'rule/OverrideRule', 30), + ('RULE', 'RULE_CHARGEBACK', '환수 규정', '/rules/chargeback', 'rule/ChargebackRule', 40), + ('RULE', 'RULE_EXCEPTION', '예외코드 관리', '/rules/exceptions', 'rule/ExceptionCode', 50), + -- 데이터 수신 + ('RECEIVE', 'RECEIVE_MAPPING', '매핑 관리', '/receive/mapping', 'receive/Mapping', 10), + ('RECEIVE', 'RECEIVE_DATA', '수신 데이터', '/receive/data', 'receive/RawData', 20), + -- 원장 + ('LEDGER', 'LEDGER_RECRUIT', '모집수수료원장', '/ledger/recruit', 'ledger/RecruitLedger', 10), + ('LEDGER', 'LEDGER_MAINTAIN', '유지수수료원장', '/ledger/maintain', 'ledger/MaintainLedger',20), + ('LEDGER', 'LEDGER_EXCEPTION', '예외금액원장', '/ledger/exception', 'ledger/ExceptionLedger',30), + -- 정산/지급 + ('SETTLE', 'SETTLE_LIST', '정산 결과', '/settle', 'settle/SettleList', 10), + ('SETTLE', 'BATCH_RUN', '정산 배치', '/settle/batch', 'settle/BatchRun', 20), + ('PAYMENT', 'PAYMENT', '지급 관리', '/payments', 'settle/PaymentList', 10), + -- 시스템 + ('SYSTEM', 'SYSTEM_USER', '사용자 관리', '/system/users', 'system/UserList', 10), + ('SYSTEM', 'SYSTEM_ROLE', '역할 관리', '/system/roles', 'system/RoleList', 20), + ('SYSTEM', 'SYSTEM_MENU', '메뉴 관리', '/system/menus', 'system/MenuTree', 30), + ('SYSTEM', 'SYSTEM_CODE', '공통코드 관리', '/system/codes', 'system/CodeList', 40), + ('SYSTEM', 'SYSTEM_CONFIG', '시스템 설정', '/system/config', 'system/ConfigList', 50), + ('SYSTEM', 'SYSTEM_LOG', '시스템 로그', '/system/logs', 'system/LogList', 60) +) AS x(parent_code, code, name, path, cmpt, sort) +ON p.menu_code = x.parent_code; + +-- 2. 메뉴별 권한 항목 (READ/CREATE/UPDATE/DELETE/APPROVE/EXPORT) +INSERT INTO menu_permission (menu_id, perm_code, perm_name, sort_order) +SELECT m.menu_id, p.code, p.name, p.sort +FROM menu m +CROSS JOIN (VALUES + ('READ', '조회', 10), + ('CREATE', '등록', 20), + ('UPDATE', '수정', 30), + ('DELETE', '삭제', 40), + ('APPROVE', '승인', 50), + ('EXPORT', '엑셀', 60) +) AS p(code, name, sort) +WHERE m.menu_type = 'PAGE'; + +-- 3. SUPER_ADMIN 에 모든 메뉴 × 모든 권한 부여 +INSERT INTO role_menu_permission (role_id, menu_id, perm_code, is_granted) +SELECT r.role_id, mp.menu_id, mp.perm_code, 'Y' +FROM role r +CROSS JOIN menu_permission mp +WHERE r.role_code = 'SUPER_ADMIN' +ON CONFLICT (role_id, menu_id, perm_code) DO NOTHING; + +-- 4. ADMIN 에는 시스템관리 제외 모든 권한 (대시보드는 자동 허용) +INSERT INTO role_menu_permission (role_id, menu_id, perm_code, is_granted) +SELECT r.role_id, mp.menu_id, mp.perm_code, 'Y' +FROM role r +CROSS JOIN menu_permission mp +JOIN menu m ON m.menu_id = mp.menu_id +JOIN menu pm ON pm.menu_id = m.parent_menu_id +WHERE r.role_code = 'ADMIN' AND pm.menu_code <> 'SYSTEM' +ON CONFLICT (role_id, menu_id, perm_code) DO NOTHING; + +-- 5. MANAGER 에는 조회/등록/수정/엑셀만 (승인/삭제 제외, 시스템관리 제외) +INSERT INTO role_menu_permission (role_id, menu_id, perm_code, is_granted) +SELECT r.role_id, mp.menu_id, mp.perm_code, 'Y' +FROM role r +CROSS JOIN menu_permission mp +JOIN menu m ON m.menu_id = mp.menu_id +JOIN menu pm ON pm.menu_id = m.parent_menu_id +WHERE r.role_code = 'MANAGER' + AND pm.menu_code <> 'SYSTEM' + AND mp.perm_code IN ('READ','CREATE','UPDATE','EXPORT') +ON CONFLICT (role_id, menu_id, perm_code) DO NOTHING; + +-- 6. AGENT 에는 본인 정보 조회 권한만 (LEDGER/SETTLE READ) +INSERT INTO role_menu_permission (role_id, menu_id, perm_code, is_granted) +SELECT r.role_id, mp.menu_id, 'READ', 'Y' +FROM role r +CROSS JOIN menu_permission mp +JOIN menu m ON m.menu_id = mp.menu_id +WHERE r.role_code = 'AGENT' + AND m.menu_code IN ('LEDGER_RECRUIT','LEDGER_MAINTAIN','SETTLE_LIST') + AND mp.perm_code = 'READ' +ON CONFLICT (role_id, menu_id, perm_code) DO NOTHING; + +-- 7. admin 사용자 (BCrypt: admin1234!) +INSERT INTO users (login_id, password, user_name, email, status, fail_count, pwd_changed_at, created_at) +VALUES ('admin', '$2b$10$NClaIICfNMTGWyto9X6gV.yrnYEyiQeakgirWfxRJh.vYfDtubKdu', + '시스템 관리자', 'admin@example.com', 'ACTIVE', 0, NOW(), NOW()) +ON CONFLICT (login_id) DO NOTHING; + +-- 8. admin → SUPER_ADMIN 매핑 +INSERT INTO user_role (user_id, role_id) +SELECT u.user_id, r.role_id +FROM users u, role r +WHERE u.login_id = 'admin' AND r.role_code = 'SUPER_ADMIN' +ON CONFLICT (user_id, role_id) DO NOTHING; diff --git a/ga-common/src/main/resources/mybatis/mybatis-config.xml b/ga-common/src/main/resources/mybatis/mybatis-config.xml index 792b043..8652ef7 100644 --- a/ga-common/src/main/resources/mybatis/mybatis-config.xml +++ b/ga-common/src/main/resources/mybatis/mybatis-config.xml @@ -11,8 +11,8 @@ - - + +