arko_renual/src/script/mysql/privacy.install_mysql.sql
infraurp 2a2ab99d10 개인정보보호 기능개선 사업 구현 (SFR-001~004, 권한관리·인증체계·접속기록)
권한관리(SFR-001):
- getAuthorities() 구현(EgovUserAuthorityDAO), AuthorityInterceptor 역할별 URL 접근제어
  (COMTNMENUCREATDTLS×COMTNMENUINFO×COMTNPROGRMLIST 메뉴권한 기반, 캐시/TTL, ROLE_ADMIN 바이패스)
- 권한 신청·승인 워크플로 + AUTHOR_CHANGE_HISTORY 이력(3년 보관), 조회·다운로드
계정관리(SFR-002): 계정관리정책, 장기미사용(휴면) 확장(취급자 포함)·사전알림, 계정잠금 5회
인증체계(SFR-003): 로그인 통합 2단계 인증(SecondFactorInterceptor+SecondFactorController),
  OTP QR 등록(ZXing)·비밀키 DB 영속(OTP_DEVICE, AES-GCM), 세션재발급(고정공격 방지), 자동로그아웃 30분
접속기록(SFR-004): PERSONAL_DATA_ACCESS_LOG(월파티션), PersonalDataLogAspect 한정수집,
  SHA-256 해시체인 무결성, 업무유형매핑, IP 취득보정, 비정상접근 탐지, 정기점검 리포트
DB: privacy DDL 11종 + 설치용 통합 SQL(privacy.install_mysql.sql, DDL+시드 DML)
빌드복구: pom.xml 시스템 jar/JAXB 선언, iBatis2 SQL주석 '#'→'No.' 정정

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 18:03:02 +09:00

510 lines
39 KiB
SQL

-- #####################################################################
-- arko_renual 설치용 통합 SQL (개인정보보호 기능개선 사업 · arko 대비 변동분)
-- 대상 DB : MySQL 5.7 / MariaDB (스키마 csv)
-- 구성 : [PART 1] DDL(테이블 생성·변경) → [PART 2] DML(기준/시드 데이터)
-- 실행순서: 반드시 PART 1 → PART 2 순서로 실행(테이블 생성 후 시드 적재)
-- 주의 : 신규 설치용. 기존 테이블이 있는 환경 재실행 시 CREATE 중복 오류 가능
-- (IF NOT EXISTS 미지정 테이블). 그런 환경은 PART 2(DML)만 실행하세요.
-- #####################################################################
-- =====================================================================
-- PART 1. DDL (테이블 생성 / 컬럼 확장) ※ 시드 INSERT는 PART 2로 분리
-- =====================================================================
-- ─────────────────────────────────────────────────────────────
-- [privacy.account_mng_policy_create_mysql.sql]
-- ─────────────────────────────────────────────────────────────
-- =====================================================================
-- 계정 관리 정책 : ACCOUNT_MNG_POLICY (단일행 정책 테이블)
-- 문화품앗이 개인정보보호 기능개선 사업 (SFR-002, 장기 미사용 계정 관리)
-- 개발항목 #13(정책 설정) + #9(휴면 기준일수 정책값화) - 담당: arko-privacy-authctrl (Fork A)
-- 작성일: 2026-07-21 DB: MySQL 8 / MariaDB
-- ---------------------------------------------------------------------
-- [용도] 휴면 기준일수·사전알림 시점·삭제 보존기간·배치주기 등 계정 관리 정책을
-- 하드코딩이 아닌 관리자 설정값으로 운영하기 위한 단일행 정책 테이블.
-- [#9] 휴면 select(EgovLoginUsr_SQL_Mysql.xml)의 365 하드코딩을
-- (SELECT DORMANT_DAY FROM ACCOUNT_MNG_POLICY) 로 대체(미설정 시 365 fallback).
-- [#10] ALERT_D1/D2/D3(기본 30/7/0) = 휴면예정 D-30/D-7/D-Day 사전알림 시점.
-- ADMIN_EMAIL = 사전알림 관리자 수신 주소.
-- =====================================================================
CREATE TABLE IF NOT EXISTS ACCOUNT_MNG_POLICY (
POLICY_ID INT NOT NULL DEFAULT 1 COMMENT '정책 식별자(단일행=1)',
DORMANT_DAY INT NOT NULL DEFAULT 365 COMMENT '휴면 전환 기준 미접속 일수(#9)',
ALERT_D1 INT NOT NULL DEFAULT 30 COMMENT '사전알림 1차(휴면 D-일수)',
ALERT_D2 INT NOT NULL DEFAULT 7 COMMENT '사전알림 2차(휴면 D-일수)',
ALERT_D3 INT NOT NULL DEFAULT 0 COMMENT '사전알림 3차(D-Day, 0=당일)',
DELETE_PRESERVE_DAY INT NOT NULL DEFAULT 365 COMMENT '휴면/탈퇴 후 삭제 보존기간(일)',
BATCH_CYCLE VARCHAR(20) NOT NULL DEFAULT 'DAILY' COMMENT '배치 주기(DAILY/WEEKLY/MONTHLY)',
ADMIN_EMAIL VARCHAR(200) NULL COMMENT '사전알림 관리자 수신 이메일',
UPD_ID VARCHAR(20) NULL COMMENT '최종 수정자',
UPD_DT DATETIME NULL COMMENT '최종 수정일시',
PRIMARY KEY (POLICY_ID)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
COMMENT='계정 관리 정책(개인정보보호 SFR-002, 단일행)';
-- 기본 정책 시드(없을 때만). 기준 365일·알림 D-30/7/0·보존 365일.
-- ─────────────────────────────────────────────────────────────
-- [privacy.account_unlock_history_create_mysql.sql]
-- ─────────────────────────────────────────────────────────────
-- =====================================================================
-- 계정 잠금 해제 이력 : ACCOUNT_UNLOCK_HISTORY
-- 문화품앗이 개인정보보호 기능개선 사업 (SER-001, 계정 잠금 정책 정비)
-- 개발항목 #24 - 담당: arko-privacy-authctrl (Fork A)
-- 작성일: 2026-07-21 DB: MySQL 8 / MariaDB
-- ---------------------------------------------------------------------
-- [목적] 잠긴 계정 해제를 DB 직접조작이 아니라 관리자 화면(EgovAccountUnlockManage)
-- 에서 처리하고, 해제자·해제일시·대상·사유를 이력으로 남긴다.
-- [무결성] 애플리케이션 계층에 UPDATE/DELETE statement 미정의(INSERT/SELECT 한정).
-- =====================================================================
CREATE TABLE ACCOUNT_UNLOCK_HISTORY (
UNLOCK_HIST_ID BIGINT NOT NULL AUTO_INCREMENT COMMENT '해제 이력 일련번호(PK)',
TRGET_ID VARCHAR(50) NULL COMMENT '해제 대상 계정 ID(전체해제 시 NULL 가능)',
TRGET_SE VARCHAR(10) NULL COMMENT '대상 회원구분 GNR/GRO/ENT/USR',
UNLOCK_TY CHAR(1) NOT NULL DEFAULT 'I' COMMENT '해제 유형 I:개별 A:전체',
UNLOCK_USER_ID VARCHAR(50) NULL COMMENT '해제 처리자(관리자) ID',
UNLOCK_RESN VARCHAR(500) NULL COMMENT '해제 사유',
UNLOCK_IP VARCHAR(45) NULL COMMENT '해제자 접속 IP(IPv6 대응)',
UNLOCK_DT DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '해제 일시',
PRIMARY KEY (UNLOCK_HIST_ID),
KEY IX_AUH_TRGET (TRGET_ID, UNLOCK_DT),
KEY IX_AUH_USER (UNLOCK_USER_ID, UNLOCK_DT),
KEY IX_AUH_DT (UNLOCK_DT)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
COMMENT='계정 잠금 해제 이력(개인정보보호 SER-001 #24)';
-- =====================================================================
-- 계정 잠금 임계값 10회 → 5회 (#24)
-- 임계값은 하드코딩이 아니라 LOGIN_LOCK_COUNT.LOCK_COUNT(단일행) 데이터에서 조회됨
-- (loginDAO.selectFailTotalCount). 아래 UPDATE 로 운영 정책값을 5회로 조정한다.
-- ※ 소스(EgovLoginController)에는 값 부재 시 기본 5회 fallback 이 반영되어 있음.
-- =====================================================================
UPDATE LOGIN_LOCK_COUNT SET LOCK_COUNT = 5;
-- 행이 없을 경우 대비(최초 세팅):
-- INSERT INTO LOGIN_LOCK_COUNT (LOCK_COUNT) SELECT 5 FROM DUAL
-- WHERE NOT EXISTS (SELECT 1 FROM LOGIN_LOCK_COUNT);
-- ─────────────────────────────────────────────────────────────
-- [privacy.author_change_history_create_mysql.sql]
-- ─────────────────────────────────────────────────────────────
-- =====================================================================
-- 권한 변경 이력 테이블 : AUTHOR_CHANGE_HISTORY
-- 문화품앗이 개인정보보호 기능개선 사업 (SFR-001, 역할별 차등 접근/권한 변경 추적)
-- 개발항목 #4 - 담당: arko-privacy-authctrl (Fork A → 오케스트레이터 완료)
-- 작성일: 2026-07-21 DB: MySQL 8 / MariaDB
-- ---------------------------------------------------------------------
-- [목적] 권한 신설·변경·회수(#1 getAuthorities 대상 COMTNEMPLYRSCRTYESTBS 등)의
-- 모든 변경을 변경자·변경일시·변경전/후 권한과 함께 이력으로 적재한다.
-- 권한 신청·승인 워크플로(#3)의 승인 반영 시점에 권한반영과 단일 트랜잭션으로 적재.
--
-- [보관·파기] 3년(1,095일) 이상 보관 전제. 월 1회 @Scheduled 파기 배치(#5)가
-- 보관기간(1,095일) 경과 이력만 선별 파기한다. 개별 삭제 API 미제공.
-- 다운로드 시 사유 입력 필수 + 다운로드 이력 적재(#6)는 별도 처리.
--
-- [무결성] 이력 위·변조 억제를 위해 변경전/후 권한을 함께 보관(사후 대사 가능).
-- 애플리케이션 계층에 UPDATE statement 미정의(INSERT/SELECT/파기 DELETE 한정).
-- =====================================================================
CREATE TABLE AUTHOR_CHANGE_HISTORY (
HIST_ID BIGINT NOT NULL AUTO_INCREMENT COMMENT '이력 일련번호(PK)',
TRGET_UNIQ_ID VARCHAR(20) NOT NULL COMMENT '변경 대상자 고유식별자(ESNTL_ID)',
TRGET_ID VARCHAR(20) NULL COMMENT '변경 대상자 계정ID(참고용)',
CHG_SE_CODE CHAR(1) NOT NULL COMMENT '변경구분 G:부여(grant) R:회수(revoke) M:변경(modify)',
BEFORE_AUTHOR VARCHAR(1000) NULL COMMENT '변경 전 권한(코드 CSV 또는 스냅샷)',
AFTER_AUTHOR VARCHAR(1000) NULL COMMENT '변경 후 권한(코드 CSV 또는 스냅샷)',
CHG_RESN VARCHAR(500) NULL COMMENT '변경 사유(신청/승인 워크플로 연계 #3)',
APROVL_ID VARCHAR(20) NULL COMMENT '승인자 계정ID(승인 워크플로 #3)',
CHANGER_UNIQ_ID VARCHAR(20) NOT NULL COMMENT '변경자(처리자) 고유식별자',
CHANGER_ID VARCHAR(20) NULL COMMENT '변경자 계정ID(참고용)',
CHANGER_IP VARCHAR(45) NULL COMMENT '변경자 접속 IP(IPv6 대응)',
CHG_DT DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '변경 일시',
PRIMARY KEY (HIST_ID),
KEY IX_ACH_TRGET (TRGET_UNIQ_ID, CHG_DT),
KEY IX_ACH_CHANGER (CHANGER_UNIQ_ID, CHG_DT),
KEY IX_ACH_CHGDT (CHG_DT)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
COMMENT='권한 변경 이력(개인정보보호 SFR-001, 3년 이상 보관)';
-- ─────────────────────────────────────────────────────────────
-- [privacy.author_workflow_create_mysql.sql]
-- ─────────────────────────────────────────────────────────────
-- =====================================================================
-- 권한 신청·승인 워크플로 + 권한이력 다운로드 이력
-- 문화품앗이 개인정보보호 기능개선 사업 (SFR-001, 권한 신설·변경·회수 승인통제)
-- 개발항목 #3(신청·승인 워크플로) / #6(권한이력 조회·다운로드) - 담당: arko-privacy-authctrl (Fork A 6차)
-- 작성일: 2026-07-21 DB: MySQL 8 / MariaDB
-- ---------------------------------------------------------------------
-- [#3] AUTHOR_CHANGE_REQUEST : 권한 변경 신청→승인/반려 워크플로.
-- 승인(A) 시 권한 반영(COMTNEMPLYRSCRTYESTBS)과 이력 적재(AUTHOR_CHANGE_HISTORY)를
-- 단일 트랜잭션으로 처리한다(egovframework.com..*Impl AOP tx advisor).
-- [#6] AUTHOR_HIST_DOWNLOAD_HISTORY : 권한이력 다운로드 증빙(사유 필수).
-- =====================================================================
CREATE TABLE AUTHOR_CHANGE_REQUEST (
REQUEST_ID BIGINT NOT NULL AUTO_INCREMENT COMMENT '신청 일련번호(PK)',
TRGET_UNIQ_ID VARCHAR(20) NOT NULL COMMENT '권한변경 대상자 고유식별자(ESNTL_ID)',
TRGET_ID VARCHAR(20) NULL COMMENT '권한변경 대상자 계정ID(참고용)',
REQUEST_SE CHAR(1) NOT NULL COMMENT '신청구분 N:신설(부여) C:변경 R:회수',
BEFORE_AUTHOR VARCHAR(1000) NULL COMMENT '신청 시점 현재 권한(스냅샷)',
AFTER_AUTHOR VARCHAR(1000) NULL COMMENT '신청 목표 권한(코드/CSV)',
REQUEST_RESN VARCHAR(500) NOT NULL COMMENT '신청 사유(필수)',
REQSTER_ID VARCHAR(20) NOT NULL COMMENT '신청자 계정ID',
REQSTER_UNIQ_ID VARCHAR(20) NULL COMMENT '신청자 고유식별자',
REQUEST_DT DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '신청 일시',
CONFM_STTUS CHAR(1) NOT NULL DEFAULT 'R' COMMENT '처리상태 R:신청 A:승인 J:반려',
CONFM_ID VARCHAR(20) NULL COMMENT '승인/반려 처리자 계정ID',
CONFM_UNIQ_ID VARCHAR(20) NULL COMMENT '승인/반려 처리자 고유식별자',
CONFM_DT DATETIME NULL COMMENT '승인/반려 일시',
CONFM_RESN VARCHAR(500) NULL COMMENT '반려 사유',
PRIMARY KEY (REQUEST_ID),
KEY IX_ACR_TRGET (TRGET_UNIQ_ID, REQUEST_DT),
KEY IX_ACR_STTUS (CONFM_STTUS, REQUEST_DT)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
COMMENT='권한 변경 신청·승인 워크플로(개인정보보호 SFR-001 #3)';
CREATE TABLE AUTHOR_HIST_DOWNLOAD_HISTORY (
DWLD_ID BIGINT NOT NULL AUTO_INCREMENT COMMENT '다운로드 일련번호(PK)',
DOWNLOADER_ID VARCHAR(20) NOT NULL COMMENT '다운로드자 계정ID',
DOWNLOADER_UNIQ_ID VARCHAR(20) NULL COMMENT '다운로드자 고유식별자',
DOWNLOADER_IP VARCHAR(45) NULL COMMENT '다운로드자 접속 IP(IPv6 대응)',
DWLD_RESN VARCHAR(500) NOT NULL COMMENT '다운로드 사유(필수·미입력 차단)',
SEARCH_COND VARCHAR(1000) NULL COMMENT '다운로드 시 검색조건 스냅샷',
DWLD_CNT INT NOT NULL DEFAULT 0 COMMENT '다운로드 건수',
DWLD_DT DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '다운로드 일시',
PRIMARY KEY (DWLD_ID),
KEY IX_AHD_DWLD (DOWNLOADER_ID, DWLD_DT)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
COMMENT='권한이력 다운로드 증빙 이력(개인정보보호 SFR-001 #6)';
-- ─────────────────────────────────────────────────────────────
-- [privacy.job_mapping_create_mysql.sql]
-- ─────────────────────────────────────────────────────────────
-- =====================================================================
-- 개인정보 처리 업무유형 매핑 테이블 : PDAL_JOB_MAPPING
-- 문화품앗이 개인정보보호 기능개선 사업 (SFR-004 / SER-002)
-- 개발항목 #32 - 담당: arko-privacy-auditlog (Fork B)
-- 작성일: 2026-07-21 DB: MySQL 8 / MariaDB
-- ---------------------------------------------------------------------
-- [목적] 접속기록 수집(#31 PersonalDataLogAspect)이 가로챈 서비스 메서드를
-- 업무코드(JOB_SE_CODE)·업무명(JOB_SE_NM)으로 매핑한다.
-- AOP pointcut 범위(개인정보 처리 서비스 패키지) 안에서 신규 화면이 추가되면
-- 이 테이블에 행만 등록하면 수집되며, Aspect/pointcut 소스 수정이 불요하다.
--
-- [매칭 규칙] Aspect가 (대상클래스 단순명, 메서드명)으로 조회.
-- - TARGET_CLASS : 서비스 impl 단순 클래스명(예: EgovMberManageServiceImpl) 또는 FQN
-- - METHOD_PTTRN : 메서드명 접두 매칭(예: 'select','insertMber') 또는 '*'(전체)
-- - DML_GUBUN : 지정 시 우선, NULL이면 메서드명 접두로 유도(insert*→I/update*→U/delete*→D/그외 S)
-- - SORT_ORDR : 다중 매칭 시 낮은 값 우선(구체 규칙을 위로)
--
-- ※ URL 패턴 기반 수집이 필요하면(서블릿 필터형) 동일 테이블에 URL_PTTRN 컬럼을 추가해 확장.
-- =====================================================================
CREATE TABLE PDAL_JOB_MAPPING (
MAPPING_ID BIGINT NOT NULL AUTO_INCREMENT COMMENT '매핑 일련번호(PK)',
TARGET_CLASS VARCHAR(200) NOT NULL COMMENT '대상 서비스 impl 단순 클래스명 또는 FQN',
METHOD_PTTRN VARCHAR(100) NOT NULL DEFAULT '*' COMMENT '메서드명 접두 매칭(또는 * 전체)',
JOB_SE_CODE VARCHAR(30) NOT NULL COMMENT '수행업무 유형 코드',
JOB_SE_NM VARCHAR(100) NOT NULL COMMENT '수행업무 유형(화면·기능명)',
DML_GUBUN CHAR(1) NULL COMMENT '처리구분 강제값 S/I/U/D (NULL=메서드명 유도)',
SORT_ORDR INT NOT NULL DEFAULT 100 COMMENT '매칭 우선순위(낮을수록 우선)',
USE_AT CHAR(1) NOT NULL DEFAULT 'Y' COMMENT '사용여부 Y/N',
RM VARCHAR(300) NULL COMMENT '비고',
PRIMARY KEY (MAPPING_ID),
KEY IX_PJM_LOOKUP (USE_AT, TARGET_CLASS, SORT_ORDR)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
COMMENT='개인정보 처리 업무유형 매핑(접속기록 #31/#32)';
-- ---------------------------------------------------------------------
-- 초기 매핑 시드 : 현행 개인정보 처리 서비스(#31 pointcut 대상과 일치)
-- 신규 개인정보 화면 추가 시 아래 형식으로 행만 추가하면 수집된다.
-- ---------------------------------------------------------------------
-- ─────────────────────────────────────────────────────────────
-- [privacy.download_history_create_mysql.sql]
-- ─────────────────────────────────────────────────────────────
-- =====================================================================
-- 개인정보 접속기록 다운로드 이력 : PDAL_DOWNLOAD_HISTORY
-- 문화품앗이 개인정보보호 기능개선 사업 (SFR-004 / SER-002)
-- 개발항목 #42 - 담당: arko-privacy-auditlog (Fork B)
-- 작성일: 2026-07-21 DB: MySQL 8 / MariaDB
-- ---------------------------------------------------------------------
-- [목적] 개인정보 접속기록(PERSONAL_DATA_ACCESS_LOG) 조회결과 다운로드 시,
-- 다운로드 사유(필수)·다운로드자·일시·IP·건수를 이력으로 남긴다.
-- 사유 미입력 시 다운로드는 서비스 계층에서 차단(본 테이블 미적재).
-- [원칙] 개인정보 본문 미적재 — 다운로드 검색조건 요약(SEARCH_COND)만 보관.
-- 이 테이블은 INSERT/SELECT 만 수행(위·변조 방지, UPDATE/DELETE 미정의).
-- =====================================================================
CREATE TABLE PDAL_DOWNLOAD_HISTORY (
DL_ID BIGINT NOT NULL AUTO_INCREMENT COMMENT '다운로드 이력 일련번호(PK)',
DOWNLOADER_ID VARCHAR(20) NOT NULL COMMENT '다운로드자 계정ID',
DOWNLOAD_DT DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '다운로드 일시',
DOWNLOADER_IP VARCHAR(45) NULL COMMENT '다운로드자 접속 IP(IPv6 대응)',
DL_REASON VARCHAR(500) NOT NULL COMMENT '다운로드 사유(필수 — 미입력 시 차단)',
SEARCH_COND VARCHAR(1000) NULL COMMENT '다운로드 검색조건 요약(개인정보 본문 미포함)',
RESULT_CNT INT NOT NULL DEFAULT 0 COMMENT '다운로드 건수',
REG_DT DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '등록 일시',
PRIMARY KEY (DL_ID),
KEY IX_PDDH_DT (DOWNLOAD_DT),
KEY IX_PDDH_USER (DOWNLOADER_ID, DOWNLOAD_DT)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
COMMENT='개인정보 접속기록 다운로드 이력(#42, SER-002)';
-- [Oracle] 시퀀스 필요:
-- CREATE SEQUENCE PDAL_DOWNLOAD_HISTORY_SEQ START WITH 1 INCREMENT BY 1 NOCACHE;
-- ─────────────────────────────────────────────────────────────
-- [privacy.inspection_report_create_mysql.sql]
-- ─────────────────────────────────────────────────────────────
-- =====================================================================
-- 개인정보 접속기록 정기점검 리포트 : PDAL_INSPECTION_REPORT
-- 문화품앗이 개인정보보호 기능개선 사업 (SFR-004 / SER-002)
-- 개발항목 #43 - 담당: arko-privacy-auditlog (Fork B)
-- 작성일: 2026-07-21 DB: MySQL 8 / MariaDB
-- ---------------------------------------------------------------------
-- [목적] 월 1회 정기점검 배치가 전월분 접속기록을 집계해 1행으로 적재한다.
-- "월 1회 이상 점검 내역"을 화면 출력으로 제출(개인정보보호위 점검 대응).
--
-- [집계원] PERSONAL_DATA_ACCESS_LOG(#30) + 해시체인 무결성 검증(#40) 재사용.
-- [자리표시] 이상징후 5유형(#35)·다운로드 이력(#42)은 미구현 → 컬럼만 두고 배치가 0/요약만 적재.
-- [화면입력] INSPECTOR_ID/INSPECT_RESULT/ACTN_MATTER 는 배치가 아닌 점검자가 화면(#48)에서 입력.
-- =====================================================================
CREATE TABLE PDAL_INSPECTION_REPORT (
RPT_ID BIGINT NOT NULL AUTO_INCREMENT COMMENT '리포트 일련번호(PK)',
RPT_YM CHAR(6) NOT NULL COMMENT '점검 대상 연월(전월, yyyyMM)',
PERIOD_FROM DATETIME NOT NULL COMMENT '집계 시작일시',
PERIOD_TO DATETIME NOT NULL COMMENT '집계 종료일시',
TOTAL_LOG_CNT INT NOT NULL DEFAULT 0 COMMENT '총 접속기록 건수',
FAIL_CNT INT NOT NULL DEFAULT 0 COMMENT '처리결과 F(실패/차단) 건수 = 이상징후 일부',
ABNORMAL_SUMMARY VARCHAR(2000) NULL COMMENT '이상징후 5유형 요약(#35 연계 전 자리표시)',
INTEGRITY_RESULT VARCHAR(20) NOT NULL DEFAULT 'OK' COMMENT '해시체인 무결성: OK / VIOLATION',
INTEGRITY_MISMATCH_ID BIGINT NULL COMMENT '최초 불일치 LOG_ID(위반 시)',
INTEGRITY_TOTAL_CNT INT NOT NULL DEFAULT 0 COMMENT '무결성 검증 대상 건수',
HANDLER_SUMMARY VARCHAR(4000) NULL COMMENT '취급자별 처리현황 요약',
DOWNLOAD_CNT INT NOT NULL DEFAULT 0 COMMENT '다운로드 이력 건수(#42 연계 전 0)',
INSPECTOR_ID VARCHAR(20) NULL COMMENT '점검자 계정ID(화면 입력, #44)',
INSPECT_RESULT VARCHAR(500) NULL COMMENT '점검결과(화면 입력, #44)',
ACTN_MATTER VARCHAR(1000) NULL COMMENT '조치사항(화면 입력, #44)',
INSPECT_DT DATETIME NULL COMMENT '점검일시(점검결과 입력 시각, #44 감사증빙)',
REG_DT DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '리포트 생성일시',
PRIMARY KEY (RPT_ID),
UNIQUE KEY UX_PIR_YM (RPT_YM),
KEY IX_PIR_REGDT (REG_DT)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
COMMENT='개인정보 접속기록 정기점검 리포트(#43, 월 1회)';
-- ─────────────────────────────────────────────────────────────
-- [privacy.pdal_create_mysql.sql]
-- ─────────────────────────────────────────────────────────────
-- =====================================================================
-- 개인정보 접속기록 표준 테이블 : PERSONAL_DATA_ACCESS_LOG
-- 문화품앗이 개인정보보호 기능개선 사업 (SFR-004 / DBR-001 / SER-002)
-- 개발항목 #30 - 담당: arko-privacy-auditlog (Fork B)
-- 작성일: 2026-07-21 DB: MySQL 8 / MariaDB
-- ---------------------------------------------------------------------
-- [설계 원칙] 신규 스키마 설계가 아니라 기존 표준 PERSONAL_DATA_DML_HISTORY 를
-- 표준 접속기록 테이블로 "승격" + 보관/무결성 컬럼 확장이다.
--
-- [기존 PERSONAL_DATA_DML_HISTORY → PERSONAL_DATA_ACCESS_LOG 컬럼 매핑]
-- CHG_USER_ID → CONECT_ID (① 사용자 식별자)
-- CREATE_DATE → CONECT_DT (② 접속일시, SYSDATE())
-- CHG_CONECT_IP → CONECT_IP (③ 접속지 IP) * VARCHAR(45) IPv6 대응
-- UI_GUBUN → JOB_SE_CODE/NM (④ 수행업무 유형) * 업무유형 매핑 테이블로 코드/명 분리
-- ESNTL_ID → TRGET_ID (⑤ 처리대상 식별자)
-- DML_GUBUN → DML_GUBUN (처리구분 S/I/U/D 그대로 계승)
-- CHG_USER_SE → USER_SE (처리자 구분)
-- [신규 확장 컬럼]
-- TRGET_CN - 처리대상 건수/범위 (⑤ 보강)
-- PROCESS_RESULT - 처리결과 S:성공 F:실패/차단 (비정상접근 탐지 5유형 적재 겸용)
-- HASH_VAL - 위·변조 방지 해시 (SHA-256, 개발항목 #39)
-- PREV_HASH_VAL - 직전 레코드 해시 (해시체인)
--
-- [보관·파기] 730일 보관 전제. 월 단위 RANGE COLUMNS 파티셔닝으로
-- 파기 배치가 만료 파티션을 ALTER TABLE ... DROP PARTITION 으로 제거
-- (개별 DELETE 미사용). 애플리케이션 계층에 UPDATE/DELETE statement 미정의.
-- [분리 원칙] COMTNSYSLOG 의 7일 삭제정책은 본 테이블에 절대 적용하지 않는다.
-- =====================================================================
CREATE TABLE PERSONAL_DATA_ACCESS_LOG
(
LOG_ID BIGINT NOT NULL AUTO_INCREMENT COMMENT '로그 일련번호',
CONECT_ID VARCHAR(20) NOT NULL COMMENT '① 사용자 식별자(ID)',
CONECT_DT DATETIME NOT NULL COMMENT '② 접속일시(파티션 키)',
CONECT_IP VARCHAR(45) NOT NULL COMMENT '③ 접속지 정보(IP, IPv6 대응)',
JOB_SE_CODE VARCHAR(30) NOT NULL COMMENT '④ 수행업무 유형 코드',
JOB_SE_NM VARCHAR(100) NOT NULL COMMENT '④ 수행업무 유형 명(화면/기능명)',
TRGET_ID VARCHAR(50) NULL COMMENT '⑤ 처리대상 식별자',
TRGET_CN VARCHAR(200) NULL COMMENT '⑤ 처리대상 건수/범위',
DML_GUBUN CHAR(1) NOT NULL COMMENT '처리구분 S:조회 I:등록 U:수정 D:삭제',
PROCESS_RESULT CHAR(1) NOT NULL DEFAULT 'S' COMMENT '처리결과 S:성공 F:실패/차단',
USER_SE VARCHAR(10) NULL COMMENT '처리자 구분',
HASH_VAL VARCHAR(64) NOT NULL COMMENT '위·변조 방지 해시(SHA-256 Hex)',
PREV_HASH_VAL VARCHAR(64) NULL COMMENT '직전 레코드 해시(해시체인)',
PRIMARY KEY (LOG_ID, CONECT_DT),
KEY IDX_PDAL_01 (CONECT_ID, CONECT_DT), -- 접속자 ID 검색 (현행 CONECT_MTHD LIKE 결함 해소)
KEY IDX_PDAL_02 (CONECT_DT), -- 기간 검색 / 파티션 프루닝
KEY IDX_PDAL_03 (TRGET_ID, CONECT_DT), -- 처리대상 추적
KEY IDX_PDAL_04 (JOB_SE_CODE, CONECT_DT) -- 업무유형/이상탐지유형 집계
)
ENGINE=InnoDB DEFAULT CHARSET=utf8
COMMENT='개인정보 접속기록 표준 테이블(PERSONAL_DATA_DML_HISTORY 승격, 730일 보관)'
PARTITION BY RANGE COLUMNS(CONECT_DT)
(
-- 파티션 키(CONECT_DT)를 PK에 포함해야 RANGE COLUMNS 파티셔닝 성립 (MySQL/MariaDB 제약)
-- 월 단위 사전 생성. 유지보수 배치가 매월 다음 달 파티션을 ADD PARTITION 으로 선행 생성하고,
-- 파기 배치(월 1회)가 보관기간(기본 730일) 경과 파티션을 DROP PARTITION 으로 제거한다.
-- ※ MAXVALUE 파티션은 두지 않는다 — 만료 데이터가 catch-all 에 갇혀 DROP 불가해지는 것을 방지.
PARTITION p202607 VALUES LESS THAN ('2026-08-01'),
PARTITION p202608 VALUES LESS THAN ('2026-09-01'),
PARTITION p202609 VALUES LESS THAN ('2026-10-01'),
PARTITION p202610 VALUES LESS THAN ('2026-11-01'),
PARTITION p202611 VALUES LESS THAN ('2026-12-01'),
PARTITION p202612 VALUES LESS THAN ('2027-01-01'),
PARTITION p202701 VALUES LESS THAN ('2027-02-01'),
PARTITION p202702 VALUES LESS THAN ('2027-03-01')
)
;
-- ---------------------------------------------------------------------
-- [유지보수 참고] 월별 파티션 추가/삭제 예시 (배치가 동적으로 수행)
--
-- -- 다음 달 파티션 선행 생성
-- ALTER TABLE PERSONAL_DATA_ACCESS_LOG
-- ADD PARTITION (PARTITION p202703 VALUES LESS THAN ('2027-04-01'));
--
-- -- 보관기간(730일) 경과 파티션 파기
-- ALTER TABLE PERSONAL_DATA_ACCESS_LOG DROP PARTITION p202607;
-- ---------------------------------------------------------------------
-- ─────────────────────────────────────────────────────────────
-- [privacy.pdal_purge_history_create_mysql.sql]
-- ─────────────────────────────────────────────────────────────
-- =====================================================================
-- 개인정보 접속기록 파기·증설 이력 : PDAL_PURGE_HISTORY
-- 문화품앗이 개인정보보호 기능개선 사업 (SFR-004 / DBR-001)
-- 개발항목 #37 - 담당: arko-privacy-auditlog (Fork B)
-- 작성일: 2026-07-21 DB: MySQL 8 / MariaDB
-- ---------------------------------------------------------------------
-- [목적] PERSONAL_DATA_ACCESS_LOG 의 보관정책(730일) 파기 배치가 수행한
-- 파티션 DROP(파기)·ADD(선행 증설) 내역을 증빙으로 기록한다.
-- 개인정보 접속기록의 유일한 삭제 경로가 "파티션 DROP"임을 감사에서 입증하는 근거.
--
-- [원칙] 접속기록 본문(PERSONAL_DATA_ACCESS_LOG)에는 UPDATE/DELETE 를 정의하지 않으며,
-- 파기는 개별 DELETE 가 아니라 파티션 단위 DROP 으로만 수행한다(개발항목 #37).
-- =====================================================================
CREATE TABLE PDAL_PURGE_HISTORY
(
PURGE_ID BIGINT NOT NULL AUTO_INCREMENT COMMENT '이력 일련번호',
PARTITION_NAME VARCHAR(64) NOT NULL COMMENT '대상 파티션명(예: p202607)',
BOUNDARY_DT VARCHAR(30) NULL COMMENT '파티션 상한 경계값(LESS THAN, 예: 2026-08-01)',
PURGE_TYPE VARCHAR(10) NOT NULL COMMENT '유형 DROP:파기 ADD:선행증설',
PURGE_DT DATETIME NOT NULL COMMENT '수행 일시',
NOTE VARCHAR(300) NULL COMMENT '비고(보관기간·사유)',
PRIMARY KEY (PURGE_ID),
KEY IDX_PDAL_PURGE_01 (PURGE_DT),
KEY IDX_PDAL_PURGE_02 (PARTITION_NAME)
)
ENGINE=InnoDB DEFAULT CHARSET=utf8
COMMENT='개인정보 접속기록 파티션 파기·증설 이력(개발항목 #37, 파기 증빙)';
-- ─────────────────────────────────────────────────────────────
-- [privacy.otp_device_create_mysql.sql]
-- ─────────────────────────────────────────────────────────────
-- =====================================================================
-- OTP(2단계 인증) 비밀키 영구 저장 테이블
-- 문화품앗이 개인정보보호 기능개선 사업 (SFR-003 / IAR-001, 추가 인증수단 1차 OTP)
-- 개발항목 No.18 후속 - 담당: arko-privacy-authctrl
-- 작성일: 2026-07-22 DB: MySQL 5.7/8 / MariaDB
-- ---------------------------------------------------------------------
-- [배경] OtpSecretStore 기본 구현이 InMemory(재기동 시 유실)라 이를 대체하는
-- DB 영속 저장소(DaoOtpSecretStore)가 사용하는 테이블.
-- [보안] SECRET_ENC 는 OtpSecretCipher(AES-GCM) 암호문(Base64)만 저장한다.
-- 평문 비밀키/OTP 코드는 저장하지 않는다(SER-003).
-- [키] UNIQ_ID = 개인정보취급자 고유식별자(ESNTL_ID), 취급자당 1건(PK).
-- =====================================================================
CREATE TABLE IF NOT EXISTS OTP_DEVICE (
UNIQ_ID VARCHAR(20) NOT NULL COMMENT '개인정보취급자 고유식별자(ESNTL_ID, PK)',
SECRET_ENC VARCHAR(255) NOT NULL COMMENT 'OTP 비밀키 AES-GCM 암호문(Base64) - 평문 금지',
REG_DT DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '등록(발급) 일시',
LAST_VERIFY_DT DATETIME NULL COMMENT '최종 검증 성공 일시(참고용)',
USE_CNT INT NOT NULL DEFAULT 0 COMMENT '검증 성공 누적 횟수(참고용)',
DEVICE_LABEL VARCHAR(100) NULL COMMENT '기기/계정 라벨(참고용)',
USE_YN CHAR(1) NOT NULL DEFAULT 'Y' COMMENT '사용여부 Y:사용 N:해지',
PRIMARY KEY (UNIQ_ID)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
COMMENT='OTP 2단계 인증 비밀키 영구 저장(개인정보보호 SFR-003 No.18)';
-- ─────────────────────────────────────────────────────────────
-- [privacy.diapause_emplyr_extend_mysql.sql]
-- ─────────────────────────────────────────────────────────────
-- =====================================================================
-- 휴면(장기 미사용) 대상 확장 : COMTNDIAPAUSEMBER 회원유형 구분 컬럼 추가
-- 문화품앗이 개인정보보호 기능개선 사업 (SFR-002, 장기 미사용 계정 관리)
-- 개발항목 #7 - 담당: arko-privacy-authctrl (Fork A)
-- 작성일: 2026-07-21 DB: MySQL 8 / MariaDB
-- ---------------------------------------------------------------------
-- [배경] 기존 휴면 대상은 일반회원(COMTNGNRLMBER)뿐이며, 휴면 테이블
-- COMTNDIAPAUSEMBER 에는 회원유형 구분 컬럼이 없다. 개인정보취급자
-- (COMTNEMPLYRINFO)를 휴면 대상에 포함(#7)하면서 일반회원 휴면/해제
-- 흐름과 혼선되지 않도록 회원유형 구분 컬럼을 신설한다.
--
-- [안전] DEFAULT 'GNR'(일반회원)로 신설 → 기존 적재 행은 자동 'GNR' 처리되어
-- 기존 selectDiapauseList(일반회원 join COMTNGNRLMBER) 흐름 무영향.
-- 취급자 휴면 행은 'EMP'로 적재하여 별도 select/notify 경로로 처리한다.
--
-- [멱등] 재실행 안전을 위해 컬럼 존재 시 무시(수동 확인 후 실행).
-- =====================================================================
ALTER TABLE COMTNDIAPAUSEMBER
ADD COLUMN MBER_TY_CODE CHAR(3) NOT NULL DEFAULT 'GNR'
COMMENT '회원유형 GNR:일반회원 EMP:개인정보취급자';
-- 조회 성능(취급자/일반 분리 조회) 보조 인덱스
ALTER TABLE COMTNDIAPAUSEMBER
ADD INDEX IX_DIAPAUSE_MBERTY (MBER_TY_CODE, DIAPAUSE_STAT);
-- =====================================================================
-- PART 2. DML (기준/시드 데이터) ※ 멱등: NOT EXISTS 가드로 중복 적재 방지
-- 수록: PDAL_JOB_MAPPING(업무유형 매핑 13행), ACCOUNT_MNG_POLICY(기본정책 1행)
-- 미수록: OTP_DEVICE / PERSONAL_DATA_ACCESS_LOG / *_HISTORY = 런타임 적재(시드 없음)
-- =====================================================================
-- 1) PDAL_JOB_MAPPING — 개인정보 처리 업무유형 매핑(접속기록 AOP 분류 기준, 필수)
INSERT INTO PDAL_JOB_MAPPING (TARGET_CLASS, METHOD_PTTRN, JOB_SE_CODE, JOB_SE_NM, DML_GUBUN, SORT_ORDR, RM)
SELECT * FROM (
SELECT 'EgovMberManageServiceImpl' AS TARGET_CLASS, 'select' AS METHOD_PTTRN, 'MBER_VIEW' AS JOB_SE_CODE, '회원관리-조회' AS JOB_SE_NM, 'S' AS DML_GUBUN, 10 AS SORT_ORDR, '회원 개인정보 조회' AS RM UNION ALL
SELECT 'EgovMberManageServiceImpl', 'insert', 'MBER_REG', '회원관리-등록', 'I', 10, NULL UNION ALL
SELECT 'EgovMberManageServiceImpl', 'update', 'MBER_MOD', '회원관리-수정', 'U', 10, NULL UNION ALL
SELECT 'EgovMberManageServiceImpl', 'delete', 'MBER_DEL', '회원관리-삭제', 'D', 10, NULL UNION ALL
SELECT 'EgovMberManageServiceImpl', '*', 'MBER_ETC', '회원관리-기타', NULL, 90, '미분류 폴백' UNION ALL
SELECT 'EgovEntrprsManageServiceImpl', 'select', 'ENTRPRS_VIEW', '업체관리-조회', 'S', 10, '업체 담당자 개인정보 조회' UNION ALL
SELECT 'EgovEntrprsManageServiceImpl', 'insert', 'ENTRPRS_REG', '업체관리-등록', 'I', 10, NULL UNION ALL
SELECT 'EgovEntrprsManageServiceImpl', 'update', 'ENTRPRS_MOD', '업체관리-수정', 'U', 10, NULL UNION ALL
SELECT 'EgovEntrprsManageServiceImpl', 'delete', 'ENTRPRS_DEL', '업체관리-삭제', 'D', 10, NULL UNION ALL
SELECT 'EgovEntrprsManageServiceImpl', '*', 'ENTRPRS_ETC', '업체관리-기타', NULL, 90, '미분류 폴백' UNION ALL
SELECT 'MberSsnServiceImpl', '*', 'MBER_SSN', '회원 고유식별정보 처리', NULL, 20, '주민등록번호 등 고유식별정보' UNION ALL
SELECT 'BizMberMergeServiceImpl', '*', 'MBER_MERGE', '회원 통합/이관', NULL, 30, NULL UNION ALL
SELECT 'BizTalentMberManageServiceImpl', '*', 'TALENT_MBER', '재능나눔 회원관리', NULL, 30, NULL
) seed
WHERE NOT EXISTS (SELECT 1 FROM PDAL_JOB_MAPPING pjm WHERE pjm.JOB_SE_CODE = seed.JOB_SE_CODE);
-- 2) ACCOUNT_MNG_POLICY — 장기 미사용 계정 관리 기본정책(단일행 POLICY_ID=1)
INSERT INTO ACCOUNT_MNG_POLICY (POLICY_ID, DORMANT_DAY, ALERT_D1, ALERT_D2, ALERT_D3, DELETE_PRESERVE_DAY, BATCH_CYCLE, UPD_ID, UPD_DT)
SELECT 1, 365, 30, 7, 0, 365, 'DAILY', 'SYSTEM', NOW()
FROM DUAL
WHERE NOT EXISTS (SELECT 1 FROM ACCOUNT_MNG_POLICY WHERE POLICY_ID = 1);
-- (부록) LOGIN_LOCK_COUNT — 기존 arko 테이블(변동분 아님). 미존재 신규 환경에서만 사용(기본 5):
-- INSERT INTO LOGIN_LOCK_COUNT (LOCK_COUNT)
-- SELECT 5 FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM LOGIN_LOCK_COUNT);
-- ############################## END ##############################