김진영 김진영 09-15
전송자격인증제 migration
@a3957e7b96828a41f2312869b2bc9bf0277ba6a7
DATABASE/mysql/all_ebt_ddl_mysql.sql
--- DATABASE/mysql/all_ebt_ddl_mysql.sql
+++ DATABASE/mysql/all_ebt_ddl_mysql.sql
@@ -148,6 +148,8 @@
   ESNTL_ID char(20) NOT NULL,
   CRTFC_DN_VALUE varchar(20) DEFAULT NULL,
   SBSCRB_DE datetime DEFAULT NULL,
+  REGISTER_ID varchar(20) DEFAULT NULL COMMENT '등록자(계정을 등록한 관리자 로그인ID)',
+  REGIST_RESN varchar(500) DEFAULT NULL COMMENT '등록사유(권한 부여 사유)',
   PRIMARY KEY (EMPLYR_ID),
   KEY LETTNEMPLYRINFO_ibfk_2 (GROUP_ID),
   KEY LETTNEMPLYRINFO_ibfk_1 (ORGNZT_ID),
 
DATABASE/mysql/alter_LETTNEMPLYRINFO_register_info.sql (added)
+++ DATABASE/mysql/alter_LETTNEMPLYRINFO_register_info.sql
@@ -0,0 +1,11 @@
+-- =====================================================================
+-- 전송자격인증제 3.2 접근권한 부여의 적정성 ③
+--  : 관리자(업무사용자) 계정 등록 시 "등록자 / 등록사유" 기록
+-- 대상 테이블 : LETTNEMPLYRINFO (업무사용자 정보)
+-- Redmine #5799
+-- 적용 순서 : local -> dev -> prod (배포 전 각 환경 DB에 수동 반영)
+-- =====================================================================
+
+ALTER TABLE LETTNEMPLYRINFO
+    ADD COLUMN REGISTER_ID varchar(20)  DEFAULT NULL COMMENT '등록자(계정을 등록한 관리자 로그인ID)' AFTER SBSCRB_DE,
+    ADD COLUMN REGIST_RESN varchar(500) DEFAULT NULL COMMENT '등록사유(권한 부여 사유)'          AFTER REGISTER_ID;
 
docs/superpowers/.sdd-reports/task-5-report.md (added)
+++ docs/superpowers/.sdd-reports/task-5-report.md
@@ -0,0 +1,84 @@
+# Task 5 Report: 토큰 인증 인터셉터 + 매핑 + 시큐리티 예외
+
+## Files Changed
+
+### Created
+- `src/main/java/itn/com/cmm/interceptor/DashboardApiAuthInterceptor.java`
+
+### Modified
+- `src/main/webapp/WEB-INF/config/egovframework/springmvc/egov-interceptor-servlet.xml`
+- `src/main/resources/egovframework/spring/com/context-security.xml`
+
+---
+
+## XML Snippets Added
+
+### egov-interceptor-servlet.xml — inside `<interceptors>`, first position
+
+```xml
+    <!-- 대시보드 요약 API 토큰 인증 -->
+    <interceptor>
+        <mapping path="/api/dashboard/**"/>
+        <beans:bean class="itn.com.cmm.interceptor.DashboardApiAuthInterceptor"/>
+    </interceptor>
+```
+
+Style mirrors existing interceptors: `<interceptor>`/`<mapping>` are in the default `mvc` namespace; the bean uses the `beans:` prefix as `<beans:bean>`, matching `InterceptorHandler` and `IPIgnoreInterceptorHandler`.
+
+### context-security.xml — after existing `security="none"` entries (line 16)
+
+```xml
+<security:http pattern="/api/dashboard/**" security="none"/>
+```
+
+Placed immediately after the `\A/WEB-INF/jsp/.*\Z` regex entry, before `<egov-security:config>`.
+
+---
+
+## @Value / globalSettings Pattern Verification
+
+Reference file: `src/main/java/itn/let/mjo/api/sms/web/ApiSmsTestMsgController.java` line 32:
+```java
+@Value("#{globalSettings['Globals.api.ip']}")
+private String API_IP;
+```
+
+The new interceptor uses:
+```java
+@Value("#{globalSettings['Globals.dashboard.api.token']}")
+private String apiToken;
+```
+
+Identical SpEL pattern `#{globalSettings['<key>']}`. The `globalSettings` bean is defined in `context-properties.xml` and is available in the dispatcher servlet context (interceptors are registered there and Spring injects `@Value` into interceptor beans declared via `<beans:bean>` in the servlet context). Pattern confirmed to match the reference.
+
+---
+
+## XML Well-Formedness Confirmation
+
+### egov-interceptor-servlet.xml
+- Root element: `<beans:beans>` (line 2) — closed at line 40 `</beans:beans>`. Balanced.
+- `<interceptors>` (line 10) — closed at line 38 `</interceptors>`. Balanced.
+- New `<interceptor>` block (lines 11-15): `<mapping/>` self-closing, `<beans:bean/>` self-closing, `</interceptor>` closes. Balanced.
+- Namespaces: `mvc` default, `beans:` prefix. New snippet uses correct prefixes.
+
+### context-security.xml
+- Root element: `<beans>` (line 2) — closed at line 95 (original line 95) `</beans>`. Balanced.
+- New entry is a self-closing `<security:http ... />` element using the already-declared `security:` namespace. Well-formed.
+
+---
+
+## Commit Short Hash
+
+(See below — recorded after commit)
+
+---
+
+## Concerns / Notes
+
+1. **@Value injection into interceptor**: Spring injects `@Value` into interceptor beans only when the bean is instantiated by the application context (i.e., declared as `<beans:bean>` in the servlet XML). This pattern is consistent with how the project already declares interceptor beans in `egov-interceptor-servlet.xml`.
+
+2. **IPIgnoreInterceptorHandler also matches `/api/dashboard/**`**: The `/**` mapping interceptor still runs on this path. That interceptor only logs specific URI patterns (`errorLogInsert`, `*Ajax.do`, etc.) and will not block the API flow.
+
+3. **mvn/curl verification deferred**: Plan Steps 4-6 (mvn clean package, mvn tomcat7:run, curl 401/200 checks) could NOT be run in this environment — mvn and curl are not available. Verification was performed statically: file content read-back, XML tag balance check, @Value pattern cross-reference. Runtime verification must be performed by the developer in IntelliJ (Run → Deploy, then manual curl or browser test).
+
+4. **Token value**: `globals_local.properties` / `globals_dev.properties` / `globals_prod.properties` all contain `Globals.dashboard.api.token=CHANGE_ME_TOKEN`. Replace with a real secret before deploying to production.
 
docs/superpowers/n8n/README.md (added)
+++ docs/superpowers/n8n/README.md
@@ -0,0 +1,23 @@
+# 대시보드 일일 리포트 → Slack (n8n)
+
+## 구성
+- `n8n-workflow.json` : import용 워크플로우 (Schedule → HTTP Request → Code → Slack)
+- `code-node.js` : Code 노드에 붙여넣을 변환 스니펫
+
+## 설정 순서
+1. n8n에서 Settings → Variables/Environment에 `MJON_DASH_TOKEN` 추가
+   (값 = 앱 `globals_<profile>.properties`의 `Globals.dashboard.api.token`).
+2. `n8n-workflow.json` import.
+3. HTTP Request 노드의 `CHANGE_ME_HOST`를 관리자 호스트로 교체.
+4. Code 노드(`Format Slack Blocks`)에 `code-node.js` 내용 붙여넣기.
+5. Slack 노드: 자격증명 연결 후 `CHANGE_ME_CHANNEL`을 대상 채널로 교체.
+6. 스케줄: 기본 매일 09:00(`0 9 * * *`). 필요 시 cron 수정.
+
+## 수동 검증
+- 워크플로우 상단 **Execute Workflow** 실행 → 대상 Slack 채널에 리포트 수신 확인.
+- 토큰 불일치 시 HTTP Request 노드가 401로 실패하는지 확인.
+
+## 참고: 사내 n8n / 테스트 webhook
+- n8n 호스트: https://n8n.iten.co.kr
+- 테스트용 webhook(추후 사용): https://n8n.iten.co.kr/webhook-test/b8404529-b7d2-4ed9-8b11-1e4f8f07c554
+- 참고: n8n의 `/webhook-test/` URL은 에디터에서 "Listen for test event" 상태일 때만 동작하며, 운영은 `/webhook/` 경로를 사용한다.
 
docs/superpowers/n8n/code-node.js (added)
+++ docs/superpowers/n8n/code-node.js
@@ -0,0 +1,36 @@
+// n8n Code 노드: 도메인 JSON → Slack Block Kit
+// 입력: 이전 HTTP Request 노드의 JSON 응답
+const d = $input.first().json;
+const won = (n) => (n == null ? '0' : Number(n).toLocaleString('ko-KR')) + '원';
+
+const sales = d.sales || {};
+const m = d.members || {};
+const sms = d.sms || {};
+
+const agentLines = (sms.agents || [])
+  .map(a => `• ${a.agentCode}: 성공 ${Number(a.succCnt).toLocaleString('ko-KR')} / 실패 ${Number(a.failCnt).toLocaleString('ko-KR')} (성공률 ${a.succRate}%)`)
+  .join('\n') || '데이터 없음';
+
+const dayLines = (sales.dayChart || [])
+  .map(p => `${p.label} ${won(p.amt)}`)
+  .join('  |  ') || '데이터 없음';
+
+const blocks = [
+  { type: 'header', text: { type: 'plain_text', text: `�� 문자ON 일일 리포트 — ${d.baseDate}`, emoji: true } },
+  { type: 'section', fields: [
+    { type: 'mrkdwn', text: `*당일 매출*\n${won(sales.todayAmt)}` },
+    { type: 'mrkdwn', text: `*연간 누적*\n${won(sales.yearAmtSum)}` },
+  ] },
+  { type: 'section', text: { type: 'mrkdwn', text: `*최근 매출(일별)*\n${dayLines}` } },
+  { type: 'divider' },
+  { type: 'section', fields: [
+    { type: 'mrkdwn', text: `*개인/기업 회원*\n${m.userNorCnt} / ${m.userComCnt}` },
+    { type: 'mrkdwn', text: `*기업 신청/승인/반려*\n${m.cmpApply} / ${m.cmpApprove} / ${m.cmpReject}` },
+    { type: 'mrkdwn', text: `*금일 탈퇴/정지*\n${m.todayExpireCnt} / ${m.todayStopCnt}` },
+    { type: 'mrkdwn', text: `*일 가입자수*\n${sms.todaySignupCnt}` },
+  ] },
+  { type: 'divider' },
+  { type: 'section', text: { type: 'mrkdwn', text: `*전송사별 발송*\n${agentLines}` } },
+];
+
+return [{ json: { blocks } }];
 
docs/superpowers/n8n/n8n-workflow.json (added)
+++ docs/superpowers/n8n/n8n-workflow.json
@@ -0,0 +1,63 @@
+{
+  "name": "mjon-dashboard-daily-slack",
+  "nodes": [
+    {
+      "parameters": {
+        "rule": { "interval": [ { "field": "cronExpression", "expression": "0 9 * * *" } ] }
+      },
+      "id": "schedule",
+      "name": "Schedule Trigger",
+      "type": "n8n-nodes-base.scheduleTrigger",
+      "typeVersion": 1,
+      "position": [ 240, 300 ]
+    },
+    {
+      "parameters": {
+        "url": "https://CHANGE_ME_HOST/api/dashboard/summary.do",
+        "options": {},
+        "sendHeaders": true,
+        "headerParameters": {
+          "parameters": [
+            { "name": "X-DASHBOARD-TOKEN", "value": "={{ $env.MJON_DASH_TOKEN }}" }
+          ]
+        }
+      },
+      "id": "http",
+      "name": "HTTP Request",
+      "type": "n8n-nodes-base.httpRequest",
+      "typeVersion": 4,
+      "position": [ 460, 300 ]
+    },
+    {
+      "parameters": {
+        "language": "javaScript",
+        "jsCode": "// docs/superpowers/n8n/code-node.js 내용을 여기에 붙여넣는다"
+      },
+      "id": "code",
+      "name": "Format Slack Blocks",
+      "type": "n8n-nodes-base.code",
+      "typeVersion": 2,
+      "position": [ 680, 300 ]
+    },
+    {
+      "parameters": {
+        "resource": "message",
+        "operation": "post",
+        "channelId": "CHANGE_ME_CHANNEL",
+        "blocksUi": "={{ $json.blocks }}",
+        "text": "문자ON 일일 리포트"
+      },
+      "id": "slack",
+      "name": "Slack",
+      "type": "n8n-nodes-base.slack",
+      "typeVersion": 2,
+      "position": [ 900, 300 ]
+    }
+  ],
+  "connections": {
+    "Schedule Trigger": { "main": [ [ { "node": "HTTP Request", "type": "main", "index": 0 } ] ] },
+    "HTTP Request": { "main": [ [ { "node": "Format Slack Blocks", "type": "main", "index": 0 } ] ] },
+    "Format Slack Blocks": { "main": [ [ { "node": "Slack", "type": "main", "index": 0 } ] ] }
+  },
+  "settings": {}
+}
 
docs/superpowers/plans/2026-06-23-dashboard-slack-n8n.md (added)
+++ docs/superpowers/plans/2026-06-23-dashboard-slack-n8n.md
@@ -0,0 +1,849 @@
+# 대시보드 → n8n → Slack 정기 리포트 Implementation Plan
+
+> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
+
+**Goal:** 문자ON 대시보드의 매출/회원/문자발송 지표를 토큰 인증 JSON API로 노출하고, n8n이 스케줄로 호출해 Slack에 정기 요약을 게시한다.
+
+**Architecture:** 신규 모듈 `itn.let.mjo.dashboardapi`에 `@RestController` 1개 + Service/Impl + 응답 DTO + 토큰 인증 인터셉터를 추가한다. 집계는 기존 검증된 서비스(`mjonPayService`, `conectStatsService`, `mjonMsgService`)를 **재사용**하며 신규 SQL/DAO는 없다. Slack 표현(콤마/원화/Block Kit)은 n8n이 담당하고 앱은 raw 숫자 JSON만 반환한다.
+
+**Tech Stack:** Java 1.8, Spring MVC 4.3 (eGovFramework 3.9.0), iBATIS(SqlMapClient), Jackson 2.5.1, Lombok 1.18.24, Maven(WAR). n8n(Schedule + HTTP Request + Code + Slack).
+
+## Global Constraints
+
+- Java 1.8 / Spring 4.3 문법만 사용. 신규 라이브러리 추가 금지(기존 pom.xml 의존성만).
+- 신규 SQL/DAO 작성 금지 — 기존 서비스 메서드만 호출.
+- 기존 4종 패턴 준수: `web`(@Controller/@RestController) / `service`(인터페이스+VO) / `service.impl`(@Service).
+- 빈 스캔 분리 규칙: 컨트롤러·인터셉터=디스패처 컨텍스트(`*-servlet.xml`), 서비스=루트 컨텍스트(`context-*.xml`).
+- 관리자 로그 AOP(`itn..*Controller.select*` 등) 회피를 위해 컨트롤러 메서드명은 `getDashboardSummary`(=`select*`/`insert*`/`update*`/`delete*` 아님)로 짓는다.
+- 토큰 헤더명: `X-DASHBOARD-TOKEN`. 프로퍼티 키: `Globals.dashboard.api.token`.
+- **테스트 인프라 없음**: 본 저장소는 `src/test`가 없고 surefire `skipTests=true`다. 따라서 각 태스크의 검증은 **`mvn compile` 성공 + 수동 curl/실행 확인**으로 수행한다(자동 단위테스트는 본 작업 범위 아님 — 스펙에서 수동 검증으로 합의됨).
+- 인코딩 UTF-8. 토큰 값은 로그/응답에 출력 금지.
+
+---
+
+### Task 1: 토큰 프로퍼티 추가
+
+**Files:**
+- Modify: `src/main/resources/egovframework/egovProps/globals.properties` (끝에 추가)
+- Modify: `src/main/resources/egovframework/egovProps/globals_local.properties`
+- Modify: `src/main/resources/egovframework/egovProps/globals_dev.properties`
+- Modify: `src/main/resources/egovframework/egovProps/globals_prod.properties`
+
+**Interfaces:**
+- Consumes: 없음
+- Produces: 프로퍼티 키 `Globals.dashboard.api.token` (이후 Task 5 인터셉터가 `globalSettings`로 읽음)
+
+- [ ] **Step 1: `globals.properties` 끝에 기본 토큰 추가**
+
+`globals.properties` 파일 맨 끝(line 101 이후)에 아래 블록 추가:
+
+```properties
+
+# 대시보드 요약 API(n8n→Slack) 공유 토큰
+Globals.dashboard.api.token=CHANGE_ME_DEV_TOKEN
+```
+
+- [ ] **Step 2: 환경별 프로퍼티에 동일 키 추가(override)**
+
+`globals_local.properties`, `globals_dev.properties`, `globals_prod.properties` 각 파일 끝에 아래를 추가(운영 값은 배포 시 교체):
+
+```properties
+
+# 대시보드 요약 API(n8n→Slack) 공유 토큰
+Globals.dashboard.api.token=CHANGE_ME_TOKEN
+```
+
+> 활성 프로파일은 `-Dspring.profiles.active`로 결정되며 `globals_<profile>.properties`가 실제 사용된다(`context-properties.xml`의 `globalSettings`). `globals.properties`는 공통 기본값.
+
+- [ ] **Step 3: 추가 확인**
+
+Run: `grep -rn "Globals.dashboard.api.token" src/main/resources/egovframework/egovProps/`
+Expected: 4개 파일 모두에서 키가 출력됨.
+
+- [ ] **Step 4: Commit**
+
+```bash
+git add src/main/resources/egovframework/egovProps/globals*.properties
+git commit -m "feat(dashboard-api): 대시보드 요약 API 토큰 프로퍼티 추가"
+```
+
+---
+
+### Task 2: 응답 DTO (DashboardSummaryVO)
+
+**Files:**
+- Create: `src/main/java/itn/let/mjo/dashboardapi/service/DashboardSummaryVO.java`
+
+**Interfaces:**
+- Consumes: 없음
+- Produces: 아래 타입들(이후 Task 3 서비스가 채우고 Task 4 컨트롤러가 반환). Lombok `@Getter @Setter` 사용.
+  - `DashboardSummaryVO` { `boolean isSuccess`, `String msg`, `String baseDate`, `Sales sales`, `Members members`, `Sms sms` }
+  - `DashboardSummaryVO.Sales` { `long todayAmt`, `List<AmtPoint> dayChart`, `List<AmtPoint> monthChart`, `long yearAmtSum` }
+  - `DashboardSummaryVO.AmtPoint` { `String label`, `long amt` }
+  - `DashboardSummaryVO.Members` { `int userNorCnt, userComCnt, mberNorTot, mberBlockTot, mberSecessTot, cmpApply, cmpApprove, cmpReject, todayExpireCnt, todayStopCnt` }
+  - `DashboardSummaryVO.Sms` { `List<AgentStat> agents`, `int todaySignupCnt` }
+  - `DashboardSummaryVO.AgentStat` { `String agentCode`, `int succCnt`, `int failCnt`, `int succRate` }
+
+- [ ] **Step 1: DTO 파일 작성**
+
+`src/main/java/itn/let/mjo/dashboardapi/service/DashboardSummaryVO.java`:
+
+```java
+package itn.let.mjo.dashboardapi.service;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 대시보드 요약 API(n8n→Slack) 응답 DTO.
+ * 앱은 표현 포맷 없이 raw 숫자만 제공한다(콤마/원화는 n8n에서 처리).
+ */
+@Getter
+@Setter
+public class DashboardSummaryVO implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private boolean isSuccess = true;
+    private String msg = "";
+    private String baseDate;
+
+    private Sales sales = new Sales();
+    private Members members = new Members();
+    private Sms sms = new Sms();
+
+    /** 매출(VAT 포함, 단위: 원) */
+    @Getter
+    @Setter
+    public static class Sales implements Serializable {
+        private static final long serialVersionUID = 1L;
+        private long todayAmt;
+        private List<AmtPoint> dayChart = new ArrayList<AmtPoint>();
+        private List<AmtPoint> monthChart = new ArrayList<AmtPoint>();
+        private long yearAmtSum;
+    }
+
+    /** 금액 시계열 한 점 (label = "MM-DD" 또는 "N월") */
+    @Getter
+    @Setter
+    public static class AmtPoint implements Serializable {
+        private static final long serialVersionUID = 1L;
+        private String label;
+        private long amt;
+
+        public AmtPoint() {
+        }
+
+        public AmtPoint(String label, long amt) {
+            this.label = label;
+            this.amt = amt;
+        }
+    }
+
+    /** 회원 현황 */
+    @Getter
+    @Setter
+    public static class Members implements Serializable {
+        private static final long serialVersionUID = 1L;
+        private int userNorCnt;
+        private int userComCnt;
+        private int mberNorTot;
+        private int mberBlockTot;
+        private int mberSecessTot;
+        private int cmpApply;
+        private int cmpApprove;
+        private int cmpReject;
+        private int todayExpireCnt;
+        private int todayStopCnt;
+    }
+
+    /** 문자 발송 현황 */
+    @Getter
+    @Setter
+    public static class Sms implements Serializable {
+        private static final long serialVersionUID = 1L;
+        private List<AgentStat> agents = new ArrayList<AgentStat>();
+        private int todaySignupCnt;
+    }
+
+    /** 전송사별 발송 통계 */
+    @Getter
+    @Setter
+    public static class AgentStat implements Serializable {
+        private static final long serialVersionUID = 1L;
+        private String agentCode;
+        private int succCnt;
+        private int failCnt;
+        private int succRate;
+    }
+}
+```
+
+> 주의: Jackson 2.5.1은 `boolean isSuccess` 게터를 `success`로 직렬화할 수 있다. 기존 코드와 동일하게 키를 `isSuccess`로 노출하려면 Task 4에서 확인한다(필요 시 `@com.fasterxml.jackson.annotation.JsonProperty("isSuccess")`를 게터에 부여). 본 DTO는 우선 lombok 기본 게터로 두고 Task 4 검증 단계에서 키를 확정한다.
+
+- [ ] **Step 2: 컴파일 확인**
+
+Run: `mvn -q -o compile` (오프라인 불가 시 `mvn -q compile`)
+Expected: BUILD SUCCESS. `DashboardSummaryVO` 컴파일 에러 없음.
+
+- [ ] **Step 3: Commit**
+
+```bash
+git add src/main/java/itn/let/mjo/dashboardapi/service/DashboardSummaryVO.java
+git commit -m "feat(dashboard-api): 요약 응답 DTO 추가"
+```
+
+---
+
+### Task 3: 집계 서비스 (Service + Impl)
+
+**Files:**
+- Create: `src/main/java/itn/let/mjo/dashboardapi/service/DashboardSummaryService.java`
+- Create: `src/main/java/itn/let/mjo/dashboardapi/service/impl/DashboardSummaryServiceImpl.java`
+
+**Interfaces:**
+- Consumes:
+  - `DashboardSummaryVO` (Task 2)
+  - 기존 빈: `mjonPayService`(`itn.let.mjo.pay.service.MjonPayService`), `conectStatsService`(`itn.let.sts.cst.service.EgovConectStatsService`), `mjonMsgService`(`itn.let.mjo.msg.service.MjonMsgService`)
+- Produces: `DashboardSummaryService.getDashboardSummary(String baseDate) -> DashboardSummaryVO`
+
+- [ ] **Step 1: 서비스 인터페이스 작성**
+
+`src/main/java/itn/let/mjo/dashboardapi/service/DashboardSummaryService.java`:
+
+```java
+package itn.let.mjo.dashboardapi.service;
+
+/**
+ * 대시보드 요약 API 집계 서비스.
+ * 기존 대시보드 서비스 메서드를 조합해 raw 숫자 요약을 만든다(신규 SQL 없음).
+ */
+public interface DashboardSummaryService {
+
+    /**
+     * @param baseDate "yyyy-MM-dd" 또는 null(오늘)
+     * @return 매출/회원/문자 요약
+     */
+    DashboardSummaryVO getDashboardSummary(String baseDate) throws Exception;
+}
+```
+
+- [ ] **Step 2: 구현체 작성**
+
+`src/main/java/itn/let/mjo/dashboardapi/service/impl/DashboardSummaryServiceImpl.java`:
+
+```java
+package itn.let.mjo.dashboardapi.service.impl;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+
+import javax.annotation.Resource;
+
+import org.springframework.stereotype.Service;
+
+import itn.let.mjo.dashboardapi.service.DashboardSummaryService;
+import itn.let.mjo.dashboardapi.service.DashboardSummaryVO;
+import itn.let.mjo.msg.service.MjonMsgService;
+import itn.let.mjo.msg.service.MjonMsgStatVO;
+import itn.let.mjo.msg.service.MjonMsgVO;
+import itn.let.mjo.pay.service.MjonPayService;
+import itn.let.mjo.pay.service.MjonPayVO;
+import itn.let.sts.cst.service.EgovConectStatsService;
+import itn.let.uss.umt.service.MberManageVO;
+
+@Service("dashboardSummaryService")
+public class DashboardSummaryServiceImpl implements DashboardSummaryService {
+
+    @Resource(name = "mjonPayService")
+    private MjonPayService mjonPayService;
+
+    @Resource(name = "conectStatsService")
+    private EgovConectStatsService conectStatsService;
+
+    @Resource(name = "mjonMsgService")
+    private MjonMsgService mjonMsgService;
+
+    @Override
+    public DashboardSummaryVO getDashboardSummary(String baseDate) throws Exception {
+        DashboardSummaryVO vo = new DashboardSummaryVO();
+
+        if (baseDate == null || baseDate.trim().isEmpty()) {
+            baseDate = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
+        }
+        vo.setBaseDate(baseDate);
+
+        // 지표 블록별 try/catch: 개별 실패가 전체 응답을 막지 않도록 한다.
+        try {
+            fillSales(vo.getSales());
+        } catch (Exception e) {
+            vo.setSuccess(false);
+            vo.setMsg(appendMsg(vo.getMsg(), "sales:" + e.getMessage()));
+        }
+        try {
+            fillMembers(vo.getMembers());
+        } catch (Exception e) {
+            vo.setSuccess(false);
+            vo.setMsg(appendMsg(vo.getMsg(), "members:" + e.getMessage()));
+        }
+        try {
+            fillSms(vo.getSms());
+        } catch (Exception e) {
+            vo.setSuccess(false);
+            vo.setMsg(appendMsg(vo.getMsg(), "sms:" + e.getMessage()));
+        }
+        return vo;
+    }
+
+    /** 매출(일/월/연) — selectPayDayChartDashboard, selectPayMonthChartDashboard, selectPayYearChart 재사용 */
+    private void fillSales(DashboardSummaryVO.Sales sales) throws Exception {
+        // 일별(최근 4일, 최신순)
+        MjonPayVO dayReq = new MjonPayVO();
+        dayReq.setFirstIndex(0);
+        dayReq.setRecordCountPerPage(4);
+        dayReq.setSearchSortCnd("regDate");
+        dayReq.setSearchSortOrd("desc");
+        List<MjonPayVO> dayList = mjonPayService.selectPayDayChartDashboard(dayReq);
+        if (dayList != null) {
+            for (MjonPayVO p : dayList) {
+                String label = p.getRegDate();
+                if (label != null && label.length() >= 10) {
+                    label = label.substring(5, 10); // MM-DD
+                }
+                sales.getDayChart().add(new DashboardSummaryVO.AmtPoint(label, toLong(p.getAmtTotSum())));
+            }
+            if (!dayList.isEmpty()) {
+                sales.setTodayAmt(toLong(dayList.get(0).getAmtTotSum())); // 최신순 첫 행 = 당일
+            }
+        }
+
+        // 월별(최근 4개월, 최신순)
+        MjonPayVO monthReq = new MjonPayVO();
+        monthReq.setFirstIndex(0);
+        monthReq.setRecordCountPerPage(4);
+        monthReq.setSearchSortCnd("regDate");
+        monthReq.setSearchSortOrd("desc");
+        List<MjonPayVO> monthList = mjonPayService.selectPayMonthChartDashboard(monthReq);
+        if (monthList != null) {
+            for (MjonPayVO p : monthList) {
+                String label = p.getRegDate();
+                if (label != null && label.length() >= 7) {
+                    label = Integer.parseInt(label.substring(5, 7)) + "월";
+                }
+                sales.getMonthChart().add(new DashboardSummaryVO.AmtPoint(label, toLong(p.getAmtTotSum())));
+            }
+        }
+
+        // 연간 누적
+        MjonPayVO yearInfo = mjonPayService.selectPayYearChart(new MjonPayVO());
+        if (yearInfo != null) {
+            sales.setYearAmtSum(toLong(yearInfo.getAmtYearSum()));
+        }
+    }
+
+    /** 회원 현황 — EgovMainController.selectMemberStatsAjax 로직 재현 */
+    private void fillMembers(DashboardSummaryVO.Members m) throws Exception {
+        MberManageVO req = new MberManageVO();
+
+        req.setHstSttus("01");
+        List<MberManageVO> apply = conectStatsService.selectMberCmpHstStatsDashboard(req);
+        req.setHstSttus("02");
+        List<MberManageVO> approve = conectStatsService.selectMberCmpHstStatsDashboard(req);
+        req.setHstSttus("03");
+        List<MberManageVO> reject = conectStatsService.selectMberCmpHstStatsDashboard(req);
+        m.setCmpApply((apply == null || apply.isEmpty()) ? 0 : apply.get(0).getTotCnt());
+        m.setCmpApprove((approve == null || approve.isEmpty()) ? 0 : approve.get(0).getTotCnt());
+        m.setCmpReject((reject == null || reject.isEmpty()) ? 0 : reject.get(0).getTotCnt());
+
+        MberManageVO totReq = new MberManageVO();
+        totReq.setDept("P");
+        List<MberManageVO> priv = conectStatsService.selectMberTotStats(totReq);
+        totReq.setDept("C");
+        List<MberManageVO> comp = conectStatsService.selectMberTotStats(totReq);
+
+        if (priv != null) {
+            for (MberManageVO v : priv) {
+                accumulateMember(m, v, true);
+            }
+        }
+        if (comp != null) {
+            for (MberManageVO v : comp) {
+                accumulateMember(m, v, false);
+            }
+        }
+
+        String statStr = conectStatsService.selectTodaySttCountString(totReq);
+        if (statStr != null) {
+            String[] split = statStr.split("_");
+            if (split.length == 3) {
+                m.setTodayExpireCnt(toInt(split[0]));
+                m.setTodayStopCnt(toInt(split[1]));
+                // split[2]=환불신청수는 1차 범위 제외
+            }
+        }
+    }
+
+    private void accumulateMember(DashboardSummaryVO.Members m, MberManageVO v, boolean isPrivate) {
+        String sttus = v.getMberSttus();
+        int cnt = v.getTotCnt();
+        if ("Y".equals(sttus)) {
+            if (isPrivate) {
+                m.setUserNorCnt(cnt);
+            } else {
+                m.setUserComCnt(cnt);
+            }
+            m.setMberNorTot(m.getMberNorTot() + cnt);
+        } else if ("B".equals(sttus)) {
+            m.setMberBlockTot(m.getMberBlockTot() + cnt);
+        } else if ("N".equals(sttus)) {
+            m.setMberSecessTot(m.getMberSecessTot() + cnt);
+        }
+    }
+
+    /** 문자 발송 현황 — selectAgentSmsCountStatMainList, selectMemDayChartDashboard 재사용 */
+    private void fillSms(DashboardSummaryVO.Sms s) throws Exception {
+        MjonMsgStatVO statReq = new MjonMsgStatVO();
+        statReq.setFirstIndex(0);
+        statReq.setRecordCountPerPage(3);
+        List<MjonMsgStatVO> agents = mjonMsgService.selectAgentSmsCountStatMainList(statReq);
+        if (agents != null) {
+            for (MjonMsgStatVO a : agents) {
+                DashboardSummaryVO.AgentStat stat = new DashboardSummaryVO.AgentStat();
+                stat.setAgentCode(a.getAgentCode());
+                int succ = a.getSumSuccCnt();
+                int fail = a.getSumFailCnt();
+                stat.setSuccCnt(succ);
+                stat.setFailCnt(fail);
+                int total = succ + fail;
+                stat.setSuccRate(total == 0 ? 0 : (int) Math.round(succ * 100.0 / total));
+                s.getAgents().add(stat);
+            }
+        }
+
+        MjonMsgVO memReq = new MjonMsgVO();
+        memReq.setFirstIndex(0);
+        memReq.setRecordCountPerPage(4);
+        memReq.setSearchSortCnd("regDate");
+        memReq.setSearchSortOrd("desc");
+        List<MjonMsgVO> memDay = mjonMsgService.selectMemDayChartDashboard(memReq);
+        if (memDay != null && !memDay.isEmpty()) {
+            s.setTodaySignupCnt(memDay.get(0).getRegCount());
+        }
+    }
+
+    /** "12345", "12,345", "12345.0", null → long(0) 안전 변환 */
+    private long toLong(String s) {
+        if (s == null) {
+            return 0L;
+        }
+        String digits = s.replaceAll("[^0-9-]", "");
+        if (digits.isEmpty() || "-".equals(digits)) {
+            return 0L;
+        }
+        try {
+            return Long.parseLong(digits);
+        } catch (NumberFormatException e) {
+            return 0L;
+        }
+    }
+
+    private int toInt(String s) {
+        return (int) toLong(s);
+    }
+
+    private String appendMsg(String base, String add) {
+        if (base == null || base.isEmpty()) {
+            return add;
+        }
+        return base + "; " + add;
+    }
+}
+```
+
+> 검증 포인트(구현 중 확인): `MberManageVO.getTotCnt()`, `MjonMsgStatVO.getSumFailCnt()`, `MjonMsgVO.getRegCount()`가 존재해야 한다(기존 `EgovMainController`/VO에서 사용 중). 시그니처가 다르면 해당 게터명으로 맞춘다. `vo.setSuccess(false)`는 lombok이 `boolean isSuccess` 필드에 대해 생성하는 setter다(필드명 기준 `setSuccess`).
+
+- [ ] **Step 3: 컴파일 확인**
+
+Run: `mvn -q compile`
+Expected: BUILD SUCCESS. 메서드/게터 미스매치 없음(에러 시 위 검증 포인트의 실제 게터명으로 수정).
+
+- [ ] **Step 4: Commit**
+
+```bash
+git add src/main/java/itn/let/mjo/dashboardapi/service/
+git commit -m "feat(dashboard-api): 매출/회원/문자 요약 집계 서비스 추가"
+```
+
+---
+
+### Task 4: REST 컨트롤러
+
+**Files:**
+- Create: `src/main/java/itn/let/mjo/dashboardapi/web/DashboardApiController.java`
+
+**Interfaces:**
+- Consumes: `DashboardSummaryService.getDashboardSummary(String)` (Task 3), `DashboardSummaryVO` (Task 2)
+- Produces: HTTP `GET /api/dashboard/summary.do` → JSON 직렬화된 `DashboardSummaryVO`
+
+- [ ] **Step 1: 컨트롤러 작성**
+
+`src/main/java/itn/let/mjo/dashboardapi/web/DashboardApiController.java`:
+
+```java
+package itn.let.mjo.dashboardapi.web;
+
+import javax.annotation.Resource;
+
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import itn.let.mjo.dashboardapi.service.DashboardSummaryService;
+import itn.let.mjo.dashboardapi.service.DashboardSummaryVO;
+
+/**
+ * 대시보드 요약 JSON API(n8n→Slack 전용).
+ * 인증은 DashboardApiAuthInterceptor(토큰 헤더)가 담당한다.
+ * 메서드명은 select* 가 아니어서 관리자 로그 AOP 대상에서 제외된다.
+ */
+@RestController
+public class DashboardApiController {
+
+    @Resource(name = "dashboardSummaryService")
+    private DashboardSummaryService dashboardSummaryService;
+
+    @RequestMapping(value = "/api/dashboard/summary.do", method = RequestMethod.GET)
+    public DashboardSummaryVO getDashboardSummary(
+            @RequestParam(value = "date", required = false) String date) throws Exception {
+        return dashboardSummaryService.getDashboardSummary(date);
+    }
+}
+```
+
+- [ ] **Step 2: 빌드(WAR) 확인**
+
+Run: `mvn -q clean package`
+Expected: BUILD SUCCESS, `target/mjon.war` 생성.
+
+- [ ] **Step 3: 로컬 기동 후 JSON 키 확인(인증 인터셉터 적용 전, 임시)**
+
+> 이 시점엔 아직 인증이 없으므로 토큰 없이 호출된다. JSON 직렬화 키만 확인한다.
+
+Run(터미널 A): `mvn tomcat7:run`
+Run(터미널 B): `curl -s "http://localhost/api/dashboard/summary.do?date=2026-06-23"`
+Expected: `sales`/`members`/`sms` 블록이 있는 JSON. 성공 플래그 키가 `isSuccess`인지 `success`인지 확인.
+- 키가 `success`로 나오면 `DashboardSummaryVO`의 게터에 `@com.fasterxml.jackson.annotation.JsonProperty("isSuccess")`를 추가:
+  ```java
+  @com.fasterxml.jackson.annotation.JsonProperty("isSuccess")
+  public boolean isSuccess() { return isSuccess; }
+  ```
+  (lombok 게터와 충돌 시 lombok `@Getter`를 필드에서 제거하고 위 명시 게터만 둔다.)
+- 확인 후 터미널 A 종료(Ctrl+C).
+
+- [ ] **Step 4: Commit**
+
+```bash
+git add src/main/java/itn/let/mjo/dashboardapi/web/DashboardApiController.java src/main/java/itn/let/mjo/dashboardapi/service/DashboardSummaryVO.java
+git commit -m "feat(dashboard-api): /api/dashboard/summary.do RestController 추가"
+```
+
+---
+
+### Task 5: 토큰 인증 인터셉터 + 매핑 + 시큐리티 예외
+
+**Files:**
+- Create: `src/main/java/itn/com/cmm/interceptor/DashboardApiAuthInterceptor.java`
+- Modify: `src/main/webapp/WEB-INF/config/egovframework/springmvc/egov-interceptor-servlet.xml`
+- Modify: `src/main/resources/egovframework/spring/com/context-security.xml:14` (security="none" 블록 인근에 추가)
+
+**Interfaces:**
+- Consumes: 프로퍼티 `Globals.dashboard.api.token` via `globalSettings`(Task 1)
+- Produces: `/api/dashboard/**` 요청에 대한 토큰 검증(불일치/누락 시 401 JSON, 컨트롤러 진입 차단)
+
+- [ ] **Step 1: 인터셉터 작성**
+
+`src/main/java/itn/com/cmm/interceptor/DashboardApiAuthInterceptor.java`:
+
+```java
+package itn.com.cmm.interceptor;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
+
+/**
+ * 대시보드 요약 API 토큰 인증.
+ * X-DASHBOARD-TOKEN 헤더가 설정 토큰과 일치할 때만 통과시킨다.
+ */
+public class DashboardApiAuthInterceptor extends HandlerInterceptorAdapter {
+
+    private static final String HEADER = "X-DASHBOARD-TOKEN";
+
+    @Value("#{globalSettings['Globals.dashboard.api.token']}")
+    private String apiToken;
+
+    @Override
+    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
+            throws Exception {
+
+        String token = request.getHeader(HEADER);
+
+        boolean ok = apiToken != null && !apiToken.trim().isEmpty()
+                && apiToken.equals(token);
+
+        if (!ok) {
+            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); // 401
+            response.setContentType("application/json;charset=UTF-8");
+            response.getWriter().write("{\"isSuccess\":false,\"msg\":\"unauthorized\"}");
+            return false; // 컨트롤러 진입 차단 (토큰 값은 로그/응답에 출력하지 않음)
+        }
+        return true;
+    }
+}
+```
+
+- [ ] **Step 2: 인터셉터 매핑 등록**
+
+`egov-interceptor-servlet.xml`의 `<interceptors>` 블록 안(첫 `<interceptor>` 위, line 10 직후)에 추가:
+
+```xml
+	    <!-- 대시보드 요약 API 토큰 인증 -->
+	    <interceptor>
+	        <mapping path="/api/dashboard/**"/>
+	        <beans:bean class="itn.com.cmm.interceptor.DashboardApiAuthInterceptor"/>
+	    </interceptor>
+```
+
+> 기존 `IPIgnoreInterceptorHandler`는 `/**` 매핑에 `/cmm/**`, `/js/**`, `/publish/**`만 제외한다. `/api/dashboard/**`도 그 인터셉터를 거치지만, 해당 핸들러는 특정 URI(`errorLogInsert`, `*Ajax.do` 등)에만 동작하므로 본 API 흐름에는 영향 없음(통과). 빌드 후 Step 6에서 실제 통과를 확인한다.
+
+- [ ] **Step 3: 시큐리티 예외 추가**
+
+`context-security.xml`의 `security="none"` 목록(line 9~14 인근)에 한 줄 추가:
+
+```xml
+    <security:http pattern="/api/dashboard/**" security="none"/>
+```
+
+> 이 엔드포인트는 토큰으로 자체 보호하므로 Spring Security 필터 체인/세션이 필요 없다. DB 기반 URL 권한(`secured-object`)에 걸리는 것을 방지한다.
+
+- [ ] **Step 4: 빌드 확인**
+
+Run: `mvn -q clean package`
+Expected: BUILD SUCCESS, `target/mjon.war` 생성.
+
+- [ ] **Step 5: 토큰 없는 호출 → 401 확인**
+
+Run(터미널 A): `mvn tomcat7:run`
+Run(터미널 B): `curl -s -o /dev/null -w "%{http_code}\n" "http://localhost/api/dashboard/summary.do"`
+Expected: `401`
+
+- [ ] **Step 6: 올바른 토큰 → 200 + JSON 확인**
+
+> 토큰 값은 활성 프로파일의 `globals_<profile>.properties`에 설정된 값. 로컬 기동은 보통 `local` 프로파일.
+
+Run(터미널 B):
+```bash
+curl -s -H "X-DASHBOARD-TOKEN: CHANGE_ME_TOKEN" "http://localhost/api/dashboard/summary.do" | head -c 600
+```
+Expected: HTTP 200, `sales`/`members`/`sms` 블록이 채워진 JSON. (틀린 토큰으로는 401)
+- 확인 후 터미널 A 종료.
+
+- [ ] **Step 7: Commit**
+
+```bash
+git add src/main/java/itn/com/cmm/interceptor/DashboardApiAuthInterceptor.java \
+        src/main/webapp/WEB-INF/config/egovframework/springmvc/egov-interceptor-servlet.xml \
+        src/main/resources/egovframework/spring/com/context-security.xml
+git commit -m "feat(dashboard-api): 토큰 인증 인터셉터 및 시큐리티 예외 추가"
+```
+
+---
+
+### Task 6: n8n 워크플로우 + Slack 산출물
+
+**Files:**
+- Create: `docs/superpowers/n8n/n8n-workflow.json`
+- Create: `docs/superpowers/n8n/code-node.js`
+- Create: `docs/superpowers/n8n/README.md`
+
+**Interfaces:**
+- Consumes: `GET /api/dashboard/summary.do` 응답 JSON(Task 2~5)
+- Produces: import 가능한 n8n 워크플로우 + Slack Block Kit 변환 스니펫
+
+- [ ] **Step 1: Code 노드 변환 스니펫 작성**
+
+`docs/superpowers/n8n/code-node.js`:
+
+```javascript
+// n8n Code 노드: 도메인 JSON → Slack Block Kit
+// 입력: 이전 HTTP Request 노드의 JSON 응답
+const d = $input.first().json;
+const won = (n) => (n == null ? '0' : Number(n).toLocaleString('ko-KR')) + '원';
+
+const sales = d.sales || {};
+const m = d.members || {};
+const sms = d.sms || {};
+
+const agentLines = (sms.agents || [])
+  .map(a => `• ${a.agentCode}: 성공 ${Number(a.succCnt).toLocaleString('ko-KR')} / 실패 ${Number(a.failCnt).toLocaleString('ko-KR')} (성공률 ${a.succRate}%)`)
+  .join('\n') || '데이터 없음';
+
+const dayLines = (sales.dayChart || [])
+  .map(p => `${p.label} ${won(p.amt)}`)
+  .join('  |  ') || '데이터 없음';
+
+const blocks = [
+  { type: 'header', text: { type: 'plain_text', text: `�� 문자ON 일일 리포트 — ${d.baseDate}`, emoji: true } },
+  { type: 'section', fields: [
+    { type: 'mrkdwn', text: `*당일 매출*\n${won(sales.todayAmt)}` },
+    { type: 'mrkdwn', text: `*연간 누적*\n${won(sales.yearAmtSum)}` },
+  ] },
+  { type: 'section', text: { type: 'mrkdwn', text: `*최근 매출(일별)*\n${dayLines}` } },
+  { type: 'divider' },
+  { type: 'section', fields: [
+    { type: 'mrkdwn', text: `*개인/기업 회원*\n${m.userNorCnt} / ${m.userComCnt}` },
+    { type: 'mrkdwn', text: `*기업 신청/승인/반려*\n${m.cmpApply} / ${m.cmpApprove} / ${m.cmpReject}` },
+    { type: 'mrkdwn', text: `*금일 탈퇴/정지*\n${m.todayExpireCnt} / ${m.todayStopCnt}` },
+    { type: 'mrkdwn', text: `*일 가입자수*\n${sms.todaySignupCnt}` },
+  ] },
+  { type: 'divider' },
+  { type: 'section', text: { type: 'mrkdwn', text: `*전송사별 발송*\n${agentLines}` } },
+];
+
+return [{ json: { blocks } }];
+```
+
+- [ ] **Step 2: 워크플로우 JSON 작성**
+
+`docs/superpowers/n8n/n8n-workflow.json`:
+
+```json
+{
+  "name": "mjon-dashboard-daily-slack",
+  "nodes": [
+    {
+      "parameters": {
+        "rule": { "interval": [ { "field": "cronExpression", "expression": "0 9 * * *" } ] }
+      },
+      "id": "schedule",
+      "name": "Schedule Trigger",
+      "type": "n8n-nodes-base.scheduleTrigger",
+      "typeVersion": 1,
+      "position": [ 240, 300 ]
+    },
+    {
+      "parameters": {
+        "url": "https://CHANGE_ME_HOST/api/dashboard/summary.do",
+        "options": {},
+        "sendHeaders": true,
+        "headerParameters": {
+          "parameters": [
+            { "name": "X-DASHBOARD-TOKEN", "value": "={{ $env.MJON_DASH_TOKEN }}" }
+          ]
+        }
+      },
+      "id": "http",
+      "name": "HTTP Request",
+      "type": "n8n-nodes-base.httpRequest",
+      "typeVersion": 4,
+      "position": [ 460, 300 ]
+    },
+    {
+      "parameters": {
+        "language": "javaScript",
+        "jsCode": "// docs/superpowers/n8n/code-node.js 내용을 여기에 붙여넣는다"
+      },
+      "id": "code",
+      "name": "Format Slack Blocks",
+      "type": "n8n-nodes-base.code",
+      "typeVersion": 2,
+      "position": [ 680, 300 ]
+    },
+    {
+      "parameters": {
+        "resource": "message",
+        "operation": "post",
+        "channelId": "CHANGE_ME_CHANNEL",
+        "blocksUi": "={{ $json.blocks }}",
+        "text": "문자ON 일일 리포트"
+      },
+      "id": "slack",
+      "name": "Slack",
+      "type": "n8n-nodes-base.slack",
+      "typeVersion": 2,
+      "position": [ 900, 300 ]
+    }
+  ],
+  "connections": {
+    "Schedule Trigger": { "main": [ [ { "node": "HTTP Request", "type": "main", "index": 0 } ] ] },
+    "HTTP Request": { "main": [ [ { "node": "Format Slack Blocks", "type": "main", "index": 0 } ] ] },
+    "Format Slack Blocks": { "main": [ [ { "node": "Slack", "type": "main", "index": 0 } ] ] }
+  },
+  "settings": {}
+}
+```
+
+- [ ] **Step 3: README 작성**
+
+`docs/superpowers/n8n/README.md`:
+
+```markdown
+# 대시보드 일일 리포트 → Slack (n8n)
+
+## 구성
+- `n8n-workflow.json` : import용 워크플로우 (Schedule → HTTP Request → Code → Slack)
+- `code-node.js` : Code 노드에 붙여넣을 변환 스니펫
+
+## 설정 순서
+1. n8n에서 Settings → Variables/Environment에 `MJON_DASH_TOKEN` 추가
+   (값 = 앱 `globals_<profile>.properties`의 `Globals.dashboard.api.token`).
+2. `n8n-workflow.json` import.
+3. HTTP Request 노드의 `CHANGE_ME_HOST`를 관리자 호스트로 교체.
+4. Code 노드(`Format Slack Blocks`)에 `code-node.js` 내용 붙여넣기.
+5. Slack 노드: 자격증명 연결 후 `CHANGE_ME_CHANNEL`을 대상 채널로 교체.
+6. 스케줄: 기본 매일 09:00(`0 9 * * *`). 필요 시 cron 수정.
+
+## 수동 검증
+- 워크플로우 상단 **Execute Workflow** 실행 → 대상 Slack 채널에 리포트 수신 확인.
+- 토큰 불일치 시 HTTP Request 노드가 401로 실패하는지 확인.
+```
+
+- [ ] **Step 4: 산출물 확인**
+
+Run: `ls docs/superpowers/n8n/`
+Expected: `README.md  code-node.js  n8n-workflow.json`
+
+- [ ] **Step 5: Commit**
+
+```bash
+git add docs/superpowers/n8n/
+git commit -m "feat(dashboard-api): n8n 워크플로우 및 Slack 변환 산출물 추가"
+```
+
+---
+
+## 검증(통합) 시나리오
+
+모든 태스크 완료 후:
+
+1. `mvn clean package` → `target/mjon.war` 생성(BUILD SUCCESS).
+2. `mvn tomcat7:run` 기동.
+3. `curl -s -o /dev/null -w "%{http_code}" http://localhost/api/dashboard/summary.do` → `401`.
+4. `curl -s -H "X-DASHBOARD-TOKEN: <토큰>" http://localhost/api/dashboard/summary.do` → `200` + 매출/회원/문자 JSON.
+5. n8n: `MJON_DASH_TOKEN` 설정 → 워크플로우 import → **Execute Workflow** → Slack 채널 수신 확인.
+6. 운영 배포: `globals_prod.properties`의 토큰을 실제 값으로 교체 후 WAR 배포.
+
+## 자체 검토 결과
+
+- **스펙 커버리지**: 엔드포인트 계약(Task 2·4) / 인증(Task 1·5) / Java 컴포넌트(Task 2~5) / n8n·Slack(Task 6) / 에러처리·검증(서비스 블록별 try/catch, 통합 시나리오) — 스펙 8개 결정사항 모두 태스크에 매핑됨.
+- **placeholder**: `CHANGE_ME_*`는 의도된 사용자 치환값(호스트/채널/토큰)이며 코드 placeholder 아님.
+- **타입 일관성**: `getDashboardSummary(String)`, `DashboardSummaryVO`/`Sales`/`Members`/`Sms`/`AmtPoint`/`AgentStat`, 빈 이름(`dashboardSummaryService`, `mjonPayService`, `conectStatsService`, `mjonMsgService`)이 태스크 간 일치. `setSuccess`(lombok, `boolean isSuccess`) 사용 일관.
+- **리스크**: 기존 VO 게터명(`getTotCnt`/`getSumFailCnt`/`getRegCount`/`getAmtTotSum`) 미스매치 가능성 → Task 3 Step 3 컴파일에서 검출·수정. Jackson의 `isSuccess`/`success` 키 차이 → Task 4 Step 3에서 확정.
 
docs/superpowers/specs/2026-06-23-dashboard-slack-n8n-design.md (added)
+++ docs/superpowers/specs/2026-06-23-dashboard-slack-n8n-design.md
@@ -0,0 +1,122 @@
+# 대시보드 → n8n → Slack 정기 리포트 연동 설계
+
+작성일: 2026-06-23
+
+## 1. 목적 / 범위
+
+문자ON 관리자 대시보드(`/cmm/main/mainPage.do`)의 주요 운영 지표를 **매일(또는 매주) 정해진 시각에 Slack 채널로 요약 발송**한다.
+
+- 연동 방식: 앱에 **신규 JSON API 엔드포인트**를 추가하고, **n8n이 스케줄로 호출**하여 Slack으로 게시(pull 방식).
+- 포함 지표(1차): **매출(일/월), 회원 현황, 문자 발송 현황**.
+- 인증: **공유 토큰**(헤더) 단독. (회사 내부망 사용 전제로 IP 허용목록은 제외)
+- 비범위(추후): 발신번호/환불 대기 지표, 실시간 이벤트 알림, IP 허용목록.
+
+## 2. 현황 (재사용 자산)
+
+`itn.let.main.web.EgovMainController`가 대시보드 데이터를 아래 서비스 메서드로 조회하고 있으며, **그대로 재사용**한다(신규 SQL 없음).
+
+- 매출: `MjonPayService.selectPayDayChartDashboard`, `selectPayMonthChartDashboard`, `selectPayYearChart`
+- 회원: `EgovConectStatsService.selectMberTotStats`, `selectMberCmpHstStatsDashboard`, `selectTodaySttCountString`
+- 문자: `MjonMsgService.selectAgentSmsCountStatMainList`, `selectMemDayChartDashboard`
+
+## 3. 엔드포인트 계약 (Contract)
+
+**요청**
+```
+GET /api/dashboard/summary.do
+Header: X-DASHBOARD-TOKEN: <공유 토큰>   (필수)
+Query : ?date=YYYY-MM-DD                 (선택, 미지정 시 오늘)
+```
+
+**응답** — 앱은 Slack 포맷이 아닌 **순수 도메인 JSON**만 반환(Slack 표현은 n8n 담당, 앱-Slack 결합도 제거).
+```jsonc
+{
+  "isSuccess": true,
+  "msg": "",
+  "baseDate": "2026-06-23",
+  "sales": {                              // 매출(VAT 포함, 단위: 원, 숫자)
+    "todayAmt": 1234500,                  // 당일 매출액
+    "dayChart":   [ {"date":"06-20","amt":900000}, ... ],   // 최근 4일
+    "monthChart": [ {"month":"6월","amt":25000000}, ... ],  // 최근 4개월
+    "yearAmtSum": 310000000               // 연간 누적
+  },
+  "members": {                            // 회원 현황
+    "userNorCnt": 0, "userComCnt": 0,     // 개인/기업 정상회원수
+    "mberNorTot": 0,                      // 정상회원 합계
+    "mberBlockTot": 0, "mberSecessTot": 0,// 정지/탈퇴 누적
+    "cmpApply": 0, "cmpApprove": 0, "cmpReject": 0, // 기업회원 신청/승인/반려
+    "todayExpireCnt": 0, "todayStopCnt": 0          // 금일 탈퇴/정지
+  },
+  "sms": {                                // 문자 발송 현황(전송사별)
+    "agents": [
+      {"agentCode":"ITN019","succCnt":12000,"failCnt":30,"succRate":99}, ...
+    ],
+    "todaySignupCnt": 0                   // 일 회원가입자수(참고)
+  }
+}
+```
+
+- 원본 서비스가 문자열로 반환하는 금액/건수는 서비스 계층에서 **숫자로 정규화**한다.
+- 천단위 콤마/원화 표기 등 **표현 포맷은 n8n**에서 처리한다(앱은 raw 숫자만 제공).
+- 누락 지표는 1차 범위에서 제외하며, 향후 `sales`/`members`/`sms` 블록에 필드를 추가하는 식으로 확장한다.
+
+## 4. 인증 / 보호
+
+- `globals.properties`에 `Globals.dashboard.api.token` 추가, 환경별 `globals_*.properties`에서 override.
+- 신규 인터셉터 `DashboardApiAuthInterceptor`를 **`/api/dashboard/**` 경로에만** 매핑(`egov-interceptor-servlet.xml`).
+  - 요청 헤더 `X-DASHBOARD-TOKEN` 값이 설정 토큰과 불일치/누락 → **401** JSON(`{"isSuccess":false,"msg":"unauthorized"}`)을 직접 작성하고 컨트롤러 진입 차단.
+- 엔드포인트가 `*.do`이므로 Spring Security의 DB 기반 URL 권한(`context-security.xml`)에 걸릴 수 있다 → `/api/dashboard/**`를 `security="none"`으로 예외 추가(토큰으로 자체 보호, 세션 불필요).
+- 토큰 값은 응답/로그에 노출 금지.
+
+## 5. Java 컴포넌트 구성 (4종 패턴)
+
+신규 모듈 `itn.let.mjo.dashboardapi`:
+
+| 파일 | 역할 |
+|---|---|
+| `web/DashboardApiController.java` | **`@RestController`**. `GET /api/dashboard/summary.do` → `getDashboardSummary(...)`가 `DashboardSummaryVO`를 직접 반환(Jackson 직렬화, jsonView 미사용). 얇게 유지 |
+| `service/DashboardSummaryService.java` | 인터페이스 |
+| `service/DashboardSummaryVO.java` | 응답 DTO(sales/members/sms 중첩 + isSuccess/msg/baseDate). Jackson 직렬화용 getter 포함 |
+| `service/impl/DashboardSummaryServiceImpl.java` | `@Service`. 기존 `mjonPayService`·`conectStatsService`·`mjonMsgService`를 주입해 조합·숫자 정규화 |
+| `web/DashboardApiAuthInterceptor.java` | 토큰 헤더 검증 인터셉터 |
+
+설계 근거 / 규칙:
+- **DAO 신규 없음** — 기존 검증된 서비스 메서드만 호출.
+- `@RestController`는 `@Controller`를 메타포함 → 디스패처 컨텍스트의 `@Controller` 스캔에 잡힘. Jackson 컨버터는 `<mvc:annotation-driven/>` + `jackson-databind` 의존성 + 기존 `@ResponseBody` 선례로 동작 검증됨.
+- 빈 스캔 분리 유지: 컨트롤러/인터셉터=디스패처 컨텍스트, 서비스=루트 컨텍스트.
+- 관리자 로그 AOP가 `itn..*Controller.select*`에 걸리므로, 메서드명을 `getDashboardSummary`로(=`select*` 아님) 지어 불필요한 잡로그를 피한다.
+- 지표 블록별 try/catch — 개별 지표 실패가 전체 응답을 막지 않도록 하고 실패 블록은 null/0으로 둔다(기존 대시보드 Ajax 관례).
+
+## 6. n8n 워크플로우 / Slack
+
+```
+[Schedule Trigger]   매일 09:00 (cron)
+       ↓
+[HTTP Request]       GET https://<admin-host>/api/dashboard/summary.do
+                     Header X-DASHBOARD-TOKEN = {{ $env.MJON_DASH_TOKEN }}
+       ↓
+[Code (Function)]    도메인 JSON → Slack Block Kit 변환(콤마/원화 포맷 여기서)
+       ↓
+[Slack node]         지정 채널 게시(OAuth 또는 Incoming Webhook)
+```
+
+- Slack 메시지: 제목(`�� 문자ON 일일 리포트 — {baseDate}`) + 매출/회원/문자 섹션을 Block Kit `section` 블록으로 구성.
+- 토큰은 n8n 환경변수 `MJON_DASH_TOKEN`에 보관(워크플로우 JSON에 평문 미포함).
+- 산출물: import 가능한 `n8n-workflow.json` 예시 + Code 노드 포맷 스니펫.
+
+## 7. 에러처리 / 테스트 / 배포
+
+- 앱 서비스: 지표 블록별 try/catch, 전역 실패 시 `isSuccess:false` + `msg`. 인증 실패는 인터셉터에서 401 JSON.
+- 테스트: 본 저장소는 단위테스트 인프라가 없음(surefire `skipTests=true`) → **수동 검증**.
+  - `curl -H "X-DASHBOARD-TOKEN: <token>" http://localhost/api/dashboard/summary.do` (토큰 유/무 케이스 모두).
+  - n8n 워크플로우 Execute → Slack 채널 수신 확인.
+- 설정: `globals.properties`에 `Globals.dashboard.api.token` 추가, 환경별 override. 운영 토큰은 별도 공유.
+- 배포: WAR 재빌드 후 WAS 반영. 신규 엔드포인트는 추가 전용이라 기존 기능 영향 없음.
+
+## 8. 결정 사항 요약
+
+- 연동: pull(신규 JSON API + n8n 스케줄)  ✅
+- 집계 위치: 신규 Service(접근안 A)  ✅
+- 컨트롤러: `@RestController`  ✅
+- 인증: 공유 토큰 단독(IP 허용목록 제외)  ✅
+- 지표: 매출(일/월) / 회원 현황 / 문자 발송 현황  ✅
 
src/main/java/itn/com/annotation/PersonalLog.java (added)
+++ src/main/java/itn/com/annotation/PersonalLog.java
@@ -0,0 +1,67 @@
+package itn.com.annotation;
+
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 개인정보 처리 이력 로그 기록을 위한 메서드 어노테이션.
+ *
+ * <p>개인정보 조회, 수정, 삭제, 다운로드 등이 발생하는 컨트롤러 메서드에 선언한다.
+ * AOP가 메서드 실행 후 이 어노테이션의 설정값과 요청 정보를 읽어
+ * 개인정보 처리 이력 로그를 저장한다.</p>
+ *
+ * <pre>
+ * {@code
+ * @PersonalLog(
+ *     action = "삭제",
+ *     description = "기업회원 상세정보",
+ *     target = "#{object}.{method}" or "#{object}
+ *     search = "#{object}.{method}" or "#{object}
+ * )
+ * }
+ * </pre>
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface PersonalLog {
+    /**
+     * 개인정보 처리 행위.
+     *
+     * <p>예: 조회, 수정, 삭제, 다운로드</p>
+     *
+     * @return 개인정보 처리 행위명
+     */
+    String action();
+
+    /**
+     * 개인정보를 처리한 화면 또는 업무의 설명.
+     *
+     * <p>예: 회원 상세정보, 기업회원 목록, 회원 엑셀 다운로드</p>
+     *
+     * @return 처리 화면·업무 설명
+     */
+    String description();
+
+    /**
+     * 개인정보 처리 대상.
+     *
+     * <p>단건 처리 시 대상 회원 ID 등을 기록한다.
+     * SpEL 표현식을 사용할 수 있으며, 메서드 첫 번째 인자의 회원 ID는
+     * {@code "#{object}.{method}"}처럼 지정한다.</p>
+     *
+     * @return 처리 대상 정보, 미지정 시 빈 문자열
+     */
+    String target() default "";
+
+    /**
+     * 목록 조회 또는 다운로드 시 사용한 검색 조건.
+     *
+     * <p>검색어, 기간, 조회 건수 등 대상 정보를 보완하기 위한 용도다.</p>
+     *
+     * @return 검색 조건 정보, 미지정 시 빈 문자열
+     */
+    String search() default "";
+}
 
src/main/java/itn/com/cmm/interceptor/DashboardApiAuthInterceptor.java (added)
+++ src/main/java/itn/com/cmm/interceptor/DashboardApiAuthInterceptor.java
@@ -0,0 +1,37 @@
+package itn.com.cmm.interceptor;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
+
+/**
+ * 대시보드 요약 API 토큰 인증.
+ * X-DASHBOARD-TOKEN 헤더가 설정 토큰과 일치할 때만 통과시킨다.
+ */
+public class DashboardApiAuthInterceptor extends HandlerInterceptorAdapter {
+
+    private static final String HEADER = "X-DASHBOARD-TOKEN";
+
+    @Value("#{globalSettings['Globals.dashboard.api.token']}")
+    private String apiToken;
+
+    @Override
+    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
+            throws Exception {
+
+        String token = request.getHeader(HEADER);
+
+        boolean ok = apiToken != null && !apiToken.trim().isEmpty()
+                && apiToken.equals(token);
+
+        if (!ok) {
+            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); // 401
+            response.setContentType("application/json;charset=UTF-8");
+            response.getWriter().write("{\"isSuccess\":false,\"msg\":\"unauthorized\"}");
+            return false; // 컨트롤러 진입 차단 (토큰 값은 로그/응답에 출력하지 않음)
+        }
+        return true;
+    }
+}
src/main/java/itn/com/cmm/util/StringUtil2.java
--- src/main/java/itn/com/cmm/util/StringUtil2.java
+++ src/main/java/itn/com/cmm/util/StringUtil2.java
@@ -45,6 +45,14 @@
         return (value == null || value.length() == 0);
     }
 
+    public static boolean isEmpty(Object value) {
+        return value == null || value.toString().trim().isEmpty();
+    }
+
+    public static String stringValue(Object value) {
+        return value == null ? "" : value.toString();
+    }
+
     public static boolean isNotEmpty(String value) {
         return !isEmpty(value);
     }
src/main/java/itn/com/cmm/web/EgovFileDownloadController.java
--- src/main/java/itn/com/cmm/web/EgovFileDownloadController.java
+++ src/main/java/itn/com/cmm/web/EgovFileDownloadController.java
@@ -13,6 +13,7 @@
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import itn.com.annotation.PersonalLog;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Value;
@@ -124,6 +125,11 @@
 	 * @param response
 	 * @throws Exception
 	 */
+	@PersonalLog(
+			action = "다운로드",
+			description = "첨부파일 다운로드",
+			search = "#commandMap['atchFileId'] + ':' + #commandMap['fileSn']"
+	)
 	@RequestMapping(value = "/cmm/fms/FileDown.do")
 	public void cvplFileDownload(@RequestParam Map<String, Object> commandMap, HttpServletRequest request, HttpServletResponse response) throws Exception {
 
 
src/main/java/itn/com/uss/olh/hpc/service/GeoIpBlockLogVO.java (added)
+++ src/main/java/itn/com/uss/olh/hpc/service/GeoIpBlockLogVO.java
@@ -0,0 +1,40 @@
+package itn.com.uss.olh.hpc.service;
+
+import itn.com.cmm.ComDefaultVO;
+
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.List;
+
+public class GeoIpBlockLogVO extends ComDefaultVO{
+
+	private long blockLogId;
+	private String blockDt;
+	private String accessIp;
+	private String requestUri;
+	private String countryCode;
+	private String countryName;
+	private String blockYn;
+
+	public Long getBlockLogId() { return blockLogId; }
+	public void setBlockLogId(Long blockLogId) { this.blockLogId = blockLogId; }
+
+	public String getBlockDt() { return blockDt; }
+	public void setBlockDt(String blockDt) { this.blockDt = blockDt; }
+
+	public String getAccessIp() { return accessIp; }
+	public void setAccessIp(String accessIp) { this.accessIp = accessIp; }
+
+	public String getRequestUri() { return requestUri; }
+	public void setRequestUri(String requestUri) { this.requestUri = requestUri; }
+
+	public String getCountryCode() { return countryCode; }
+	public void setCountryCode(String countryCode) { this.countryCode = countryCode; }
+
+	public String getCountryName() { return countryName; }
+	public void setCountryName(String countryName) { this.countryName = countryName; }
+
+	public String getBlockYn() { return blockYn; }
+	public void setBlockYn(String blockYn) { this.blockYn = blockYn; }
+		
+}
src/main/java/itn/com/uss/olh/hpc/service/HackIpService.java
--- src/main/java/itn/com/uss/olh/hpc/service/HackIpService.java
+++ src/main/java/itn/com/uss/olh/hpc/service/HackIpService.java
@@ -38,4 +38,11 @@
 	
 	// 차단아이피가 아닌 고트래픽 유저 검색 후 차단처리
 	public void selectHighTrafficNotIgnoreIp() throws Exception;
+
+	// 해외접근 IP 차단 리스트
+	public List<GeoIpBlockLogVO> selecForeignAccessBlockList(GeoIpBlockLogVO blockLogVO)  throws Exception ;
+
+	public String updateAccessBlockYn(GeoIpBlockLogVO blockLogVO) throws Exception ;
+
+	public String selectAccessBlockYn() throws Exception ;
 }
src/main/java/itn/com/uss/olh/hpc/service/impl/HackIpDAO.java
--- src/main/java/itn/com/uss/olh/hpc/service/impl/HackIpDAO.java
+++ src/main/java/itn/com/uss/olh/hpc/service/impl/HackIpDAO.java
@@ -2,6 +2,7 @@
 
 import java.util.List;
 
+import itn.com.uss.olh.hpc.service.GeoIpBlockLogVO;
 import org.springframework.stereotype.Repository;
 
 import itn.com.cmm.service.impl.EgovComAbstractDAO;
@@ -79,6 +80,18 @@
 	@SuppressWarnings("unchecked")
 	public List<HackIpVO> selectHighTrafficNotIgnoreIp() {
 		return (List<HackIpVO>) list("hackIpDAO.selectHighTrafficNotIgnoreIp");
-	}	
+	}
+
+	public List<GeoIpBlockLogVO> selecForeignAccessBlockList(GeoIpBlockLogVO blockLogVO) throws Exception{
+		return (List<GeoIpBlockLogVO>) list("hackIpDAO.selecForeignAccessBlockList", blockLogVO);
+	}
+
+	public String updateAccessBlockYn(GeoIpBlockLogVO blockLogVO) throws Exception{
+		return (String) insert("hackIpDAO.updateAccessBlockYn", blockLogVO);
+	}
+
+	public String selectAccessBlockYn() throws Exception{
+		return (String) select("hackIpDAO.selectAccessBlockYn");
+	}
 	
 }
src/main/java/itn/com/uss/olh/hpc/service/impl/HackIpServiceImpl.java
--- src/main/java/itn/com/uss/olh/hpc/service/impl/HackIpServiceImpl.java
+++ src/main/java/itn/com/uss/olh/hpc/service/impl/HackIpServiceImpl.java
@@ -5,6 +5,7 @@
 
 import javax.annotation.Resource;
 
+import itn.com.uss.olh.hpc.service.GeoIpBlockLogVO;
 import org.springframework.stereotype.Service;
 
 import egovframework.rte.fdl.cmmn.EgovAbstractServiceImpl;
@@ -139,5 +140,20 @@
 		
 		
 	}
-	
+
+	@Override
+	public List<GeoIpBlockLogVO> selecForeignAccessBlockList(GeoIpBlockLogVO blockLogVO) throws Exception{
+		return hackIpDAO.selecForeignAccessBlockList(blockLogVO);
+	}
+
+	@Override
+	public String updateAccessBlockYn(GeoIpBlockLogVO blockLogVO) throws Exception {
+		return hackIpDAO.updateAccessBlockYn(blockLogVO);
+	}
+
+	@Override
+	public String selectAccessBlockYn() throws Exception {
+		return hackIpDAO.selectAccessBlockYn();
+	}
+
 }
src/main/java/itn/com/uss/olh/hpc/web/EgovHpcmController.java
--- src/main/java/itn/com/uss/olh/hpc/web/EgovHpcmController.java
+++ src/main/java/itn/com/uss/olh/hpc/web/EgovHpcmController.java
@@ -5,14 +5,12 @@
 import java.net.HttpURLConnection;
 import java.net.URL;
 import java.net.URLEncoder;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.List;
+import java.util.*;
 
 import javax.annotation.Resource;
 import javax.servlet.http.HttpServletRequest;
 
+import itn.com.uss.olh.hpc.service.*;
 import org.apache.commons.lang3.StringUtils;
 import org.json.simple.JSONObject;
 import org.json.simple.parser.JSONParser;
@@ -22,6 +20,7 @@
 import org.springframework.web.bind.annotation.ModelAttribute;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
 import org.springframework.web.servlet.ModelAndView;
 import org.springframework.web.servlet.mvc.support.RedirectAttributes;
 
@@ -35,10 +34,6 @@
 import itn.com.cmm.service.EgovCmmUseService;
 import itn.com.cmm.util.RedirectUrlMaker;
 import itn.com.cmm.util.StringUtil;
-import itn.com.uss.olh.hpc.service.EgovHpcmService;
-import itn.com.uss.olh.hpc.service.HackIpService;
-import itn.com.uss.olh.hpc.service.HackIpVO;
-import itn.com.uss.olh.hpc.service.HpcmVO;
 import itn.com.utl.fcc.service.EgovStringUtil;
 
 /**
@@ -306,6 +301,52 @@
         model.addAttribute("paginationInfo", paginationInfo);
         return "/uss/olp/hpc/HackIpList";
     }
+
+	@RequestMapping(value="/uss/olp/hak/ForeignAccessBlock.do")
+	public String selectForeignAccessBlockList(@ModelAttribute("searchVO") GeoIpBlockLogVO searchVO,
+								 ModelMap model) throws Exception {
+
+		if(searchVO.getPageUnit() != 10) {
+			searchVO.setPageUnit(searchVO.getPageUnit());
+		}
+
+		PaginationInfo paginationInfo = new PaginationInfo();
+		paginationInfo.setCurrentPageNo(searchVO.getPageIndex());
+		paginationInfo.setRecordCountPerPage(searchVO.getPageUnit());
+		paginationInfo.setPageSize(searchVO.getPageSize());
+
+		searchVO.setFirstIndex(paginationInfo.getFirstRecordIndex());
+		searchVO.setLastIndex(paginationInfo.getLastRecordIndex());
+		searchVO.setRecordCountPerPage(paginationInfo.getRecordCountPerPage());
+
+		List<GeoIpBlockLogVO> blockIpList = hackIpService.selecForeignAccessBlockList(searchVO);
+		String accessBlockYn = hackIpService.selectAccessBlockYn();
+		model.addAttribute("resultList", blockIpList);
+		model.addAttribute("accessBlockYn", accessBlockYn);
+		paginationInfo.setTotalRecordCount(blockIpList.size() > 0 ? blockIpList.get(0).getTotCnt() : 0);
+		model.addAttribute("paginationInfo", paginationInfo);
+		return "/uss/olp/hpc/ForeignAccessBlockList";
+	}
+
+	@RequestMapping("/uss/olp/hak/updateAccessBlockYn.do")
+	@ResponseBody
+	public Map<String, Object> updateAccessBlockYn(
+			@ModelAttribute("searchVO") GeoIpBlockLogVO searchVO, Model model) throws Exception {
+
+		Map<String, Object> resultMap = new HashMap<>();
+
+		try {
+			String blockYn = hackIpService.updateAccessBlockYn(searchVO);
+
+			resultMap.put("blockYn", blockYn);
+			resultMap.put("result", "success");
+		} catch (Exception e) {
+			resultMap.put("result", "fail");
+			resultMap.put("message", e.getMessage());
+		}
+
+		return resultMap;
+	}
     
     /**
      * 로그인 로그 관리 (pageing)
 
src/main/java/itn/com/utl/aop/AopExpressionHelper.java (added)
+++ src/main/java/itn/com/utl/aop/AopExpressionHelper.java
@@ -0,0 +1,72 @@
+package itn.com.utl.aop;
+
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.springframework.expression.EvaluationContext;
+import org.springframework.expression.Expression;
+import org.springframework.expression.ExpressionParser;
+import org.springframework.expression.spel.standard.SpelExpressionParser;
+import org.springframework.expression.spel.support.StandardEvaluationContext;
+import org.springframework.ui.ModelMap;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+public class AopExpressionHelper {
+
+    private static final ExpressionParser PARSER = new SpelExpressionParser();
+    private static final Map<String, Expression> EXPRESSION_CACHE = new ConcurrentHashMap<String, Expression>();
+
+    private AopExpressionHelper() {
+    }
+
+    public static EvaluationContext createContext(JoinPoint joinPoint, MethodSignature signature) {
+
+        StandardEvaluationContext context = new StandardEvaluationContext();
+
+        Object[] args = joinPoint.getArgs();
+        String[] names = signature.getParameterNames();
+
+        if (names != null) {
+            for (int i = 0; i < names.length; i++) {
+                context.setVariable(names[i], args[i]);
+            }
+        }
+
+        for (Object arg : args) {
+            if (arg instanceof ModelMap) {
+                ModelMap model = (ModelMap) arg;
+
+                for (Map.Entry<String, Object> entry : model.entrySet()) {
+                    context.setVariable(entry.getKey(), entry.getValue());
+                }
+            }
+        }
+
+        return context;
+    }
+
+    public static Object evaluate(EvaluationContext context, String expression) {
+
+        if (!hasText(expression)) {
+            return null;
+        }
+
+        Expression compiled = EXPRESSION_CACHE.get(expression);
+
+        if (compiled == null) {
+            Expression parsed = PARSER.parseExpression(expression);
+
+            Expression existing = EXPRESSION_CACHE.putIfAbsent(expression, parsed);
+
+            compiled = existing != null
+                    ? existing
+                    : parsed;
+        }
+
+        return compiled.getValue(context);
+    }
+
+    public static boolean hasText(String value) {
+        return value != null && !value.trim().isEmpty();
+    }
+}
 
src/main/java/itn/com/utl/page/BasePageableVO.java (added)
+++ src/main/java/itn/com/utl/page/BasePageableVO.java
@@ -0,0 +1,77 @@
+package itn.com.utl.page;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class BasePageableVO implements PageableVO {
+
+    private int pageIndex = 1;
+    private int pageUnit = 10;
+    private int pageSize = 10;
+
+    private int firstIndex;
+    private int lastIndex;
+    private int recordCountPerPage;
+    private String searchKeyword;
+
+
+    // searchVO 로 빼야함 -> BaseVO implements PageableVO, SearchVO
+    private String searchSortCnd;
+    private String searchSortOrd;
+
+    private String searchCondition;
+    private String searchStartDate;
+    private String searchEndDate;
+
+    @Override
+    public int getPageIndex() {
+        return pageIndex;
+    }
+    @Override
+    public int getPageUnit() {
+        return pageUnit;
+    }
+
+    @Override
+    public int getPageSize() {
+        return pageSize;
+    }
+
+    @Override
+    public String getSearchSortCnd() {
+        return searchSortCnd;
+    }
+
+    @Override
+    public void setSearchSortCnd(String searchSortCnd) {
+        this.searchSortCnd = searchSortCnd;
+    }
+
+    @Override
+    public String getSearchSortOrd() {
+        return searchSortOrd;
+    }
+
+    @Override
+    public void setSearchSortOrd(String searchSortOrd) {
+        this.searchSortOrd = searchSortOrd;
+    }
+
+    @Override
+    public void setFirstIndex(int firstIndex) {
+        this.firstIndex = firstIndex;
+    }
+
+    @Override
+    public void setLastIndex(int lastIndex) {
+        this.lastIndex = lastIndex;
+    }
+
+    @Override
+    public void setRecordCountPerPage(int recordCountPerPage) {
+        this.recordCountPerPage = recordCountPerPage;
+    }
+
+}(No newline at end of file)
 
src/main/java/itn/com/utl/page/PageableVO.java (added)
+++ src/main/java/itn/com/utl/page/PageableVO.java
@@ -0,0 +1,16 @@
+package itn.com.utl.page;
+
+public interface PageableVO {
+    int getPageIndex();
+    int getPageUnit();
+    int getPageSize();
+    String getSearchSortCnd();
+    String getSearchSortOrd();
+
+    void setFirstIndex(int firstIndex);
+    void setLastIndex(int lastIndex);
+    void setRecordCountPerPage(int recordCountPerPage);
+    void setSearchSortCnd(String defaultCnd);
+    void setSearchSortOrd(String defaultOrd);
+}
+
 
src/main/java/itn/com/utl/page/PaginationUtil.java (added)
+++ src/main/java/itn/com/utl/page/PaginationUtil.java
@@ -0,0 +1,41 @@
+package itn.com.utl.page;
+
+import egovframework.rte.ptl.mvc.tags.ui.pagination.PaginationInfo;
+
+
+public class PaginationUtil {
+    /**
+     * 작성자   : 조민수
+     * 작성일자 : 2026/07/24
+     * 공통 페이징 정보를 초기화한다.
+     *
+     * <p>사용 방법 및 적용 예시는 사내 Wiki의
+     * 'https://wiki.iten.co.kr/40.프로젝트:2026_base_프로젝트:0.참고자료:공용함수정보:pagination-util' 문서를 참고한다.</p>
+     *
+     * @param <T vo> BasePaginationVO를 상속한 VO
+     * @return 초기화된 PaginationInfo
+     */
+    public static <T extends PageableVO> PaginationInfo init(T vo) {
+        PaginationInfo paginationInfo = new PaginationInfo();
+        paginationInfo.setCurrentPageNo(vo.getPageIndex());
+        paginationInfo.setRecordCountPerPage(vo.getPageUnit());
+        paginationInfo.setPageSize(vo.getPageSize());
+
+        vo.setFirstIndex(paginationInfo.getFirstRecordIndex());
+        vo.setLastIndex(paginationInfo.getLastRecordIndex());
+        vo.setRecordCountPerPage(paginationInfo.getRecordCountPerPage());
+        return paginationInfo;
+    }
+
+    public static <T extends PageableVO> PaginationInfo initWithSort(T vo, String defaultCnd, String defaultOrd) {
+        if(vo.getSearchSortCnd() == null || vo.getSearchSortCnd().isEmpty()) {
+            vo.setSearchSortCnd(defaultCnd);
+        }
+        if (vo.getSearchSortOrd() == null || vo.getSearchSortOrd().isEmpty()) {
+            vo.setSearchSortOrd(defaultOrd);  // asc / desc
+        }
+        return init(vo);
+    }
+
+
+}
 
src/main/java/itn/com/utl/response/ApiResponse.java (added)
+++ src/main/java/itn/com/utl/response/ApiResponse.java
@@ -0,0 +1,58 @@
+
+
+package itn.com.utl.response;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Setter
+@Getter
+public class ApiResponse<T> {
+    private boolean success;
+    private String message;
+    private T data;
+
+    public static <T> ApiResponse<T> success() {
+        return new ApiResponse<>(true, null, null);
+    }
+
+    public static <T> ApiResponse<T> success(T data) {
+        return new ApiResponse<>(true, null, data);
+    }
+
+    public static <T> ApiResponse<T> success(T data, String message) {
+        return new ApiResponse<>(true, message, data);
+    }
+
+    public static <T> ApiResponse<T> fail(String message) {
+        return new ApiResponse<>(false, message, null);
+    }
+
+    public ApiResponse() {
+    }
+
+    public ApiResponse(boolean success, String message, T data) {
+        this.success = success;
+        this.message = message;
+        this.data = data;
+    }
+
+    public static <T> ApiResponse<T> successWithMessage(String message) {
+        ApiResponse<T> res = new ApiResponse<>();
+        res.success = true;
+        res.message = message;
+        res.data = null;
+        return res;
+    }
+
+    @Override
+    public String toString() {
+        return "ApiResponse{" +
+                "success=" + success +
+                ", message='" + message + '\'' +
+                ", data=" + data +
+                '}';
+    }
+}
+
+
src/main/java/itn/let/cert/phone/service/MberCertPhoneVO.java
--- src/main/java/itn/let/cert/phone/service/MberCertPhoneVO.java
+++ src/main/java/itn/let/cert/phone/service/MberCertPhoneVO.java
@@ -33,6 +33,7 @@
 	private String certUseYn;
 	
 	private String checkNo;
+	private String mberRegDate;
 	
 	
 	
@@ -74,6 +75,12 @@
 	public void setCheckNo(String checkNo) {
 		this.checkNo = checkNo;
 	}
+	public String getMberRegDate() {
+		return mberRegDate;
+	}
+	public void setMberRegDate(String mberRegDate) {
+		this.mberRegDate = mberRegDate;
+	}
 	
 	
 	
src/main/java/itn/let/cert/phone/web/CertPhoneController.java
--- src/main/java/itn/let/cert/phone/web/CertPhoneController.java
+++ src/main/java/itn/let/cert/phone/web/CertPhoneController.java
@@ -7,6 +7,8 @@
 import javax.annotation.Resource;
 import javax.servlet.http.HttpServletRequest;
 
+import itn.let.uss.umt.service.EgovMberManageService;
+import itn.let.uss.umt.service.MberManageVO;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
@@ -49,6 +51,10 @@
 	
 	@Resource(name = "MjonMsgDataService")
 	private MjonMsgDataService mjonMsgDataService;
+
+	@Resource(name = "mberManageService")
+	private EgovMberManageService mberManageService;
+
 	
 	
 	
@@ -91,8 +97,7 @@
 		
 		ModelAndView modelAndView = new ModelAndView();
 		modelAndView.setViewName("jsonView");
-		
-		
+
 		System.out.println(" :: insertCertPhone :: ");
 		
 		//로그인 권한정보 불러오기
@@ -103,10 +108,23 @@
 			if(StringUtils.isEmpty(userId)) return ResponseEntity.ok().body(new StatusResponse(HttpStatus.BAD_REQUEST, "로그인 후 이용해 주세요", LocalDateTime.now()));
 		}
 		mberCertPhoneVO.setFrstRegisterId(userId);
-		mberCertPhoneVO.setMberId(userId);
+		if(mberCertPhoneVO.getMberId() == null || mberCertPhoneVO.getMberId().equals("")){
+			mberCertPhoneVO.setMberId(userId);
+		}
 
+		StatusResponse statusResponse = certPhoneService.insertCertPhone(mberCertPhoneVO, mberCertPhoneVO.getMbtlnum());
+
+		if (statusResponse.getStatus().equals(HttpStatus.OK)) {
+			MberManageVO mberManageVO = new MberManageVO();
+			String memo = "";
+			memo = "보안로그인 번호 관리자 등록 :" + mberCertPhoneVO.getMbtlnum();
+			mberManageVO.setMberId(mberCertPhoneVO.getMberId());
+			mberManageVO.setMemoCn(memo);
+			mberManageVO.setFrstRegisterId(userId);
+			mberManageService.insertMberMemo(mberManageVO);
+		}
 		
-		return ResponseEntity.ok().body(certPhoneService.insertCertPhone(mberCertPhoneVO, loginVO.getMoblphonNo()));
+		return ResponseEntity.ok().body(statusResponse);
 	}	
 	
 	@RequestMapping(value = {"/cert/phone/updateCertPhone.do"})
@@ -149,12 +167,20 @@
 		if(StringUtils.isEmpty(mberCertPhoneVO.getMberId()) ) {
 			mberCertPhoneVO.setMberId(userId);
 		}
+		StatusResponse statusResponse = certPhoneService.deleteCertPhone(mberCertPhoneVO);
+
+		if (statusResponse.getStatus().equals(HttpStatus.OK)) {
+			MberManageVO mberManageVO = new MberManageVO();
+			String memo = "";
+			memo = "보안로그인 번호 관리자 삭제 :" + mberCertPhoneVO.getMbtlnum();
+			mberManageVO.setMberId(mberCertPhoneVO.getMberId());
+			mberManageVO.setMemoCn(memo);
+			mberManageVO.setFrstRegisterId(userId);
+			mberManageService.insertMberMemo(mberManageVO);
+		}
 		
-		
-		return ResponseEntity.ok().body(certPhoneService.deleteCertPhone(mberCertPhoneVO));
-	}	
-	
-	
+		return ResponseEntity.ok().body(statusResponse);
+	}
 	
 	
 	
src/main/java/itn/let/cop/bbs/service/Board.java
--- src/main/java/itn/let/cop/bbs/service/Board.java
+++ src/main/java/itn/let/cop/bbs/service/Board.java
@@ -272,6 +272,8 @@
    	private String pubDetail;  //사전정보공표 디테일
    	
    	private List<FileVO> fileList = new ArrayList<FileVO>();  //리스트목록에서 파일들을 가져오기 위해
+
+	private String commenterNms;
    	
 	public String getSiteId() {
 		return siteId;
@@ -1094,5 +1096,14 @@
 	public void setPubDetail(String pubDetail) {
 		this.pubDetail = pubDetail;
 	}
+
+	public String getCommenterNms() {
+		return commenterNms;
+	}
+
+	public void setCommenterNms(String commenterNms) {
+		this.commenterNms = commenterNms;
+	}
+
 	
 }
src/main/java/itn/let/cop/bbs/service/BoardVO.java
--- src/main/java/itn/let/cop/bbs/service/BoardVO.java
+++ src/main/java/itn/let/cop/bbs/service/BoardVO.java
@@ -171,6 +171,10 @@
 	private String ntcrId;
     
     private String ntcrNm;
+
+    private String searchStartDate = ""; // 검색 시작일자
+
+    private String searchEndDate = "";	// 검색 종료일자
     
     
     //---------------------------------
@@ -804,5 +808,13 @@
 	public void setNiceNm(String niceNm) {
 		this.niceNm = niceNm;
 	}
+
+    public String getSearchStartDate() { return searchStartDate; }
+
+    public void setSearchStartDate(String searchStartDate) {this.searchStartDate = searchStartDate;}
+
+    public String getSearchEndDate() { return searchEndDate; }
+
+    public void setSearchEndDate(String searchEndDate) {this.searchEndDate = searchEndDate;}
 	
 }
(No newline at end of file)
src/main/java/itn/let/cop/bbs/service/EgovBBSManageService.java
--- src/main/java/itn/let/cop/bbs/service/EgovBBSManageService.java
+++ src/main/java/itn/let/cop/bbs/service/EgovBBSManageService.java
@@ -215,6 +215,8 @@
 	
 	public List<BoardVO> selectAdminMainBoard(BoardVO boardVO) throws Exception;
 
+	public List<BoardVO> selectBbsContentsListExcelDownload(BoardVO boardVO) throws Exception;
+
 	public List<BoardVO> selectAdminMainBoardByDash(BoardVO boardVO) throws Exception;
 	
 	public List<BoardVO> selectUserBbsWriteList(BoardVO boardVO) throws Exception;
src/main/java/itn/let/cop/bbs/service/impl/BBSManageDAO.java
--- src/main/java/itn/let/cop/bbs/service/impl/BBSManageDAO.java
+++ src/main/java/itn/let/cop/bbs/service/impl/BBSManageDAO.java
@@ -345,6 +345,10 @@
     	return (List<BoardVO>) list("BBSManageDAO.selectAdminMainBoard", boardVO);
     }
 
+	public List<BoardVO> selectBbsContentsListExcelDownload(BoardVO boardVO) throws Exception {
+		return (List<BoardVO>) list("BBSManageDAO.selectBbsContentsListExcelDownload", boardVO);
+	}
+
     @SuppressWarnings("unchecked")
     public List<BoardVO> selectAdminMainBoardByDash(BoardVO boardVO) throws Exception {
     	return (List<BoardVO>) list("BBSManageDAO.selectAdminMainBoardByDash", boardVO);
src/main/java/itn/let/cop/bbs/service/impl/EgovBBSManageServiceImpl.java
--- src/main/java/itn/let/cop/bbs/service/impl/EgovBBSManageServiceImpl.java
+++ src/main/java/itn/let/cop/bbs/service/impl/EgovBBSManageServiceImpl.java
@@ -328,6 +328,11 @@
 	}
 
 	@Override
+	public List<BoardVO> selectBbsContentsListExcelDownload(BoardVO boardVO) throws Exception {
+		return bbsMngDAO.selectBbsContentsListExcelDownload(boardVO);
+	}
+
+	@Override
 	public List<BoardVO> selectAdminMainBoardByDash(BoardVO boardVO) throws Exception {
 		return bbsMngDAO.selectAdminMainBoardByDash(boardVO);
 	}
src/main/java/itn/let/cop/bbs/web/EgovBBSAttributeManageController.java
--- src/main/java/itn/let/cop/bbs/web/EgovBBSAttributeManageController.java
+++ src/main/java/itn/let/cop/bbs/web/EgovBBSAttributeManageController.java
@@ -13,6 +13,7 @@
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSession;
 
+import itn.let.uat.uap.service.LoginPolicyVO;
 import org.apache.poi.ss.usermodel.Cell;
 import org.apache.poi.ss.usermodel.CellStyle;
 import org.apache.poi.ss.usermodel.Font;
@@ -29,6 +30,7 @@
 import org.springframework.web.bind.support.SessionStatus;
 import org.springframework.web.servlet.ModelAndView;
 import org.springframework.web.servlet.mvc.support.RedirectAttributes;
+import org.springframework.web.util.HtmlUtils;
 import org.springmodules.validation.commons.DefaultBeanValidator;
 
 import egovframework.rte.fdl.property.EgovPropertyService;
@@ -115,6 +117,17 @@
 	    {"5", "사용여부" , "test@itn.co.kr", ""},
 	    {"6", "생성일" , "02-123-4567", ""} 
 	} ;
+
+	//게시글 리스트 컬럼 정의
+	private String[][] bbsContentsExcelValue ={
+			{"0" ,"번호" , "1" , "" },
+			{"1", "제목" , "제목테스트" , ""},
+			{"2", "내용" , "내용테스트", ""},
+			{"3", "등록ID" , "testId", ""},
+			{"4", "등록자" , "사용자", ""},
+			{"5", "답변자" , "관리자", ""},
+			{"6", "등록일" , "2026-08-26", ""}
+	} ;
 	
 	
 	/**
@@ -182,6 +195,99 @@
 		
 		return "cop/bbs/EgovBoardContentsList";
 	}
+
+	// 게시글 리스트 엑셀 다운로드
+	@RequestMapping(value="/cop/bbs/SelectBbsListExcelDownload.do")
+	public void SelectBbsListExcelDownload(BoardVO boardVO,
+											 HttpServletRequest request,
+											 HttpServletResponse response ,
+											 ModelMap model) throws Exception {
+
+		boardVO.setRecordCountPerPage(5000);
+		boardVO.setFirstIndex(0);
+
+		// 메모리에 100개의 행을 유지합니다. 행의 수가 넘으면 디스크에 적습니다.
+		SXSSFWorkbook wb = new SXSSFWorkbook(100);
+		CellStyle style = wb.createCellStyle();
+		style.setBorderBottom(CellStyle.BORDER_THIN); //테두리 두껍게
+		style.setBorderLeft(CellStyle.BORDER_THIN);
+		style.setBorderRight(CellStyle.BORDER_THIN);
+		style.setBorderTop(CellStyle.BORDER_THIN);
+		Font font = wb.createFont();
+		font.setBoldweight(Font.BOLDWEIGHT_BOLD);  //글씨 bold
+		Cell cell = null;
+		Row row = null;
+		String fileName ="게시글 리스트";
+		String sheetTitle = "";
+
+		try{
+			List<BoardVO> bbsContentsList = bbsMngService.selectBbsContentsListExcelDownload(boardVO);
+
+			{ //화면 리스트
+				sheetTitle = "게시글 리스트" ; //제목
+				Sheet sheet = wb.createSheet(sheetTitle);
+				row = sheet.createRow(0);
+				for(int i=0 ; i < bbsContentsExcelValue.length ; i++) {
+					cell = row.createCell(i);
+					cell.setCellStyle(style);
+					cell.setCellValue(bbsContentsExcelValue[i][1]);
+				}
+
+				for(int i=0; i <  bbsContentsList.size(); i++){
+					row = sheet.createRow(i+1);
+					for(int j=0 ; j < bbsContentsExcelValue.length ; j++) {
+						cell = row.createCell(j);
+						cell.setCellStyle(style);
+						if(j==0) cell.setCellValue(i+1); //번호
+						if(j==1) cell.setCellValue(bbsContentsList.get(i).getNttSj()); //제목
+						if (j == 2) {
+							String rawContent = bbsContentsList.get(i).getNttCn();
+							if (rawContent != null) {
+								String decodedContent = HtmlUtils.htmlUnescape(rawContent);
+								String plainText = decodedContent.replaceAll("<(/)?([a-zA-Z]*)(\\s[a-zA-Z]*=[^>]*)?>", "");
+								plainText = plainText.replaceAll("[\r\n]+", " ").replaceAll("<br>", "\n").replaceAll("<br />", "\n").trim();
+								String safeContent = plainText.length() > 300 ? plainText.substring(0, 300) : plainText;
+								cell.setCellValue(safeContent);
+							} else {
+								cell.setCellValue("");
+							}
+						}
+						if(j==3) cell.setCellValue(bbsContentsList.get(i).getNtcrId()); //등록ID
+						if(j==4) cell.setCellValue(bbsContentsList.get(i).getNtcrNm()); //등록자
+						if(j==5) cell.setCellValue(bbsContentsList.get(i).getCommenterNms()); //답변자
+						if(j==6) cell.setCellValue(bbsContentsList.get(i).getFrstRegisterPnttm()); //등록일
+					}
+				}
+			}
+			response.setHeader("Set-Cookie", "fileDownload=true; path=/");
+			SimpleDateFormat mSimpleDateFormat = new SimpleDateFormat ( "yyyy_MM_dd_HH_mm_ss", Locale.KOREA );
+			Date currentTime = new Date ();
+			String mTime = mSimpleDateFormat.format ( currentTime );
+			fileName = fileName+"("+mTime+")";
+
+			response.setHeader("Content-Disposition", String.format("attachment; filename=\""+new String((fileName).getBytes("KSC5601"),"8859_1")+".xlsx"));
+			wb.write(response.getOutputStream());
+
+		}catch(Exception e) {
+			response.setHeader("Set-Cookie", "fileDownload=false; path=/");
+			response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
+			response.setHeader("Content-Type","text/html; charset=utf-8");
+			OutputStream out = null;
+			try {
+				out = response.getOutputStream();
+				byte[] data = new String("fail..").getBytes();
+				out.write(data, 0, data.length);
+			} catch(Exception ignore) {
+				ignore.printStackTrace();
+			} finally {
+				if(out != null) try { out.close(); } catch(Exception ignore) {}
+			}
+		}finally {
+			// 디스크 적었던 임시파일을 제거합니다.
+			wb.dispose();
+			try { wb.close(); } catch(Exception ignore) {}
+		}
+	}
 	
 	
 	/**
src/main/java/itn/let/fax/admin/web/FaxAdmController.java
--- src/main/java/itn/let/fax/admin/web/FaxAdmController.java
+++ src/main/java/itn/let/fax/admin/web/FaxAdmController.java
@@ -9,6 +9,7 @@
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import itn.com.annotation.PersonalLog;
 import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -99,6 +100,7 @@
 	 * @return
 	 * @throws Exception 
 	 */
+	@PersonalLog(action = "조회", description = "팩스 발송내역", search = "#resultList.size()")
 	@RequestMapping(value= {"/uss/ion/fax/faxAdmSendList.do"})
 	public String faxAdmSendList(@ModelAttribute("searchVO") FaxGroupDataVO faxGroupDataVO
 			, ModelMap model) throws Exception{
@@ -165,6 +167,7 @@
 	 * @return
 	 * @throws Exception 
 	 */
+	@PersonalLog(action = "조회", description = "팩스 발송내역", search = "#resultList.size()")
 	@RequestMapping(value= {"/uss/ion/fax/faxAdmSendDetailList.do"})
 	public String faxAdmSendDetailList(@ModelAttribute("searchVO") FaxGroupDataVO faxGroupDataVO
 			, ModelMap model) throws Exception{
src/main/java/itn/let/kakao/admin/kakaoAt/web/MjonKakaoATController.java
--- src/main/java/itn/let/kakao/admin/kakaoAt/web/MjonKakaoATController.java
+++ src/main/java/itn/let/kakao/admin/kakaoAt/web/MjonKakaoATController.java
@@ -11,6 +11,7 @@
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import itn.com.annotation.PersonalLog;
 import org.apache.poi.ss.usermodel.Cell;
 import org.apache.poi.ss.usermodel.CellStyle;
 import org.apache.poi.ss.usermodel.Font;
@@ -97,6 +98,7 @@
      * @return	"/uss/ion/kakaoat/SendKakaoATList.do"
      * @throws Exception
      */
+	@PersonalLog(action = "조회", description = "카카오 발송내역", search = "#resultList.size()")
 	@RequestMapping(value= {"/uss/ion/kakaoat/SendKakaoATList.do"})
 	public String sendKakaoATList(@ModelAttribute("searchVO") KakaoVO kakaoVO,
 			HttpServletRequest request ,
@@ -173,10 +175,10 @@
 		return "/uss/ion/kakaoat/SendKakaoATList";
         
 	}
-	
 
-    
-	  //문자 전송 리스트(전체) 엑셀 다운로드
+
+
+		@PersonalLog(action = "다운로드", description = "카카오 엑셀 다운로드", search = "#resultList.size()")
 	  	@RequestMapping(value= {"/uss/ion/kakaoat/SendMsgExcelDownload.do"})
 	  	public void sendMsgExcelDownload( KakaoVO kakaoVO, 
 	  			HttpServletRequest request, 
@@ -207,6 +209,7 @@
 	  		String sheetTitle = ""; 
 	  		try{
 				List<KakaoVO> resultList = mjonKakaoATService.selectMjonKakaoATGroupCompleteByUserList_advc(kakaoVO);
+				model.addAttribute("resultList", resultList);
 	  			{ //화면 리스트
 	  				sheetTitle = "문자 전송 리스트(전체)" ; //제목
 	  				Sheet sheet = wb.createSheet(sheetTitle);
@@ -312,6 +315,7 @@
      * uss/ion/msg/SendMsgDetailList.do(개별 문자리스트)
      * @throws Exception
      */
+	 @PersonalLog(action = "조회", description = "카카오 발송내역", search = "#resultList.size()")
 	@RequestMapping(value= { "/uss/ion/kakaoat/SendKakaoATDetailList.do"})
 	public String sendKakaoATDetailList(@ModelAttribute("searchVO") KakaoVO searchVO, 
 			HttpServletRequest request ,
src/main/java/itn/let/kakao/admin/kakaoAt/web/MjonKakaoSendResultController.java
--- src/main/java/itn/let/kakao/admin/kakaoAt/web/MjonKakaoSendResultController.java
+++ src/main/java/itn/let/kakao/admin/kakaoAt/web/MjonKakaoSendResultController.java
@@ -10,6 +10,7 @@
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import itn.com.annotation.PersonalLog;
 import org.apache.poi.ss.usermodel.Cell;
 import org.apache.poi.ss.usermodel.CellStyle;
 import org.apache.poi.ss.usermodel.Font;
@@ -54,6 +55,7 @@
      * @return	"/uss/ion/kakaoat/sendresult/selectKakaoSendResultList.do"
      * @throws Exception
      */
+	@PersonalLog(action = "조회", description = "카카오 발송내역", search = "#resultList.size()")
 	@RequestMapping(value= {"/uss/ion/kakaoat/sendresult/selectKakaoSendResultList.do"})
 	public String selectKakaoSendResultList(@ModelAttribute("searchVO") MjonMsgResultCodeVO searchVO, 
 			HttpServletRequest request ,
src/main/java/itn/let/mjo/addragency/web/AddrAgencyController.java
--- src/main/java/itn/let/mjo/addragency/web/AddrAgencyController.java
+++ src/main/java/itn/let/mjo/addragency/web/AddrAgencyController.java
@@ -6,6 +6,7 @@
 import javax.annotation.Resource;
 import javax.servlet.http.HttpServletRequest;
 
+import itn.com.annotation.PersonalLog;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Controller;
@@ -188,7 +189,7 @@
      * @return
      * @throws Exception
      */
-        
+
     @RequestMapping(value= {"/uss/ion/addragency/selectAddrAgencyList.do"})    
     public String selectAddrAgencyList(
     		HttpServletRequest request
@@ -216,7 +217,7 @@
     	addrAgencyVO.setUrl(request.getRequestURI()); 
     	
     	
-		return "/uss/ion/addragency/AddrAgencyList";    	
+		return "/uss/ion/addragency/AddrAgencyList";
     	
     }
     
@@ -227,7 +228,7 @@
      * @return
      * @throws Exception
      */
-    
+	@PersonalLog(action = "조회", description = "주소록 입력 대행", search = "#resultList.size()")
     @RequestMapping(value= {"/uss/ion/addragency/selectAddrAgencyListAjax.do"})
     public String selectAddrAgencyListAjaxAdmin(
     		HttpServletRequest request
 
src/main/java/itn/let/mjo/dashboardapi/service/DashboardSummaryService.java (added)
+++ src/main/java/itn/let/mjo/dashboardapi/service/DashboardSummaryService.java
@@ -0,0 +1,14 @@
+package itn.let.mjo.dashboardapi.service;
+
+/**
+ * 대시보드 요약 API 집계 서비스.
+ * 기존 대시보드 서비스 메서드를 조합해 raw 숫자 요약을 만든다(신규 SQL 없음).
+ */
+public interface DashboardSummaryService {
+
+    /**
+     * @param baseDate "yyyy-MM-dd" 또는 null(오늘)
+     * @return 매출/회원/문자 요약
+     */
+    DashboardSummaryVO getDashboardSummary(String baseDate) throws Exception;
+}
 
src/main/java/itn/let/mjo/dashboardapi/service/DashboardSummaryVO.java (added)
+++ src/main/java/itn/let/mjo/dashboardapi/service/DashboardSummaryVO.java
@@ -0,0 +1,96 @@
+package itn.let.mjo.dashboardapi.service;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 대시보드 요약 API(n8n→Slack) 응답 DTO.
+ * 앱은 표현 포맷 없이 raw 숫자만 제공한다(콤마/원화는 n8n에서 처리).
+ */
+@Getter
+@Setter
+public class DashboardSummaryVO implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    // 필드명을 success로 두어 Lombok 게터 isSuccess()와 동일 프로퍼티로 묶이게 한다.
+    // (필드명을 isSuccess로 두면 Jackson이 isSuccess/success 두 키를 모두 출력하는 문제가 있음)
+    @JsonProperty("isSuccess")
+    private boolean success = true;
+    private String msg = "";
+    private String baseDate;
+
+    private Sales sales = new Sales();
+    private Members members = new Members();
+    private Sms sms = new Sms();
+
+    /** 매출(VAT 포함, 단위: 원) */
+    @Getter
+    @Setter
+    public static class Sales implements Serializable {
+        private static final long serialVersionUID = 1L;
+        private long todayAmt;
+        private List<AmtPoint> dayChart = new ArrayList<AmtPoint>();
+        private List<AmtPoint> monthChart = new ArrayList<AmtPoint>();
+        private long yearAmtSum;
+    }
+
+    /** 금액 시계열 한 점 (label = "MM-DD" 또는 "N월") */
+    @Getter
+    @Setter
+    public static class AmtPoint implements Serializable {
+        private static final long serialVersionUID = 1L;
+        private String label;
+        private long amt;
+
+        public AmtPoint() {
+        }
+
+        public AmtPoint(String label, long amt) {
+            this.label = label;
+            this.amt = amt;
+        }
+    }
+
+    /** 회원 현황 */
+    @Getter
+    @Setter
+    public static class Members implements Serializable {
+        private static final long serialVersionUID = 1L;
+        private int userNorCnt;
+        private int userComCnt;
+        private int mberNorTot;
+        private int mberBlockTot;
+        private int mberSecessTot;
+        private int cmpApply;
+        private int cmpApprove;
+        private int cmpReject;
+        private int todayExpireCnt;
+        private int todayStopCnt;
+    }
+
+    /** 문자 발송 현황 */
+    @Getter
+    @Setter
+    public static class Sms implements Serializable {
+        private static final long serialVersionUID = 1L;
+        private List<AgentStat> agents = new ArrayList<AgentStat>();
+        private int todaySignupCnt;
+    }
+
+    /** 전송사별 발송 통계 */
+    @Getter
+    @Setter
+    public static class AgentStat implements Serializable {
+        private static final long serialVersionUID = 1L;
+        private String agentCode;
+        private int succCnt;
+        private int failCnt;
+        private int succRate;
+    }
+}
 
src/main/java/itn/let/mjo/dashboardapi/service/impl/DashboardSummaryServiceImpl.java (added)
+++ src/main/java/itn/let/mjo/dashboardapi/service/impl/DashboardSummaryServiceImpl.java
@@ -0,0 +1,226 @@
+package itn.let.mjo.dashboardapi.service.impl;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+
+import javax.annotation.Resource;
+
+import org.springframework.stereotype.Service;
+
+import itn.let.mjo.dashboardapi.service.DashboardSummaryService;
+import itn.let.mjo.dashboardapi.service.DashboardSummaryVO;
+import itn.let.mjo.msg.service.MjonMsgService;
+import itn.let.mjo.msg.service.MjonMsgStatVO;
+import itn.let.mjo.msg.service.MjonMsgVO;
+import itn.let.mjo.pay.service.MjonPayService;
+import itn.let.mjo.pay.service.MjonPayVO;
+import itn.let.sts.cst.service.EgovConectStatsService;
+import itn.let.uss.umt.service.MberManageVO;
+
+@Service("dashboardSummaryService")
+public class DashboardSummaryServiceImpl implements DashboardSummaryService {
+
+    @Resource(name = "mjonPayService")
+    private MjonPayService mjonPayService;
+
+    @Resource(name = "conectStatsService")
+    private EgovConectStatsService conectStatsService;
+
+    @Resource(name = "mjonMsgService")
+    private MjonMsgService mjonMsgService;
+
+    @Override
+    public DashboardSummaryVO getDashboardSummary(String baseDate) throws Exception {
+        DashboardSummaryVO vo = new DashboardSummaryVO();
+
+        if (baseDate == null || baseDate.trim().isEmpty()) {
+            baseDate = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
+        }
+        vo.setBaseDate(baseDate);
+
+        // 지표 블록별 try/catch: 개별 실패가 전체 응답을 막지 않도록 한다.
+        try {
+            fillSales(vo.getSales());
+        } catch (Exception e) {
+            vo.setSuccess(false);
+            vo.setMsg(appendMsg(vo.getMsg(), "sales:" + e.getMessage()));
+        }
+        try {
+            fillMembers(vo.getMembers());
+        } catch (Exception e) {
+            vo.setSuccess(false);
+            vo.setMsg(appendMsg(vo.getMsg(), "members:" + e.getMessage()));
+        }
+        try {
+            fillSms(vo.getSms());
+        } catch (Exception e) {
+            vo.setSuccess(false);
+            vo.setMsg(appendMsg(vo.getMsg(), "sms:" + e.getMessage()));
+        }
+        return vo;
+    }
+
+    /** 매출(일/월/연) — selectPayDayChartDashboard, selectPayMonthChartDashboard, selectPayYearChart 재사용 */
+    private void fillSales(DashboardSummaryVO.Sales sales) throws Exception {
+        // 일별(최근 4일, 최신순)
+        MjonPayVO dayReq = new MjonPayVO();
+        dayReq.setFirstIndex(0);
+        dayReq.setRecordCountPerPage(4);
+        dayReq.setSearchSortCnd("regDate");
+        dayReq.setSearchSortOrd("desc");
+        List<MjonPayVO> dayList = mjonPayService.selectPayDayChartDashboard(dayReq);
+        if (dayList != null) {
+            for (MjonPayVO p : dayList) {
+                String label = p.getRegDate();
+                if (label != null && label.length() >= 10) {
+                    label = label.substring(5, 10); // MM-DD
+                }
+                sales.getDayChart().add(new DashboardSummaryVO.AmtPoint(label, toLong(p.getAmtTotSum())));
+            }
+            if (!dayList.isEmpty()) {
+                sales.setTodayAmt(toLong(dayList.get(0).getAmtTotSum())); // 최신순 첫 행 = 당일
+            }
+        }
+
+        // 월별(최근 4개월, 최신순)
+        MjonPayVO monthReq = new MjonPayVO();
+        monthReq.setFirstIndex(0);
+        monthReq.setRecordCountPerPage(4);
+        monthReq.setSearchSortCnd("regDate");
+        monthReq.setSearchSortOrd("desc");
+        List<MjonPayVO> monthList = mjonPayService.selectPayMonthChartDashboard(monthReq);
+        if (monthList != null) {
+            for (MjonPayVO p : monthList) {
+                String label = p.getRegDate();
+                if (label != null && label.length() >= 7) {
+                    label = Integer.parseInt(label.substring(5, 7)) + "월";
+                }
+                sales.getMonthChart().add(new DashboardSummaryVO.AmtPoint(label, toLong(p.getAmtTotSum())));
+            }
+        }
+
+        // 연간 누적
+        MjonPayVO yearInfo = mjonPayService.selectPayYearChart(new MjonPayVO());
+        if (yearInfo != null) {
+            sales.setYearAmtSum(toLong(yearInfo.getAmtYearSum()));
+        }
+    }
+
+    /** 회원 현황 — EgovMainController.selectMemberStatsAjax 로직 재현 */
+    private void fillMembers(DashboardSummaryVO.Members m) throws Exception {
+        MberManageVO req = new MberManageVO();
+
+        req.setHstSttus("01");
+        List<MberManageVO> apply = conectStatsService.selectMberCmpHstStatsDashboard(req);
+        req.setHstSttus("02");
+        List<MberManageVO> approve = conectStatsService.selectMberCmpHstStatsDashboard(req);
+        req.setHstSttus("03");
+        List<MberManageVO> reject = conectStatsService.selectMberCmpHstStatsDashboard(req);
+        m.setCmpApply((apply == null || apply.isEmpty()) ? 0 : apply.get(0).getTotCnt());
+        m.setCmpApprove((approve == null || approve.isEmpty()) ? 0 : approve.get(0).getTotCnt());
+        m.setCmpReject((reject == null || reject.isEmpty()) ? 0 : reject.get(0).getTotCnt());
+
+        MberManageVO totReq = new MberManageVO();
+        totReq.setDept("P");
+        List<MberManageVO> priv = conectStatsService.selectMberTotStats(totReq);
+        totReq.setDept("C");
+        List<MberManageVO> comp = conectStatsService.selectMberTotStats(totReq);
+
+        if (priv != null) {
+            for (MberManageVO v : priv) {
+                accumulateMember(m, v, true);
+            }
+        }
+        if (comp != null) {
+            for (MberManageVO v : comp) {
+                accumulateMember(m, v, false);
+            }
+        }
+
+        String statStr = conectStatsService.selectTodaySttCountString(totReq);
+        if (statStr != null) {
+            String[] split = statStr.split("_");
+            if (split.length == 3) {
+                m.setTodayExpireCnt(toInt(split[0]));
+                m.setTodayStopCnt(toInt(split[1]));
+                // split[2]=환불신청수는 1차 범위 제외
+            }
+        }
+    }
+
+    private void accumulateMember(DashboardSummaryVO.Members m, MberManageVO v, boolean isPrivate) {
+        String sttus = v.getMberSttus();
+        int cnt = v.getTotCnt();
+        if ("Y".equals(sttus)) {
+            if (isPrivate) {
+                m.setUserNorCnt(cnt);
+            } else {
+                m.setUserComCnt(cnt);
+            }
+            m.setMberNorTot(m.getMberNorTot() + cnt);
+        } else if ("B".equals(sttus)) {
+            m.setMberBlockTot(m.getMberBlockTot() + cnt);
+        } else if ("N".equals(sttus)) {
+            m.setMberSecessTot(m.getMberSecessTot() + cnt);
+        }
+    }
+
+    /** 문자 발송 현황 — selectAgentSmsCountStatMainList, selectMemDayChartDashboard 재사용 */
+    private void fillSms(DashboardSummaryVO.Sms s) throws Exception {
+        MjonMsgStatVO statReq = new MjonMsgStatVO();
+        statReq.setFirstIndex(0);
+        statReq.setRecordCountPerPage(3);
+        List<MjonMsgStatVO> agents = mjonMsgService.selectAgentSmsCountStatMainList(statReq);
+        if (agents != null) {
+            for (MjonMsgStatVO a : agents) {
+                DashboardSummaryVO.AgentStat stat = new DashboardSummaryVO.AgentStat();
+                stat.setAgentCode(a.getAgentCode());
+                int succ = a.getSumSuccCnt();
+                int fail = a.getSumFailCnt();
+                stat.setSuccCnt(succ);
+                stat.setFailCnt(fail);
+                int total = succ + fail;
+                stat.setSuccRate(total == 0 ? 0 : (int) Math.round(succ * 100.0 / total));
+                s.getAgents().add(stat);
+            }
+        }
+
+        MjonMsgVO memReq = new MjonMsgVO();
+        memReq.setFirstIndex(0);
+        memReq.setRecordCountPerPage(4);
+        memReq.setSearchSortCnd("regDate");
+        memReq.setSearchSortOrd("desc");
+        List<MjonMsgVO> memDay = mjonMsgService.selectMemDayChartDashboard(memReq);
+        if (memDay != null && !memDay.isEmpty()) {
+            s.setTodaySignupCnt(memDay.get(0).getRegCount());
+        }
+    }
+
+    /** "12345", "12,345", "12345.0", null → long(0) 안전 변환 */
+    private long toLong(String s) {
+        if (s == null) {
+            return 0L;
+        }
+        String digits = s.replaceAll("[^0-9-]", "");
+        if (digits.isEmpty() || "-".equals(digits)) {
+            return 0L;
+        }
+        try {
+            return Long.parseLong(digits);
+        } catch (NumberFormatException e) {
+            return 0L;
+        }
+    }
+
+    private int toInt(String s) {
+        return (int) toLong(s);
+    }
+
+    private String appendMsg(String base, String add) {
+        if (base == null || base.isEmpty()) {
+            return add;
+        }
+        return base + "; " + add;
+    }
+}
 
src/main/java/itn/let/mjo/dashboardapi/web/DashboardApiController.java (added)
+++ src/main/java/itn/let/mjo/dashboardapi/web/DashboardApiController.java
@@ -0,0 +1,29 @@
+package itn.let.mjo.dashboardapi.web;
+
+import javax.annotation.Resource;
+
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import itn.let.mjo.dashboardapi.service.DashboardSummaryService;
+import itn.let.mjo.dashboardapi.service.DashboardSummaryVO;
+
+/**
+ * 대시보드 요약 JSON API(n8n→Slack 전용).
+ * 인증은 DashboardApiAuthInterceptor(토큰 헤더)가 담당한다.
+ * 메서드명은 select* 가 아니어서 관리자 로그 AOP 대상에서 제외된다.
+ */
+@RestController
+public class DashboardApiController {
+
+    @Resource(name = "dashboardSummaryService")
+    private DashboardSummaryService dashboardSummaryService;
+
+    @RequestMapping(value = "/api/dashboard/summary.do", method = RequestMethod.GET)
+    public DashboardSummaryVO getDashboardSummary(
+            @RequestParam(value = "date", required = false) String date) throws Exception {
+        return dashboardSummaryService.getDashboardSummary(date);
+    }
+}
 
src/main/java/itn/let/mjo/msg/service/EmployeeCertService.java (added)
+++ src/main/java/itn/let/mjo/msg/service/EmployeeCertService.java
@@ -0,0 +1,15 @@
+package itn.let.mjo.msg.service;
+
+import java.util.List;
+
+public interface EmployeeCertService {
+
+	List<EmployeeCertVO> selectEmployeeCertList(EmployeeCertVO searchVO) throws Exception;
+	int selectEmployeeCertListCnt(EmployeeCertVO searchVO) throws Exception;
+
+	EmployeeCertVO selectEmployeeCertDetail(EmployeeCertVO searchVO) throws Exception;
+
+	List<EmployeeCertVO> selectEmployeeCertHstryList(EmployeeCertVO searchVO) throws Exception;
+
+	void processEmployeeCert(EmployeeCertVO employeeCertVO) throws Exception;
+}
 
src/main/java/itn/let/mjo/msg/service/EmployeeCertVO.java (added)
+++ src/main/java/itn/let/mjo/msg/service/EmployeeCertVO.java
@@ -0,0 +1,38 @@
+package itn.let.mjo.msg.service;
+
+import itn.com.cmm.ComDefaultVO;
+import itn.com.utl.page.PageableVO;
+import lombok.Getter;
+import lombok.Setter;
+
+@Setter
+@Getter
+public class EmployeeCertVO extends ComDefaultVO implements PageableVO {
+
+	private static final long serialVersionUID = 1L;
+
+	private String mberId;
+	private String mberNm;
+	private String bizNo;
+	private String managerNm;
+	private String employeeCertHstrySeq;
+	private Integer certCnt;
+	private Integer applyCnt;
+	private String authYnTxt;
+	private String agreeYn;
+	private String agreePnttm;
+	private String atchFileId;
+	private String dept;
+	private String rejectCode;
+	private String rejectCodeTxt;
+	private String rejectReason;
+	private String lastHstrySeq;
+	private String authHstrySeq;
+	private String frstRegistPnttm;
+	private String lastUpdusrId;
+	private String lastUpdusrNm;
+	private String lastUpdtPnttm;
+	private String authYn;
+
+	private String searchCondition2;
+}
 
src/main/java/itn/let/mjo/msg/service/impl/EmployeeCertDAO.java (added)
+++ src/main/java/itn/let/mjo/msg/service/impl/EmployeeCertDAO.java
@@ -0,0 +1,43 @@
+package itn.let.mjo.msg.service.impl;
+
+import java.util.List;
+
+import org.springframework.stereotype.Repository;
+
+import egovframework.rte.psl.dataaccess.EgovAbstractDAO;
+import itn.let.mjo.msg.service.EmployeeCertVO;
+
+@Repository("employeeCertDAO")
+public class EmployeeCertDAO extends EgovAbstractDAO {
+
+	@SuppressWarnings("unchecked")
+	public List<EmployeeCertVO> selectEmployeeCertList(EmployeeCertVO searchVO) {
+		return (List<EmployeeCertVO>) list("employeeCertDAO.selectEmployeeCertList", searchVO);
+	}
+
+	public int selectEmployeeCertListCnt(EmployeeCertVO searchVO) {
+		return (Integer) select("employeeCertDAO.selectEmployeeCertListCnt", searchVO);
+	}
+
+	public EmployeeCertVO selectEmployeeCertDetail(EmployeeCertVO searchVO) {
+		return (EmployeeCertVO) select("employeeCertDAO.selectEmployeeCertDetail", searchVO);
+	}
+
+	@SuppressWarnings("unchecked")
+	public List<EmployeeCertVO> selectEmployeeCertHstryList(EmployeeCertVO searchVO) {
+		return (List<EmployeeCertVO>) list("employeeCertDAO.selectEmployeeCertHstryList", searchVO);
+	}
+
+	public EmployeeCertVO selectEmployeeCertForUpdate(EmployeeCertVO employeeCertVO) {
+		return (EmployeeCertVO) select("employeeCertDAO.selectEmployeeCertForUpdate", employeeCertVO);
+	}
+
+	public int updateEmployeeCertHstryAuth(EmployeeCertVO employeeCertVO) {
+		return update("employeeCertDAO.updateEmployeeCertHstryAuth", employeeCertVO);
+	}
+
+	public int refreshEmployeeCertApproval(EmployeeCertVO employeeCertVO) {
+		return update("employeeCertDAO.refreshEmployeeCertApproval", employeeCertVO);
+	}
+
+}
 
src/main/java/itn/let/mjo/msg/service/impl/EmployeeCertServiceImpl.java (added)
+++ src/main/java/itn/let/mjo/msg/service/impl/EmployeeCertServiceImpl.java
@@ -0,0 +1,99 @@
+package itn.let.mjo.msg.service.impl;
+
+import java.util.List;
+
+import javax.annotation.Resource;
+
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import egovframework.rte.fdl.cmmn.EgovAbstractServiceImpl;
+import itn.let.mjo.msg.service.EmployeeCertService;
+import itn.let.mjo.msg.service.EmployeeCertVO;
+
+import static itn.com.cmm.util.StringUtil2.isEmpty;
+import static itn.com.cmm.util.StringUtil2.stringValue;
+
+@Service("employeeCertService")
+public class EmployeeCertServiceImpl extends EgovAbstractServiceImpl implements EmployeeCertService {
+
+	@Resource(name = "employeeCertDAO")
+	private EmployeeCertDAO employeeCertDAO;
+
+	@Override
+	public List<EmployeeCertVO> selectEmployeeCertList(EmployeeCertVO searchVO) {
+		return employeeCertDAO.selectEmployeeCertList(searchVO);
+	}
+
+	@Override
+	public int selectEmployeeCertListCnt(EmployeeCertVO searchVO) throws Exception {
+		return employeeCertDAO.selectEmployeeCertListCnt(searchVO);
+	}
+
+
+	@Override
+	public EmployeeCertVO selectEmployeeCertDetail(EmployeeCertVO searchVO) {
+		return employeeCertDAO.selectEmployeeCertDetail(searchVO);
+	}
+
+	@Override
+	public List<EmployeeCertVO> selectEmployeeCertHstryList(EmployeeCertVO searchVO) {
+		return employeeCertDAO.selectEmployeeCertHstryList(searchVO);
+	}
+
+	@Override
+	@Transactional(rollbackFor = Exception.class)
+	public void processEmployeeCert(EmployeeCertVO employeeCertVO) throws Exception {
+		validateProcessRequest(employeeCertVO);
+
+		EmployeeCertVO current = employeeCertDAO.selectEmployeeCertForUpdate(employeeCertVO);
+		if (current == null) {
+			throw new IllegalStateException("종사자 수 인증 신청정보를 찾을 수 없습니다.");
+		}
+
+		employeeCertVO.setMberId(current.getMberId());
+		employeeCertVO.setApplyCnt(current.getApplyCnt());
+		employeeCertVO.setCertCnt(current.getApplyCnt());
+
+		if (employeeCertDAO.updateEmployeeCertHstryAuth(employeeCertVO) != 1) {
+			throw new IllegalStateException("종사자 수 인증 상태 변경에 실패했습니다.");
+		}
+		if (employeeCertDAO.refreshEmployeeCertApproval(employeeCertVO) != 1) {
+			throw new IllegalStateException("인증 종사자 수 반영에 실패했습니다.");
+		}
+	}
+
+	private void validateProcessRequest(EmployeeCertVO employeeCertVO) {
+		if (employeeCertVO == null || isEmpty(employeeCertVO.getEmployeeCertHstrySeq())) {
+			throw new IllegalArgumentException("종사자 수 인증 신청정보가 없습니다.");
+		}
+
+		String authYn = stringValue(employeeCertVO.getAuthYn());
+		if (!("Y".equals(authYn) || "C".equals(authYn))) {
+			throw new IllegalArgumentException("승인 또는 반려 상태를 선택해 주세요.");
+		}
+		if (isEmpty(employeeCertVO.getLastUpdusrId())) {
+			throw new IllegalArgumentException("관리자 정보를 확인할 수 없습니다.");
+		}
+
+		if ("C".equals(authYn)) {
+			String rejectCode = stringValue(employeeCertVO.getRejectCode());
+			if (rejectCode.isEmpty()) {
+				throw new IllegalArgumentException("반려 사유 유형을 선택해 주세요.");
+			}
+			String rejectReason = stringValue(employeeCertVO.getRejectReason()).trim();
+			if (rejectReason.isEmpty()) {
+				throw new IllegalArgumentException("반려 사유를 입력해 주세요.");
+			}
+			employeeCertVO.setRejectReason(rejectReason);
+		} else {
+			employeeCertVO.setRejectCode(null);
+			employeeCertVO.setRejectReason(null);
+		}
+
+		String rejectReason = stringValue(employeeCertVO.getRejectReason());
+		if (rejectReason.length() > 1000) {
+			throw new IllegalArgumentException("반려 사유는 1,000자 이하로 입력해 주세요.");
+		}
+	}
+}
 
src/main/java/itn/let/mjo/msg/web/EmployeeCertController.java (added)
+++ src/main/java/itn/let/mjo/msg/web/EmployeeCertController.java
@@ -0,0 +1,159 @@
+package itn.let.mjo.msg.web;
+
+import egovframework.rte.ptl.mvc.tags.ui.pagination.PaginationInfo;
+import itn.com.annotation.PersonalLog;
+import itn.com.cmm.ComDefaultCodeVO;
+import itn.com.cmm.service.EgovCmmUseService;
+import itn.com.cmm.service.EgovFileMngService;
+import itn.com.cmm.service.FileVO;
+import itn.com.cmm.util.PdfUtil;
+import itn.com.cmm.util.StringUtil;
+import itn.com.utl.page.PaginationUtil;
+import itn.let.mjo.msg.service.EmployeeCertService;
+import itn.let.mjo.msg.service.EmployeeCertVO;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.ModelAttribute;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.servlet.mvc.support.RedirectAttributes;
+
+import javax.annotation.Resource;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+@Controller
+public class EmployeeCertController {
+
+    @Resource(name = "employeeCertService")
+    private EmployeeCertService employeeCertService;
+
+    @Resource(name = "EgovFileMngService")
+    private EgovFileMngService fileMngService;
+
+    @Resource(name = "EgovCmmUseService")
+    private EgovCmmUseService cmmUseService;
+
+    @PersonalLog(action = "조회", description = "종사자 수 인증")
+    @RequestMapping("/uss/ion/msg/EmployeeCertList.do")
+    public String EmployeeCertList(
+            @ModelAttribute("searchVO") EmployeeCertVO searchVO,
+            Model model) throws Exception{
+        PaginationInfo paginationInfo = PaginationUtil.init(searchVO);
+        List<EmployeeCertVO> result = employeeCertService.selectEmployeeCertList(searchVO);
+        int totCnt = employeeCertService.selectEmployeeCertListCnt(searchVO);
+        paginationInfo.setTotalRecordCount(totCnt);
+
+        model.addAttribute("resultList", result);
+        model.addAttribute("paginationInfo", paginationInfo);
+        return "uss/ion/msg/EmployeeCertList";
+    }
+
+    @PersonalLog(action = "조회", description = "종사자 수 인증 상세")
+    @RequestMapping("/uss/ion/msg/EmployeeCertDetail.do")
+    public String EmployeeCertDetail(
+            @RequestParam("employeeCertHstrySeq") String employeeCertHstrySeq,
+            Model model,
+            RedirectAttributes redirectAttributes) throws Exception {
+        if (StringUtil.isEmpty(employeeCertHstrySeq)) {
+            redirectAttributes.addFlashAttribute("message", "종사자 수 인증 신청정보가 없습니다.");
+            return "redirect:/uss/ion/msg/EmployeeCertList.do";
+        }
+
+        EmployeeCertVO searchVO = new EmployeeCertVO();
+        searchVO.setEmployeeCertHstrySeq(employeeCertHstrySeq);
+        EmployeeCertVO employeeCertVO = employeeCertService.selectEmployeeCertDetail(searchVO);
+        if (employeeCertVO == null) {
+            redirectAttributes.addFlashAttribute("message", "종사자 수 인증 신청정보를 찾을 수 없습니다.");
+            return "redirect:/uss/ion/msg/EmployeeCertList.do";
+        }
+
+        EmployeeCertVO historySearchVO = new EmployeeCertVO();
+        historySearchVO.setMberId(employeeCertVO.getMberId());
+        model.addAttribute("employeeCertVO", employeeCertVO);
+        model.addAttribute("historyList", employeeCertService.selectEmployeeCertHstryList(historySearchVO));
+
+        if (StringUtil.isNotEmpty(employeeCertVO.getAtchFileId())) {
+            FileVO fileVO = new FileVO();
+            fileVO.setAtchFileId(employeeCertVO.getAtchFileId());
+            model.addAttribute("fileList", fileMngService.selectFileInfs(fileVO));
+        }
+        return "uss/ion/msg/EmployeeCertDetail";
+    }
+
+    @PersonalLog(action = "조회", description = "종사자 수 인증 반려 팝업")
+    @RequestMapping("/uss/ion/msg/EmployeeCertRejectPop.do")
+    public String employeeCertRejectPop(
+            @RequestParam("employeeCertHstrySeq") String employeeCertHstrySeq,
+            Model model) throws Exception {
+        if (StringUtil.isEmpty(employeeCertHstrySeq)) {
+            throw new IllegalArgumentException("종사자 수 인증 신청정보가 없습니다.");
+        }
+
+        EmployeeCertVO searchVO = new EmployeeCertVO();
+        searchVO.setEmployeeCertHstrySeq(employeeCertHstrySeq);
+        EmployeeCertVO employeeCertVO = employeeCertService.selectEmployeeCertDetail(searchVO);
+        if (employeeCertVO == null) {
+            throw new IllegalArgumentException("종사자 수 인증 신청정보를 찾을 수 없습니다.");
+        }
+
+        ComDefaultCodeVO codeVO = new ComDefaultCodeVO();
+        codeVO.setCodeId("EMP001");
+        model.addAttribute("employeeCertVO", employeeCertVO);
+        model.addAttribute("rejectCodeList", cmmUseService.selectCmmCodeDetail(codeVO));
+        return "uss/ion/msg/EmployeeCertRejectPop";
+    }
+
+    @PersonalLog(action = "조회", description = "종사자 수 인증 증빙서류 미리보기")
+    @RequestMapping("/uss/ion/msg/EmpPdfView.do")
+    public String empPdfView(
+            @ModelAttribute FileVO fileVO,
+            @RequestParam(value = "employeeCertHstrySeq", required = false) String employeeCertHstrySeq,
+            Model model) throws Exception {
+        List<FileVO> fileList = fileMngService.selectFileInfs(fileVO);
+        FileVO selectedFile = fileMngService.selectFileInf(fileVO);
+        if (selectedFile == null && !fileList.isEmpty()) {
+            selectedFile = fileList.get(0);
+            fileVO.setFileSn(selectedFile.getFileSn());
+        }
+        String pdfPath = "";
+        String fileType = "";
+
+        if (selectedFile != null && StringUtil.isNotEmpty(selectedFile.getFileExtsn())) {
+            String fileExtension = selectedFile.getFileExtsn().toLowerCase();
+            List<String> imageExtensions = new ArrayList<>(Arrays.asList(
+                    "bmp", "gif", "jpeg", "jpg", "png", "tif", "tiff", "psd", "rle"));
+
+            if ("pdf".equals(fileExtension)) {
+                pdfPath = "/cmm/fms/pdfView.do?atchFileId=" + selectedFile.getAtchFileId()
+                        + "&fileSn=" + selectedFile.getFileSn();
+                fileType = "pdf";
+            } else {
+                String storePath = selectedFile.getFileStreCours() + selectedFile.getStreFileNm();
+                pdfPath = "/cmm/fms/FileDowntest.do?fileNm="
+                        + PdfUtil.makeImgPdf(storePath, selectedFile.getFileExtsn());
+                fileType = imageExtensions.contains(fileExtension) ? "img" : "etc";
+            }
+        }
+
+        model.addAttribute("pdfPath", pdfPath);
+        model.addAttribute("fileType", fileType);
+        model.addAttribute("atchFileId", fileVO.getAtchFileId());
+        model.addAttribute("fileSn", fileVO.getFileSn());
+        model.addAttribute("selectedFile", selectedFile);
+        model.addAttribute("fileList", fileList);
+        model.addAttribute("employeeCertHstrySeq", employeeCertHstrySeq);
+
+        if (StringUtil.isNotEmpty(employeeCertHstrySeq)) {
+            EmployeeCertVO searchVO = new EmployeeCertVO();
+            searchVO.setEmployeeCertHstrySeq(employeeCertHstrySeq);
+            model.addAttribute("employeeCertVO", employeeCertService.selectEmployeeCertDetail(searchVO));
+
+            ComDefaultCodeVO codeVO = new ComDefaultCodeVO();
+            codeVO.setCodeId("EMP001");
+            model.addAttribute("rejectCodeList", cmmUseService.selectCmmCodeDetail(codeVO));
+        }
+        return "uss/ion/msg/EmpPdfView";
+    }
+}
 
src/main/java/itn/let/mjo/msg/web/EmployeeCertRestController.java (added)
+++ src/main/java/itn/let/mjo/msg/web/EmployeeCertRestController.java
@@ -0,0 +1,109 @@
+package itn.let.mjo.msg.web;
+
+import itn.com.utl.response.ApiResponse;
+import itn.com.cmm.LoginVO;
+import itn.let.mjo.mjocommon.MjonCommon;
+import itn.let.mjo.msg.service.EmployeeCertService;
+import itn.let.mjo.msg.service.EmployeeCertVO;
+import itn.let.mjo.msg.service.MjonMsgService;
+import itn.let.mjo.msg.service.MjonMsgVO;
+import itn.let.mjo.msgdata.service.MjonMsgDataService;
+import itn.let.uss.umt.service.EgovMberManageService;
+import itn.let.uss.umt.service.MberManageVO;
+import egovframework.rte.fdl.security.userdetails.util.EgovUserDetailsHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+
+@RestController
+public class EmployeeCertRestController {
+    private static final Logger LOGGER = LoggerFactory.getLogger(EmployeeCertRestController.class);
+
+    @Resource(name = "employeeCertService")
+    private EmployeeCertService employeeCertService;
+
+    @Resource(name = "mjonMsgService")
+    private MjonMsgService mjonMsgService;
+
+    @Resource(name = "MjonMsgDataService")
+    private MjonMsgDataService mjonMsgDataService;
+
+    @Resource(name = "mberManageService")
+    private EgovMberManageService mberManageService;
+
+    @Resource(name = "MjonCommon")
+    private MjonCommon mjonCommon;
+
+    @PostMapping("/uss/ion/msg/updateEmployeeAuth.do")
+    public ApiResponse<Void> updateEmployeeAuth(EmployeeCertVO employeeCertVO) {
+        try {
+            LoginVO loginVO = EgovUserDetailsHelper.isAuthenticated() ? (LoginVO) EgovUserDetailsHelper.getAuthenticatedUser() : null;
+            if (loginVO == null) {
+                throw new IllegalStateException("관리자 로그인 정보를 확인할 수 없습니다.");
+            }
+            employeeCertVO.setLastUpdusrId(loginVO.getId());
+            employeeCertService.processEmployeeCert(employeeCertVO);
+            sendEmployeeCertResultSms(employeeCertVO);
+            return ApiResponse.successWithMessage("Y".equals(employeeCertVO.getAuthYn()) ? "종사자 수 인증을 완료했습니다." : "종사자 수 인증을 반려했습니다.");
+        } catch (Exception e) {
+            return ApiResponse.fail(e.getMessage());
+        }
+    }
+
+    private void sendEmployeeCertResultSms(EmployeeCertVO employeeCertVO) {
+        try {
+            String smsTxt;
+            if ("Y".equals(employeeCertVO.getAuthYn())) {
+                int wiredMaxCnt = employeeCertVO.getApplyCnt() == null
+                        ? 1 : Math.max(1, employeeCertVO.getApplyCnt());
+                smsTxt = "[문자온] 종사자 수 인증이 완료되었습니다. 유선 발신번호 최대 "
+                        + wiredMaxCnt + "개 등록 신청 가능합니다.";
+            } else {
+                smsTxt = employeeCertVO.getRejectReason();
+            }
+
+            MberManageVO member = mberManageService.selectMber(employeeCertVO.getMberId());
+            if (member == null || "B".equals(member.getMberSttus())) {
+                return;
+            }
+
+            String callTo = member.getMoblphonNo();
+            if (smsTxt == null || smsTxt.trim().isEmpty()
+                    || callTo == null || callTo.trim().isEmpty()) {
+                return;
+            }
+
+            MjonMsgVO mjonMsgVO = new MjonMsgVO();
+            mjonMsgVO.setCallFrom("15518011");
+            mjonMsgVO.setCallTo(callTo);
+            mjonMsgVO.setSmsTxt(smsTxt);
+            mjonMsgVO.setFileCnt("0");
+
+            int messageBytes = smsTxt.replace("\r\n", "\n").getBytes("euc-kr").length;
+            if (messageBytes > 90) {
+                mjonMsgVO.setMsgType("6");
+                mjonMsgVO.setMsgDiv("L");
+            } else {
+                mjonMsgVO.setMsgType("4");
+                mjonMsgVO.setMsgDiv("S");
+            }
+
+            MjonMsgVO agentInfo = mjonMsgService.selectRepMsgAgetnInfo(mjonMsgVO);
+            if (agentInfo == null || agentInfo.getAgentPrice() == null) {
+                throw new IllegalStateException("대표 문자 전송사 정보를 찾을 수 없습니다.");
+            }
+            mjonMsgVO.setAgentCode(agentInfo.getAgentCode());
+            mjonMsgVO.setTotPrice(agentInfo.getAgentPrice().toString());
+            mjonMsgVO.setEachPrice(agentInfo.getAgentPrice().toString());
+
+            MjonMsgVO sendMessage = mjonCommon.getAdminToMberPhoneSendMsgDataComm(mjonMsgVO);
+            mjonMsgDataService.insertAdmToMberMsgDataInfo(sendMessage);
+//            mjonCommon.sendSimpleSlackMsg(smsTxt);
+        } catch (Exception e) {
+            LOGGER.warn("종사자 수 인증 결과 안내문자 발송에 실패했습니다. mberId={}", employeeCertVO.getMberId(), e);
+        }
+    }
+}
src/main/java/itn/let/mjo/msg/web/MjonMsgController.java
--- src/main/java/itn/let/mjo/msg/web/MjonMsgController.java
+++ src/main/java/itn/let/mjo/msg/web/MjonMsgController.java
@@ -19,6 +19,7 @@
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSession;
 
+import itn.com.annotation.PersonalLog;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.poi.ss.usermodel.Cell;
 import org.apache.poi.ss.usermodel.CellStyle;
@@ -164,6 +165,7 @@
      * @return	"/uss/ion/msg/SendMsgList.do"
      * @throws Exception
      */
+	@PersonalLog(action = "조회", description = "발생내역 목록", search = "#resultList.size()")
 	@RequestMapping(value= {"/uss/ion/msg/SendMsgList.do"})
 	public String sendMsgList(@ModelAttribute("searchVO") MjonMsgVO searchVO, 
 			HttpServletRequest request ,
@@ -1076,6 +1078,7 @@
      * @return	uss/ion/msg/ReceiveNumberList.do(수신 문자리스트)
      * @throws Exception
      */
+	 @PersonalLog(action = "조회", description = "수신번호 목록", search = "#resultList.size()")
 	@RequestMapping(value= {"/uss/ion/msg/ReceiveNumberList.do"})
 	public String receiveNumberList(@ModelAttribute("searchVO") MjonMsgVO searchVO, 
 			HttpServletRequest request ,
@@ -1706,6 +1709,7 @@
      * @return	"/uss/ion/msg/SendNumberList"
      * @throws Exception
      */
+	@PersonalLog(action = "조회", description = "발신번호 목록", search = "#resultList.size()")
     @RequestMapping(value= {"/uss/ion/msg/SendNumberList.do","/uss/ion/msg/BlockNumberList.do"})
 	public String MjonNumberList(@ModelAttribute("searchVO") MjPhoneMemberVO searchVO, 
 			HttpServletRequest request,
@@ -2481,6 +2485,7 @@
      * @return	"/uss/ion/msg/SendMsgList.do"
      * @throws Exception
      */
+	 @PersonalLog(action = "조회", description = "실시간 발송", search = "#resultList.size()")
 	@RequestMapping(value= {"/uss/ion/msg/RealTimeMsgList.do", "/uss/ion/msg/RealTimeMsgListAjax.do"})
 	public String RealTimeMsgList(@ModelAttribute("searchVO") MjonMsgVO searchVO, 
 			HttpServletRequest request ,
@@ -2843,6 +2848,7 @@
 	}
     
     //회원정보 팝업 문자 전송 리스트(전체) 엑셀 다운로드
+	@PersonalLog(action = "다운로드", description = "팝업 문자 전송", search = "#resultList.size()")
   	@RequestMapping(value= {"/uss/ion/msg/selectMberSendMsgExcelDownload.do"})
   	public void selectMberSendMsgExcelDownload( MjonMsgVO mjonMsgVO, 
   			@ModelAttribute MberManageVO reqMberManageVO,
@@ -2921,6 +2927,7 @@
   			
   			mjonMsgVO.setMsgType("");
   			List<MjonMsgVO> resultList = mjonMsgService.selectUserMsgDataListByMbrId(mjonMsgVO);
+			  model.addAttribute("resultList", resultList);
   			{ //화면 리스트
   				sheetTitle = "문자 전송 리스트(전체)" ; //제목
   				Sheet sheet = wb.createSheet(sheetTitle);
@@ -3030,6 +3037,7 @@
   	}
      
   //문자 전송 리스트(전체) 엑셀 다운로드
+  	@PersonalLog(action = "다운로드", description = "엑셀 다운로드", search = "#resultList.size()")
   	@RequestMapping(value= {"/uss/ion/msg/SendMsgExcelDownload.do"})
   	public void sendMsgExcelDownload( MjonMsgVO mjonMsgVO, 
   			HttpServletRequest request, 
@@ -3060,6 +3068,7 @@
   		String sheetTitle = ""; 
   		try{
   			List<MjonMsgVO> resultList = mjonMsgService.selectMjonMsgGroupList(mjonMsgVO);
+			model.addAttribute("resultList", resultList);
   			{ //화면 리스트
   				sheetTitle = "문자 전송 리스트(전체)" ; //제목
   				Sheet sheet = wb.createSheet(sheetTitle);
@@ -3119,6 +3128,7 @@
     
   	
   	 //문자 전송 리스트(전체) 엑셀 다운로드
+	@PersonalLog(action = "다운로드", description = "엑셀 다운로드", search = "#resultList.size()")
   	@RequestMapping(value="/uss/ion/msg/SendMsgDtlExcelDownload.do")
   	public void sendMsgDtlExcelDownload( MjonMsgVO mjonMsgVO, 
   			HttpServletRequest request, 
@@ -3149,6 +3159,7 @@
   		String sheetTitle = ""; 
   		try{
   			List<MjonMsgVO> resultList = mjonMsgService.selectMjonMsgGroupDtList(mjonMsgVO);
+			model.addAttribute("resultList", resultList);
   			{ //화면 리스트
   				sheetTitle = "문자 전송 리스트(상세)" ; //제목
   				Sheet sheet = wb.createSheet(sheetTitle);
@@ -4658,6 +4669,7 @@
      * @return	"/uss/ion/msg/admSystemSendMsgList.do"
      * @throws Exception
      */
+	@PersonalLog(action = "조회", description = "시스템 발생내역", search = "#resultList.size()")
 	@RequestMapping(value= {"/uss/ion/msg/admSystemSendMsgList.do"})
 	public String admSystemSendMsgList(@ModelAttribute("searchVO") MjonMsgVO searchVO, 
 			HttpServletRequest request ,
src/main/java/itn/let/mjo/pay/web/MjonPayController.java
--- src/main/java/itn/let/mjo/pay/web/MjonPayController.java
+++ src/main/java/itn/let/mjo/pay/web/MjonPayController.java
@@ -24,6 +24,7 @@
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import itn.com.annotation.PersonalLog;
 import org.apache.poi.ss.usermodel.Cell;
 import org.apache.poi.ss.usermodel.CellStyle;
 import org.apache.poi.ss.usermodel.Font;
@@ -91,6 +92,7 @@
      * @return	"/uss/ion/msg/SendNumberList"
      * @throws Exception
      */
+	 @PersonalLog(action = "조회", description = "캐시 내역", search = "#resultList.size()")
     @RequestMapping(value= {"/uss/ion/pay/CashList.do"})
 	public String selectCashList(@ModelAttribute("searchVO") MjonPayVO mjonPayVO, 
 			HttpServletRequest request,
@@ -150,7 +152,8 @@
      * @return	"/uss/ion/msg/SendNumberList"
      * @throws Exception
      */
-    @RequestMapping(value= {"/uss/ion/pay/CashRemainList.do"})
+	 @PersonalLog(action = "조회", description = "캐시 내역", search = "#resultList.size()")
+	 @RequestMapping(value= {"/uss/ion/pay/CashRemainList.do"})
 	public String selectCashRemainList(@ModelAttribute("searchVO") MjonPayVO mjonPayVO, 
 			HttpServletRequest request,
 			ModelMap model) throws Exception{
@@ -416,6 +419,7 @@
      * @return	"/uss/ion/msg/SendNumberList"
      * @throws Exception
      */
+	@PersonalLog(action = "조회", description = "결제 내역", search = "#resultList.size()")
     @RequestMapping(value= {"/uss/ion/pay/PayList.do"})
 	public String selectPayList(@ModelAttribute("searchVO") MjonPayVO mjonPayVO, 
 			HttpServletRequest request,
src/main/java/itn/let/schdlr/service/SchdlrManageService.java
--- src/main/java/itn/let/schdlr/service/SchdlrManageService.java
+++ src/main/java/itn/let/schdlr/service/SchdlrManageService.java
@@ -51,4 +51,6 @@
 	public void payBack(String type, int limitCout) throws Exception;
 
 	public void payBack_advc(String p_type) throws Exception;
+
+	public void sendNumberFailNoticeScheduler() throws Exception;
 }
src/main/java/itn/let/schdlr/service/SchdlrVO.java
--- src/main/java/itn/let/schdlr/service/SchdlrVO.java
+++ src/main/java/itn/let/schdlr/service/SchdlrVO.java
@@ -73,8 +73,7 @@
 	private String searchKeyword = "";	// 검색어
 
 	private int toCnt = 0;	// 목록 조회 개수
-	
-	
+
 	
 	private String emailAdres = "";	// 메일 주소
 	
@@ -170,8 +169,12 @@
 	
 	private String[] cmplntIdNSn;	// 목록 로우 처리 키값 (구분자: '|') 
 	private String updateStateCd;	// 목록 일괄 처리상태값 
-	private String updateUseYn;	// 목록 일괄 삭제 
-	
+	private String updateUseYn;	// 목록 일괄 삭제
+
+	private String callFrom;
+	private String msgGroupId;
+	private String regDate;
+	private String userId;
 	
 	public String getSchdlrUserName() {
 		return schdlrUserName;
@@ -845,5 +848,28 @@
 	public void setOrgnAlarmDateTime(String orgnAlarmDateTime) {
 		this.orgnAlarmDateTime = orgnAlarmDateTime;
 	}
-	
+
+	public String getCallFrom() {return callFrom;}
+	public void setCallFrom(String callFrom) {
+		this.callFrom = callFrom;
+	}
+	public String getMsgGroupId() {
+		return msgGroupId;
+	}
+	public void setMsgGroupId(String msgGroupId) {
+		this.msgGroupId = msgGroupId;
+	}
+	public String getRegDate() {
+		return regDate;
+	}
+	public void setRegDate(String regDate) {
+		this.regDate = regDate;
+	}
+	public String getUserId() {
+		return userId;
+	}
+	public void setUserId(String userId) {
+		this.userId = userId;
+	}
+
 }
src/main/java/itn/let/schdlr/service/SchedulerUtil.java
--- src/main/java/itn/let/schdlr/service/SchedulerUtil.java
+++ src/main/java/itn/let/schdlr/service/SchedulerUtil.java
@@ -7,6 +7,9 @@
 import javax.annotation.Resource;
 import javax.sql.DataSource;
 
+import itn.let.mjo.pay.service.MjonPayService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Profile;
@@ -44,5 +47,22 @@
 @EnableScheduling
 @EnableSchedulerLock(defaultLockAtMostFor = "PT30S") // Scheduler Lock 사용 가능 설정 (기본 30초동안 Lock)
 public class SchedulerUtil {
-	
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(SchedulerUtil.class);
+
+    @Resource(name = "SchdlrManageService")
+    private SchdlrManageService schdlrManageService;
+
+    @Scheduled(cron = "0 */5 * * * *")
+    public void sendNumberFailNoticeScheduler() throws Exception {
+        try {
+            LOGGER.info(" ============= sendNumberFailNoticeScheduler START ============= ");
+
+            schdlrManageService.sendNumberFailNoticeScheduler();
+
+            LOGGER.info(" ============= sendNumberFailNoticeScheduler END ============= ");
+        }catch(Exception ex) {
+            ex.printStackTrace();
+        }
+    }
 }
src/main/java/itn/let/schdlr/service/impl/SchdlrManageDAO.java
--- src/main/java/itn/let/schdlr/service/impl/SchdlrManageDAO.java
+++ src/main/java/itn/let/schdlr/service/impl/SchdlrManageDAO.java
@@ -208,6 +208,10 @@
 	public SchdlrVO selectCvlCmplntByPk(SchdlrVO schdlrVO) throws Exception{
 		return (SchdlrVO)select("schdlrManageDAO.selectCvlCmplntByPk", schdlrVO);
 	}
+
+	public List<SchdlrVO> selectSendNumberFailList() throws Exception {
+		return (List<SchdlrVO>) list("schdlrManageDAO.selectSendNumberFailList");
+	}
 	
 	
 	// 사업(계약)관리 임시저장 삭제
src/main/java/itn/let/schdlr/service/impl/SchdlrManageServiceImpl.java
--- src/main/java/itn/let/schdlr/service/impl/SchdlrManageServiceImpl.java
+++ src/main/java/itn/let/schdlr/service/impl/SchdlrManageServiceImpl.java
@@ -2,12 +2,15 @@
 
 import java.io.File;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Date;
 import java.util.List;
 import java.util.stream.Collectors;
 
 import javax.annotation.Resource;
 
+import itn.let.mjo.msg.service.MjonMsgService;
+import itn.let.mjo.msgdata.service.MjonMsgReturnVO;
 import org.jsoup.Jsoup;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -102,6 +105,12 @@
 
 	@Resource(name = "faxDAO")
 	public FaxDAO faxDao;
+
+	@Resource(name = "mjonMsgService")
+	private MjonMsgService mjonMsgService;
+
+	private String agentCode;
+	private String agentPrice;
 
 	private static final Logger LOGGER = LoggerFactory.getLogger(SchdlrManageServiceImpl.class);
 
@@ -519,6 +528,93 @@
 
 	}
 
+	@Override
+	public void sendNumberFailNoticeScheduler() throws Exception {
+
+		try {
+			List<SchdlrVO> failUserList = schdlrManageDAO.selectSendNumberFailList();
+
+			if (failUserList == null || failUserList.isEmpty()) {
+				return;
+			}
+
+			String smsTxt = "[문자온] 문자발송 결과(실패) 안내\n"
+							+ "고객님은 현재 이동통신사의 \"번호도용 문자차단 서비스\"에 가입되어 있어 "
+							+ "인터넷 문자사이트를 통한 문자발송이 모두 차단되어 있습니다.\n"
+							+ "문자발송 서비스를 정상적으로 이용하기 위해서는 이용중인 이동통신사에 "
+							+ "문의하시어 상기 서비스를 해지하신 후 문자를 재발송해 주시길 바랍니다.\n"
+							+ "(서비스 해지 후 정상 발송까지 영업일 기준 2~3일 정도 소요될 수 있습니다.)\n"
+							+ "※번호도용 문자차단 서비스 : 웹에서 발송되는 스팸, 스미싱 문자에 "
+							+ "내 번호가 회신번호로 악용되는 것을 방지해주는 서비스";
+
+			MjonMsgVO mjonMsgVO = new MjonMsgVO();
+			mjonMsgVO.setMsgKind("S");
+			mjonMsgVO.setMsgType("6");
+			mjonMsgVO.setFileCnt("0");
+			mjonMsgVO.setMsgDiv("L");
+			mjonMsgVO.setCallFrom("15518011");
+			mjonMsgVO.setSmsTxt(smsTxt);
+
+			if (agentCode == null || agentPrice == null) {
+				MjonMsgVO mjonMsgVO2 = mjonMsgService.selectRepMsgAgetnInfo(mjonMsgVO);
+				agentCode = mjonMsgVO2.getAgentCode();
+				agentPrice = mjonMsgVO2.getAgentPrice().toString();
+			}
+
+			mjonMsgVO.setAgentCode(agentCode);
+			mjonMsgVO.setTotPrice(agentPrice);
+			mjonMsgVO.setEachPrice(agentPrice);
+
+			mjonMsgVO.setBefPoint("0.0");
+			mjonMsgVO.setBefCash("0.0");
+			mjonMsgVO.setReserveYn("N");
+			mjonMsgVO.setUserId("system");
+
+			for (SchdlrVO failUserVo : failUserList) {
+
+				mjonMsgVO.setCallToList(new String[] { failUserVo.getCallFrom() });
+				//문자 발송 처리
+				MjonMsgReturnVO returnVO = mjonMsgDataService.insertAdmToMberMsgDataInfo(mjonMsgVO);
+
+				if (returnVO != null
+						&& returnVO.getSendMsgCnt() != null
+						&& !returnVO.getSendMsgCnt().isEmpty()) {
+					try {
+						MjonMsgVO callbackVO = new MjonMsgVO();
+
+						callbackVO.setUserId(failUserVo.getUserId());
+						callbackVO.setMsgGroupId(failUserVo.getMsgGroupId());
+
+						mjonMsgService.updateMsgGroupDataCallBackAll(callbackVO);
+
+					} catch (Exception e) {
+
+						LOGGER.error(
+								"번호도용 문자차단 CALLBACK 처리 실패. "
+										+ "MSG_GROUP_ID={}, USER_ID={}, CALL_FROM={}",
+								failUserVo.getMsgGroupId(),
+								failUserVo.getUserId(),
+								failUserVo.getCallFrom(),
+								e
+						);
+					}
+				} else {
+					LOGGER.error(
+							"번호도용 문자차단 알림발송 실패 "
+									+ "MSG_GROUP_ID={}, USER_ID={}, CALL_FROM={}",
+							failUserVo.getMsgGroupId(),
+							failUserVo.getUserId(),
+							failUserVo.getCallFrom()
+					);
+				}
+			}
+
+        } catch (Exception e) {
+			LOGGER.error("번호도용 문자차단 안내문자 스케줄러 오류", e);
+        }
+
+	}
+
 	/**
 	 * @methodName : getMsgFailList
 	 * @author : 이호영
@@ -543,4 +639,6 @@
 
 		return msgFailList;
 	}
+
+
 }
 
src/main/java/itn/let/sym/log/access/UserAccessLogService.java (added)
+++ src/main/java/itn/let/sym/log/access/UserAccessLogService.java
@@ -0,0 +1,8 @@
+package itn.let.sym.log.access;
+
+import java.util.List;
+
+public interface UserAccessLogService {
+    List<UserAccessLogVO> selectUserAccessLogList(UserAccessLogVO logVO) throws Exception;
+    Integer selectUserAccessLogListTotCnt(UserAccessLogVO logVO) throws Exception;
+}
 
src/main/java/itn/let/sym/log/access/UserAccessLogVO.java (added)
+++ src/main/java/itn/let/sym/log/access/UserAccessLogVO.java
@@ -0,0 +1,19 @@
+package itn.let.sym.log.access;
+
+import itn.com.utl.page.BasePageableVO;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Getter
+@Setter
+@NoArgsConstructor
+public class UserAccessLogVO extends BasePageableVO {
+    private String logId;
+    private String userId;
+    private String accessIp;
+    private String menuNm;
+    private String uri;
+    private String result;
+    private String frstRegistPnttm;
+}
 
src/main/java/itn/let/sym/log/access/service/UserAccessLogDAO.java (added)
+++ src/main/java/itn/let/sym/log/access/service/UserAccessLogDAO.java
@@ -0,0 +1,19 @@
+package itn.let.sym.log.access.service;
+
+import itn.com.cmm.service.impl.EgovComAbstractDAO;
+import itn.let.sym.log.access.UserAccessLogVO;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+@Repository("userAccessLogDAO")
+public class UserAccessLogDAO extends EgovComAbstractDAO {
+    @SuppressWarnings("unchecked")
+    public List<UserAccessLogVO> selectUserAccessLogList(UserAccessLogVO logVO) throws Exception {
+        return (List<UserAccessLogVO>) list("userAccessLogDAO.selectUserAccessLogList", logVO);
+    }
+
+    public int selectUserAccessLogListTotCnt(UserAccessLogVO logVO) throws Exception {
+        return (Integer) select("userAccessLogDAO.selectUserAccessLogListTotCnt", logVO);
+    }
+}
 
src/main/java/itn/let/sym/log/access/service/UserAccessLogServiceImpl.java (added)
+++ src/main/java/itn/let/sym/log/access/service/UserAccessLogServiceImpl.java
@@ -0,0 +1,26 @@
+package itn.let.sym.log.access.service;
+
+import egovframework.rte.fdl.cmmn.EgovAbstractServiceImpl;
+import itn.let.sym.log.access.UserAccessLogService;
+import itn.let.sym.log.access.UserAccessLogVO;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+@Service(value = "userAccessLogService")
+public class UserAccessLogServiceImpl  extends EgovAbstractServiceImpl implements UserAccessLogService {
+
+    @Resource(name = "userAccessLogDAO")
+    private UserAccessLogDAO userAccessLogDAO;
+
+    @Override
+    public List<UserAccessLogVO> selectUserAccessLogList(UserAccessLogVO logVO) throws Exception {
+        return userAccessLogDAO.selectUserAccessLogList(logVO);
+    }
+
+    @Override
+    public Integer selectUserAccessLogListTotCnt(UserAccessLogVO logVO) throws Exception {
+        return userAccessLogDAO.selectUserAccessLogListTotCnt(logVO);
+    }
+}
 
src/main/java/itn/let/sym/log/access/web/UserAccessLogController.java (added)
+++ src/main/java/itn/let/sym/log/access/web/UserAccessLogController.java
@@ -0,0 +1,33 @@
+package itn.let.sym.log.access.web;
+
+import egovframework.rte.ptl.mvc.tags.ui.pagination.PaginationInfo;
+import itn.com.annotation.PersonalLog;
+import itn.com.utl.page.PaginationUtil;
+import itn.let.sym.log.access.UserAccessLogService;
+import itn.let.sym.log.access.UserAccessLogVO;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+@Controller
+public class UserAccessLogController {
+    @Resource(name = "userAccessLogService")
+    private UserAccessLogService userAccessLogService;
+
+    @PersonalLog(action = "조회", description = "이용자 접속로그", search = "#resultList.size()")
+    @RequestMapping(value = "/uss/umt/user/UserAccessLog.do")
+    public String userAccessLog(UserAccessLogVO searchVO, Model model) throws Exception {
+        PaginationInfo paginationInfo = PaginationUtil.initWithSort(searchVO, "FRST_REGIST_PNTTM", "desc");
+        List<UserAccessLogVO> result = userAccessLogService.selectUserAccessLogList(searchVO);
+        int totCnt = userAccessLogService.selectUserAccessLogListTotCnt(searchVO);
+        paginationInfo.setTotalRecordCount(totCnt);
+
+        model.addAttribute("resultList", result);
+        model.addAttribute("paginationInfo", paginationInfo);
+        model.addAttribute("searchVO", searchVO);
+        return "sym/log/access/UserAccessLog";
+    }
+}
src/main/java/itn/let/sym/log/clg/web/EgovLoginLogController.java
--- src/main/java/itn/let/sym/log/clg/web/EgovLoginLogController.java
+++ src/main/java/itn/let/sym/log/clg/web/EgovLoginLogController.java
@@ -16,6 +16,7 @@
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSession;
 
+import itn.com.annotation.PersonalLog;
 import org.apache.poi.ss.usermodel.Cell;
 import org.apache.poi.ss.usermodel.CellStyle;
 import org.apache.poi.ss.usermodel.Font;
@@ -206,6 +207,7 @@
 	}
 	
 	/* 엑셀 다운로드 */
+	@PersonalLog(action = "다운로드", description = "관리자 로그 엑셀", search = "#adminLogList.size()")
 	@RequestMapping(value = "/sym/log/clg/SelectLoginLogListExcelDown.do")
 	public void SelectLoginLogListExcelDown(@ModelAttribute("searchVO") LoginLog loginLog, @RequestParam Map<String, Object> commandMap ,ModelMap model, HttpServletResponse response) throws Exception {
 		PaginationInfo paginationInfo = new PaginationInfo();
@@ -504,6 +506,7 @@
 	 * @return sym/log/clg/SelectWebLogList.do
 	 * @throws Exception
 	 */
+	@PersonalLog(action = "조회", description = "이용자 웹로그", search = "#resultList.size()")
 	@RequestMapping(value = "/sym/log/clg/SelectWebLogList.do")
 	public String selectWebLogList(@ModelAttribute("searchVO") LoginLog loginLog, 
 			@RequestParam Map<String, Object> commandMap ,
@@ -676,6 +679,7 @@
 	}
 	
 	//리스트 엑셀 다운로드
+	@PersonalLog(action = "다운로드", description = "이용자 웹로그", search = "#resultList.size()")
   	@RequestMapping(value="/sym/log/clg/webLogListExcelDownload.do")
   	public void webLogListExcelDownload(LoginLog loginLog, 
   			HttpServletRequest request, 
@@ -704,7 +708,7 @@
   		try{
   			List<LoginLog> webMenuLogList  = loginLogService.selectWebMenuLogList(loginLog);   //사용자 매뉴 리스트
   			List<LoginLog> userMenuList  = loginLogService.selectUserMenuList(loginLog);   //사용자 매뉴(전체)
-  			
+			model.addAttribute("resultList", userMenuList);
   			for(LoginLog userMenuVO :userMenuList){
   				List<LoginLog> tempDataList = new ArrayList<LoginLog>();
   				for(LoginLog logVO : webMenuLogList) {
src/main/java/itn/let/sym/log/lgm/service/EgovSysLogAspect.java
--- src/main/java/itn/let/sym/log/lgm/service/EgovSysLogAspect.java
+++ src/main/java/itn/let/sym/log/lgm/service/EgovSysLogAspect.java
@@ -1,12 +1,27 @@
 package itn.let.sym.log.lgm.service;
 
+import java.lang.reflect.Method;
+import java.util.Collection;
 import java.util.Enumeration;
+import java.util.Map;
 
 import javax.annotation.Resource;
 import javax.servlet.http.HttpServletRequest;
 
+import itn.com.annotation.PersonalLog;
+import itn.com.cmm.util.IpUtil;
+import itn.com.utl.aop.AopExpressionHelper;
+import itn.let.sym.log.personal.PersonalInformationLogService;
+import itn.let.sym.log.personal.PersonalInformationLogVO;
 import org.aspectj.lang.JoinPoint;
 import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.springframework.expression.EvaluationContext;
+import org.springframework.expression.ExpressionParser;
+import org.springframework.expression.spel.standard.SpelExpressionParser;
+import org.springframework.expression.spel.support.StandardEvaluationContext;
+import org.springframework.ui.ModelMap;
 import org.springframework.util.StopWatch;
 import org.springframework.web.context.request.RequestContextHolder;
 import org.springframework.web.context.request.ServletRequestAttributes;
@@ -17,466 +32,117 @@
 
 /**
  * 시스템 로그 생성을 위한 ASPECT 클래스
- * @author 공통서비스개발팀 이삼섭
- * @since 2009.03.11
- * @version 1.0
- * @see
  *
- * <pre>
+ * @author 공통서비스개발팀 이삼섭
+ * @version 1.0
+ * @see <pre>
  * << 개정이력(Modification Information) >>
- *   
+ *
  *   수정일      수정자           수정내용
  *  -------    --------    ---------------------------
  *   2009.03.11  이삼섭          최초 생성
  *   2011.07.01  이기하         패키지 분리(sym.log -> sym.log.lgm)
- *   2011.08.31  JJY            경량환경 템플릿 커스터마이징버전 생성 
+ *   2011.08.31  JJY            경량환경 템플릿 커스터마이징버전 생성
  *
  * </pre>
+ * @since 2009.03.11
  */
 public class EgovSysLogAspect {
 
-	@Resource(name="EgovSysLogService")
-	private EgovSysLogService sysLogService;
+    @Resource(name = "EgovSysLogService")
+    private EgovSysLogService sysLogService;
 
-	@Resource(name="EgovLoginLogService")
-	private EgovLoginLogService loginLogService;
-	
-	/**
-	 * 시스템 로그정보를 생성한다.
-	 * sevice Class의 insert로 시작되는 Method
-	 *
-	 * @param ProceedingJoinPoint
-	 * @return Object
-	 * @throws Exception
-	 */
-	public Object logInsert(ProceedingJoinPoint joinPoint) throws Throwable {
+    @Resource(name = "personalInformationLogService")
+    private PersonalInformationLogService personalInformationLogService;
 
-		StopWatch stopWatch = new StopWatch();
+    public void personalInformationLog(JoinPoint joinPoint) {
+        try {
+            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
+            PersonalLog log = signature.getMethod().getAnnotation(PersonalLog.class);
 
-		try {
-			stopWatch.start();
+            if (log == null) {
+                return;
+            }
 
-			Object retValue = joinPoint.proceed();
-			return retValue;
-		} catch (Throwable e) {
-			throw e;
-		} finally {
-			stopWatch.stop();
+            EvaluationContext context = AopExpressionHelper.createContext(joinPoint, signature);
+            Object target = AopExpressionHelper.evaluate(context, log.target());
+            Object search = AopExpressionHelper.evaluate(context, log.search());
 
-			SysLog sysLog = new SysLog();
-			String className = joinPoint.getTarget().getClass().getName();
-			String methodName = joinPoint.getSignature().getName();
-			String processSeCode = "C";
-			String processTime = Long.toString(stopWatch.getTotalTimeMillis());
-			String uniqId = "";
-			String ip = "";
+            String logTarget = "";
+            if (target != null) {
+                logTarget = target.toString();
+            } else if (search != null) {
+                logTarget = search.toString() + "건";
+            }
 
-	    	/* Authenticated  */
-	        Boolean isAuthenticated = EgovUserDetailsHelper.isAuthenticated();
-	    	if(isAuthenticated.booleanValue()) {
-				LoginVO user = (LoginVO)EgovUserDetailsHelper.getAuthenticatedUser();
-				uniqId = user.getUniqId();
-				//ip = user.getIp();
-				HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
-				ip = request.getRemoteAddr();
-				sysLog.setUrl(request.getRequestURI());
-	    	}
+            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
+            LoginVO loginVO = (LoginVO) EgovUserDetailsHelper.getAuthenticatedUser();
 
-			sysLog.setSrvcNm(className);
-			sysLog.setMethodNm(methodName);
-			sysLog.setProcessSeCode(processSeCode);
-			sysLog.setProcessTime(processTime);
-			sysLog.setRqesterId(uniqId);
-			sysLog.setRqesterIp(ip);
+            PersonalInformationLogVO vo = new PersonalInformationLogVO();
+            vo.setMenuNm(log.description());
+            vo.setAction(log.action());
+            vo.setTarget(logTarget);
+            vo.setUserId(loginVO != null ? loginVO.getId() : "ANONYMOUS");
+            vo.setAccessIp(IpUtil.getClientIP(request));
+            vo.setUri(request.getRequestURI());
 
-			sysLogService.logInsertSysLog(sysLog);
-			//sysLogService.logInsertAdminSysLog(sysLog);
-		}
+            personalInformationLogService.insertPersonalInformationLog(vo);
+        } catch (Exception e) {
+            System.out.println("개인정보 처리 로그 AOP 오류 : " + e.getMessage());
+        }
+    }
 
-	}
+    /**
+     * 시스템 로그정보를 생성한다.
+     * sevice Class의 select로 시작되는 Method
+     *
+     * @param ProceedingJoinPoint
+     * @return Object
+     * @throws Exception
+     */
+    public void logAdminSelect(JoinPoint joinPoint) throws Throwable {
+        Boolean isAuthenticated = EgovUserDetailsHelper.isAuthenticated();
+        if (isAuthenticated.booleanValue()) {
+            SysLog sysLog = new SysLog();
+            String className = joinPoint.getTarget().getClass().getName();
+            String methodName = joinPoint.getSignature().getName();
+            String processSeCode = "";
+            String uniqId = "";
+            String ip = "";
 
-	/**
-	 * 시스템 로그정보를 생성한다.
-	 * sevice Class의 update로 시작되는 Method
-	 *
-	 * @param ProceedingJoinPoint
-	 * @return Object
-	 * @throws Exception
-	 */
-	public Object logUpdate(ProceedingJoinPoint joinPoint) throws Throwable {
+            /* Authenticated  */
 
-		StopWatch stopWatch = new StopWatch();
+            LoginVO user = (LoginVO) EgovUserDetailsHelper.getAuthenticatedUser();
+            uniqId = user.getUniqId();
 
-		try {
-			stopWatch.start();
+            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
+            ip = request.getRemoteAddr();
+            sysLog.setUrl(request.getRequestURI());
 
-			Object retValue = joinPoint.proceed();
-			return retValue;
-		} catch (Throwable e) {
-			throw e;
-		} finally {
-			stopWatch.stop();
+            sysLog.setSrvcNm(className);
+            sysLog.setMethodNm(methodName);
+            sysLog.setParam(getParam(methodName, "logParam", request)); //모든 파라미터 검사한다.
+            sysLog.setProcessSeCode(processSeCode);
+            sysLog.setRqesterId(uniqId);
+            sysLog.setRqesterIp(ip);
 
-			SysLog sysLog = new SysLog();
-			String className = joinPoint.getTarget().getClass().getName();
-			String methodName = joinPoint.getSignature().getName();
-			String processSeCode = "U";
-			String processTime = Long.toString(stopWatch.getTotalTimeMillis());
-			String uniqId = "";
-			String ip = "";
+            //sysLogService.logInsertSysLog(sysLog);
+            sysLogService.logInsertAdminSysLog(sysLog);
+        }
+    }
 
-	    	/* Authenticated  */
-	        Boolean isAuthenticated = EgovUserDetailsHelper.isAuthenticated();
-	    	if(isAuthenticated.booleanValue()) {
-				LoginVO user = (LoginVO)EgovUserDetailsHelper.getAuthenticatedUser();
-				uniqId = user.getUniqId();
-				//ip = user.getIp();
-				HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
-				ip = request.getRemoteAddr();
-				sysLog.setUrl(request.getRequestURI());
-	    	}
-
-			sysLog.setSrvcNm(className);
-			sysLog.setMethodNm(methodName);
-			sysLog.setProcessSeCode(processSeCode);
-			sysLog.setProcessTime(processTime);
-			sysLog.setRqesterId(uniqId);
-			sysLog.setRqesterIp(ip);
-
-			sysLogService.logInsertSysLog(sysLog);
-			//sysLogService.logInsertAdminSysLog(sysLog);
-
-		}
-
-	}
-
-	/**
-	 * 시스템 로그정보를 생성한다.
-	 * sevice Class의 delete로 시작되는 Method
-	 *
-	 * @param ProceedingJoinPoint
-	 * @return Object
-	 * @throws Exception
-	 */
-	public Object logDelete(ProceedingJoinPoint joinPoint) throws Throwable {
-
-		StopWatch stopWatch = new StopWatch();
-
-		try {
-			stopWatch.start();
-
-			Object retValue = joinPoint.proceed();
-			return retValue;
-		} catch (Throwable e) {
-			throw e;
-		} finally {
-			stopWatch.stop();
-
-			SysLog sysLog = new SysLog();
-			String className = joinPoint.getTarget().getClass().getName();
-			String methodName = joinPoint.getSignature().getName();
-			String processSeCode = "D";
-			String processTime = Long.toString(stopWatch.getTotalTimeMillis());
-			String uniqId = "";
-			String ip = "";
-
-	    	/* Authenticated  */
-	        Boolean isAuthenticated = EgovUserDetailsHelper.isAuthenticated();
-	    	if(isAuthenticated.booleanValue()) {
-				LoginVO user = (LoginVO)EgovUserDetailsHelper.getAuthenticatedUser();
-				uniqId = user.getUniqId();
-				HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
-				ip = request.getRemoteAddr();
-				//ip = user.getIp();
-				sysLog.setUrl(request.getRequestURI());
-	    	}
-
-			sysLog.setSrvcNm(className);
-			sysLog.setMethodNm(methodName);
-			sysLog.setProcessSeCode(processSeCode);
-			sysLog.setProcessTime(processTime);
-			sysLog.setRqesterId(uniqId);
-			sysLog.setRqesterIp(ip);
-
-			sysLogService.logInsertSysLog(sysLog);
-			//sysLogService.logInsertAdminSysLog(sysLog);
-
-		}
-
-	}
-
-	/**
-	 * 시스템 로그정보를 생성한다.
-	 * sevice Class의 select로 시작되는 Method
-	 *
-	 * @param ProceedingJoinPoint
-	 * @return Object
-	 * @throws Exception
-	 */
-	public Object logSelect(ProceedingJoinPoint joinPoint) throws Throwable {
-
-		StopWatch stopWatch = new StopWatch();
-
-		try {
-			stopWatch.start();
-
-			Object retValue = joinPoint.proceed();
-			return retValue;
-		} catch (Throwable e) {
-			throw e;
-		} finally {
-			stopWatch.stop();
-
-			SysLog sysLog = new SysLog();
-			String className = joinPoint.getTarget().getClass().getName();
-			String methodName = joinPoint.getSignature().getName();
-			String processSeCode = "R";
-			String processTime = Long.toString(stopWatch.getTotalTimeMillis());
-			String uniqId = "";
-			String ip = "";
-
-	    	/* Authenticated  */
-	        Boolean isAuthenticated = EgovUserDetailsHelper.isAuthenticated();
-	    	if(isAuthenticated.booleanValue()) {
-				LoginVO user = (LoginVO)EgovUserDetailsHelper.getAuthenticatedUser();
-				uniqId = user.getUniqId();
-				//ip = user.getIp();
-				HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
-				ip = request.getRemoteAddr();
-				sysLog.setUrl(request.getRequestURI());
-	    	}
-
-	    	//String userIp = EgovClntInfo.getClntIP((HttpServletRequest) request);
-			sysLog.setSrvcNm(className);
-			sysLog.setMethodNm(methodName);
-			sysLog.setProcessSeCode(processSeCode);
-			sysLog.setProcessTime(processTime);
-			sysLog.setRqesterId(uniqId);
-			sysLog.setRqesterIp(ip);
-
-			sysLogService.logInsertSysLog(sysLog);
-			//sysLogService.logInsertAdminSysLog(sysLog);
-
-		}
-
-	}
-	
-	/**
-	 * 시스템 로그정보를 생성한다.
-	 * sevice Class의 insert로 시작되는 Method
-	 *
-	 * @param ProceedingJoinPoint
-	 * @return Object
-	 * @throws Exception
-	 */
-	public Object logAdminInsert(ProceedingJoinPoint joinPoint) throws Throwable {
-
-		StopWatch stopWatch = new StopWatch();
-
-		try {
-			stopWatch.start();
-
-			Object retValue = joinPoint.proceed();
-			return retValue;
-		} catch (Throwable e) {
-			throw e;
-		} finally {
-			stopWatch.stop();
-
-			SysLog sysLog = new SysLog();
-			String className = joinPoint.getTarget().getClass().getName();
-			String methodName = joinPoint.getSignature().getName();
-			String processSeCode = "C";
-			String processTime = Long.toString(stopWatch.getTotalTimeMillis());
-			String uniqId = "";
-			String ip = "";
-
-	    	/* Authenticated  */
-	        Boolean isAuthenticated = EgovUserDetailsHelper.isAuthenticated();
-	    	if(isAuthenticated.booleanValue()) {
-				LoginVO user = (LoginVO)EgovUserDetailsHelper.getAuthenticatedUser();
-				uniqId = user.getUniqId();
-				//ip = user.getIp();
-				HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
-				ip = request.getRemoteAddr();
-				sysLog.setUrl(request.getRequestURI());
-	    	}
-
-			sysLog.setSrvcNm(className);
-			sysLog.setMethodNm(methodName);
-			sysLog.setProcessSeCode(processSeCode);
-			sysLog.setProcessTime(processTime);
-			sysLog.setRqesterId(uniqId);
-			sysLog.setRqesterIp(ip);
-
-			//sysLogService.logInsertSysLog(sysLog);
-			sysLogService.logInsertAdminSysLog(sysLog);
-
-		}
-
-	}
-	
-	/**
-	 * 시스템 로그정보를 생성한다.
-	 * sevice Class의 update로 시작되는 Method
-	 *
-	 * @param ProceedingJoinPoint
-	 * @return Object
-	 * @throws Exception
-	 */
-	public Object logAdminUpdate(ProceedingJoinPoint joinPoint) throws Throwable {
-
-		StopWatch stopWatch = new StopWatch();
-
-		try {
-			stopWatch.start();
-
-			Object retValue = joinPoint.proceed();
-			return retValue;
-		} catch (Throwable e) {
-			throw e;
-		} finally {
-			stopWatch.stop();
-
-			SysLog sysLog = new SysLog();
-			String className = joinPoint.getTarget().getClass().getName();
-			String methodName = joinPoint.getSignature().getName();
-			String processSeCode = "U";
-			String processTime = Long.toString(stopWatch.getTotalTimeMillis());
-			String uniqId = "";
-			String ip = "";
-
-	    	/* Authenticated  */
-	        Boolean isAuthenticated = EgovUserDetailsHelper.isAuthenticated();
-	    	if(isAuthenticated.booleanValue()) {
-				LoginVO user = (LoginVO)EgovUserDetailsHelper.getAuthenticatedUser();
-				uniqId = user.getUniqId();
-				//ip = user.getIp();
-				HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
-				ip = request.getRemoteAddr();
-				sysLog.setUrl(request.getRequestURI());
-	    	}
-
-			sysLog.setSrvcNm(className);
-			sysLog.setMethodNm(methodName);
-			sysLog.setProcessSeCode(processSeCode);
-			sysLog.setProcessTime(processTime);
-			sysLog.setRqesterId(uniqId);
-			sysLog.setRqesterIp(ip);
-
-			//sysLogService.logInsertSysLog(sysLog);
-			sysLogService.logInsertAdminSysLog(sysLog);
-
-		}
-
-	}
-	
-	/**
-	 * 시스템 로그정보를 생성한다.
-	 * sevice Class의 delete로 시작되는 Method
-	 *
-	 * @param ProceedingJoinPoint
-	 * @return Object
-	 * @throws Exception
-	 */
-	public Object logAdminDelete(ProceedingJoinPoint joinPoint) throws Throwable {
-
-		StopWatch stopWatch = new StopWatch();
-
-		try {
-			stopWatch.start();
-
-			Object retValue = joinPoint.proceed();
-			return retValue;
-		} catch (Throwable e) {
-			throw e;
-		} finally {
-			stopWatch.stop();
-
-			SysLog sysLog = new SysLog();
-			String className = joinPoint.getTarget().getClass().getName();
-			String methodName = joinPoint.getSignature().getName();
-			String processSeCode = "D";
-			String processTime = Long.toString(stopWatch.getTotalTimeMillis());
-			String uniqId = "";
-			String ip = "";
-
-	    	/* Authenticated  */
-	        Boolean isAuthenticated = EgovUserDetailsHelper.isAuthenticated();
-	    	if(isAuthenticated.booleanValue()) {
-				LoginVO user = (LoginVO)EgovUserDetailsHelper.getAuthenticatedUser();
-				uniqId = user.getUniqId();
-				HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
-				ip = request.getRemoteAddr();
-				//ip = user.getIp();
-				sysLog.setUrl(request.getRequestURI());
-	    	}
-
-			sysLog.setSrvcNm(className);
-			sysLog.setMethodNm(methodName);
-			sysLog.setProcessSeCode(processSeCode);
-			sysLog.setProcessTime(processTime);
-			sysLog.setRqesterId(uniqId);
-			sysLog.setRqesterIp(ip);
-
-			//sysLogService.logInsertSysLog(sysLog);
-			sysLogService.logInsertAdminSysLog(sysLog);
-
-		}
-
-	}
-	
-	/**
-	 * 시스템 로그정보를 생성한다.
-	 * sevice Class의 select로 시작되는 Method
-	 *
-	 * @param ProceedingJoinPoint
-	 * @return Object
-	 * @throws Exception
-	 */
-	public void logAdminSelect(JoinPoint joinPoint) throws Throwable {
-		Boolean isAuthenticated = EgovUserDetailsHelper.isAuthenticated();
-    	if(isAuthenticated.booleanValue()) {
-    		SysLog sysLog = new SysLog();
-    		String className = joinPoint.getTarget().getClass().getName();
-    		String methodName = joinPoint.getSignature().getName();
-    		String processSeCode = "";
-    		String uniqId = "";
-    		String ip = "";
-
-        	/* Authenticated  */
-            
-			LoginVO user = (LoginVO)EgovUserDetailsHelper.getAuthenticatedUser();
-			uniqId = user.getUniqId();
-			
-			HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
-			ip = request.getRemoteAddr();
-			sysLog.setUrl(request.getRequestURI());
-			
-			sysLog.setSrvcNm(className);
-			sysLog.setMethodNm(methodName);
-			sysLog.setParam(getParam(methodName, "logParam" ,request)); //모든 파라미터 검사한다.
-			sysLog.setProcessSeCode(processSeCode);
-			sysLog.setRqesterId(uniqId);
-			sysLog.setRqesterIp(ip);
-
-			//sysLogService.logInsertSysLog(sysLog);
-			sysLogService.logInsertAdminSysLog(sysLog);
-    	}
-	}
-
-	private String getParam(String methodName, String param , HttpServletRequest request) {
-		Enumeration params = request.getParameterNames();
-		String paramValue = "";
-		String returnValue ="";
-		while (params.hasMoreElements()){
-			paramValue = (String)params.nextElement();
-		    if(paramValue.equals(param)){
-		    	//returnValue =  param+"="+request.getParameter(paramValue) ;
-		    	returnValue = request.getParameter(paramValue) ;
-		    	break;
-		    }
-		}
-		return returnValue;
-	}
+    private String getParam(String methodName, String param, HttpServletRequest request) {
+        Enumeration params = request.getParameterNames();
+        String paramValue = "";
+        String returnValue = "";
+        while (params.hasMoreElements()) {
+            paramValue = (String) params.nextElement();
+            if (paramValue.equals(param)) {
+                //returnValue =  param+"="+request.getParameter(paramValue) ;
+                returnValue = request.getParameter(paramValue);
+                break;
+            }
+        }
+        return returnValue;
+    }
 }
 
src/main/java/itn/let/sym/log/personal/PersonalInformationLogService.java (added)
+++ src/main/java/itn/let/sym/log/personal/PersonalInformationLogService.java
@@ -0,0 +1,10 @@
+package itn.let.sym.log.personal;
+
+import java.util.List;
+
+public interface PersonalInformationLogService {
+    List<PersonalInformationLogVO> selectPersonalInformationLogList(PersonalInformationLogVO logVO) throws Exception;
+    Integer selectPersonalInformationLogListTotCnt(PersonalInformationLogVO logVO) throws Exception;
+    void insertPersonalInformationLog(PersonalInformationLogVO logVO) throws Exception;
+}
+
 
src/main/java/itn/let/sym/log/personal/PersonalInformationLogVO.java (added)
+++ src/main/java/itn/let/sym/log/personal/PersonalInformationLogVO.java
@@ -0,0 +1,28 @@
+package itn.let.sym.log.personal;
+
+import itn.com.utl.page.BasePageableVO;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Getter
+@Setter
+@NoArgsConstructor
+public class PersonalInformationLogVO extends BasePageableVO {
+    private String logId;
+    // 행위자
+    private String userId;
+    // IP
+    private String accessIp;
+    // 메뉴명
+    private String menuNm;
+    // 요청 URI
+    private String uri;
+    // 행위
+    private String action;
+
+    private String target;
+    private String frstRegistPnttm;
+}
+
+
 
src/main/java/itn/let/sym/log/personal/service/impl/PersonalInformationLogDAO.java (added)
+++ src/main/java/itn/let/sym/log/personal/service/impl/PersonalInformationLogDAO.java
@@ -0,0 +1,25 @@
+package itn.let.sym.log.personal.service.impl;
+
+import itn.com.cmm.service.impl.EgovComAbstractDAO;
+import itn.let.sym.log.personal.PersonalInformationLogVO;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+@Repository("personalInformationLogDAO")
+public class PersonalInformationLogDAO extends EgovComAbstractDAO {
+    @SuppressWarnings("unchecked")
+    public List<PersonalInformationLogVO> selectPersonalInformationLogList(PersonalInformationLogVO logVO) throws Exception{
+        return (List<PersonalInformationLogVO>)select("personalInformationLogDAO.selectPersonalInformationLogList", logVO);
+    }
+
+
+    public Integer selectPersonalInformationLogListTotCnt(PersonalInformationLogVO logVO) throws Exception{
+        return (Integer) select("personalInformationLogDAO.selectPersonalInformationLogListTotCnt", logVO);
+    }
+
+
+    public void insertPersonalInformationLog(PersonalInformationLogVO logVO) throws Exception {
+        insert("personalInformationLogDAO.insertPersonalInformationLog", logVO);
+    }
+}
 
src/main/java/itn/let/sym/log/personal/service/impl/PersonalInformationLogServiceImpl.java (added)
+++ src/main/java/itn/let/sym/log/personal/service/impl/PersonalInformationLogServiceImpl.java
@@ -0,0 +1,36 @@
+package itn.let.sym.log.personal.service.impl;
+
+import egovframework.rte.fdl.cmmn.EgovAbstractServiceImpl;
+import egovframework.rte.fdl.idgnr.EgovIdGnrService;
+import itn.let.sym.log.personal.PersonalInformationLogService;
+import itn.let.sym.log.personal.PersonalInformationLogVO;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+@Service(value = "personalInformationLogService")
+public class PersonalInformationLogServiceImpl extends EgovAbstractServiceImpl implements PersonalInformationLogService {
+
+    @Resource(name = "personalInformationLogDAO")
+    private PersonalInformationLogDAO personalInformationLogDAO;
+
+    @Resource(name = "egovPersonalInformationLogIdgenService")
+    private EgovIdGnrService idGenService;
+
+    @Override
+    public List<PersonalInformationLogVO> selectPersonalInformationLogList(PersonalInformationLogVO logVO) throws Exception {
+        return personalInformationLogDAO.selectPersonalInformationLogList(logVO);
+    }
+
+    @Override
+    public Integer selectPersonalInformationLogListTotCnt(PersonalInformationLogVO logVO) throws Exception {
+        return personalInformationLogDAO.selectPersonalInformationLogListTotCnt(logVO);
+    }
+
+    @Override
+    public void insertPersonalInformationLog(PersonalInformationLogVO logVO) throws Exception {
+        logVO.setLogId(idGenService.getNextStringId());
+        personalInformationLogDAO.insertPersonalInformationLog(logVO);
+    }
+}
 
src/main/java/itn/let/sym/log/personal/service/web/PersonalInformationLogController.java (added)
+++ src/main/java/itn/let/sym/log/personal/service/web/PersonalInformationLogController.java
@@ -0,0 +1,28 @@
+package itn.let.sym.log.personal.service.web;
+
+import egovframework.rte.ptl.mvc.tags.ui.pagination.PaginationInfo;
+import itn.com.utl.page.PaginationUtil;
+import itn.let.sym.log.personal.PersonalInformationLogService;
+import itn.let.sym.log.personal.PersonalInformationLogVO;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+@Controller
+public class PersonalInformationLogController {
+
+    @Resource(name = "personalInformationLogService")
+    private PersonalInformationLogService personalInformationLogService;
+
+//    @RequestMapping(value = "")
+//    public String personalInformationLog(PersonalInformationLogVO searchVO) throws Exception {
+//        PaginationInfo paginationInfo = PaginationUtil.initWithSort(searchVO, "FRST_REGIST_PNTTM", "desc");
+//        List<PersonalInformationLogVO> result = personalInformationLogService.selectPersonalInformationLogList(searchVO);
+//        int totCnt = personalInformationLogService.selectPersonalInformationLogListTotCnt(searchVO);
+//        paginationInfo.setTotalRecordCount(totCnt);
+//
+//        return "";
+//    }
+}
src/main/java/itn/let/sym/mnu/mcm/web/EgovMenuCreateManageController.java
--- src/main/java/itn/let/sym/mnu/mcm/web/EgovMenuCreateManageController.java
+++ src/main/java/itn/let/sym/mnu/mcm/web/EgovMenuCreateManageController.java
@@ -81,7 +81,7 @@
 	/** EgovMenuManageService */
 	@Resource(name = "meunManageService")
 	private EgovMenuManageService menuManageService;
-	
+
 	/** cmmUseService */
 	@Resource(name = "EgovCmmUseService")
 	private EgovCmmUseService cmmUseService;
@@ -89,23 +89,23 @@
 
 	@Resource(name = "menuCreateManageDAO")
 	private MenuCreateManageDAO menuCreateManageDAO;
-	
+
 	@Resource(name = "egovMenuIdGnrService")
-    private EgovIdGnrService idgenService;
-	
+	private EgovIdGnrService idgenService;
+
 	/** EgovProgrmManageService */
 	@Resource(name = "progrmManageService")
 	private EgovProgrmManageService progrmManageService;
-	
+
 	@Resource(name = "egovSiteManagerService")
 	EgovSiteManagerService egovSiteManagerService;
-	
+
 	@Resource(name = "EgovBBSAttributeManageService")
 	private EgovBBSAttributeManageService bbsAttrbService;
-	
+
 	@Resource(name = "egovCntManageService")
 	private EgovCntManageService egovCntManageService;
-	
+
 	/**
 	 * *메뉴생성목록을 조회한다.
 	 *
@@ -119,7 +119,7 @@
 		String resultMsg = "";
 		// 0. Spring Security 사용자권한 처리
 		if(searchVO.getPageUnit() != 10) {
-    		searchVO.setPageUnit(searchVO.getPageUnit());
+			searchVO.setPageUnit(searchVO.getPageUnit());
 		}
 
 		/** pageing */
@@ -141,7 +141,7 @@
 				searchVO.setSearchKeyword(vo.getAuthorCode());
 			}
 		}
-		
+
 		if("".equals(searchVO.getSearchSortCnd())){ //최초조회시 최신것 조회List
 			searchVO.setSearchSortCnd("tempSortNum");
 			searchVO.setSearchSortOrd("desc");
@@ -179,7 +179,7 @@
 		/*if(null == menuCreatVO.getSiteId()  || "".equals(menuCreatVO.getSiteId() ) ){
 			menuCreatVO.setSiteId("N");
 		}*/
-		//관리자 매뉴만 보이게 
+		//관리자 매뉴만 보이게
 		menuCreatVO.setUnderMenuNo("9"); //MENU_NO  < 9900000
 		List<?> list_menulist = menuCreateManageService.selectMenuCreatList(menuCreatVO) ;
 		model.addAttribute("list_menulist", list_menulist );
@@ -199,7 +199,7 @@
 	 */
 	@RequestMapping("/sym/mnu/mcm/EgovMenuCreatInsert.do")
 	public String insertMenuCreatList(@RequestParam("checkedAuthorForInsert") String checkedAuthorForInsert, @RequestParam("checkedMenuNoForInsert") String checkedMenuNoForInsert,
-			@ModelAttribute("menuCreatVO") MenuCreatVO menuCreatVO, ModelMap model) throws Exception {
+	                                  @ModelAttribute("menuCreatVO") MenuCreatVO menuCreatVO, ModelMap model) throws Exception {
 		String resultMsg = "";
 		// 0. Spring Security 사용자권한 처리
 		Boolean isAuthenticated = EgovUserDetailsHelper.isAuthenticated();
@@ -216,14 +216,14 @@
 			}catch(Exception e){
 				resultMsg = egovMessageSource.getMessage("fail.common.insert");
 			}
-			
+
 			resultMsg = egovMessageSource.getMessage("success.common.insert");
 		}
 		model.addAttribute("message", resultMsg);
 		return "forward:/sym/mnu/mcm/EgovMenuCreatSelect.do";
 	}
-	
-	
+
+
 	/* 메뉴생성 세부조회 */
 	/**
 	 * 메뉴생성 세부화면을 조회한다.
@@ -235,32 +235,32 @@
 	 */
 	@RequestMapping(value = "/sym/mnu/mcm/EgovMenuCreatSelectJtree.do")
 	public String selectEgovMenuCreatSelectJtree(@ModelAttribute("menuCreatVO") MenuCreatVO menuCreatVO, @ModelAttribute("searchVO") ComDefaultVO searchVO,
-			ModelMap model, MenuManageVO menuManageVO , HttpSession session ) throws Exception {
+	                                             ModelMap model, MenuManageVO menuManageVO , HttpSession session ) throws Exception {
 		// 0. Spring Security 사용자권한 처리
-		
+
 		if(menuCreatVO.getMenuUserType() == null){
 			menuCreatVO.setMenuUserType("A"); //사용자 디폴트
 		}
-		
+
 		if(null == menuManageVO.getAuthorCode()) {
 			menuManageVO.setAuthorCode("ROLE_ANONYMOUS");
 		}
 		model.addAttribute("menuCreatVO", menuCreatVO);
 		return "sym/mnu/mpm/EgovMenuCreatSelectJtree";
 	}
-	
-	
+
+
 	@RequestMapping(value = {"/sym/mnu/mcm/EgovMenuCreatSelectJtreeAjax.do", "/sym/mnu/mcm/EgovMenuQuickSelectJtreeAjax.do" } )
-	public void EgovMenuCreatSelectJtreeAjax(@ModelAttribute("menuManageVO") MenuManageJTreeVO menuManageVO, ModelMap model, 
-			HttpServletResponse response , HttpServletRequest request) throws Exception {
+	public void EgovMenuCreatSelectJtreeAjax(@ModelAttribute("menuManageVO") MenuManageJTreeVO menuManageVO, ModelMap model,
+	                                         HttpServletResponse response , HttpServletRequest request) throws Exception {
 		ObjectMapper mapper = new ObjectMapper();
 		response.setHeader("Content-Type", "text/html;charset=utf-8");
 		PrintWriter out = new PrintWriter(new OutputStreamWriter(response.getOutputStream(), "UTF-8"));
-		
+
 		menuManageVO.setMenuUserType(menuManageVO.getMenuUserType());
-		
+
 		List<MenuManageJTreeVO> resultList = null ;
-		
+
 		if(request.getServletPath().equals("/sym/mnu/mcm/EgovMenuQuickSelectJtreeAjax.do")) { //즐겨찾기
 			resultList =  menuCreateManageService.selectQuickListJtree(menuManageVO) ;
 		}else {
@@ -270,16 +270,16 @@
 		menuManageTopVO.setUpperMenuId("#");
 		menuManageTopVO.setMenuNo("0");
 		menuManageTopVO.setMenuNm("사용자메뉴");
-		
+
 		if("ROLE_ADMIN".equals(menuManageVO.getAuthorCode())){
 			menuManageTopVO.setMenuNm("관리자메뉴");
 		}
-		
+
 		resultList.add(0, menuManageTopVO);
 		mapper.writeValue(out, resultList);
 		out.flush();
 	}
-	
+
 	/**
 	 * 매뉴 정보를 조회한다.
 	 *
@@ -289,16 +289,16 @@
 	 * @throws Exception
 	 */
 	@RequestMapping("/sym/mnu/mcm/EgovMenuInfoAjax.do")
-	public ModelAndView EgovMenuInfoAjax(@ModelAttribute("menuManageVO") MenuManageJTreeVO menuManageVO, @RequestParam("menuNo") String menuNo , 
-			@ModelAttribute("searchVO") ComDefaultVO searchVO , ModelMap model) throws Exception {
+	public ModelAndView EgovMenuInfoAjax(@ModelAttribute("menuManageVO") MenuManageJTreeVO menuManageVO, @RequestParam("menuNo") String menuNo ,
+	                                     @ModelAttribute("searchVO") ComDefaultVO searchVO , ModelMap model) throws Exception {
 		ModelAndView modelAndView = new ModelAndView();
 		modelAndView.setViewName("jsonView");
-		
-		
+
+
 		MenuManageVO tempMenuManageVO = new MenuManageVO();
 		tempMenuManageVO.setSearchKeyword(menuNo);
 		tempMenuManageVO.setAuthorCode(menuManageVO.getAuthorCode());
-		
+
 		MenuManageVO resultVO = menuManageService.selectMenuManage(tempMenuManageVO);
 		if(resultVO.getProgrmFileNm() !=null){
 			searchVO.setSearchKeyword(resultVO.getProgrmFileNm());
@@ -310,7 +310,7 @@
 			}
 		}
 		model.addAttribute("menuManageVO", resultVO);
-		
+
 		//메뉴 화면구분
 		ComDefaultCodeVO vo = new ComDefaultCodeVO();
 		vo.setCodeId("COM039");
@@ -341,7 +341,7 @@
 			menuManageVO.setRelateImageNm("/"); //임시
 			menuManageVO.setProgrmFileNm("dir"); //임시
 			menuManageVO.setMenuUserType("U"); //임시
-			
+
 			{ //동급 레벨 번호 조회
 				String equiLevel = (menuManageVO.getUpperMenuId()+"").replaceFirst("0" , "%");
 				List<MenuManageVO> equiMenuManageList = menuManageService.selectEquiLevelList(equiLevel);
@@ -354,7 +354,7 @@
 						}else {
 							insertMenNo = (menuManageVO.getUpperMenuId()+"").replaceFirst("0" , i+"") ;
 						}
-						
+
 						try{
 							existMenuManageVO.setMenuNo(Integer.parseInt(insertMenNo) );
 						}catch(Exception e){
@@ -365,13 +365,13 @@
 							break ;
 						}
 					}
-					menuManageVO.setMenuNo(Integer.parseInt(insertMenNo) ); 
+					menuManageVO.setMenuNo(Integer.parseInt(insertMenNo) );
 				}else{
 					insertMenNo = (menuManageVO.getUpperMenuId()+"").replaceFirst("0" , "1");
-					menuManageVO.setMenuNo( Integer.parseInt(insertMenNo)); 
+					menuManageVO.setMenuNo( Integer.parseInt(insertMenNo));
 				}
 			}
-			
+
 			/*{ //프로그램 리스트 테이블에 insert
 				String progrmFileNm = idgenService.getNextStringId();
 				progrmManageVO.setProgrmFileNm(progrmFileNm);
@@ -380,35 +380,35 @@
 				progrmManageVO.setProgrmDc(menuManageVO.getMenuNm());
 				progrmManageService.insertProgrm(progrmManageVO);
 			}*/
-			
-			//LoginVO user = (LoginVO)EgovUserDetailsHelper.getAuthenticatedUser() ; 
+
+			//LoginVO user = (LoginVO)EgovUserDetailsHelper.getAuthenticatedUser() ;
 			/*if(null == user.getSiteId()){
 				menuManageVO.setSiteId("N");
 			}else{
 				menuManageVO.setSiteId(user.getSiteId());
 			}*/
-			
+
 			menuManageService.insertMenuManage(menuManageVO);
 			//메뉴생성내역 테이블에 등록
 			menuCreateManageService.insertMenuCreat(menuManageVO);
-			modelAndView.addObject("menuManageResultVO", menuManageVO);	
-			modelAndView.addObject("status", "success");	
+			modelAndView.addObject("menuManageResultVO", menuManageVO);
+			modelAndView.addObject("status", "success");
 		}catch (Exception e) {
 			MenuManageVO tempMenuManageVO = new MenuManageVO();
 			tempMenuManageVO.setSearchKeyword(menuManageVO.getMenuNo()+"");
 			tempMenuManageVO.setAuthorCode(menuManageVO.getAuthorCode());
 			menuManageVO = menuManageService.selectMenuManage(tempMenuManageVO);
 			if(menuManageVO != null){//현제 매뉴 조회
-				modelAndView.addObject("status", "dupl");	
+				modelAndView.addObject("status", "dupl");
 				modelAndView.addObject("menuManageResultVO", menuManageVO);
 			}else{ //하위 매뉴 조회
-				modelAndView.addObject("status", "fail");	
+				modelAndView.addObject("status", "fail");
 			}
 		}
 		return modelAndView;
 	}
-	
-	
+
+
 	/**
 	 * 매뉴 정보를 삭제한다.(트리구조에서)
 	 *
@@ -425,31 +425,31 @@
 		try{
 			List<MenuManageVO> menuManagePkList = new ArrayList<>(); //참조키 리스트 조회
 			menuManagePkList = menuManageService.selectUpperMenuNoByPkList(menuManageVO) ;
-			if(menuManagePkList.size() != 0){    
+			if(menuManagePkList.size() != 0){
 				modelAndView.addObject("status", "duplPk");
 				MenuManageVO menuManageResultVO = new MenuManageVO();
 				StringBuffer pKmenuCours = null;
 				for(MenuManageVO tempMenuManageVO : menuManagePkList){
-					pKmenuCours.append(tempMenuManageVO.getMenuCours()+" "); 
+					pKmenuCours.append(tempMenuManageVO.getMenuCours()+" ");
 				}
 				menuManageResultVO.setMenuCours(pKmenuCours+"");
 				modelAndView.addObject("menuManageResultVO", menuManageResultVO);
 				return modelAndView;
 			}
-			
-			
+
+
 			int usingOtherSiteCnt = menuCreateManageDAO.selectMenuCreatAuthCnt(menuCreatVO) ; //다른 사이트 아이디가 매뉴를 사용할시 매뉴 삭제안한다.
 			if(usingOtherSiteCnt == 1){
 				menuManageService.deleteMenuManage(menuManageVO);
 			}
-			
+
 			/*LoginVO loginVO = (LoginVO)EgovUserDetailsHelper.getAuthenticatedUser();
 			if(null == loginVO){
 				menuCreatVO.setSiteId("N");
 			}else{
 				menuCreatVO.setSiteId(loginVO.getSiteId());
 			}*/
-			
+
 			menuCreateManageDAO.deleteMenuCreatAuthNo(menuCreatVO);
 			if(null != progrmManageVO.getProgrmFileNm() && !progrmManageVO.getProgrmFileNm().equals("dir")){ //프로그램만 지움
 				if(usingOtherSiteCnt == 1){ //다른 사이트 아이디가 매뉴를 사용할시 매뉴 삭제안한다.
@@ -462,7 +462,7 @@
 		}
 		return modelAndView;
 	}
-	
+
 	/**
 	 * 매뉴 정보를 수정한다.
 	 *
@@ -474,11 +474,11 @@
 	@SuppressWarnings("unused")
 	@Transactional(rollbackFor = Exception.class)
 	@RequestMapping("/sym/mnu/mcm/EgovMenuInfoUpdateAjax.do")
-	public ModelAndView updateEgovMenuInfoAjax(@ModelAttribute("menuManageVO") MenuManageVO menuManageVO, 
-			MenuCreatVO menuCreatVO ,
-			ProgrmManageVO progrmManageVO , 
-			@ModelAttribute("searchVO") ComDefaultVO searchVO ,
-			ModelMap model) throws Exception {
+	public ModelAndView updateEgovMenuInfoAjax(@ModelAttribute("menuManageVO") MenuManageVO menuManageVO,
+	                                           MenuCreatVO menuCreatVO ,
+	                                           ProgrmManageVO progrmManageVO ,
+	                                           @ModelAttribute("searchVO") ComDefaultVO searchVO ,
+	                                           ModelMap model) throws Exception {
 		ModelAndView modelAndView = new ModelAndView();
 		modelAndView.setViewName("jsonView");
 		int cnt = 0;
@@ -491,9 +491,9 @@
 						return modelAndView;
 					}
 				}
-				
+
 				LoginVO loginVO = (LoginVO) EgovUserDetailsHelper.getAuthenticatedUser();
-				
+
 				//프로그램에 목록이 있는지 조회후 있으면 update/ 아닌경우 insert
 				progrmManageVO.setProgrmStrePath("/web/");
 				progrmManageVO.setProgrmKoreanNm(menuManageVO.getMenuNm());
@@ -504,14 +504,14 @@
 				}/*else if("B".equals(menuManageVO.getMenuType())){
 					progrmManageVO.setURL("/web/cop/bbsWeb/selectBoardList.do?bbsId="+progrmManageVO.getProgrmFileNm());
 				}*/
-				
+
 				boolean delFlag = false;
 				if(!menuManageVO.getMenuType().equals("M") && menuManageVO.getTmp_Name().equals("dir")){ //디렉토리 폴더에서 프로그램으로 바꿀경우 프로그램 목록 insert
 					searchVO.setSearchKeyword(progrmManageVO.getProgrmFileNm());
 					if(progrmManageService.selectProgrm(searchVO) != null){ //중복  프로그램 이름 확인
 						modelAndView.addObject("status", "duplProNm");
 						return modelAndView;
-					}; 
+					};
 					menuManageVO.setProgrmFileNm(progrmManageVO.getProgrmFileNm());
 					progrmManageVO.setProgrmFileNm(progrmManageVO.getProgrmFileNm());
 					progrmManageService.insertProgrm(progrmManageVO);
@@ -520,8 +520,8 @@
 						menuManageVO.setProgrmFileNm(progrmManageVO.getProgrmFileNm());
 						progrmManageVO.setProgrmFileNm(menuManageVO.getProgrmFileNm());
 						progrmManageService.updateProgrm(progrmManageVO);
-						menuCreateManageDAO.updateMenuNo(menuCreatVO); 
-					}else{ //중복프로그램 조회 > del > insert 
+						menuCreateManageDAO.updateMenuNo(menuCreatVO);
+					}else{ //중복프로그램 조회 > del > insert
 						if(menuManageVO.getMenuType().equals("M")){ //프로그램에서 매뉴로 바꿀시 lettnmenuinfo 만 업데이트 / lettnprogrmlist 삭제
 							menuManageService.updateMenuManageJtree(menuManageVO);
 							ProgrmManageVO delProgrmManageVO = new ProgrmManageVO();
@@ -530,37 +530,37 @@
 							modelAndView.addObject("status", "success");
 							return modelAndView;
 						}
-						
+
 						searchVO.setSearchKeyword(progrmManageVO.getProgrmFileNm());
 						if(progrmManageService.selectProgrm(searchVO) != null){ //중복  프로그램 이름 확인
 							modelAndView.addObject("status", "duplProNm");
 							return modelAndView;
-						}; 
-						
+						};
+
 						menuManageVO.setProgrmFileNm(progrmManageVO.getProgrmFileNm());
 						progrmManageVO.setProgrmFileNm(menuManageVO.getProgrmFileNm());
 						searchVO.setSearchKeyword(progrmManageVO.getProgrmFileNm());
-						progrmManageService.insertProgrm(progrmManageVO);  
+						progrmManageService.insertProgrm(progrmManageVO);
 						delFlag = true; //프로그램 등록 후 MENUINFO를 업데이트시킨다.(lettnprogrmlist` (`PROGRM_FILE_NM`) ON DELETE CASCADE) 이후 이전 삭제
 					}
 				}
-				
+
 				menuManageVO.setRelateImagePath("/");
 				menuManageVO.setRelateImageNm("/");
-				
+
 				MenuManageVO tempMenuManageVO = new MenuManageVO();
 				tempMenuManageVO.setSearchKeyword(menuManageVO.getTmp_Id()+"");
 				tempMenuManageVO.setAuthorCode(menuManageVO.getAuthorCode());
-				
+
 				MenuManageVO resultVO = menuManageService.selectMenuManage(tempMenuManageVO);
-				
-				if(resultVO.getMenuOrdr() > menuManageVO.getMenuOrdr() ){  //이전 sortOrder > 바꾸려는  sortOrder 
+
+				if(resultVO.getMenuOrdr() > menuManageVO.getMenuOrdr() ){  //이전 sortOrder > 바꾸려는  sortOrder
 					menuManageVO.setSortOver("D");
 				}
-				
+
 				//매뉴업데이트시에는 항상 lettnmenucreatdtls 에 값이 있으면 메뉴번호가 변경안됨.(deleteMenuCreatByNo > updateMenuManageJtree > insertMenuCreat)
 				menuCreatVO.setMenuNo(Integer.parseInt(menuManageVO.getTmp_Id()));
-				
+
 				if(menuCreatVO.getExistChildNode().equals("Y")) { //하위노드가 있을경우 업데이트만
 					menuManageVO.setMenuNo(Integer.parseInt(menuManageVO.getTmp_Id()));
 					cnt = menuManageService.updateMenuManageJtree(menuManageVO);
@@ -578,10 +578,10 @@
 						menuCreateManageDAO.deleteMenuCreatAuthNo(menuCreatVO);
 						cnt = menuManageService.updateMenuManageJtree(menuManageVO);
 						menuCreatVO.setMenuNo(menuManageVO.getMenuNo());
-						menuCreateManageDAO.insertMenuCreat(menuCreatVO);	
+						menuCreateManageDAO.insertMenuCreat(menuCreatVO);
 					}
 				}
-				
+
 				if(menuManageVO.getUpperMenuId()!=0){ //최상위는 제외
 					menuManageService.resortMenuManage(menuManageVO);
 				}
@@ -590,15 +590,15 @@
 					delProgrmManageVO.setProgrmFileNm(menuManageVO.getTmp_Name());
 					progrmManageService.deleteProgrm(delProgrmManageVO);  //삭제
 				}
-				
+
 				//프로그램 파일명에 등록된  menuNO 게시판,컨텐츠 삭제
 				{
 					CntManageVO tempCntManageVO = new CntManageVO();
 					tempCntManageVO.setMenuNo(menuManageVO.getMenuNo()+"");
 					egovCntManageService.deleteMenuNo(tempCntManageVO) ;
-					
+
 				}
-				
+
 				if("B".equals(menuManageVO.getMenuType())){ //단일 게시판 선택시에 마스터 테이블에 메뉴번호를 넣어준다. solr 검색을 위해.
 					BoardMasterVO boardMasterVO = new BoardMasterVO();
 					List<String> bbsIds = new ArrayList<String>();
@@ -625,10 +625,10 @@
 		}catch (Exception e) {
 			modelAndView.addObject("status", "fail");
 		}
-	
+
 		return modelAndView;
 	}
-	
+
 	/**
 	 * 매뉴 이름 변경한다.
 	 *
@@ -649,11 +649,11 @@
 		}
 		return modelAndView;
 	}
-	
+
 	@Transactional(rollbackFor = Exception.class)
 	@RequestMapping("/sym/mnu/mcm/EgovMenuInfoMoveAjax.do")
-	public ModelAndView EgovMenuInfoMoveAjax(@ModelAttribute("menuManageVO") MenuManageVO menuManageVO, 
-			@ModelAttribute("searchVO") ComDefaultVO searchVO  ,ModelMap model) throws Exception {
+	public ModelAndView EgovMenuInfoMoveAjax(@ModelAttribute("menuManageVO") MenuManageVO menuManageVO,
+	                                         @ModelAttribute("searchVO") ComDefaultVO searchVO  ,ModelMap model) throws Exception {
 		ModelAndView modelAndView = new ModelAndView();
 		modelAndView.setViewName("jsonView");
 		try{
@@ -661,9 +661,9 @@
 			tempMenuManageVO.setSearchKeyword(menuManageVO.getMenuNo()+"");
 			tempMenuManageVO.setAuthorCode(menuManageVO.getAuthorCode());
 			MenuManageVO resultVO = menuManageService.selectMenuManage(tempMenuManageVO);
-			
+
 			if(resultVO.getUpperMenuId()==menuManageVO.getUpperMenuId()){  //같은 레벨이면
-				if(resultVO.getMenuOrdr() > menuManageVO.getMenuOrdr() ){  //이전 sortOrder > 바꾸려는  sortOrder 
+				if(resultVO.getMenuOrdr() > menuManageVO.getMenuOrdr() ){  //이전 sortOrder > 바꾸려는  sortOrder
 					menuManageVO.setSortOver("D");
 				}
 			}else{//다른레벨
@@ -672,13 +672,13 @@
 			menuManageService.updateMenuManageJtreeNo(menuManageVO);
 			menuManageService.resortMenuManage(menuManageVO);
 			modelAndView.addObject("status", "success");
-			
+
 		}catch (Exception e) {
 			modelAndView.addObject("status", "fail");
 		}
 		return modelAndView;
 	}
-	
+
 	/* 즐겨찾기 세부조회 */
 	/**
 	 * 메뉴생성 세부화면을 조회한다.
@@ -690,16 +690,16 @@
 	 */
 	@RequestMapping(value = "/sym/mnu/mcm/QuickMenuMng.do")
 	public String selectQuickMenuMngJtree(@ModelAttribute("menuCreatVO") MenuCreatVO menuCreatVO, @ModelAttribute("searchVO") ComDefaultVO searchVO,
-			ModelMap model, MenuManageVO menuManageVO , HttpSession session ) throws Exception {
+	                                      ModelMap model, MenuManageVO menuManageVO , HttpSession session ) throws Exception {
 		// 0. Spring Security 사용자권한 처리
 		Boolean isAuthenticated = EgovUserDetailsHelper.isAuthenticated();
 		LoginVO loginVo = (LoginVO)EgovUserDetailsHelper.getAuthenticatedUser() ;
 		model.addAttribute("siteId", loginVo.getSiteId());
-		
+
 		if(menuCreatVO.getMenuUserType() == null){
 			menuCreatVO.setMenuUserType("A"); //관리자 디폴트
 		}
-		
+
 		if(null != loginVo && !"super".equals(loginVo.getSiteId())){
 			menuCreatVO.setSiteId(loginVo.getSiteId());
 		}else{ //수퍼관리자
@@ -710,15 +710,15 @@
 		model.addAttribute("menuCreatVO", menuCreatVO);
 		return "sym/mnu/mpm/QuickMenuMng";
 	}
-	
+
 	/**
 	 * 체크된 즐겨찾기 목록을 저장한다..
 	 */
 	@RequestMapping(value = "/sym/mnu/mcm/QuickMenuMngUpdateAjax.do")
-	public ModelAndView updateQuickMenuMngUpdateAjax(@RequestParam Map<?, ?> commandMap, 
-			@ModelAttribute("menuManageVO") MenuManageJTreeVO menuManageVO, 
-			@ModelAttribute("searchVO") CmmnDetailCodeVO searchVO
-			)throws Exception {
+	public ModelAndView updateQuickMenuMngUpdateAjax(@RequestParam Map<?, ?> commandMap,
+	                                                 @ModelAttribute("menuManageVO") MenuManageJTreeVO menuManageVO,
+	                                                 @ModelAttribute("searchVO") CmmnDetailCodeVO searchVO
+	)throws Exception {
 		ModelAndView modelAndView = new ModelAndView();
 		modelAndView.setViewName("jsonView");
 		Boolean isAuthenticated = EgovUserDetailsHelper.isAuthenticated();
@@ -731,19 +731,19 @@
 			modelAndView.addObject("result", "success");
 		}catch (Exception e) {
 			modelAndView.addObject("result", "fail");
-		} 
+		}
 		return modelAndView;
 	}
-	
-	
+
+
 	/**
 	 * 매뉴의 게시판을 조회한다.
 	 */
 	@RequestMapping("/sym/mnu/mcm/MenuBbsSelectAjax.do")
-	public ModelAndView MenuAddBbsInsertAjax(@ModelAttribute("menuManageVO") MenuManageVO menuManageVO, 
-			BoardMasterVO boardMasterVO,
-			
-			ModelMap model) throws Exception {
+	public ModelAndView MenuAddBbsInsertAjax(@ModelAttribute("menuManageVO") MenuManageVO menuManageVO,
+	                                         BoardMasterVO boardMasterVO,
+
+	                                         ModelMap model) throws Exception {
 		ModelAndView modelAndView = new ModelAndView();
 		modelAndView.setViewName("jsonView");
 		try{
@@ -755,16 +755,16 @@
 		}
 		return modelAndView;
 	}
-	
-	
+
+
 	/**
 	 * 매뉴의 게시판을 업데이트한다.
 	 */
 	@RequestMapping("/sym/mnu/mcm/MenuBbsInsertAjax.do")
-	public ModelAndView MenuBbsInsertAjax(@ModelAttribute("menuManageVO") MenuManageVO menuManageVO, 
-			BoardMasterVO boardMasterVO,
-			
-			ModelMap model) throws Exception {
+	public ModelAndView MenuBbsInsertAjax(@ModelAttribute("menuManageVO") MenuManageVO menuManageVO,
+	                                      BoardMasterVO boardMasterVO,
+
+	                                      ModelMap model) throws Exception {
 		ModelAndView modelAndView = new ModelAndView();
 		modelAndView.setViewName("jsonView");
 		try{
@@ -775,15 +775,15 @@
 		}
 		return modelAndView;
 	}
-	
+
 	/**
 	 * 매뉴의 컨텐츠 확인링크 조회
-	 * 	 
+	 *
 	 * */
 	@RequestMapping("/sym/mnu/mcm/HtmlComfirmAjax.do")
-	public ModelAndView HtmlComfirmAjax(@ModelAttribute("menuManageVO") MenuManageVO menuManageVO, 
-			@ModelAttribute("cntManageVO") CntManageVO cntManageVO,
-			ModelMap model) throws Exception {
+	public ModelAndView HtmlComfirmAjax(@ModelAttribute("menuManageVO") MenuManageVO menuManageVO,
+	                                    @ModelAttribute("cntManageVO") CntManageVO cntManageVO,
+	                                    ModelMap model) throws Exception {
 		ModelAndView modelAndView = new ModelAndView();
 		modelAndView.setViewName("jsonView");
 		try{
src/main/java/itn/let/sym/site/web/EgovSiteManagerController.java
--- src/main/java/itn/let/sym/site/web/EgovSiteManagerController.java
+++ src/main/java/itn/let/sym/site/web/EgovSiteManagerController.java
@@ -2577,4 +2577,42 @@
 		
     	return modelAndView;
     }
+
+	/**
+	 * 추가인증 유효시간 관리
+	 * @param loginPolicyVO - 로그인정책 VO
+	 * @return String - 리턴 Url
+	 */
+	@RequestMapping("/sym/site/authValidityTimeMng.do")
+	public String selectAuthValidityTimeMng( @RequestParam Map<?, ?> commandMap
+			, @ModelAttribute("siteManagerVO") SiteManagerVO siteManagerVO
+			, ModelMap model) throws Exception {
+
+		if(siteManagerVO.getPageUnit() != 10) {
+			siteManagerVO.setPageUnit(siteManagerVO.getPageUnit());
+		}
+
+		/** paging */
+		PaginationInfo paginationInfo = new PaginationInfo();
+		paginationInfo.setCurrentPageNo(siteManagerVO.getPageIndex());
+		paginationInfo.setRecordCountPerPage(siteManagerVO.getPageUnit());
+		paginationInfo.setPageSize(siteManagerVO.getPageSize());
+
+		siteManagerVO.setFirstIndex(paginationInfo.getFirstRecordIndex());
+		siteManagerVO.setLastIndex(paginationInfo.getLastRecordIndex());
+		siteManagerVO.setRecordCountPerPage(paginationInfo.getRecordCountPerPage());
+
+		List<SiteManagerVO> sessionTimeList = new ArrayList<SiteManagerVO>();
+		if("".equals(siteManagerVO.getSearchSortCnd())){ //최초조회시 최신것 조회List
+			siteManagerVO.setSearchSortCnd("frstRegistPnttm");
+			siteManagerVO.setSearchSortOrd("desc");
+		}
+		sessionTimeList = egovSiteManagerService.selectSiteManagerList(siteManagerVO);
+		model.addAttribute("sessionTimeList", sessionTimeList);
+
+		ComDefaultCodeVO vo = new ComDefaultCodeVO();  //관리자로그기간설정
+		vo.setCodeId("ITN059");
+		model.addAttribute("sessionTimeCdList", cmmUseService.selectCmmCodeDetail(vo));
+		return "/sym/site/authValidityTimeMng";
+	}
 }
 
src/main/java/itn/let/uat/uia/service/SecondAuthLogService.java (added)
+++ src/main/java/itn/let/uat/uia/service/SecondAuthLogService.java
@@ -0,0 +1,15 @@
+package itn.let.uat.uia.service;
+
+import java.util.List;
+
+public interface SecondAuthLogService {
+    public void insertSecondAuthLog(SecondAuthLogVO logVO) throws Exception;
+
+    public void deleteSecondAuthLog(SecondAuthLogVO logVO) throws Exception;
+
+    public void selectSecondAuthLog(SecondAuthLogVO logVO) throws Exception;
+
+    public int selectSecondAuthLogCnt(SecondAuthLogVO logVO) throws Exception;
+
+    public List<SecondAuthLogVO> selectSecondAuthLogList(SecondAuthLogVO logVO) throws Exception;
+}
 
src/main/java/itn/let/uat/uia/service/SecondAuthLogVO.java (added)
+++ src/main/java/itn/let/uat/uia/service/SecondAuthLogVO.java
@@ -0,0 +1,33 @@
+package itn.let.uat.uia.service;
+
+import itn.com.utl.page.BasePageableVO;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Getter
+@Setter
+@NoArgsConstructor
+public class SecondAuthLogVO extends BasePageableVO {
+    // log PK
+    private String logId;
+    // SUCCESS, FAIL
+    private String loginResult;
+    // 1차, 2차
+    private String authStep;
+    // TRY Login ID
+    private String tryLoginId;
+    private String reason;
+    // IP, UserAgent
+    private String accessIp;
+    private String userAgent;
+
+    // 2차 인증
+    private String msgId;
+    // 입력한 2차 인증번호
+    private String resultCode;
+    // 전화번호
+    private String receive;
+
+    private String frstRegistPnttm;
+}
 
src/main/java/itn/let/uat/uia/service/impl/SecondAuthLogDAO.java (added)
+++ src/main/java/itn/let/uat/uia/service/impl/SecondAuthLogDAO.java
@@ -0,0 +1,29 @@
+package itn.let.uat.uia.service.impl;
+
+import itn.com.cmm.service.impl.EgovComAbstractDAO;
+import itn.let.uat.uia.service.SecondAuthLogVO;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+@Repository("secondAuthLogDAO")
+public class SecondAuthLogDAO extends EgovComAbstractDAO {
+    public void insertSecondAuthLog(SecondAuthLogVO logVO) {
+        insert("secondAuthLogDAO.insertSecondAuthLog", logVO);
+    }
+
+    public void deleteSecondAuthLog(SecondAuthLogVO logVO) {
+    }
+
+    public SecondAuthLogVO selectSecondAuthLog(SecondAuthLogVO logVO) {
+        return (SecondAuthLogVO) select("secondAuthLogDAO.selectSecondAuthLog", logVO);
+    }
+
+    public int selectSecondAuthLogCnt(SecondAuthLogVO logVO) {
+        return (Integer) select("secondAuthLogDAO.selectSecondAuthLogCnt", logVO);
+    }
+    @SuppressWarnings("unchecked")
+    public List<SecondAuthLogVO> selectSecondAuthLogList(SecondAuthLogVO logVO) {
+        return (List<SecondAuthLogVO>) list("secondAuthLogDAO.selectSecondAuthLogList", logVO);
+    }
+}
 
src/main/java/itn/let/uat/uia/service/impl/SecondAuthLogServiceImpl.java (added)
+++ src/main/java/itn/let/uat/uia/service/impl/SecondAuthLogServiceImpl.java
@@ -0,0 +1,40 @@
+package itn.let.uat.uia.service.impl;
+
+import egovframework.rte.fdl.cmmn.EgovAbstractServiceImpl;
+import egovframework.rte.fdl.idgnr.EgovIdGnrService;
+import itn.let.uat.uia.service.SecondAuthLogService;
+import itn.let.uat.uia.service.SecondAuthLogVO;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+@Service("secondAuthLogService")
+public class SecondAuthLogServiceImpl extends EgovAbstractServiceImpl implements SecondAuthLogService {
+    @Resource(name = "secondAuthLogDAO")
+    private SecondAuthLogDAO dao;
+
+    @Resource(name = "egovSecondAuthLogIdGnrService")
+    private EgovIdGnrService idGenService;
+
+    public void insertSecondAuthLog(SecondAuthLogVO logVO) throws Exception{
+        logVO.setLogId(idGenService.getNextStringId());
+        dao.insertSecondAuthLog(logVO);
+    }
+
+    public void deleteSecondAuthLog(SecondAuthLogVO logVO) throws Exception{
+        dao.deleteSecondAuthLog(logVO);
+    }
+
+    public void selectSecondAuthLog(SecondAuthLogVO logVO) throws Exception{
+        dao.selectSecondAuthLog(logVO);
+    }
+
+    public int selectSecondAuthLogCnt(SecondAuthLogVO logVO) throws Exception{
+        return dao.selectSecondAuthLogCnt(logVO);
+    }
+
+    public List<SecondAuthLogVO> selectSecondAuthLogList(SecondAuthLogVO logVO) throws Exception{
+        return dao.selectSecondAuthLogList(logVO);
+    }
+}
 
src/main/java/itn/let/uat/uia/web/SecondAuthLogController.java (added)
+++ src/main/java/itn/let/uat/uia/web/SecondAuthLogController.java
@@ -0,0 +1,33 @@
+package itn.let.uat.uia.web;
+
+import egovframework.rte.ptl.mvc.tags.ui.pagination.PaginationInfo;
+import itn.com.annotation.PersonalLog;
+import itn.com.utl.page.PaginationUtil;
+import itn.let.uat.uia.service.SecondAuthLogService;
+import itn.let.uat.uia.service.SecondAuthLogVO;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+@Controller
+public class SecondAuthLogController {
+    @Resource(name = "secondAuthLogService")
+    private SecondAuthLogService secondAuthLogService;
+
+    @PersonalLog(action = "조회", description = "2차 인증 로그", search = "#resultList.size()")
+    @RequestMapping(value = "/uss/umt/user/SecondAuthLog.do")
+    public String secondAuthLog(SecondAuthLogVO searchVO, Model model) throws Exception {
+        PaginationInfo paginationInfo = PaginationUtil.initWithSort(searchVO, "FRST_REGIST_PNTTM", "desc");
+        List<SecondAuthLogVO> result = secondAuthLogService.selectSecondAuthLogList(searchVO);
+        int totCnt = secondAuthLogService.selectSecondAuthLogCnt(searchVO);
+        paginationInfo.setTotalRecordCount(totCnt);
+
+        model.addAttribute("resultList", result);
+        model.addAttribute("paginationInfo", paginationInfo);
+        model.addAttribute("searchVO", searchVO);
+        return "sym/log/second/SecondAuthLog";
+    }
+}
src/main/java/itn/let/uss/umt/service/UserManageVO.java
--- src/main/java/itn/let/uss/umt/service/UserManageVO.java
+++ src/main/java/itn/let/uss/umt/service/UserManageVO.java
@@ -219,8 +219,15 @@
 	private float paymentCash;		//이전달에 실제 사용한 캐시 정보
 	
 	private String exceptSpamYn;		//금지어 예외여부 온(on) - Y, 오프(off) - N
-	
-	
+
+	/** 전송자격인증제 3.2 : 등록자(계정을 등록한 관리자 로그인ID) */
+	private String registerId;
+	/** 전송자격인증제 3.2 : 등록자명(표시용, 조회 시 조인) */
+	private String registerNm;
+	/** 전송자격인증제 3.2 : 등록사유(권한 부여 사유) */
+	private String registResn;
+
+
 
 	public UserManageVO(String userId) {
 		this.mberId = userId;
src/main/java/itn/let/uss/umt/web/EgovMberCmpHstController.java
--- src/main/java/itn/let/uss/umt/web/EgovMberCmpHstController.java
+++ src/main/java/itn/let/uss/umt/web/EgovMberCmpHstController.java
@@ -5,6 +5,7 @@
 import javax.annotation.Resource;
 import javax.servlet.http.HttpServletRequest;
 
+import itn.com.annotation.PersonalLog;
 import org.springframework.stereotype.Controller;
 import org.springframework.ui.Model;
 import org.springframework.ui.ModelMap;
@@ -474,11 +475,12 @@
 	 * @return
 	 * @throws Exception
 	 */
+	@PersonalLog(action = "삭제", description = "기업회원 상세정보", target = "#mberCmpHstVO.mberId")
 	@RequestMapping("/uss/umt/user/mberCmpHstStatusDeleteAjax.do")
 	public ModelAndView mberCmpHstStatusDeleteAjax(
 			@ModelAttribute("searchVO") MberCmpHstVO mberCmpHstVO 
 			) throws Exception{
-		
+
 		ModelAndView modelAndView = new ModelAndView();
 		modelAndView.setViewName("jsonView");
 		
@@ -506,12 +508,8 @@
     	}
 		catch(Exception e) {
 			isSuccess = false;
-    		msg = "오류 : " + e.getMessage();
-    	}
-		
-		
-		mberCmpHstVO.setMberId(""); //업데이트 처리 후 mberId 초기화 - 리스트 select 조건절에 mberId때문에 승인, 반려 처리 후 그 ID 목록만 조회되는 것 방지
-			
+			msg = "오류 : " + e.getMessage();
+		}
 		modelAndView.addObject("isSuccess", isSuccess);        		
 		modelAndView.addObject("msg", msg);
 
src/main/java/itn/let/uss/umt/web/EgovUserManageController.java
--- src/main/java/itn/let/uss/umt/web/EgovUserManageController.java
+++ src/main/java/itn/let/uss/umt/web/EgovUserManageController.java
This diff is too big to display.
src/main/resources/egovframework/egovProps/globals.properties
--- src/main/resources/egovframework/egovProps/globals.properties
+++ src/main/resources/egovframework/egovProps/globals.properties
@@ -1,25 +1,25 @@
 #-----------------------------------------------------------------------
 #
-#   globals.properties : \uc2dc\uc2a4\ud15c
+#   globals.properties : \uC2DC\uC2A4\uD15C
 #
 #-----------------------------------------------------------------------
-#   1.  key = value \uad6c\uc870\uc785\ub2c8\ub2e4.
-#   2.  key\uac12\uc740 \uacf5\ubc31\ubb38\uc790\ub97c \ud3ec\ud568\ubd88\uac00, value\uac12\uc740 \uacf5\ubc31\ubb38\uc790\ub97c \uac00\ub2a5
-#   3.  key\uac12\uc73c\ub85c \ud55c\uae00\uc744 \uc0ac\uc6a9\ubd88\uac00,   value\uac12\uc740 \ud55c\uae00\uc0ac\uc6a9\uc774 \uac00\ub2a5
-#   4.  \uc904\uc744 \ubc14\uafc0 \ud544\uc694\uac00 \uc788\uc73c\uba74 '\'\ub97c \ub77c\uc778\uc758 \ub05d\uc5d0 \ucd94\uac00(\ub9cc\uc57d  '\'\ubb38\uc790\ub97c \uc0ac\uc6a9\ud574\uc57c \ud558\ub294 \uacbd\uc6b0\ub294 '\\'\ub97c \uc0ac\uc6a9)
-#   5.  Windows\uc5d0\uc11c\uc758 \ub514\ub809\ud1a0\ub9ac \ud45c\uc2dc : '\\' or '/'  ('\' \uc0ac\uc6a9\ud558\uba74 \uc548\ub428)
-#   6.  Unix\uc5d0\uc11c\uc758 \ub514\ub809\ud1a0\ub9ac \ud45c\uc2dc : '/'
-#   7.  \uc8fc\uc11d\ubb38 \ucc98\ub9ac\ub294  #\uc0ac\uc6a9
-#   8.  value\uac12 \ub4a4\uc5d0 \uc2a4\ud398\uc774\uc2a4\uac00 \uc874\uc7ac\ud558\ub294 \uacbd\uc6b0 \uc11c\ube14\ub9bf\uc5d0\uc11c \ucc38\uc870\ud560\ub54c\ub294 \uc5d0\ub7ec\ubc1c\uc0dd\ud560 \uc218 \uc788\uc73c\ubbc0\ub85c trim()\ud558\uac70\ub098 \ub9c8\uc9c0\ub9c9 \uacf5\ubc31\uc5c6\uc774 properties \uac12\uc744 \uc124\uc815\ud560\uac83
+#   1.  key = value \uAD6C\uC870\uC785\uB2C8\uB2E4.
+#   2.  key\uAC12\uC740 \uACF5\uBC31\uBB38\uC790\uB97C \uD3EC\uD568\uBD88\uAC00, value\uAC12\uC740 \uACF5\uBC31\uBB38\uC790\uB97C \uAC00\uB2A5
+#   3.  key\uAC12\uC73C\uB85C \uD55C\uAE00\uC744 \uC0AC\uC6A9\uBD88\uAC00,   value\uAC12\uC740 \uD55C\uAE00\uC0AC\uC6A9\uC774 \uAC00\uB2A5
+#   4.  \uC904\uC744 \uBC14\uAFC0 \uD544\uC694\uAC00 \uC788\uC73C\uBA74 '\'\uB97C \uB77C\uC778\uC758 \uB05D\uC5D0 \uCD94\uAC00(\uB9CC\uC57D  '\'\uBB38\uC790\uB97C \uC0AC\uC6A9\uD574\uC57C \uD558\uB294 \uACBD\uC6B0\uB294 '\\'\uB97C \uC0AC\uC6A9)
+#   5.  Windows\uC5D0\uC11C\uC758 \uB514\uB809\uD1A0\uB9AC \uD45C\uC2DC : '\\' or '/'  ('\' \uC0AC\uC6A9\uD558\uBA74 \uC548\uB428)
+#   6.  Unix\uC5D0\uC11C\uC758 \uB514\uB809\uD1A0\uB9AC \uD45C\uC2DC : '/'
+#   7.  \uC8FC\uC11D\uBB38 \uCC98\uB9AC\uB294  #\uC0AC\uC6A9
+#   8.  value\uAC12 \uB4A4\uC5D0 \uC2A4\uD398\uC774\uC2A4\uAC00 \uC874\uC7AC\uD558\uB294 \uACBD\uC6B0 \uC11C\uBE14\uB9BF\uC5D0\uC11C \uCC38\uC870\uD560\uB54C\uB294 \uC5D0\uB7EC\uBC1C\uC0DD\uD560 \uC218 \uC788\uC73C\uBBC0\uB85C trim()\uD558\uAC70\uB098 \uB9C8\uC9C0\uB9C9 \uACF5\uBC31\uC5C6\uC774 properties \uAC12\uC744 \uC124\uC815\uD560\uAC83
 #-----------------------------------------------------------------------
 
-# \uc6b4\uc601\uc11c\ubc84 \ud0c0\uc785(WINDOWS, UNIX)
+# \uC6B4\uC601\uC11C\uBC84 \uD0C0\uC785(WINDOWS, UNIX)
 Globals.OsType = WINDOWS
 
-# G4C \uc5f0\uacb0\uc6a9 IP (localhost)
+# G4C \uC5F0\uACB0\uC6A9 IP (localhost)
 Globals.LocalIp = 127.0.0.1
 
-# DB\uc11c\ubc84 \ud0c0\uc785(mysql,oracle,altibase,tibero) - datasource \ubc0f sqlMap \ud30c\uc77c \uc9c0\uc815\uc5d0 \uc0ac\uc6a9\ub428
+# DB\uC11C\uBC84 \uD0C0\uC785(mysql,oracle,altibase,tibero) - datasource \uBC0F sqlMap \uD30C\uC77C \uC9C0\uC815\uC5D0 \uC0AC\uC6A9\uB428
 Globals.DbType = mysql
 
 
@@ -54,7 +54,7 @@
 
 # MainPage Setting(admin)
 Globals.MainPage = /cmm/main/mainPage.do
-#\ucee8\ud150\uce20 \ud30c\uc77c\uc704\uce58
+#\uCEE8\uD150\uCE20 \uD30C\uC77C\uC704\uCE58
 #Globals.ckeditorUploadDir=/home/file/ckeditor/
 Globals.ckeditorUploadDir=/usr/local/tomcat/file/ckeditor/
 #TEST SERVER
@@ -65,18 +65,18 @@
 Globals.file.saveDir=/usr/local/tomcat
 
 
-#SNS \ub85c\uadf8\uc778 KEY \uac12
-#ITN \ub124\uc774\ubc84
+#SNS \uB85C\uADF8\uC778 KEY \uAC12
+#ITN \uB124\uC774\uBC84
 Globals.itn.naver.clentId=d9Ohvhty_RVsfrq9p_2J
 Globals.itn.naver.clientSecret=kwiEmpkLg5
 Globals.itn.naver.returnUrl=http://localhost:80/snsLogin/naverOauth.do
-#ITN \uce74\uce74\uc624
+#ITN \uCE74\uCE74\uC624
 Globals.itn.kakao.restApiKey=10b66ad0c44b68b659855ddd64db2c44
 Globals.itn.kakao.returnUrl=http://localhost:80/snsLogin/kakaoOauth.do
 
-#\uc0ac\uc774\ud2b8 \uc544\uc774\ub514 \uc81c\uac70\ub85c JSP\uc5d0\uc11c siteId/siteNm \ubcf4\uc5ec\uc8fc\uae30 \uc704\ud574 
-Globals.homepage.siteId=mjon
-Globals.homepage.siteNm=\ubb38\uc790ON
+#\uC0AC\uC774\uD2B8 \uC544\uC774\uB514 \uC81C\uAC70\uB85C JSP\uC5D0\uC11C siteId/siteNm \uBCF4\uC5EC\uC8FC\uAE30 \uC704\uD574 
+Globals.homepage.siteId=mjgo
+Globals.homepage.siteNm=\uBB38\uC790GO
 
 
 
@@ -88,7 +88,7 @@
 Globals.fax.file.permit.ext=hwp,hwpml,doc,xls,ppt,pdf,txt,docx,xlsx,pptx,tif,htm,html,jpg,jpeg,gif,bmp,gul
 
 
-#KG \ubaa8\ube4c\ub9ac\uc5b8\uc2a4 \uc124\uc815
+#KG \uBAA8\uBE4C\uB9AC\uC5B8\uC2A4 \uC124\uC815
 #CARD
 Globals.pay.kgm.card.cnSvcid=191017078687
 Globals.pay.kgm.card.payMode=10
@@ -98,3 +98,6 @@
 #MOBILE
 Globals.pay.kgm.mobile.mcSvcid=170622040674
 Globals.pay.kgm.mobile.payMode=00
+
+# \uB300\uC2DC\uBCF4\uB4DC \uC694\uC57D API(n8n\u2192Slack) \uACF5\uC720 \uD1A0\uD070
+Globals.dashboard.api.token=mjon_783439232074797a6fd5a8d6d32ce5d201e4b9a1ef6159e1
src/main/resources/egovframework/egovProps/globals_dev.properties
--- src/main/resources/egovframework/egovProps/globals_dev.properties
+++ src/main/resources/egovframework/egovProps/globals_dev.properties
@@ -1,25 +1,25 @@
 #-----------------------------------------------------------------------
 #
-#   globals.properties : \uc2dc\uc2a4\ud15c
+#   globals.properties : \uC2DC\uC2A4\uD15C
 #
 #-----------------------------------------------------------------------
-#   1.  key = value \uad6c\uc870\uc785\ub2c8\ub2e4.
-#   2.  key\uac12\uc740 \uacf5\ubc31\ubb38\uc790\ub97c \ud3ec\ud568\ubd88\uac00, value\uac12\uc740 \uacf5\ubc31\ubb38\uc790\ub97c \uac00\ub2a5
-#   3.  key\uac12\uc73c\ub85c \ud55c\uae00\uc744 \uc0ac\uc6a9\ubd88\uac00,   value\uac12\uc740 \ud55c\uae00\uc0ac\uc6a9\uc774 \uac00\ub2a5
-#   4.  \uc904\uc744 \ubc14\uafc0 \ud544\uc694\uac00 \uc788\uc73c\uba74 '\'\ub97c \ub77c\uc778\uc758 \ub05d\uc5d0 \ucd94\uac00(\ub9cc\uc57d  '\'\ubb38\uc790\ub97c \uc0ac\uc6a9\ud574\uc57c \ud558\ub294 \uacbd\uc6b0\ub294 '\\'\ub97c \uc0ac\uc6a9)
-#   5.  Windows\uc5d0\uc11c\uc758 \ub514\ub809\ud1a0\ub9ac \ud45c\uc2dc : '\\' or '/'  ('\' \uc0ac\uc6a9\ud558\uba74 \uc548\ub428)
-#   6.  Unix\uc5d0\uc11c\uc758 \ub514\ub809\ud1a0\ub9ac \ud45c\uc2dc : '/'
-#   7.  \uc8fc\uc11d\ubb38 \ucc98\ub9ac\ub294  #\uc0ac\uc6a9
-#   8.  value\uac12 \ub4a4\uc5d0 \uc2a4\ud398\uc774\uc2a4\uac00 \uc874\uc7ac\ud558\ub294 \uacbd\uc6b0 \uc11c\ube14\ub9bf\uc5d0\uc11c \ucc38\uc870\ud560\ub54c\ub294 \uc5d0\ub7ec\ubc1c\uc0dd\ud560 \uc218 \uc788\uc73c\ubbc0\ub85c trim()\ud558\uac70\ub098 \ub9c8\uc9c0\ub9c9 \uacf5\ubc31\uc5c6\uc774 properties \uac12\uc744 \uc124\uc815\ud560\uac83
+#   1.  key = value \uAD6C\uC870\uC785\uB2C8\uB2E4.
+#   2.  key\uAC12\uC740 \uACF5\uBC31\uBB38\uC790\uB97C \uD3EC\uD568\uBD88\uAC00, value\uAC12\uC740 \uACF5\uBC31\uBB38\uC790\uB97C \uAC00\uB2A5
+#   3.  key\uAC12\uC73C\uB85C \uD55C\uAE00\uC744 \uC0AC\uC6A9\uBD88\uAC00,   value\uAC12\uC740 \uD55C\uAE00\uC0AC\uC6A9\uC774 \uAC00\uB2A5
+#   4.  \uC904\uC744 \uBC14\uAFC0 \uD544\uC694\uAC00 \uC788\uC73C\uBA74 '\'\uB97C \uB77C\uC778\uC758 \uB05D\uC5D0 \uCD94\uAC00(\uB9CC\uC57D  '\'\uBB38\uC790\uB97C \uC0AC\uC6A9\uD574\uC57C \uD558\uB294 \uACBD\uC6B0\uB294 '\\'\uB97C \uC0AC\uC6A9)
+#   5.  Windows\uC5D0\uC11C\uC758 \uB514\uB809\uD1A0\uB9AC \uD45C\uC2DC : '\\' or '/'  ('\' \uC0AC\uC6A9\uD558\uBA74 \uC548\uB428)
+#   6.  Unix\uC5D0\uC11C\uC758 \uB514\uB809\uD1A0\uB9AC \uD45C\uC2DC : '/'
+#   7.  \uC8FC\uC11D\uBB38 \uCC98\uB9AC\uB294  #\uC0AC\uC6A9
+#   8.  value\uAC12 \uB4A4\uC5D0 \uC2A4\uD398\uC774\uC2A4\uAC00 \uC874\uC7AC\uD558\uB294 \uACBD\uC6B0 \uC11C\uBE14\uB9BF\uC5D0\uC11C \uCC38\uC870\uD560\uB54C\uB294 \uC5D0\uB7EC\uBC1C\uC0DD\uD560 \uC218 \uC788\uC73C\uBBC0\uB85C trim()\uD558\uAC70\uB098 \uB9C8\uC9C0\uB9C9 \uACF5\uBC31\uC5C6\uC774 properties \uAC12\uC744 \uC124\uC815\uD560\uAC83
 #-----------------------------------------------------------------------
 
-# \uc6b4\uc601\uc11c\ubc84 \ud0c0\uc785(WINDOWS, UNIX)
+# \uC6B4\uC601\uC11C\uBC84 \uD0C0\uC785(WINDOWS, UNIX)
 Globals.OsType = WINDOWS
 
-# G4C \uc5f0\uacb0\uc6a9 IP (localhost)
+# G4C \uC5F0\uACB0\uC6A9 IP (localhost)
 Globals.LocalIp = 127.0.0.1
 
-# DB\uc11c\ubc84 \ud0c0\uc785(mysql,oracle,altibase,tibero) - datasource \ubc0f sqlMap \ud30c\uc77c \uc9c0\uc815\uc5d0 \uc0ac\uc6a9\ub428
+# DB\uC11C\uBC84 \uD0C0\uC785(mysql,oracle,altibase,tibero) - datasource \uBC0F sqlMap \uD30C\uC77C \uC9C0\uC815\uC5D0 \uC0AC\uC6A9\uB428
 Globals.DbType = mysql
 
 
@@ -29,9 +29,9 @@
 # mysql
 Globals.DriverClassName=com.mysql.jdbc.Driver
 #Globals.Url=jdbc:mysql://139.150.73.12:3306/mjon
-Globals.Url=jdbc:mysql://192.168.0.60:3308/mjon_advc
-Globals.UserName= mjonUr
-Globals.Password= mjon!@#$
+Globals.Url=jdbc:mysql://192.168.0.60:3309/mjgo
+Globals.UserName= mjgoUr
+Globals.Password= itntest123
 #Globals.Url=jdbc:mysql://192.168.0.125:3306/mjon
 
 #Globals.DriverClassName=com.mysql.jdbc.Driver
@@ -47,7 +47,7 @@
 
 # MainPage Setting(admin)
 Globals.MainPage = /cmm/main/mainPage.do
-#\ucee8\ud150\uce20 \ud30c\uc77c\uc704\uce58
+#\uCEE8\uD150\uCE20 \uD30C\uC77C\uC704\uCE58
 #Globals.ckeditorUploadDir=/home/file/ckeditor/
 Globals.ckeditorUploadDir=/usr/local/tomcat/file/ckeditor/
 #TEST SERVER
@@ -57,46 +57,46 @@
 #Globals.file.saveDir=D:/dv/eGovFrameDev-3.9.0-64bit/workspace/mjon/
 Globals.file.saveDir=/usr/local/tomcat/
 
-#whois openApi \uc544\uc774\ud53c \uccb4\ud06c
+#whois openApi \uC544\uC774\uD53C \uCCB4\uD06C
 whois.api.key = 8nrytiochRBf3uEZ8GuIaTWdSTZP6Gw+9x9PIhAOjOt6+9fhyvOrpgVmlThdNL2kz1Eh/6jLVv7O+YnwE4bs7g==
 whois.api.url = http://apis.data.go.kr/B551505/whois/ipas_country_code
 
 
 
-#SNS \ub85c\uadf8\uc778 KEY \uac12
-#ITN \ub124\uc774\ubc84
+#SNS \uB85C\uADF8\uC778 KEY \uAC12
+#ITN \uB124\uC774\uBC84
 Globals.itn.naver.clentId=d9Ohvhty_RVsfrq9p_2J
 Globals.itn.naver.clientSecret=kwiEmpkLg5
 Globals.itn.naver.returnUrl=http://localhost:80/snsLogin/naverOauth.do
-#ITN \uce74\uce74\uc624
+#ITN \uCE74\uCE74\uC624
 Globals.itn.kakao.restApiKey=10b66ad0c44b68b659855ddd64db2c44
 Globals.itn.kakao.returnUrl=http://localhost:80/snsLogin/kakaoOauth.do
 
-#\uc0ac\uc774\ud2b8 \uc544\uc774\ub514 \uc81c\uac70\ub85c JSP\uc5d0\uc11c siteId/siteNm \ubcf4\uc5ec\uc8fc\uae30 \uc704\ud574 
+#\uC0AC\uC774\uD2B8 \uC544\uC774\uB514 \uC81C\uAC70\uB85C JSP\uC5D0\uC11C siteId/siteNm \uBCF4\uC5EC\uC8FC\uAE30 \uC704\uD574 
 Globals.homepage.siteId=mjon
-Globals.homepage.siteNm=\ubb38\uc790ON
+Globals.homepage.siteNm=\uBB38\uC790ON
 
-#\ub098\uc774\uc2a4\ud398\uc774 \ud604\uae08\uc601\uc218\uc99d \ubc1c\ud589\uc744 \uc704\ud55c \ub098\uc774\uc2a4\ud398\uc774 ID
+#\uB098\uC774\uC2A4\uD398\uC774 \uD604\uAE08\uC601\uC218\uC99D \uBC1C\uD589\uC744 \uC704\uD55C \uB098\uC774\uC2A4\uD398\uC774 ID
 Globals.Nicepay.Id = itn180208
-#\ub098\uc774\uc2a4\ud398\uc774 \ud604\uae08\uc601\uc218\uc99d \ubc1c\ud589\uc744 \uc704\ud55c \ud68c\uc0ac \uc0ac\uc5c5\uc790\ubc88\ud638
+#\uB098\uC774\uC2A4\uD398\uC774 \uD604\uAE08\uC601\uC218\uC99D \uBC1C\uD589\uC744 \uC704\uD55C \uD68C\uC0AC \uC0AC\uC5C5\uC790\uBC88\uD638
 Globals.Business.number = 6538700858
 
 
-#itn \ucc44\uc6a9\uacf5\uace0\ub97c \uc704\ud55c \uc124\uc815
+#itn \uCC44\uC6A9\uACF5\uACE0\uB97C \uC704\uD55C \uC124\uC815
 
-#\ud30c\uc77c \ub2e4\uc6b4\ub85c\ub4dc \uacbd\ub85c
+#\uD30C\uC77C \uB2E4\uC6B4\uB85C\uB4DC \uACBD\uB85C
 Globals.itn.file.saveDir=D:/fileTesttset/
-#\uba54\uc77c \ucc44\uc6a9 \ud15c\ud50c\ub9bf URL
+#\uBA54\uC77C \uCC44\uC6A9 \uD15C\uD50C\uB9BF URL
 Globals.itn.recruit.template.url=http://localhost:8080/publish/email_form_itn_recruit.html
-#\uba54\uc77c \ubb38\uc758\ud558\uae30 \ud15c\ud50c\ub9bf URL
+#\uBA54\uC77C \uBB38\uC758\uD558\uAE30 \uD15C\uD50C\uB9BF URL
 Globals.itn.contact.us.template.url=http://localhost:8080/publish/email_form_itn_contact_us.html
-#\uba54\uc77c \uc218\uc2e0\uc790 \uc8fc\uc18c #TODO : \ucd94\ud6c4\uc5d0 \ubcc0\uacbd\ud574\uc57c\ud568 
+#\uBA54\uC77C \uC218\uC2E0\uC790 \uC8FC\uC18C #TODO : \uCD94\uD6C4\uC5D0 \uBCC0\uACBD\uD574\uC57C\uD568 
 Globals.itn.mail.to.address=rlaqhal6613@duam.net
 
 
-#\ube44\uc988\ubfcc\ub9ac\uc624 \uc124\uc815 
+#\uBE44\uC988\uBFCC\uB9AC\uC624 \uC124\uC815 
 Globals.mjon.kakao.dir=/usr/local/tomcat/file/kakao
-#\ubb38\uc790\uc628 \uce74\uce74\uc624 \uc11c\ube44\uc2a4 \uc815\ubcf4 (\uc804\uc1a1\uc0ac : \ube44\uc988\ubfcc\ub9ac\uc624)
+#\uBB38\uC790\uC628 \uCE74\uCE74\uC624 \uC11C\uBE44\uC2A4 \uC815\uBCF4 (\uC804\uC1A1\uC0AC : \uBE44\uC988\uBFCC\uB9AC\uC624)
 Globals.mjon.biz.url=https://kapi.ppurio.com
 Globals.mjon.biz.id=itn0202
 Globals.mjon.biz.kakao.apiKey=dheBWCONP6J5
@@ -110,7 +110,7 @@
 Globals.fax.file.ori.path=/usr/local/tomcat/file/sht/fax
 Globals.fax.file.permit.ext=hwp,hwpml,doc,xls,ppt,pdf,txt,docx,xlsx,pptx,tif,jpg,jpeg,gif,bmp,gul
 
-#KG \ubaa8\ube4c\ub9ac\uc5b8\uc2a4 \uc124\uc815
+#KG \uBAA8\uBE4C\uB9AC\uC5B8\uC2A4 \uC124\uC815
 #CARD
 Globals.pay.kgm.card.cnSvcid=191017078687
 Globals.pay.kgm.card.payMode=10
@@ -122,8 +122,11 @@
 Globals.pay.kgm.mobile.payMode=00
 
 #Slack
-Globals.slack.hooks.url=https://hooks.slack.com/services/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
-Globals.slack.channel.name=\ud14c\uc2a4\ud2b8_mjon\uba54\uc2dc\uc9c0
+Globals.slack.hooks.url=https://hooks.slack.com/services/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
+Globals.slack.channel.name=\uD14C\uC2A4\uD2B8-\uBB38\uC790\uACE0-message
 
 #API
 Globals.api.ip=http://119.193.215.98:8087
+
+# \uB300\uC2DC\uBCF4\uB4DC \uC694\uC57D API(n8n\u2192Slack) \uACF5\uC720 \uD1A0\uD070
+Globals.dashboard.api.token=mjon_783439232074797a6fd5a8d6d32ce5d201e4b9a1ef6159e1
src/main/resources/egovframework/spring/com/context-idgen.xml
--- src/main/resources/egovframework/spring/com/context-idgen.xml
+++ src/main/resources/egovframework/spring/com/context-idgen.xml
@@ -1092,6 +1092,45 @@
 		<property name="cipers" value="10" />
 		<property name="fillChar" value="0" />
 	</bean>
-	
-		
+
+    <!-- 사용자 접근 로그 ID Generation Strategy Config -->
+    <bean name="egovSecondAuthLogIdGnrService"
+          class="egovframework.rte.fdl.idgnr.impl.EgovTableIdGnrServiceImpl"
+          destroy-method="destroy">
+
+        <property name="dataSource" ref="dataSource" />
+        <property name="strategy" ref="secondAuthLogStrategy" />
+
+        <property name="blockSize" value="12" />
+        <property name="table" value="IDS" />
+        <property name="tableName" value="SECOND_AUTH_LOG_ID" />
+    </bean>
+
+    <bean name="secondAuthLogStrategy"
+          class="egovframework.rte.fdl.idgnr.impl.strategy.EgovIdGnrStrategyImpl">
+
+        <property name="prefix" value="UAL_" />
+        <property name="cipers" value="12" />
+        <property name="fillChar" value="0" />
+    </bean>
+
+    <bean name="egovPersonalInformationLogIdgenService"
+          class="egovframework.rte.fdl.idgnr.impl.EgovTableIdGnrServiceImpl"
+          destroy-method="destroy">
+
+        <property name="dataSource" ref="dataSource" />
+        <property name="strategy" ref="personalInformationLogStrategy" />
+
+        <property name="blockSize" value="12" />
+        <property name="table" value="IDS" />
+        <property name="tableName" value="PERS_INFO_LOG" />
+    </bean>
+
+    <bean name="personalInformationLogStrategy"
+          class="egovframework.rte.fdl.idgnr.impl.strategy.EgovIdGnrStrategyImpl">
+
+        <property name="prefix" value="PIL_" />
+        <property name="cipers" value="12" />
+        <property name="fillChar" value="0" />
+    </bean>
 </beans>
src/main/resources/egovframework/spring/com/context-security.xml
--- src/main/resources/egovframework/spring/com/context-security.xml
+++ src/main/resources/egovframework/spring/com/context-security.xml
@@ -13,7 +13,8 @@
  	<security:http pattern="/resource/**" security="none"/>
  	<security:http pattern="/pb/**" security="none"/>
  	<security:http pattern="\A/WEB-INF/jsp/.*\Z" request-matcher="regex" security="none"/>
- 	
+ 	<security:http pattern="/api/dashboard/**" security="none"/>
+
     <egov-security:config id="securityConfig"
         loginUrl="/uat/uia/actionMain.do"
         logoutSuccessUrl="/uat/uia/actionMain.do"
src/main/resources/egovframework/sqlmap/com/uss/olh/hpc/EgovHpcm_SQL_mysql.xml
--- src/main/resources/egovframework/sqlmap/com/uss/olh/hpc/EgovHpcm_SQL_mysql.xml
+++ src/main/resources/egovframework/sqlmap/com/uss/olh/hpc/EgovHpcm_SQL_mysql.xml
@@ -8,6 +8,7 @@
 <sqlMap namespace="Hpcm">
 	<typeAlias  alias="HpcmVO" type="itn.com.uss.olh.hpc.service.HpcmVO"/>
 	<typeAlias  alias="hackIpVO" type="itn.com.uss.olh.hpc.service.HackIpVO"/>
+	<typeAlias  alias="blockLogVO" type="itn.com.uss.olh.hpc.service.GeoIpBlockLogVO"/>
 	
 	<select id="Hpcm.selectHpcmDetail" parameterClass="HpcmVO" resultClass="HpcmVO">
 			SELECT 	A.HPCM_ID AS hpcmId,
@@ -490,5 +491,43 @@
 			</isNotEmpty>
 			LIMIT  #recordCountPerPage# OFFSET #firstIndex#	
 	</select>
-	
+
+	<select id="hackIpDAO.selecForeignAccessBlockList" parameterClass="blockLogVO" resultClass="blockLogVO">
+		select
+		COUNT(BLOCK_LOG_ID) OVER() as totCnt,
+		BLOCK_LOG_ID as blockLogId,
+		BLOCK_DT as blockDt,
+		ACCESS_IP as accessIp,
+		COUNTRY_CODE as countryCode,
+		COUNTRY_NAME as countryName,
+		BLOCK_YN as blockYn
+		from MJ_ACCESS_BLOCK_LOG
+		where 1 = 1
+		<isNotEmpty property="searchKeyword">
+			<isEqual property="searchCondition" compareValue="1">
+				AND ACCESS_IP LIKE CONCAT('%', #searchKeyword#, '%')
+			</isEqual>
+		</isNotEmpty>
+		<isNotEmpty prepend="AND" property="searchStartDate">
+			<![CDATA[
+				BLOCK_DT >= DATE_FORMAT(#searchStartDate#, '%Y-%m-%d')
+			]]>
+		</isNotEmpty>
+		<isNotEmpty prepend="AND" property="searchEndDate">
+			<![CDATA[
+				BLOCK_DT < DATE_FORMAT(DATE_ADD(#searchEndDate#, INTERVAL 1 DAY), '%Y-%m-%d')
+			]]>
+		</isNotEmpty>
+		ORDER BY BLOCK_LOG_ID desc
+		LIMIT  #recordCountPerPage# OFFSET #firstIndex#
+	</select>
+
+	<update id="hackIpDAO.updateAccessBlockYn" parameterClass="blockLogVO">
+		update SITEMANAGER set ACCESS_IP_BLOCK_YN = #blockYn#
+	</update>
+
+	<select id="hackIpDAO.selectAccessBlockYn" resultClass="String">
+		select ACCESS_IP_BLOCK_YN from SITEMANAGER
+	</select>
+
 </sqlMap>   
(No newline at end of file)
src/main/resources/egovframework/sqlmap/config/mysql/sql-map-config-mysql-msg.xml
--- src/main/resources/egovframework/sqlmap/config/mysql/sql-map-config-mysql-msg.xml
+++ src/main/resources/egovframework/sqlmap/config/mysql/sql-map-config-mysql-msg.xml
@@ -4,6 +4,7 @@
 <sqlMapConfig>
 	<settings cacheModelsEnabled="true" useStatementNamespaces="true" />
 	<sqlMap resource="egovframework/sqlmap/let/msg/MjonMsgData_SQL_mysql.xml"/>	 <!-- 문자메세지 -->
+	<sqlMap resource="egovframework/sqlmap/let/msg/MjonEmployeeCert_SQL_mysql.xml"/><!-- 종사자 수 인증 -->
 	<sqlMap resource="egovframework/sqlmap/let/msg/MjonMsgCampainData_SQL_mysql.xml"/>	 <!-- 선거문자메세지 -->
 	<sqlMap resource="egovframework/sqlmap/let/msg/MjonMsgCustom_SQL_mysql.xml"/><!-- 문자 커스텀 -->		
 	<sqlMap resource="egovframework/sqlmap/let/msg/MjonMsgSent_SQL_mysql.xml"/><!-- 문자 발송관리 -->		
 
src/main/resources/egovframework/sqlmap/config/mysql/sql-map-config-mysql-sym-log-access.xml (added)
+++ src/main/resources/egovframework/sqlmap/config/mysql/sql-map-config-mysql-sym-log-access.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE sqlMapConfig PUBLIC "-//iBATIS.com//DTD SQL Map Config 2.0//EN"
+    "http://www.ibatis.com/dtd/sql-map-config-2.dtd">
+
+<sqlMapConfig>
+	<sqlMap resource="egovframework/sqlmap/let/sym/log/access/UserAccessLog_SQL_Mysql.xml"/>
+</sqlMapConfig>
 
src/main/resources/egovframework/sqlmap/config/mysql/sql-map-config-mysql-sym-log-personal.xml (added)
+++ src/main/resources/egovframework/sqlmap/config/mysql/sql-map-config-mysql-sym-log-personal.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE sqlMapConfig PUBLIC "-//iBATIS.com//DTD SQL Map Config 2.0//EN"
+    "http://www.ibatis.com/dtd/sql-map-config-2.dtd">
+
+<sqlMapConfig>
+	<sqlMap resource="egovframework/sqlmap/let/sym/log/personal/PersonalInformationLog_SQL_Mysql.xml"/>
+</sqlMapConfig>
src/main/resources/egovframework/sqlmap/config/mysql/sql-map-config-mysql-uat.xml
--- src/main/resources/egovframework/sqlmap/config/mysql/sql-map-config-mysql-uat.xml
+++ src/main/resources/egovframework/sqlmap/config/mysql/sql-map-config-mysql-uat.xml
@@ -3,4 +3,5 @@
     "http://ibatis.apache.org/dtd/sql-map-config-2.dtd">
 <sqlMapConfig>
 	<sqlMap resource="egovframework/sqlmap/let/uat/uia/EgovLoginUsr_SQL_Mysql.xml"/>
+	<sqlMap resource="egovframework/sqlmap/let/uat/uia/SecondAuthLog_SQL_Mysql.xml"/>
 </sqlMapConfig>
src/main/resources/egovframework/sqlmap/let/cert/MjonCertPhone_SQL_mysql.xml
--- src/main/resources/egovframework/sqlmap/let/cert/MjonCertPhone_SQL_mysql.xml
+++ src/main/resources/egovframework/sqlmap/let/cert/MjonCertPhone_SQL_mysql.xml
@@ -15,6 +15,7 @@
 			, '-' AS certMemo
 			, '대표번호' AS certAlias
 			, '-' AS frstRegistPnttm
+			, sbscrb_de AS mberRegDate
 		FROM 
 		    lettngnrlmber
 		WHERE MBER_ID = #userId#
@@ -24,6 +25,7 @@
 			, CERT_MEMO AS certMemo
 			, CERT_ALIAS AS certAlias
 			, FRST_REGIST_PNTTM AS frstRegistPnttm
+			, FRST_REGIST_PNTTM AS mberRegDate
 		FROM 
 		    lettngnrlmber_cert_phone
 		WHERE MBER_ID = #userId#
src/main/resources/egovframework/sqlmap/let/cop/bbs/EgovBoard_SQL_Mysql.xml
--- src/main/resources/egovframework/sqlmap/let/cop/bbs/EgovBoard_SQL_Mysql.xml
+++ src/main/resources/egovframework/sqlmap/let/cop/bbs/EgovBoard_SQL_Mysql.xml
@@ -1714,7 +1714,6 @@
 			, a.NTT_ID 				AS nttId
 			, a.NTCR_ID 			AS ntcrId
 			, a.NTCR_NM 			AS ntcrNm
-			/*, (select EMPLYR_ID from lettnemplyrinfo c where a.FRST_REGISTER_ID = c.ESNTL_ID) AS frstRegisterId*/
 			, a.NTCR_NM AS frstRegisterId
 			, a.FRST_REGIST_PNTTM	AS frstRegisterPnttm
 		FROM
@@ -1723,11 +1722,39 @@
 			ON a.BBS_ID = b.BBS_ID
 		WHERE 1=1 
 		AND a.USE_AT = 'Y'
+	   <isNotEmpty prepend="AND" property="searchStartDate">
+		   <![CDATA[
+				DATE_FORMAT(a.FRST_REGIST_PNTTM, '%Y-%m-%d') >= DATE_FORMAT(#searchStartDate#, '%Y-%m-%d')
+			]]>
+	   </isNotEmpty>
+	   <isNotEmpty prepend="AND" property="searchEndDate">
+		   <![CDATA[
+				DATE_FORMAT(a.FRST_REGIST_PNTTM, '%Y-%m-%d') <= DATE_FORMAT(#searchEndDate#, '%Y-%m-%d')
+			]]>
+	   </isNotEmpty>
 		<isEqual prepend="AND" property="searchCnd" compareValue="1">
 	        <isNotEmpty property="searchWrd">
   				<![CDATA[	( a.NTT_SJ LIKE CONCAT ('%', #searchWrd#,'%') OR  a.NTT_CN LIKE CONCAT ('%', #searchWrd#,'%') ) ]]>
   			</isNotEmpty>		
 		</isEqual>
+	   <isEqual prepend="AND" property="searchCnd" compareValue="2">
+		   <isNotEmpty property="searchWrd">
+			   a.NTCR_ID LIKE CONCAT('%', #searchWrd#, '%')
+		   </isNotEmpty>
+	   </isEqual>
+	   <isEqual prepend="AND" property="searchCnd" compareValue="3">
+		   <isNotEmpty property="searchWrd">
+				EXISTS (
+				  SELECT 1
+				  FROM lettncomment c
+				  WHERE
+			   			c.USE_AT = 'Y'
+				    AND c.BBS_ID = a.BBS_ID
+					AND c.NTT_ID = a.NTT_ID
+					AND c.WRTER_NM LIKE CONCAT('%', #searchWrd#, '%')
+				)
+		   </isNotEmpty>
+	   </isEqual>
 		ORDER BY 1=1
 	        <isNotEmpty property="searchSortCnd">
   				,$searchSortCnd$
@@ -1737,6 +1764,73 @@
   			</isNotEmpty>
 	    LIMIT #recordCountPerPage# OFFSET #firstIndex#
    </select>
+
+	<select id="BBSManageDAO.selectBbsContentsListExcelDownload" parameterClass="BoardVO" resultClass="BoardVO"  >
+		SELECT
+			COUNT(1) OVER() AS totCnt,
+			b.BBS_NM AS bbsNm,
+			a.NTT_SJ AS nttSj,
+			a.NTT_CN AS nttCn,
+			a.NTCR_ID AS ntcrId,
+			a.NTCR_NM as ntcrNm,
+			COALESCE(c.commenterNms, '') AS commenterNms,
+			DATE_FORMAT(a.FRST_REGIST_PNTTM, '%Y-%m-%d %T') AS frstRegisterPnttm
+		FROM
+			lettnbbs a
+		INNER JOIN lettnbbsmaster b
+			ON a.BBS_ID = b.BBS_ID
+		LEFT JOIN (
+			SELECT
+			BBS_ID,
+			NTT_ID,
+			GROUP_CONCAT(
+			DISTINCT WRTER_NM
+			ORDER BY ANSWER_NO
+			SEPARATOR ', '
+		) AS commenterNms
+		FROM lettncomment
+		WHERE USE_AT = 'Y'
+		GROUP BY BBS_ID, NTT_ID
+		) c
+			ON a.BBS_ID = c.BBS_ID
+			AND a.NTT_ID = c.NTT_ID
+		WHERE 1=1
+		AND a.USE_AT = 'Y'
+		<isNotEmpty prepend="AND" property="searchStartDate">
+			<![CDATA[
+				DATE_FORMAT(a.FRST_REGIST_PNTTM, '%Y-%m-%d') >= DATE_FORMAT(#searchStartDate#, '%Y-%m-%d')
+			]]>
+		</isNotEmpty>
+		<isNotEmpty prepend="AND" property="searchEndDate">
+			<![CDATA[
+				DATE_FORMAT(a.FRST_REGIST_PNTTM, '%Y-%m-%d') <= DATE_FORMAT(#searchEndDate#, '%Y-%m-%d')
+			]]>
+		</isNotEmpty>
+		<isEqual prepend="AND" property="searchCnd" compareValue="1">
+			<isNotEmpty property="searchWrd">
+				<![CDATA[	( a.NTT_SJ LIKE CONCAT ('%', #searchWrd#,'%') OR  a.NTT_CN LIKE CONCAT ('%', #searchWrd#,'%') ) ]]>
+			</isNotEmpty>
+		</isEqual>
+		<isEqual prepend="AND" property="searchCnd" compareValue="2">
+			<isNotEmpty property="searchWrd">
+				a.NTCR_ID LIKE CONCAT('%', #searchWrd#, '%')
+			</isNotEmpty>
+		</isEqual>
+		<isEqual prepend="AND" property="searchCnd" compareValue="3">
+			<isNotEmpty property="searchWrd">
+				EXISTS (
+				SELECT 1
+				FROM lettncomment c
+				WHERE
+				c.USE_AT = 'Y'
+				AND c.BBS_ID = a.BBS_ID
+				AND c.NTT_ID = a.NTT_ID
+				AND c.WRTER_NM LIKE CONCAT('%', #searchWrd#, '%')
+				)
+			</isNotEmpty>
+		</isEqual>
+		ORDER BY a.FRST_REGIST_PNTTM desc
+	</select>
    
    <select id="BBSManageDAO.selectAdminMainBoardByDash" parameterClass="BoardVO" resultClass="BoardVO"  >
 		SELECT
 
src/main/resources/egovframework/sqlmap/let/msg/MjonEmployeeCert_SQL_mysql.xml (added)
+++ src/main/resources/egovframework/sqlmap/let/msg/MjonEmployeeCert_SQL_mysql.xml
@@ -0,0 +1,232 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE sqlMap PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd">
+<sqlMap namespace="EmployeeCert">
+	<typeAlias alias="employeeCertVO" type="itn.let.mjo.msg.service.EmployeeCertVO"/>
+
+	<select id="employeeCertDAO.selectEmployeeCertList" parameterClass="employeeCertVO" resultClass="employeeCertVO">
+	/* employeeCertDAO.selectEmployeeCertList */
+		SELECT
+			EH.EMPLOYEE_CERT_HSTRY_SEQ AS employeeCertHstrySeq
+			, EH.MBER_ID AS mberId
+			, LM.DEPT AS dept
+		    , LM.MBER_NM AS mberNm
+			, LM.biz_no AS bizNo
+			, LM.CEO_NM AS managerNm
+			, EC.CERT_CNT AS certCnt
+			, EH.APPLY_CNT AS applyCnt
+			, EH.AUTH_YN AS authYn
+			, AC.CODE_NM AS authYnTxt
+			, EH.REJECT_CODE AS rejectCode
+			, RC.CODE_NM AS rejectCodeTxt
+			, EH.REJECT_REASON AS rejectReason
+			, EH.ATCH_FILE_ID AS atchFileId
+			, EH.AGREE_YN AS agreeYn
+			, DATE_FORMAT(EH.FRST_REGIST_PNTTM, '%Y-%m-%d %H:%i') AS frstRegistPnttm
+			, EH.FRST_REGISTER_ID AS frstRegisterId
+			, DATE_FORMAT(EH.LAST_UPDT_PNTTM, '%Y-%m-%d %H:%i') AS lastUpdtPnttm
+			, EH.LAST_UPDUSR_ID AS lastUpdusrId
+			, EI.USER_NM 		AS lastUpdusrNm
+		FROM MJ_EMPLOYEE_CERT EC
+		INNER JOIN MJ_EMPLOYEE_CERT_HSTRY EH
+			ON EC.MBER_ID = EH.MBER_ID
+			AND EC.LAST_HSTRY_SEQ = EH.EMPLOYEE_CERT_HSTRY_SEQ
+		INNER JOIN LETTNGNRLMBER LM
+		    ON EH.MBER_ID = LM.MBER_ID
+
+		LEFT JOIN LETTNEMPLYRINFO EI
+		    ON EH.LAST_UPDUSR_ID = EI.EMPLYR_ID
+		LEFT JOIN LETTCCMMNDETAILCODE AC
+			ON AC.CODE_ID = 'ITN028' AND AC.USE_AT = 'Y' AND EH.AUTH_YN = AC.CODE
+		LEFT JOIN LETTCCMMNDETAILCODE RC
+			ON RC.CODE_ID = 'EMP001' AND RC.USE_AT = 'Y' AND EH.REJECT_CODE = RC.CODE
+		WHERE 1 = 1
+		<isNotEmpty property="searchStartDate">
+			AND EH.FRST_REGIST_PNTTM &gt;= CONCAT(#searchStartDate#, ' 00:00:00')
+		</isNotEmpty>
+		<isNotEmpty property="searchEndDate">
+			AND EH.FRST_REGIST_PNTTM &lt; DATE_ADD(#searchEndDate#, INTERVAL 1 DAY)
+		</isNotEmpty>
+		<isNotEmpty property="searchCondition2">
+			<isEqual property="searchCondition2" compareValue="N">
+				AND EH.AUTH_YN IN ('N', 'H')
+			</isEqual>
+			<isNotEqual property="searchCondition2" compareValue="N">
+				AND EH.AUTH_YN = #searchCondition2#
+			</isNotEqual>
+		</isNotEmpty>
+		<isNotEmpty property="searchKeyword">
+			<isEqual property="searchCondition" compareValue="1">
+				AND EH.MBER_ID LIKE CONCAT('%', #searchKeyword#, '%')
+			</isEqual>
+			<isEqual property="searchCondition" compareValue="2">
+				AND LM.MBER_NM LIKE CONCAT('%', #searchKeyword#, '%')
+			</isEqual>
+			<isEqual property="searchCondition" compareValue="3">
+				AND LM.BIZ_NO LIKE CONCAT('%', #searchKeyword#, '%')
+			</isEqual>
+			<isEmpty property="searchCondition">
+				AND (EH.MBER_ID LIKE CONCAT('%', #searchKeyword#, '%')
+					OR LM.MBER_NM LIKE CONCAT('%', #searchKeyword#, '%')
+					OR LM.BIZ_NO LIKE CONCAT('%', #searchKeyword#, '%'))
+			</isEmpty>
+		</isNotEmpty>
+		ORDER BY EH.FRST_REGIST_PNTTM DESC
+		<isNotNull property="recordCountPerPage">
+			LIMIT #recordCountPerPage# OFFSET #firstIndex#
+		</isNotNull>
+	</select>
+
+	<select id="employeeCertDAO.selectEmployeeCertListCnt" parameterClass="employeeCertVO" resultClass="java.lang.Integer">
+        /* employeeCertDAO.selectEmployeeCertListCnt */
+        SELECT COUNT(EH.EMPLOYEE_CERT_HSTRY_SEQ)
+        FROM MJ_EMPLOYEE_CERT EC
+        INNER JOIN MJ_EMPLOYEE_CERT_HSTRY EH
+        ON EC.MBER_ID = EH.MBER_ID
+        AND EC.LAST_HSTRY_SEQ = EH.EMPLOYEE_CERT_HSTRY_SEQ
+        INNER JOIN LETTNGNRLMBER LM ON EH.MBER_ID = LM.MBER_ID
+        WHERE 1 = 1
+        <isNotEmpty property="searchStartDate">
+            AND EH.FRST_REGIST_PNTTM &gt;= CONCAT(#searchStartDate#, ' 00:00:00')
+        </isNotEmpty>
+        <isNotEmpty property="searchEndDate">
+            AND EH.FRST_REGIST_PNTTM &lt; DATE_ADD(#searchEndDate#, INTERVAL 1 DAY)
+        </isNotEmpty>
+		<isNotEmpty property="searchCondition2">
+			<isEqual property="searchCondition2" compareValue="N">
+				AND EH.AUTH_YN IN ('N', 'H')
+			</isEqual>
+			<isNotEqual property="searchCondition2" compareValue="N">
+				AND EH.AUTH_YN = #searchCondition2#
+			</isNotEqual>
+		</isNotEmpty>
+        <isNotEmpty property="searchKeyword">
+            <isEqual property="searchCondition" compareValue="1">
+                AND EH.MBER_ID LIKE CONCAT('%', #searchKeyword#, '%')
+            </isEqual>
+            <isEqual property="searchCondition" compareValue="2">
+                AND LM.MBER_NM LIKE CONCAT('%', #searchKeyword#, '%')
+            </isEqual>
+			<isEqual property="searchCondition" compareValue="3">
+				AND LM.BIZ_NO LIKE CONCAT('%', #searchKeyword#, '%')
+			</isEqual>
+            <isEmpty property="searchCondition">
+                AND (EH.MBER_ID LIKE CONCAT('%', #searchKeyword#, '%')
+                OR LM.MBER_NM LIKE CONCAT('%', #searchKeyword#, '%')
+                OR LM.BIZ_NO LIKE CONCAT('%', #searchKeyword#, '%'))
+            </isEmpty>
+        </isNotEmpty>
+    </select>
+
+	<select id="employeeCertDAO.selectEmployeeCertDetail" parameterClass="employeeCertVO" resultClass="employeeCertVO">
+	/* employeeCertDAO.selectEmployeeCertDetail */
+		SELECT
+			EH.EMPLOYEE_CERT_HSTRY_SEQ AS employeeCertHstrySeq
+			, EH.MBER_ID AS mberId
+			, LM.DEPT AS dept
+			, LM.MBER_NM AS mberNm
+			, LM.BIZ_NO AS bizNo
+			, LM.MBTLNUM AS mbtlNum
+			, LM.CEO_NM AS managerNm
+			, EC.CERT_CNT AS certCnt
+			, EH.APPLY_CNT AS applyCnt
+			, EH.AUTH_YN AS authYn
+			, AC.CODE_NM AS authYnTxt
+			, EH.REJECT_CODE AS rejectCode
+			, RC.CODE_NM AS rejectCodeTxt
+			, EH.REJECT_REASON AS rejectReason
+			, EH.ATCH_FILE_ID AS atchFileId
+			, EH.AGREE_YN AS agreeYn
+			, DATE_FORMAT(EH.AGREE_PNTTM, '%Y-%m-%d %H:%i') AS agreePnttm
+			, DATE_FORMAT(EH.FRST_REGIST_PNTTM, '%Y-%m-%d %H:%i') AS frstRegistPnttm
+			, EH.FRST_REGISTER_ID AS frstRegisterId
+			, DATE_FORMAT(EH.LAST_UPDT_PNTTM, '%Y-%m-%d %H:%i') AS lastUpdtPnttm
+			, EH.LAST_UPDUSR_ID AS lastUpdusrId
+			, EI.USER_NM AS lastUpdusrNm
+		FROM MJ_EMPLOYEE_CERT_HSTRY EH
+		LEFT JOIN MJ_EMPLOYEE_CERT EC ON EH.MBER_ID = EC.MBER_ID
+		INNER JOIN LETTNGNRLMBER LM ON EH.MBER_ID = LM.MBER_ID
+		LEFT JOIN LETTNEMPLYRINFO EI ON EH.LAST_UPDUSR_ID = EI.EMPLYR_ID
+		LEFT JOIN LETTCCMMNDETAILCODE AC
+			ON AC.CODE_ID = 'ITN028' AND AC.USE_AT = 'Y' AND EH.AUTH_YN = AC.CODE
+		LEFT JOIN LETTCCMMNDETAILCODE RC
+			ON RC.CODE_ID = 'EMP001' AND RC.USE_AT = 'Y' AND EH.REJECT_CODE = RC.CODE
+		WHERE EH.EMPLOYEE_CERT_HSTRY_SEQ = #employeeCertHstrySeq#
+	</select>
+
+	<select id="employeeCertDAO.selectEmployeeCertHstryList" parameterClass="employeeCertVO" resultClass="employeeCertVO">
+	/* employeeCertDAO.selectEmployeeCertHstryList */
+		SELECT
+			EH.EMPLOYEE_CERT_HSTRY_SEQ AS employeeCertHstrySeq
+			, EH.MBER_ID AS mberId
+			, EH.APPLY_CNT AS applyCnt
+			, EH.AUTH_YN AS authYn
+			, AC.CODE_NM AS authYnTxt
+			, EH.REJECT_CODE AS rejectCode
+			, RC.CODE_NM AS rejectCodeTxt
+			, EH.REJECT_REASON AS rejectReason
+			, EH.ATCH_FILE_ID AS atchFileId
+			, DATE_FORMAT(EH.FRST_REGIST_PNTTM, '%Y-%m-%d %H:%i') AS frstRegistPnttm
+			, DATE_FORMAT(EH.LAST_UPDT_PNTTM, '%Y-%m-%d %H:%i') AS lastUpdtPnttm
+			, EH.LAST_UPDUSR_ID AS lastUpdusrId
+			, EI.USER_NM AS lastUpdusrNm
+		FROM MJ_EMPLOYEE_CERT_HSTRY EH
+		LEFT JOIN LETTNEMPLYRINFO EI ON EH.LAST_UPDUSR_ID = EI.EMPLYR_ID
+		LEFT JOIN LETTCCMMNDETAILCODE AC
+			ON AC.CODE_ID = 'ITN028' AND AC.USE_AT = 'Y' AND EH.AUTH_YN = AC.CODE
+		LEFT JOIN LETTCCMMNDETAILCODE RC
+			ON RC.CODE_ID = 'EMP001' AND RC.USE_AT = 'Y' AND EH.REJECT_CODE = RC.CODE
+		WHERE EH.MBER_ID = #mberId#
+		ORDER BY EH.FRST_REGIST_PNTTM DESC
+	</select>
+
+	<select id="employeeCertDAO.selectEmployeeCertForUpdate" parameterClass="employeeCertVO" resultClass="employeeCertVO">
+	/* employeeCertDAO.selectEmployeeCertForUpdate */
+		SELECT
+			EH.EMPLOYEE_CERT_HSTRY_SEQ AS employeeCertHstrySeq
+			, EH.MBER_ID AS mberId
+			, EH.APPLY_CNT AS applyCnt
+			, EH.AUTH_YN AS authYn
+		FROM MJ_EMPLOYEE_CERT_HSTRY EH
+		WHERE EH.EMPLOYEE_CERT_HSTRY_SEQ = #employeeCertHstrySeq#
+		FOR UPDATE
+	</select>
+
+	<update id="employeeCertDAO.updateEmployeeCertHstryAuth" parameterClass="employeeCertVO">
+	/* employeeCertDAO.updateEmployeeCertHstryAuth */
+		UPDATE MJ_EMPLOYEE_CERT_HSTRY
+		SET AUTH_YN = #authYn#
+			, REJECT_CODE = #rejectCode#
+			, REJECT_REASON = #rejectReason#
+			, LAST_UPDT_PNTTM = NOW()
+			, LAST_UPDUSR_ID = #lastUpdusrId#
+		WHERE EMPLOYEE_CERT_HSTRY_SEQ = #employeeCertHstrySeq#
+			AND MBER_ID = #mberId#
+	</update>
+
+	<update id="employeeCertDAO.refreshEmployeeCertApproval" parameterClass="employeeCertVO">
+	/* employeeCertDAO.refreshEmployeeCertApproval */
+		UPDATE MJ_EMPLOYEE_CERT
+		SET CERT_CNT = (
+				SELECT H.APPLY_CNT
+				FROM MJ_EMPLOYEE_CERT_HSTRY H
+				WHERE H.MBER_ID = #mberId# AND H.AUTH_YN = 'Y'
+				ORDER BY H.LAST_UPDT_PNTTM DESC LIMIT 1
+			)
+			, AUTH_HSTRY_SEQ = (
+				SELECT H.EMPLOYEE_CERT_HSTRY_SEQ
+				FROM MJ_EMPLOYEE_CERT_HSTRY H
+				WHERE H.MBER_ID = #mberId# AND H.AUTH_YN = 'Y'
+				ORDER BY H.LAST_UPDT_PNTTM DESC LIMIT 1
+			)
+			, LAST_AUTH_PNTTM = (
+				SELECT H.LAST_UPDT_PNTTM
+				FROM MJ_EMPLOYEE_CERT_HSTRY H
+				WHERE H.MBER_ID = #mberId# AND H.AUTH_YN = 'Y'
+				ORDER BY H.LAST_UPDT_PNTTM DESC LIMIT 1
+			)
+			, LAST_UPDT_PNTTM = NOW()
+			, LAST_UPDUSR_ID = #lastUpdusrId#
+		WHERE MBER_ID = #mberId#
+			AND LAST_HSTRY_SEQ = #employeeCertHstrySeq#
+	</update>
+</sqlMap>
 
src/main/resources/egovframework/sqlmap/let/sym/log/access/UserAccessLog_SQL_Mysql.xml (added)
+++ src/main/resources/egovframework/sqlmap/let/sym/log/access/UserAccessLog_SQL_Mysql.xml
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd">
+
+<sqlMap namespace="userAccessLogVO">
+
+    <typeAlias alias="userAccessLogVO" type="itn.let.sym.log.access.UserAccessLogVO"/>
+    <resultMap id="userAccessLogResult" class="userAccessLogVO">
+        <result property="logId" column="LOG_ID"/>
+        <result property="userId" column="USER_ID"/>
+        <result property="accessIp" column="ACCESS_IP"/>
+        <result property="uri" column="URI"/>
+        <result property="menuNm" column="MENU_NM"/>
+        <result property="result" column="RESULT"/>
+        <result property="frstRegistPnttm" column="FRST_REGIST_PNTTM"/>
+    </resultMap>
+
+    <select id="userAccessLogDAO.selectUserAccessLogListTotCnt" parameterClass="userAccessLogVO" resultClass="java.lang.Integer">
+
+        SELECT COUNT(*)
+        FROM USER_ACCESS_LOG A
+        WHERE 1 = 1
+
+        <isNotEmpty property="result">
+            AND A.RESULT = #result#
+        </isNotEmpty>
+
+        <isNotEmpty property="searchStartDate">
+            AND A.FRST_REGIST_PNTTM
+            <![CDATA[ >= ]]>
+            CONCAT(#searchStartDate#, ' 00:00:00')
+        </isNotEmpty>
+
+        <isNotEmpty property="searchEndDate">
+            AND A.FRST_REGIST_PNTTM
+            <![CDATA[ < ]]>
+            DATE_ADD(
+            CONCAT(#searchEndDate#, ' 00:00:00'),
+            INTERVAL 1 DAY
+            )
+        </isNotEmpty>
+
+        <isNotEmpty property="searchKeyword">
+
+            <isEqual property="searchCondition" compareValue="userId">
+                AND A.USER_ID LIKE CONCAT('%', #searchKeyword#, '%')
+            </isEqual>
+
+            <isEqual property="searchCondition" compareValue="accessIp">
+                AND A.ACCESS_IP LIKE CONCAT('%', #searchKeyword#, '%')
+            </isEqual>
+
+            <isEqual property="searchCondition" compareValue="menuNm">
+                AND A.MENU_NM LIKE CONCAT('%', #searchKeyword#, '%')
+            </isEqual>
+
+        </isNotEmpty>
+
+    </select>
+
+    <select id="userAccessLogDAO.selectUserAccessLogList" parameterClass="userAccessLogVO" resultMap="userAccessLogResult">
+        SELECT
+        A.LOG_ID,
+        A.USER_ID,
+        A.ACCESS_IP,
+        A.MENU_NM,
+        A.URI,
+        A.RESULT,
+        DATE_FORMAT(A.FRST_REGIST_PNTTM, '%Y-%m-%d %H:%i:%s') AS FRST_REGIST_PNTTM
+        FROM USER_ACCESS_LOG A
+        WHERE 1 = 1
+        <isNotEmpty property="result">
+            AND A.RESULT = #result#
+        </isNotEmpty>
+        <isNotEmpty property="searchStartDate">
+            AND A.FRST_REGIST_PNTTM <![CDATA[ >= ]]> CONCAT(#searchStartDate#, ' 00:00:00')
+        </isNotEmpty>
+        <isNotEmpty property="searchEndDate">
+            AND A.FRST_REGIST_PNTTM <![CDATA[ < ]]> DATE_ADD(CONCAT(#searchEndDate#, ' 00:00:00'), INTERVAL 1 DAY)
+        </isNotEmpty>
+        <isNotEmpty property="searchKeyword">
+            <isEqual property="searchCondition" compareValue="userId">
+                AND USER_ID LIKE CONCAT('%', #searchKeyword#, '%')
+            </isEqual>
+            <isEqual property="searchCondition" compareValue="accessIp">
+                AND ACCESS_IP LIKE CONCAT('%', #searchKeyword#, '%')
+            </isEqual>
+            <isEqual property="searchCondition" compareValue="menuNm">
+                AND MENU_NM LIKE CONCAT('%', #searchKeyword#, '%')
+            </isEqual>
+        </isNotEmpty>
+        <isNotEmpty property="searchSortCnd">
+            ORDER BY $searchSortCnd$
+            <isNotEmpty property="searchSortOrd">
+                $searchSortOrd$
+            </isNotEmpty>
+        </isNotEmpty>
+
+        LIMIT #firstIndex#, #recordCountPerPage#
+    </select>
+
+</sqlMap>(No newline at end of file)
 
src/main/resources/egovframework/sqlmap/let/sym/log/personal/PersonalInformationLog_SQL_Mysql.xml (added)
+++ src/main/resources/egovframework/sqlmap/let/sym/log/personal/PersonalInformationLog_SQL_Mysql.xml
@@ -0,0 +1,165 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"
+        "http://ibatis.apache.org/dtd/sql-map-2.dtd">
+
+<sqlMap namespace="personalInformationLogVO">
+
+    <typeAlias
+            alias="personalInformationLogVO"
+            type="itn.let.sym.log.personal.PersonalInformationLogVO"/>
+
+    <resultMap id="personalInformationLogResult"
+               class="personalInformationLogVO">
+        <result property="logId" column="LOG_ID"/>
+        <result property="userId" column="USER_ID"/>
+        <result property="accessIp" column="ACCESS_IP"/>
+        <result property="uri" column="URI"/>
+        <result property="menuNm" column="MENU_NM"/>
+        <result property="action" column="ACTION"/>
+        <result property="target" column="TARGET"/>
+        <result property="frstRegistPnttm" column="FRST_REGIST_PNTTM"/>
+    </resultMap>
+
+
+    <insert id="personalInformationLogDAO.insertPersonalInformationLog"
+            parameterClass="personalInformationLogVO">
+
+        INSERT INTO PERSONAL_INFORMATION_LOG (
+            LOG_ID,
+            USER_ID,
+            ACCESS_IP,
+            URI,
+            MENU_NM,
+            ACTION,
+            TARGET,
+            FRST_REGIST_PNTTM
+        ) VALUES (
+                     #logId#,
+                     #userId#,
+                     #accessIp#,
+                     #uri#,
+                     #menuNm#,
+                     #action#,
+                     #target#,
+                     CURRENT_TIMESTAMP
+                 )
+
+    </insert>
+
+
+    <select id="personalInformationLogDAO.selectPersonalInformationLogListTotCnt"
+            parameterClass="personalInformationLogVO"
+            resultClass="java.lang.Integer">
+
+        SELECT COUNT(*)
+        FROM PERSONAL_INFORMATION_LOG A
+        WHERE 1 = 1
+
+        <isNotEmpty property="action">
+            AND A.ACTION = #action#
+        </isNotEmpty>
+
+        <isNotEmpty property="searchStartDate">
+            AND A.FRST_REGIST_PNTTM <![CDATA[ >= ]]>
+            CONCAT(#searchStartDate#, ' 00:00:00')
+        </isNotEmpty>
+
+        <isNotEmpty property="searchEndDate">
+            AND A.FRST_REGIST_PNTTM <![CDATA[ < ]]>
+            DATE_ADD(
+            CONCAT(#searchEndDate#, ' 00:00:00'),
+            INTERVAL 1 DAY
+            )
+        </isNotEmpty>
+
+        <isNotEmpty property="searchKeyword">
+
+            <isEqual property="searchCondition" compareValue="userId">
+                AND A.USER_ID LIKE CONCAT('%', #searchKeyword#, '%')
+            </isEqual>
+
+            <isEqual property="searchCondition" compareValue="accessIp">
+                AND A.ACCESS_IP LIKE CONCAT('%', #searchKeyword#, '%')
+            </isEqual>
+
+            <isEqual property="searchCondition" compareValue="menuNm">
+                AND A.MENU_NM LIKE CONCAT('%', #searchKeyword#, '%')
+            </isEqual>
+
+            <isEqual property="searchCondition" compareValue="target">
+                AND A.TARGET LIKE CONCAT('%', #searchKeyword#, '%')
+            </isEqual>
+
+        </isNotEmpty>
+
+    </select>
+
+
+    <select id="personalInformationLogDAO.selectPersonalInformationLogList"
+            parameterClass="personalInformationLogVO"
+            resultMap="personalInformationLogResult">
+
+        SELECT
+        A.LOG_ID,
+        A.USER_ID,
+        A.ACCESS_IP,
+        A.URI,
+        A.MENU_NM,
+        A.ACTION,
+        A.TARGET,
+        DATE_FORMAT(
+        A.FRST_REGIST_PNTTM,
+        '%Y-%m-%d %H:%i:%s'
+        ) AS FRST_REGIST_PNTTM
+        FROM PERSONAL_INFORMATION_LOG A
+        WHERE 1 = 1
+
+        <isNotEmpty property="action">
+            AND A.ACTION = #action#
+        </isNotEmpty>
+
+        <isNotEmpty property="searchStartDate">
+            AND A.FRST_REGIST_PNTTM <![CDATA[ >= ]]>
+            CONCAT(#searchStartDate#, ' 00:00:00')
+        </isNotEmpty>
+
+        <isNotEmpty property="searchEndDate">
+            AND A.FRST_REGIST_PNTTM <![CDATA[ < ]]>
+            DATE_ADD(
+            CONCAT(#searchEndDate#, ' 00:00:00'),
+            INTERVAL 1 DAY
+            )
+        </isNotEmpty>
+
+        <isNotEmpty property="searchKeyword">
+
+            <isEqual property="searchCondition" compareValue="userId">
+                AND A.USER_ID LIKE CONCAT('%', #searchKeyword#, '%')
+            </isEqual>
+
+            <isEqual property="searchCondition" compareValue="accessIp">
+                AND A.ACCESS_IP LIKE CONCAT('%', #searchKeyword#, '%')
+            </isEqual>
+
+            <isEqual property="searchCondition" compareValue="menuNm">
+                AND A.MENU_NM LIKE CONCAT('%', #searchKeyword#, '%')
+            </isEqual>
+
+            <isEqual property="searchCondition" compareValue="target">
+                AND A.TARGET LIKE CONCAT('%', #searchKeyword#, '%')
+            </isEqual>
+
+        </isNotEmpty>
+
+        <isNotEmpty property="searchSortCnd">
+            ORDER BY $searchSortCnd$
+            <isNotEmpty property="searchSortOrd">
+                $searchSortOrd$
+            </isNotEmpty>
+        </isNotEmpty>
+
+        LIMIT #firstIndex#, #recordCountPerPage#
+
+    </select>
+
+</sqlMap>(No newline at end of file)
src/main/resources/egovframework/sqlmap/let/sym/site/EgovSiteManage_SQL_Mysql.xml
--- src/main/resources/egovframework/sqlmap/let/sym/site/EgovSiteManage_SQL_Mysql.xml
+++ src/main/resources/egovframework/sqlmap/let/sym/site/EgovSiteManage_SQL_Mysql.xml
@@ -57,7 +57,7 @@
         	SELECT CODE_NM , CODE , CODE_DC
         	FROM LETTCCMMNDETAILCODE     
         	WHERE USE_AT = 'Y'       
-        	AND CODE_ID = 'ITN014' 
+        	AND CODE_ID = 'ITN014'
         ) C ON A.SESSION_TIME_CD = C.CODE
          LEFT JOIN(
           	SELECT CODE_NM ,CODE ,CODE_DC
@@ -159,7 +159,7 @@
                 	SELECT CODE_NM , CODE 
                 	FROM LETTCCMMNDETAILCODE     
                 	WHERE USE_AT = 'Y'       
-                	AND CODE_ID = 'ITN014' 
+                	AND CODE_ID = 'ITN014'
                 ) H ON A.SESSION_TIME_CD = H.CODE
                 LEFT JOIN ( 
                 	SELECT CODE_NM , CODE
 
src/main/resources/egovframework/sqlmap/let/uat/uia/SecondAuthLog_SQL_Mysql.xml (added)
+++ src/main/resources/egovframework/sqlmap/let/uat/uia/SecondAuthLog_SQL_Mysql.xml
@@ -0,0 +1,158 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd">
+
+<sqlMap namespace="secondAuthLogDAO">
+
+    <typeAlias alias="secondAuthLogVO" type="itn.let.uat.uia.service.SecondAuthLogVO"/>
+
+    <resultMap id="secondAuthLogResult" class="secondAuthLogVO">
+        <result property="logId" column="LOG_ID"/>
+        <result property="loginResult" column="LOGIN_RESULT"/>
+        <result property="authStep" column="AUTH_STEP"/>
+        <result property="tryLoginId" column="TRY_LOGIN_ID"/>
+        <result property="reason" column="REASON"/>
+        <result property="accessIp" column="ACCESS_IP"/>
+        <result property="userAgent" column="USER_AGENT"/>
+        <result property="msgId" column="MSG_ID"/>
+        <result property="resultCode" column="RESULT_CODE"/>
+        <result property="frstRegistPnttm" column="FRST_REGIST_PNTTM"/>
+        <result property="receive" column="RECEIVE"/>
+    </resultMap>
+
+    <insert id="secondAuthLogDAO.insertSecondAuthLog" parameterClass="secondAuthLogVO">
+
+        INSERT INTO SECOND_AUTH_LOG (LOG_ID,
+                                     LOGIN_RESULT,
+                                     AUTH_STEP,
+                                     TRY_LOGIN_ID,
+                                     REASON,
+                                     ACCESS_IP,
+                                     USER_AGENT,
+                                     MSG_ID,
+                                     RESULT_CODE,
+                                     FRST_REGIST_PNTTM)
+        VALUES (#logId#,
+                #loginResult#,
+                #authStep#,
+                #tryLoginId#,
+                #reason#,
+                #accessIp#,
+                #userAgent#,
+                #msgId#,
+                #resultCode#,
+                CURRENT_TIMESTAMP)
+
+    </insert>
+
+    <delete id="secondAuthLogDAO.deleteSecondAuthLog" parameterClass="secondAuthLogVO">
+        DELETE
+        FROM SECOND_AUTH_LOG
+        WHERE LOG_ID = #logId#
+    </delete>
+
+    <select id="secondAuthLogDAO.selectSecondAuthLog" parameterClass="secondAuthLogVO" resultMap="secondAuthLogResult">
+        SELECT LOG_ID,
+               LOGIN_RESULT,
+               AUTH_STEP,
+               TRY_LOGIN_ID,
+               REASON,
+               ACCESS_IP,
+               USER_AGENT,
+               MSG_ID,
+               RESULT_CODE,
+               FRST_REGIST_PNTTM
+        FROM SECOND_AUTH_LOG
+        WHERE LOG_ID = #logId#
+
+    </select>
+
+    <select id="secondAuthLogDAO.selectSecondAuthLogCnt" parameterClass="secondAuthLogVO"
+            resultClass="java.lang.Integer">
+
+        SELECT COUNT(*)
+        FROM SECOND_AUTH_LOG
+        WHERE 1 = 1
+
+        <isNotEmpty property="logId">
+            AND LOG_ID = #logId#
+        </isNotEmpty>
+
+        <isNotEmpty property="loginResult">
+            AND LOGIN_RESULT = #loginResult#
+        </isNotEmpty>
+
+        <isNotEmpty property="authStep">
+            AND AUTH_STEP = #authStep#
+        </isNotEmpty>
+
+        <isNotEmpty property="tryLoginId">
+            AND TRY_LOGIN_ID = #tryLoginId#
+        </isNotEmpty>
+
+        <isNotEmpty property="reason">
+            AND REASON = #reason#
+        </isNotEmpty>
+
+        <isNotEmpty property="accessIp">
+            AND ACCESS_IP = #accessIp#
+        </isNotEmpty>
+
+        <isNotEmpty property="msgId">
+            AND MSG_ID = #msgId#
+        </isNotEmpty>
+
+        <isNotEmpty property="resultCode">
+            AND RESULT_CODE = #resultCode#
+        </isNotEmpty>
+
+    </select>
+
+    <select id="secondAuthLogDAO.selectSecondAuthLogList" parameterClass="secondAuthLogVO" resultMap="secondAuthLogResult">
+        SELECT
+            A.LOG_ID,
+            A.LOGIN_RESULT,
+            A.AUTH_STEP,
+            A.TRY_LOGIN_ID,
+            A.REASON,
+            A.ACCESS_IP,
+            A.USER_AGENT,
+            A.MSG_ID,
+            A.RESULT_CODE,
+            S.RECEIVE AS RECEIVE,
+            DATE_FORMAT(A.FRST_REGIST_PNTTM, '%Y-%m-%d %H:%i:%s') AS FRST_REGIST_PNTTM
+        FROM SECOND_AUTH_LOG A
+        LEFT JOIN MJ_SYSTEM_SEND S
+        ON S.SEND_ID = A.MSG_ID
+        WHERE 1 = 1
+        <isNotEmpty property="loginResult">
+            AND A.LOGIN_RESULT = #loginResult#
+        </isNotEmpty>
+        <isNotEmpty property="searchStartDate">
+            AND A.FRST_REGIST_PNTTM <![CDATA[ >= ]]> CONCAT(#searchStartDate#, ' 00:00:00')
+        </isNotEmpty>
+        <isNotEmpty property="searchEndDate">
+            AND A.FRST_REGIST_PNTTM <![CDATA[ < ]]> DATE_ADD(CONCAT(#searchEndDate#, ' 00:00:00'), INTERVAL 1 DAY)
+        </isNotEmpty>
+        <isNotEmpty property="searchKeyword">
+            <isEqual property="searchCondition" compareValue="tryLoginId">
+                AND TRY_LOGIN_ID LIKE CONCAT('%', #searchKeyword#, '%')
+            </isEqual>
+            <isEqual property="searchCondition" compareValue="accessIp">
+                AND ACCESS_IP LIKE CONCAT('%', #searchKeyword#, '%')
+            </isEqual>
+            <isEqual property="searchCondition" compareValue="receive">
+                AND REPLACE(S.RECEIVE, '-', '')
+                LIKE CONCAT('%', REPLACE(#searchKeyword#, '-', ''), '%')
+            </isEqual>
+        </isNotEmpty>
+        <isNotEmpty property="searchSortCnd">
+            ORDER BY $searchSortCnd$
+            <isNotEmpty property="searchSortOrd">
+                $searchSortOrd$
+            </isNotEmpty>
+        </isNotEmpty>
+
+        LIMIT #firstIndex#, #recordCountPerPage#
+    </select>
+
+</sqlMap>(No newline at end of file)
src/main/resources/egovframework/sqlmap/let/uss/itsm/SchdlrManage_SQL_Mysql.xml
--- src/main/resources/egovframework/sqlmap/let/uss/itsm/SchdlrManage_SQL_Mysql.xml
+++ src/main/resources/egovframework/sqlmap/let/uss/itsm/SchdlrManage_SQL_Mysql.xml
@@ -446,8 +446,39 @@
 		GROUP BY a.schdlrId
 		ORDER BY a.schdlrBgnDatetime DESC
 		LIMIT 10
-	</select>    
-    
+	</select>
+
+	<select id="schdlrManageDAO.selectSendNumberFailList" resultClass="schdlrVO">
+		SELECT DISTINCT
+			A.MSG_GROUP_ID AS msgGroupId,
+			A.USER_ID AS userId,
+			A.CALL_FROM AS callFrom,
+			DATE_FORMAT(A.REQ_DATE, '%Y-%m-%d %H:%i') as regDate
+		FROM MJ_MSG_GROUP_DATA A
+		INNER JOIN LETTNGNRLMBER LMB
+			ON LMB.MBER_ID = A.USER_ID
+		INNER JOIN MJ_MSG_DATA B
+			ON B.MSG_GROUP_ID = A.MSG_GROUP_ID
+			AND B.RESERVE_C_YN = 'N'
+		WHERE
+			A.MSG_TYPE IN (4, 6)
+			AND A.RESERVE_C_YN = 'N'
+			AND A.CALLBACK_YN = 'N'
+			AND LMB.CALLBACK_YN = 'N'
+			AND A.REQ_DATE <![CDATA[>=]]> DATE_SUB(NOW(), INTERVAL 5 MINUTE)
+			AND A.REQ_DATE <![CDATA[<=]]> NOW()
+			AND (
+				(B.AGENT_CODE = '04'
+				AND B.RSLT_CODE IN ('4432', '4433', '6628', '6629'))
+				OR (B.AGENT_CODE = '05'
+				AND B.RSLT_CODE IN ('2404', '3404', '6404'))
+				OR (B.AGENT_CODE = '07'
+				AND B.RSLT_CODE = '9013')
+			)
+		ORDER BY
+			A.REQ_DATE DESC
+	</select>
+
     
     
     
src/main/resources/egovframework/sqlmap/let/uss/umt/EgovUserManage_SQL_Mysql.xml
--- src/main/resources/egovframework/sqlmap/let/uss/umt/EgovUserManage_SQL_Mysql.xml
+++ src/main/resources/egovframework/sqlmap/let/uss/umt/EgovUserManage_SQL_Mysql.xml
@@ -200,6 +200,8 @@
                     
                     EMPLYR_STTUS_CODE   ,
                     SBSCRB_DE           ,
+                    REGISTER_ID         ,
+                    REGIST_RESN         ,
                     <isNotEmpty  property="partIdx">
                 		PART_IDX          ,
                 	</isNotEmpty>
@@ -248,6 +250,8 @@
                     #insttCode#         ,
                     #emplyrSttusCode#   ,
                     sysdate()           ,
+                    #registerId#        ,
+                    #registResn#        ,
                     <isNotEmpty  property="partIdx">
                 		#partIdx#       ,
                 	</isNotEmpty>
@@ -298,17 +302,20 @@
             GROUP_ID          groupId           ,
             ORGNZT_ID         orgnztId          ,
             PSTINST_CODE        insttCode         ,
-            EMPLYR_STTUS_CODE emplyrSttusCode   , 
+            EMPLYR_STTUS_CODE emplyrSttusCode   ,
             SBSCRB_DE         sbscrbDe          ,
             CRTFC_DN_VALUE            subDn  ,
             PART_IDX            partIdx   ,
             AUTHOR_CODE  		authorCode ,
+            A.REGISTER_ID       registerId  ,
+            A.REGIST_RESN       registResn  ,
+            (SELECT D.USER_NM FROM LETTNEMPLYRINFO D WHERE D.EMPLYR_ID = A.REGISTER_ID) registerNm ,
        		C.CODE_NM as emplyrSttusCodeTxt,
        		USER_WORK AS userWork,
        		OUTER_CERT_YN AS outerCertYn
         FROM LETTNEMPLYRINFO A LEFT  JOIN
         LETTNEMPLYRSCRTYESTBS B ON A.ESNTL_ID = B.SCRTY_DTRMN_TRGET_ID
-        LEFT JOIN 
+        LEFT JOIN
        	( SELECT CODE_NM , CODE FROM LETTCCMMNDETAILCODE WHERE USE_AT = 'Y'    
 		 	AND CODE_ID =  'COM013' 
 	    ) C ON A.EMPLYR_STTUS_CODE = C.CODE
@@ -400,7 +407,10 @@
 				<isNotNull property="outerCertYn">
 					OUTER_CERT_YN	= #outerCertYn# ,
 				</isNotNull>
-                USER_NM           = #emplyrNm#                       
+				<isNotNull property="registResn">
+					REGIST_RESN		= #registResn# ,
+				</isNotNull>
+                USER_NM           = #emplyrNm#
             WHERE ESNTL_ID = #uniqId#
        
     </update>
src/main/webapp/WEB-INF/config/egovframework/springmvc/egov-com-servlet.xml
--- src/main/webapp/WEB-INF/config/egovframework/springmvc/egov-com-servlet.xml
+++ src/main/webapp/WEB-INF/config/egovframework/springmvc/egov-com-servlet.xml
@@ -60,5 +60,11 @@
 	              execution(public * itn..*Controller.selectMainMenuLeft(..)) || 
 	              execution(public * itn..*Controller.*Web(..)) )"  method="logAdminSelect" />
 		</aop:aspect>
+        <!-- 개인정보 로그-->
+        <aop:aspect id="personalInformationLogAspect" ref="syslog">
+            <aop:after
+                    pointcut="@annotation(itn.com.annotation.PersonalLog)"
+                    method="personalInformationLog"/>
+        </aop:aspect>
 	</aop:config>
 </beans>
(No newline at end of file)
src/main/webapp/WEB-INF/config/egovframework/springmvc/egov-interceptor-servlet.xml
--- src/main/webapp/WEB-INF/config/egovframework/springmvc/egov-interceptor-servlet.xml
+++ src/main/webapp/WEB-INF/config/egovframework/springmvc/egov-interceptor-servlet.xml
@@ -8,6 +8,12 @@
         http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
     
 	<interceptors>
+	    <!-- 대시보드 요약 API 토큰 인증 -->
+	    <interceptor>
+	        <mapping path="/api/dashboard/**"/>
+	        <beans:bean class="itn.com.cmm.interceptor.DashboardApiAuthInterceptor"/>
+	    </interceptor>
+
 	    <interceptor>
 	        <mapping path="/web/**"/>
 	        <exclude-mapping path="/web/main/mainPage.do"/>
src/main/webapp/WEB-INF/decorators.xml
--- src/main/webapp/WEB-INF/decorators.xml
+++ src/main/webapp/WEB-INF/decorators.xml
@@ -150,6 +150,7 @@
       <pattern>/naver94c82af5badbae52b1e46e77b88410c9.html</pattern><!-- 게시판템플릿 팝업 -->
       <pattern>/let/mjo/msgagent/insertMjonMsgAgentStsDataAjax.do</pattern><!-- 게시판템플릿 팝업 -->
       <pattern>/uss/ion/msg/sendNumberReturnPop.do</pattern> <!-- 발신번호 신청 반려팝업 -->
+	  <pattern>/uss/ion/msg/EmployeeCertRejectPop.do</pattern> <!-- 발신번호 신청 반려팝업 -->
       <pattern>/uss/ion/pay/PgStatusPop.do</pattern> <!-- 후불제 고객 결제완료 변경 팝업 -->
       <pattern>/uss/ion/kakaoat/KakaoATChannelIDListPop.do</pattern><!-- 채널아이디 채널 팝업 -->
       <pattern>/sym/site/termsMastEffectPopup.do</pattern><!-- 약관관리 시행  팝업 -->
@@ -161,6 +162,7 @@
       <pattern>/uss/ion/msg/weekendCsWork2.do</pattern>
       <pattern>/uss/ion/msg/pdfView.do</pattern>
       <pattern>/uss/ion/msg/pdfViewPhone.do</pattern>
+      <pattern>/uss/ion/msg/EmpPdfView.do</pattern>
     </decorator>
     
 	<!-- 관리자 게시글 작성, 템플릿 미리보기(헤더풋터 없음) -->
@@ -199,4 +201,4 @@
 	<decorator name="weblayout" page="/WEB-INF/jsp/layout/siteCheck.jsp">
 		<pattern>*</pattern>
 	</decorator>
-</decorators>
(No newline at end of file)
+</decorators>
src/main/webapp/WEB-INF/jsp/cmm/uss/umt/EgovGnrlUserSelectUpdt.jsp
--- src/main/webapp/WEB-INF/jsp/cmm/uss/umt/EgovGnrlUserSelectUpdt.jsp
+++ src/main/webapp/WEB-INF/jsp/cmm/uss/umt/EgovGnrlUserSelectUpdt.jsp
@@ -2,13 +2,13 @@
   Class Name : EgovGnrlUserSelectUpdt.jsp
   Description : 사용자상세 팝업 JSP
   Modification Information
- 
+
       수정일         수정자                   수정내용
     -------    --------    ---------------------------
      2009.03.03   JJY              최초 생성
      2011.08.31   JJY       경량환경 버전 생성
      2011.08.31   우영두            팝업 화면 개발
- 
+
     author   : 공통서비스 개발팀 JJY
     since    : 2009.03.03
 --%>
@@ -449,7 +449,7 @@
 }
 
 function passMissReset(){
-	if(!confirm("로그인실패 카운트를 초기화 시키겠습니까?")){
+	if(!confirm("1차 로그인 잠금을 해제하시겠습니까?")){
 		 return false;
 	}
 	$.ajax({
@@ -464,6 +464,7 @@
 			if(status == "success") {
 				alert("로그인 실패 카운터가 초기화 되었습니다.");
 			}else{ alert("ERROR!");return;}
+			fnMemoRefresh();
 		},
 		error:function(request , status, error){
 			alert("code:"+request.status+"\n"+"message:"+request.responseText+"\n"+"error:"+error);
@@ -2041,12 +2042,25 @@
 		alert("등록할 인증번호를 입력해주세요.");
 		return false;
 	}
+	if (!/^010\d{8}$/.test(mbtlnum)) {
+		alert('010으로 시작하는 숫자 11자리만 입력 가능합니다.');
+		$('#pop_mbtlnum').focus();
+		return false;
+	}
+
+	if("${mberManageVO.dept}" == "p" && Number('${fn:length(mberCertPhoneList)}') >= 3){
+		alert("	인증 휴대폰번호는 최대 3개까지 등록할 수 있습니다.");
+		return false;
+	}else if("${mberManageVO.dept}" == "c" && Number('${fn:length(mberCertPhoneList)}') >= 4){
+		alert("	인증 휴대폰번호는 최대 4개까지 등록할 수 있습니다.");
+		return false;
+	}
 
 	var params = {
 		"mberId" : mberId
 		, "mbtlnum" : mbtlnum
 		, "certAlias" : $('#pop_certAlias').val()
-		, "certMemo" : $('#pop_certMemo').val()
+		//, "certMemo" : $('#pop_certMemo').val()
 	}
 	console.log('params : ', params);
 
@@ -2085,7 +2099,7 @@
 		"mberId" : mberId
 		, "mbtlnum" : mbtlnum
 		, "certAlias" : $('#pop_udt_certAlias').val()
-		, "certMemo" : $('#pop_udt_certMemo').val()
+		//, "certMemo" : $('#pop_udt_certMemo').val()
 	}
 	console.log('params : ', params);
 
@@ -2134,7 +2148,7 @@
 				console.log('returnData.object.mbtlnum : ', returnData.object.mbtlnum);
 				$('#pop_udt_mbtlnum').val(returnData.object.mbtlnum);
 				$('#pop_udt_certAlias').val(returnData.object.certAlias);
-				$('#pop_udt_certMemo').val(returnData.object.certMemo);
+				//$('#pop_udt_certMemo').val(returnData.object.certMemo);
 
 				layerPopOpen('certPhoneUdt');
 			}else{
@@ -2162,7 +2176,8 @@
   }
 	console.log('params : ', params);
 
-	if(!confirm(mbtlnum+" 번호를 정말 삭제하시겠습니까?")){
+	//if(!confirm(mbtlnum+" 번호를 정말 삭제하시겠습니까?")){
+	if(!confirm("해당 인증 휴대폰번호를 삭제하시겠습니까?")){
 		return false;
 	}
 
@@ -3261,7 +3276,7 @@
 													</c:otherwise>
 												</c:choose>
 												<div class="button_box">
-													<button type="button" class="fill" style="width: 200px;" onclick="passMissReset(); return false;">비밀번호 5회실패 초기화</button>
+													<button type="button" class="fill" style="width: 200px;" onclick="passMissReset(); return false;">1차 로그인 잠금 해제</button>
 												</div>
 											</td>
 										</tr>
@@ -3647,7 +3662,7 @@
 													</c:otherwise>
 												</c:choose>
 												<div class="button_box">
-													<button type="button" class="fill" style="width: 200px;" onclick="passMissReset(); return false;">비밀번호 5회실패 초기화</button>
+													<button type="button" class="fill" style="width: 200px;" onclick="passMissReset(); return false;">1차 로그인 잠금 해제</button>
 												</div>
 											</td>
 										</tr>
@@ -5181,28 +5196,56 @@
 						</tbody>
 					</table>
 					<!-- //발신번호 리스트 -->
-					<!-- 인증 번호 리스트 -->
+					<!-- 보안로그인 인증 휴대폰번호 -->
 					<div class="title_box">
-						<p>인증 번호 리스트</p>
-						<span style="float: right;">
+						<p>보안로그인 인증 휴대폰번호</p>
+						<%--<span style="float: right;">
 							<span style="letter-spacing: 0em !important; margin-left: 5px;">
 								<button type="button" onclick="layerPopOpen('certPhoneReg');" class="fill">등록</button>
 							</span>
+						</span>--%>
+					</div>
+					<div class="title_box"
+						 style="height:42px; min-height:42px; margin:0; padding:0 10px;
+							background:#fff; border-bottom:1px solid #ddd; box-sizing:border-box;">
+							<p style="margin:0; padding-top:3px; line-height:30px; font-size:15px; font-weight:400;">
+								등록 개수 : 총
+								<strong style="color:#2f73d9;">
+									<c:out value="${fn:length(mberCertPhoneList)}"/>
+								</strong>건 /
+								최대 <strong style="color:#2f73d9;">${fn:toLowerCase(mberManageVO.dept) eq 'c' ? 4 : 3}</strong>건
+							</p>
+						<span style="float:right; padding-bottom:12px;">
+							<c:set var="maxCertPhoneCount"
+								   value="${fn:toLowerCase(mberManageVO.dept) eq 'c' ? 4 : 3}" />
+							<c:set var="certPhoneLimitReached"
+								   value="${fn:length(mberCertPhoneList) ge maxCertPhoneCount}" />
+
+							<button type="button"
+									onclick="layerPopOpen('certPhoneReg');"
+									class="fill"
+									<c:if test="${certPhoneLimitReached}">disabled="disabled"</c:if>
+									style="${certPhoneLimitReached ? 'opacity:0.45; cursor:not-allowed;' : ''}">
+								번호 등록
+							</button>
+							<%--<button type="button" onclick="layerPopOpen('certPhoneReg');" class="fill"
+							${fn:length(mberCertPhoneList) ge (fn:toLowerCase(mberManageVO.dept) eq 'c' ? 4 : 3) ? 'disabled="disabled"' : ''}>번호 등록</button>--%>
 						</span>
 					</div>
+
 					<table class="user_table_col">
 						<colgroup>
+							<col style="width:calc(25%);">
+							<col style="width:calc(30%);">
 							<col style="width:calc(20%);">
 							<col style="width:calc(20%);">
-							<col style="width:calc(45%);">
-							<col style="width:calc(15%);">
 						</colgroup>
 						<thead>
 							<tr>
-								<th>인증번호</th>
+								<th>인증 휴대폰번호</th>
 								<th>별칭</th>
-								<th>메모</th>
-								<th>삭제</th>
+								<th>등록일</th>
+								<th>관리</th>
 							</tr>
 						</thead>
 						<tbody>
@@ -5228,12 +5271,14 @@
 												<c:out value="${list.certAlias}"/>
 											</td>
 											<td>
-												<c:out value="${list.certMemo}"/>
+												<fmt:parseDate value="${list.mberRegDate}" var="mberRegDate" pattern="yyyy-MM-dd"/>
+												<fmt:formatDate value="${mberRegDate}" pattern="yyyy-MM-dd"/>
+											<%--<c:out value="${list.certMemo}"/>--%>
 											</td>
 											<td>
 											<c:choose>
 												<c:when test="${list.frstRegistPnttm eq '-'}">
-													대표번호
+													기본번호
 												</c:when>
 												<c:otherwise>
 													<div class="button_box">
@@ -6436,7 +6481,12 @@
 
 		<!-- 인증번호 수정 -->
 		<div class="layer_popup layer_certPhoneUdt">
-			<div class="title_box">인증번호 등록<button type="button" class="close_btn" onclick="layerPopClose(this);"></button></div>
+			<div class="title_box">인증 휴대폰번호 등록<button type="button" class="close_btn" onclick="layerPopClose(this);"></button></div>
+			<div style="padding:10px 12px; border:1px solid #ffcaca;
+	            border-radius:6px; background:#fff0f0; color:#e35b5b;
+	            font-size:13px; line-height:18px; box-sizing:border-box;">
+				※ 사용자가 직접 등록할 수 없는 예외 상황에 한하여 유선으로 본인확인 후 관리자 등록 진행
+			</div>
 			<div class="layer_content">
 				<table>
 					<colgroup>
@@ -6453,25 +6503,30 @@
 						<tr>
 							<th>별칭</th>
 							<td>
-								<input type="text" id="pop_udt_certAlias" title="별칭" maxlength="50"/>
+								<input type="text" id="pop_udt_certAlias" title="별칭" maxlength="50" />
 							</td>
 						</tr>
-						<tr>
+						<%--<tr>
 							<th>메모</th>
 							<td>
 								<input type="text" id="pop_udt_certMemo" title="메모" maxlength="100"/>
 							</td>
-						</tr>
+						</tr>--%>
 					</tbody>
 				</table>
 				<div class="button_box">
-					<button type="button" onclick="fn_certPhoneUdt(); return false;">인증번호 수정</button>
+					<button type="button" onclick="fn_certPhoneUdt(); return false;">수정</button>
 				</div>
 			</div>
 		</div>
 		<!-- 인증번호 등록 -->
 		<div class="layer_popup layer_certPhoneReg">
-			<div class="title_box">인증번호 등록<button type="button" class="close_btn" onclick="layerPopClose(this);"></button></div>
+			<div class="title_box">인증 휴대폰번호 등록<button type="button" class="close_btn" onclick="layerPopClose(this);"></button></div>
+			<div style="padding:10px 12px; border:1px solid #ffcaca;
+	            border-radius:6px; background:#fff0f0; color:#e35b5b;
+	            font-size:13px; line-height:18px; box-sizing:border-box;">
+				※ 사용자가 직접 등록할 수 없는 예외 상황에 한하여 유선으로 본인확인 후 관리자 등록 진행
+			</div>
 			<div class="layer_content">
 				<table>
 					<colgroup>
@@ -6482,25 +6537,25 @@
 						<tr>
 							<th>인증번호</th>
 							<td>
-								<input type="text" id="pop_mbtlnum" title="인증번호" maxlength="20"  oninput="this.value=this.value.replace(/[^0-9]/g,'')"/>
+								<input type="text" id="pop_mbtlnum" title="인증번호" maxlength="20"  oninput="this.value=this.value.replace(/[^0-9]/g, '').slice(0, 11);"/>
 							</td>
 						</tr>
 						<tr>
 							<th>별칭</th>
 							<td>
-								<input type="text" id="pop_certAlias" title="별칭" maxlength="50"/>
+								<input type="text" id="pop_certAlias" title="별칭" maxlength="50" value="관리자 등록"/>
 							</td>
 						</tr>
-						<tr>
+						<%--<tr>
 							<th>메모</th>
 							<td>
 								<input type="text" id="pop_certMemo" title="메모" maxlength="100"/>
 							</td>
-						</tr>
+						</tr>--%>
 					</tbody>
 				</table>
 				<div class="button_box">
-					<button type="button" onclick="fn_certPhoneReg(); return false;">인증번호 등록</button>
+					<button type="button" onclick="fn_certPhoneReg(); return false;">등록</button>
 				</div>
 			</div>
 		</div>
src/main/webapp/WEB-INF/jsp/cmm/uss/umt/EgovUserInsert.jsp
--- src/main/webapp/WEB-INF/jsp/cmm/uss/umt/EgovUserInsert.jsp
+++ src/main/webapp/WEB-INF/jsp/cmm/uss/umt/EgovUserInsert.jsp
@@ -23,6 +23,13 @@
 <html>
 <head>
 <meta http-equiv="Content-Language" content="ko" >
+<style type="text/css">
+	/* 등록사유 placeholder 흐리게 표시 (전송자격인증제 3.2) */
+	#registResn::-webkit-input-placeholder { color: #bbbbbb; }
+	#registResn::-moz-placeholder { color: #bbbbbb; opacity: 1; }
+	#registResn:-ms-input-placeholder { color: #bbbbbb; }
+	#registResn::placeholder { color: #bbbbbb; }
+</style>
 <script type="text/javascript" src="<c:url value="/validator.do"/>"></script>
 <validator:javascript formName="userManageVO" staticJavascript="false" xhtml="true" cdata="false"/>
 <script src="/direct/js/jquery.nice-select.min.js"></script>
@@ -102,6 +109,13 @@
         }
         if(!validatePassword(document.userManageVO.password.value)){
         	alert("비밀번호 최소 하나의 문자 + 하나의 숫자 + 하나의 특수 문자 포함, 최소 8자리, 최대 20자리입니다.");
+        	return;
+        }
+        // 등록사유 필수 체크 (전송자격인증제 3.2)
+        var registResn = document.getElementById("registResn").value;
+        if(registResn == null || registResn.replace(/(^\s*)|(\s*$)/g, "") == ""){
+        	alert("등록사유를 입력해주세요.");
+        	document.getElementById("registResn").focus();
         	return;
         }
         document.userManageVO.submit();
@@ -385,7 +399,14 @@
 		          			<form:errors path="userWork" cssClass="error" />
 						</td>
 					</tr>
-				</tbody> 
+					<tr>
+						<th><span class="reqArea">등록사유</span></th>
+						<td colspan="3">
+							<form:input path="registResn" id="registResn" cssClass="txaIpt" size="80" maxlength="500" placeholder="관리자 계정 등록/권한 부여 사유를 입력하세요. (전송자격인증제 3.2)" />
+		          			<form:errors path="registResn" cssClass="error" />
+						</td>
+					</tr>
+				</tbody>
 			</table>
 			<div class="btnWrap right">
 				<input type="button" class="btnType1" value="저 장" onclick="fnInsert(); return false;">
src/main/webapp/WEB-INF/jsp/cmm/uss/umt/EgovUserSelectUpdt.jsp
--- src/main/webapp/WEB-INF/jsp/cmm/uss/umt/EgovUserSelectUpdt.jsp
+++ src/main/webapp/WEB-INF/jsp/cmm/uss/umt/EgovUserSelectUpdt.jsp
@@ -24,6 +24,13 @@
 <head>
 <meta http-equiv="Content-Language" content="ko" >
 <title>관리자 수정</title>
+<style type="text/css">
+	/* 등록사유 placeholder 흐리게 표시 (전송자격인증제 3.2) */
+	#registResn::-webkit-input-placeholder { color: #bbbbbb; }
+	#registResn::-moz-placeholder { color: #bbbbbb; opacity: 1; }
+	#registResn:-ms-input-placeholder { color: #bbbbbb; }
+	#registResn::placeholder { color: #bbbbbb; }
+</style>
 <script type="text/javascript" src="<c:url value="/validator.do"/>"></script>
 <validator:javascript formName="userManageVO" staticJavascript="false" xhtml="true" cdata="false"/>
 <script type="text/javascript" src="<c:url value='/js/EgovCmmUtl.js'/>" ></script>
@@ -408,6 +415,23 @@
 		          			<form:errors path="userWork" cssClass="error" />
 						</td>
 					</tr>
+					<c:if test="${!empty isAdmin}">
+					<tr>
+						<th>등록자</th>
+						<td colspan="3">
+							<c:out value="${userManageVO.registerNm}"/>
+							<c:if test="${!empty userManageVO.registerId}">(<c:out value="${userManageVO.registerId}"/>)</c:if>
+							<c:if test="${empty userManageVO.registerId}">-</c:if>
+						</td>
+					</tr>
+					<tr>
+						<th>등록사유</th>
+						<td colspan="3">
+							<form:input path="registResn" id="registResn" cssClass="txaIpt" size="80" maxlength="500" placeholder="관리자 계정 등록/권한 부여 사유 (전송자격인증제 3.2)" />
+							<form:errors path="registResn" cssClass="error" />
+						</td>
+					</tr>
+					</c:if>
 					<c:if test="${empty isAdmin and empty isMember}">
 					<tr>
 						<th>비밀번호확인</th>
 
src/main/webapp/WEB-INF/jsp/cmm/uss/umt/kakao/EgovGnrlUserSelectKakaoDataDetailListPop.jsp (added)
+++ src/main/webapp/WEB-INF/jsp/cmm/uss/umt/kakao/EgovGnrlUserSelectKakaoDataDetailListPop.jsp
@@ -0,0 +1,299 @@
+<%@ page contentType="text/html; charset=utf-8"%>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="ui" uri="http://egovframework.gov/ctl/ui"%>
+<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>
+<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
+<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
+<%@ taglib prefix="ec" uri="/WEB-INF/tld/ecnet_tld.tld"%>
+<% pageContext.setAttribute("newLineChar", "\r\n"); %>
+<% pageContext.setAttribute("newLineChar2", "\n"); %>
+<%
+	response.setHeader("Cache-Control","no-store");
+	response.setHeader("Pragma","no-cache");
+	response.setDateHeader("Expires",0);
+	if (request.getProtocol().equals("HTTP/1.1")) response.setHeader("Cache-Control", "no-cache");
+%>
+<!DOCTYPE html>
+<html lang="ko">
+<head>
+<title>사용자 문자전송 관리</title>
+<meta http-equiv="content-type" content="text/html; charset=utf-8">
+<link rel="stylesheet" href="/pb/css/reset.css">
+<link rel="stylesheet" href="/pb/css/common.css">
+<link rel="stylesheet" href="/pb/css/content.css">
+<link rel="stylesheet" href="/pb/css/popup.css">
+
+<style>
+.pageCont .tbType1 tbody tr td.sms_detail {overflow:inherit;text-overflow:inherit;position:relative;}
+.pageCont .tbType1 tbody tr td.sms_detail p {overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
+.pageCont .tbType1 tbody tr td.sms_detail .sms_detail_hover {overflow:hidden;text-overflow:ellipsis;display:none;word-wrap:break-word;-webkit-line-clamp:20;-webkit-box-orient:vertical;position:absolute;left:-5px;top:45px;width:calc(100% + 150px);padding:15px;line-height:20px;white-space:normal;border:1px solid #e5e5e5;background:#fff;border-radius:5px;box-sizing:border-box;box-shadow:0px 3px 10px 0px rgb(0 0 0 / 0.2);z-index:1;font-size:14px;text-align:left;}
+.pageCont .tbType1 tbody tr td.sms_detail .sms_detail_hover:after {content:'';position:absolute;left:0;bottom:0;width:100%;height:10px;background:#fff;border-radius:0 0 5px 5px;}
+.pageCont .tbType1 tbody tr td.sms_detail:hover .sms_detail_hover {display:-webkit-box;}
+</style>
+
+<script type="text/javascript" src="/pb/js/jquery-3.5.0.js"></script>
+<script type="text/javascript" src="/pb/js/common.js"></script>
+<script type="text/javascript" src="<c:url value='/js/EgovMultiFile.js'/>"></script>
+<script type="text/javascript" src="<c:url value='/js/EgovCalPopup.js'/>"></script>
+<script type="text/javascript" src="<c:url value='/js/ncms_common.js' />"></script>
+<script type="text/javaScript" language="javascript">
+
+	function fn_search(){
+		var searchKeyword = $('input[name=searchKeyword]').val();
+		$('input[name=searchKeyword]').val(searchKeyword.replace(/(\s*)/g, ""));
+		linkPage(1);
+	}
+
+	function linkPage(pageNo){
+		var listForm = document.listForm ;
+		listForm.pageIndex.value = pageNo ;
+		listForm.submit();
+	}
+
+	function fn_detailView(userData){
+		var frm = document.modiForm ;
+		frm.userData.value = userData ;
+		frm.action = "<c:url value='/uss/umt/user/kakaoat/EgovGnrlselectedUserKakaoDataDetailAjax.do'/>";
+		frm.submit();
+	}
+
+	function goList() {
+		var form = document.modiForm;
+		form.action ='/uss/umt/user/kakaoat/EgovGnrlselectedUserKakaoDataListAjax.do';
+		form.submit();
+	}
+
+	function fnSelectMber(mberId) {
+		document.modiForm.mberId.value = mberId;
+		window.open("about:blank", 'popupSelectMber', 'width=900, height=1800, top=100, left=100, fullscreen=no, menubar=no, status=no, toolbar=no, titlebar=yes, location=no, scrollbar=no');
+		document.modiForm.action = "<c:url value='/uss/umt/user/EgovGnrlselectedUserView.do'/>";
+		document.modiForm.target = "popupSelectMber";
+		document.modiForm.submit();
+	}
+
+</script>
+<style>
+.calBtn{
+    border: none;
+    background-color: transparent !important;
+    background-image: url(/pb/img/common/calendarIcon.png);
+    background-repeat: no-repeat;
+    width: 25px;
+    height: 25px !important;
+    vertical-align: middle;
+    margin-left: -38px !important;
+    margin-top: -2px !important;
+    cursor: pointer;
+}
+.pageCont {width:100%;padding:50px 30px;box-sizing:border-box;}
+.tableWrapTotal {margin:0 0 20px;}
+.tableWrapTotal .tbType1 thead tr:first-child {border-width:1px;}
+.tableWrapTotal .tbType1 thead tr th {border-left:1px solid #e6e6e6;}
+.tableWrapTotal .tbType1 thead tr th:first-child {border-left:0 none;}
+.tableWrapTotal .tbType1 thead tr.content th {font-size:14px;}
+.tableWrapTotal .tbType1 tbody tr td {border-left:1px solid #e6e6e6;}
+.tableWrapTotal .tbType1 tbody tr td:first-child {border-left:0 none;}
+.listSerch .select {height:42px;vertical-align:top;}
+.pageCont .tbType1 tbody tr td.msg_detail {overflow:inherit;}
+.pageCont .tbType1 tbody tr td.msg_detail a {overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:block;}
+/* .layer_msg_wrap {position:relative;} */
+.layer_msg_wrap .layer_msg_detail {overflow:hidden;display:none;position:absolute;left:50%;top:600px;width:400px;max-height:600px;background:#eee;transform:translateX(-50%);z-index:1;}
+.layer_msg_wrap .layer_msg_detail button {position:absolute;right:0;top:0;width:35px;height:35px;}
+.layer_msg_wrap .layer_msg_detail button:before {content:'';position:absolute;left:50%;top:50%;width:1px;height:14px;margin:-7px 0 0;background:#fff;transform:rotate(-45deg);}
+.layer_msg_wrap .layer_msg_detail button:after {content:'';position:absolute;left:50%;top:50%;width:1px;height:14px;margin:-7px 0 0;background:#fff;transform:rotate(45deg);}
+.layer_msg_wrap .layer_msg_detail .title {height:35px;padding:0 15px;font-size:16px;line-height:35px;text-align:left;color:#fff;background:#456ded;border-radius:5px 5px 0 0;}
+.layer_msg_wrap .layer_msg_detail .content {overflow-y:auto;max-height:535px;margin:15px;padding:10px 15px;line-height:20px;white-space:normal;background:#fff;}
+.layer_msg_wrap .layer_msg_detail .content .rev_cont {text-align:left;}
+@media screen and (max-width:916px){
+	.pageCont .tableWrap table thead tr th {padding:15px 0;}
+}
+
+</style>
+</head>
+<body>
+<div class="loading_layer">
+	<div class="loading_container">
+		<div class="bar"></div>
+		<div class="text">Loading</div>
+	</div>
+</div>
+<form name="listForm" action="<c:url value='/uss/umt/user/kakaoat/EgovGnrlselectedUserKakaoDataDetailListAjax.do'/>" method="post">
+	<input name="pageIndex" type="hidden" value="<c:out value='${searchVO.pageIndex}'/>"/>
+	<input type="hidden" name="userId" value="<c:out value='${searchVO.userId}'/>"/>
+	<input type="hidden" name="delFlag" value="Y" />
+	<input type="hidden" name="selectedId" />
+	<input type="hidden" name="msgGroupId" value="<c:out value='${searchVO.msgGroupId}'/>"/>
+	<input type="hidden" name="pageType" />
+	<input type="hidden" name="searchSortCnd" value="<c:out value="${searchVO.searchSortCnd}" />" />
+	<input type="hidden" name="searchSortOrd" value="<c:out value="${searchVO.searchSortOrd}" />" />
+	<input type="hidden" name="detailType" value="<c:out value="${searchVO.detailType}" />" />
+	<input type="hidden" name="ntceBgnde" id="ntceBgnde"  value="">
+	<input type="hidden" name="ntceEndde" id="ntceEndde"  value="">
+
+	<div class="contWrap" style="position:relative;left:inherit;top:inherit;min-height:auto;padding:40px;">
+		<div class="pageTitle">
+			<h2 class="titType1 c_222222 fwBold">'<c:out value="${searchVO.userId}"/>'의 카카오톡 전송 리스트</h2>
+		</div>
+		<div class="pageCont">
+
+			<div class="listSerch">
+				<select name="searchCondition" class="select" title="검색조건 선택">
+					<option value="" <c:if test="${searchVO.searchCondition == ''}">selected="selected"</c:if>>ID/내용/발신번호(전체)</option>
+					<option value="1" <c:if test="${searchVO.searchCondition == '1'}">selected="selected"</c:if>>사용자ID</option>
+					<option value="2" <c:if test="${searchVO.searchCondition == '2'}">selected="selected"</c:if>>채널ID</option>
+					<option value="3" <c:if test="${searchVO.searchCondition == '3'}">selected="selected"</c:if>>전송내용</option>
+				</select>
+
+				<input id="searchKeyword" name="searchKeyword" class="recentSearch" type="text" value="<c:out value='${searchVO.searchKeyword}'/>" size="25" title="검색" maxlength="100" />
+				<input type="button" class="btnType1" value="검색" onclick="fn_search(); return false;">
+			</div>
+
+			<div class="listTop">
+				<p class="tType5">총 <span class="tType4 c_456ded fwBold"><fmt:formatNumber value="${paginationInfo.totalRecordCount}" pattern="#,###" /></span>건</p>
+				<div class="rightWrap">
+					<select name="pageUnit" id="pageUnit" class="select" title="검색조건선택" onchange="linkPage(1);">
+						<option value='10' <c:if test="${searchVO.pageUnit == '10' or searchVO.pageUnit == ''}">selected</c:if>>10줄</option>
+						<option value='20' <c:if test="${searchVO.pageUnit == '20'}">selected</c:if>>20줄</option>
+						<option value='30' <c:if test="${searchVO.pageUnit == '30'}">selected</c:if>>30줄</option>
+					</select>
+				</div>
+			</div>
+			<div class="tableWrap">
+				<table class="tbType1">
+					<colgroup>
+						<col style="width: 4%">
+						<col style="width: 7%">
+						<col style="width: 10%">
+						<col style="width: 9%">
+						<col style="width: 9%">
+						<col style="width: *%">
+						<col style="width: 6%">
+						<col style="width: 3%">
+						<col style="width: 6%">
+						<%-- <col style="width: 6%"> --%>
+						<col style="width: 8%">
+					</colgroup>
+					<thead>
+					<tr>
+						<th>번호<input type="button" class="sort sortBtn" id="sort_userData"></th>
+						<th>아이디<input type="button" class="sort sortBtn" id="sort_userId"></th>
+						<th>채널ID<input type="button" class="sort sortBtn" id="sort_yellowId"></th>
+						<th>수신번호<input type="button" class="sort sortBtn" id="sort_callTo"></th>
+						<th>전송시간<input type="button" class="sort sortBtn" id="sort_sentDateTxt"></th>
+						<th>내용<input type="button" class="sort sortBtn" id="sort_smsTxt"></th>
+						<th>상태<input type="button" class="sort sortBtn" id="sort_curStateTxt"></th>
+						<th>결과<input type="button" class="sort sortBtn" id="sort_rsltCode"></th>
+						<th>타입<input type="button" class="sort sortBtn" id="sort_msgType"></th>
+
+						<!-- <th>기기<input type="button" class="sort sortBtn" id="sort_conectMthdTxt"></th> -->
+						<th>대체문자<input type="button" class="sort sortBtn" id="sort_agentCode"></th>
+					</tr>
+					</thead>
+					<tbody>
+					<c:forEach var="result" items="${resultList}" varStatus="status">
+						<tr>
+							<td>
+								<c:if test="${searchVO.searchSortOrd eq 'desc' }">
+									<c:out value="${ ( paginationInfo.totalRecordCount - ((paginationInfo.currentPageNo -1)*paginationInfo.recordCountPerPage) ) - status.index }"/>
+								</c:if>
+								<c:if test="${searchVO.searchSortOrd eq 'asc' }">
+									<c:out value="${(paginationInfo.currentPageNo - 1) * paginationInfo.recordCountPerPage + status.count}"/>
+								</c:if>
+							</td>
+
+							<td><a href="#" onclick="javascript:fnSelectMber('<c:out value="${result.userId}"/>'); return false;"><c:out value="${result.userId}"/></a></td>
+							<td><a href="#" onclick="fn_detailView('${result.userData}'); return false;"><c:out value="${result.yellowId}"/></a></td>
+
+							<td><a href="#" onclick="fn_detailView('${result.userData}'); return false;"><c:out value="${result.callTo}"/></a></td>
+							<td title="<c:out value="${result.reqDate}"/>">
+								<fmt:parseDate value="${result.reqDate}" var="sentDateValue" pattern="yyyy-MM-dd HH:mm"/>
+								<fmt:formatDate value="${sentDateValue}" pattern="MM-dd HH:mm"/>
+							</td>
+
+							<c:choose>
+							<c:when test="${empty result.smsTxt}">
+							<td title="그림문자">
+								</c:when>
+								<c:otherwise>
+							<td title="<c:out value="${result.smsTxt}"/>">
+								</c:otherwise>
+								</c:choose>
+								<a href="#" onclick="fn_detailView('${result.userData}'); return false;">
+									<c:choose>
+										<c:when test="${empty result.smsTxt}">
+											그림문자
+										</c:when>
+										<c:otherwise>
+											<c:out value="${result.smsTxt}"/>
+										</c:otherwise>
+									</c:choose>
+								</a>
+							</td>
+							<td onclick="fn_detailView('${result.userData}'); return false;" style="cursor:pointer;">
+								<c:choose>
+									<c:when test="${result.reserveCYn == 'Y'}">
+										예약 취소
+									</c:when>
+									<c:otherwise>
+										<c:out value="${result.curStateTxt}"/>
+									</c:otherwise>
+								</c:choose>
+							</td>
+
+							<td onclick="fn_detailView('${result.userData}'); return false;" style="cursor:pointer;">
+								<c:choose>
+									<c:when test="${result.resultCodeTxt == 'S'}">
+										성공
+									</c:when>
+									<c:when test="${result.resultCodeTxt == 'W'}">
+										대기
+									</c:when>
+									<c:otherwise>
+										실패
+									</c:otherwise>
+								</c:choose>
+							</td>
+							<td onclick="fn_detailView('${result.userData}'); return false;" style="cursor:pointer;">
+								<c:out value="${result.msgTypeName}"/>
+							</td>
+
+							<td onclick="fn_detailView('${result.userData}'); return false;" style="cursor:pointer;">
+								<c:out value="${result.subMsgSendYn}"/>
+								<c:if test="${result.subMsgSendYn eq '발송'}">
+									(<c:out value="${result.subMsgType}"/>)
+								</c:if>
+							</td>
+						</tr>
+					</c:forEach>
+					<c:if test="${empty resultList}">
+						<tr><td colspan="10"><spring:message code="common.nodata.msg" /></td></tr>
+					</c:if>
+					</tbody>
+				</table>
+			</div>
+			<div class="btnWrap">
+				<input type="button" class="btnType1" value="목록" onclick="goList(); return false;" value="목록" >
+			</div>
+			<!-- 페이지 네비게이션 시작 -->
+			<c:if test="${!empty resultList}">
+				<div class="page">
+					<ul class="inline">
+						<ui:pagination paginationInfo = "${paginationInfo}"  type="image" jsFunction="linkPage" />
+					</ul>
+				</div>
+			</c:if>
+			<!-- //페이지 네비게이션 끝 -->
+		</div>
+	</div>
+</form>
+<form name="modiForm" method="get" action="<c:url value='/uss/umt/user/kakaoat/EgovGnrlselectedUserKakaoDataListAjax.do'/>" >
+	<input type="hidden" name="msgGroupId" value="<c:out value='${searchVO.msgGroupId}'/>"/>
+	<input type="hidden" name="msgId" value=""/>
+	<input type="hidden" name="mberId" value="<c:out value='${searchVO.userId}'/>"/>
+	<input type="hidden" name="userId" value="<c:out value='${searchVO.userId}'/>"/>
+	<input type="hidden" name="reserveType" id="reserveType"  value="${searchVO.reserveType}">
+	<input type="hidden" name="detailType" value="<c:out value='${searchVO.detailType}'/>"/>
+	<input type="hidden" name="userData" />
+</form>
+</body>
+</html>
 
src/main/webapp/WEB-INF/jsp/cmm/uss/umt/kakao/EgovGnrlUserSelectKakaoDataDetailPop.jsp (added)
+++ src/main/webapp/WEB-INF/jsp/cmm/uss/umt/kakao/EgovGnrlUserSelectKakaoDataDetailPop.jsp
@@ -0,0 +1,341 @@
+<%@ page contentType="text/html; charset=utf-8"%>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="ui" uri="http://egovframework.gov/ctl/ui"%>
+<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>
+<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
+<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
+<%@ taglib prefix="ec" uri="/WEB-INF/tld/ecnet_tld.tld"%>
+<% pageContext.setAttribute("newLineChar", "\r\n"); %>
+<% pageContext.setAttribute("newLineChar2", "\n"); %>
+<%
+	response.setHeader("Cache-Control","no-store");
+	response.setHeader("Pragma","no-cache");
+	response.setDateHeader("Expires",0);
+	if (request.getProtocol().equals("HTTP/1.1")) response.setHeader("Cache-Control", "no-cache");
+%>
+<!DOCTYPE html>
+<html lang="ko">
+<head>
+	<title>사용자 문자전송 관리</title>
+	<meta http-equiv="content-type" content="text/html; charset=utf-8">
+	<link rel="stylesheet" href="/pb/css/reset.css">
+	<link rel="stylesheet" href="/pb/css/common.css">
+	<link rel="stylesheet" href="/pb/css/content.css">
+	<link rel="stylesheet" href="/pb/css/popup.css">
+
+	<style>
+		.pageCont .tbType1 tbody tr td.sms_detail {overflow:inherit;text-overflow:inherit;position:relative;}
+		.pageCont .tbType1 tbody tr td.sms_detail p {overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
+		.pageCont .tbType1 tbody tr td.sms_detail .sms_detail_hover {overflow:hidden;text-overflow:ellipsis;display:none;word-wrap:break-word;-webkit-line-clamp:20;-webkit-box-orient:vertical;position:absolute;left:-5px;top:45px;width:calc(100% + 150px);padding:15px;line-height:20px;white-space:normal;border:1px solid #e5e5e5;background:#fff;border-radius:5px;box-sizing:border-box;box-shadow:0px 3px 10px 0px rgb(0 0 0 / 0.2);z-index:1;font-size:14px;text-align:left;}
+		.pageCont .tbType1 tbody tr td.sms_detail .sms_detail_hover:after {content:'';position:absolute;left:0;bottom:0;width:100%;height:10px;background:#fff;border-radius:0 0 5px 5px;}
+		.pageCont .tbType1 tbody tr td.sms_detail:hover .sms_detail_hover {display:-webkit-box;}
+	</style>
+
+	<script type="text/javascript" src="/pb/js/jquery-3.5.0.js"></script>
+	<script type="text/javascript" src="/pb/js/common.js"></script>
+	<script type="text/javascript" src="<c:url value='/js/EgovMultiFile.js'/>"></script>
+	<script type="text/javascript" src="<c:url value='/js/EgovCalPopup.js'/>"></script>
+	<script type="text/javascript" src="<c:url value='/js/ncms_common.js' />"></script>
+	<script type="text/javaScript" language="javascript">
+
+		function goList(){
+			var frm = document.listForm;
+			frm.submit();
+		}
+
+		function fnTemplateDetail(templateCode){
+
+			if(templateCode != ''){ //알림톡 상세보기
+				var form = document.templateForm;
+
+				form.templateCode.value = templateCode;
+
+				window.open("about:blank", 'popupTemplateDetail', 'width=1240, height=1080, top=100, left=100, fullscreen=no, menubar=no, status=no, toolbar=no, titlebar=yes, location=no, scrollbar=no');
+				form.action = "<c:url value='/uss/ion/kakaoat/KakaoATChannelIDTemplateDetailPopupAjax.do'/>";
+				form.target = "popupTemplateDetail";
+				form.submit();
+			}else{ //친구톡 상세보기
+				var form = document.fTTemplateForm;
+
+				window.open("about:blank", 'popupTemplateDetail', 'width=450, height=900, top=100, left=100, fullscreen=no, menubar=no, status=no, toolbar=no, titlebar=yes, location=no, scrollbar=no');
+				form.action = "<c:url value='/uss/ion/kakaoft/KakaoFTTemplateDetailPopupAjax.do'/>";
+				form.target = "popupTemplateDetail";
+				form.submit();
+			}
+
+		}
+
+	</script>
+	<style>
+		.pageCont {padding:50px 30px;box-sizing:border-box;}
+		.tableWrapTotal {margin:0 0 20px;}
+		.tableWrapTotal .tbType1 thead tr:first-child {border-width:1px;}
+		.tableWrapTotal .tbType1 thead tr th {border-left:1px solid #e6e6e6;}
+		.tableWrapTotal .tbType1 thead tr th:first-child {border-left:0 none;}
+		.tableWrapTotal .tbType1 thead tr.content th {font-size:14px;}
+		.tableWrapTotal .tbType1 tbody tr td {border-left:1px solid #e6e6e6;}
+		.tableWrapTotal .tbType1 tbody tr td:first-child {border-left:0 none;}
+		.listSerch .select {height:42px;vertical-align:top;}
+		.pageCont .tbType1 tbody tr td.msg_detail {overflow:inherit;}
+		.pageCont .tbType1 tbody tr td.msg_detail a {overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:block;}
+		/* .layer_msg_wrap {position:relative;} */
+		.layer_msg_wrap .layer_msg_detail {overflow:hidden;display:none;position:absolute;left:50%;top:600px;width:400px;max-height:600px;background:#eee;transform:translateX(-50%);z-index:1;}
+		.layer_msg_wrap .layer_msg_detail button {position:absolute;right:0;top:0;width:35px;height:35px;}
+		.layer_msg_wrap .layer_msg_detail button:before {content:'';position:absolute;left:50%;top:50%;width:1px;height:14px;margin:-7px 0 0;background:#fff;transform:rotate(-45deg);}
+		.layer_msg_wrap .layer_msg_detail button:after {content:'';position:absolute;left:50%;top:50%;width:1px;height:14px;margin:-7px 0 0;background:#fff;transform:rotate(45deg);}
+		.layer_msg_wrap .layer_msg_detail .title {height:35px;padding:0 15px;font-size:16px;line-height:35px;text-align:left;color:#fff;background:#456ded;border-radius:5px 5px 0 0;}
+		.layer_msg_wrap .layer_msg_detail .content {overflow-y:auto;max-height:535px;margin:15px;padding:10px 15px;line-height:20px;white-space:normal;background:#fff;}
+		.layer_msg_wrap .layer_msg_detail .content .rev_cont {text-align:left;}
+		@media screen and (max-width:916px){
+			.pageCont .tableWrap table thead tr th {padding:15px 0;}
+		}
+
+	</style>
+</head>
+<body>
+<div class="loading_layer">
+	<div class="loading_container">
+		<div class="bar"></div>
+		<div class="text">Loading</div>
+	</div>
+</div>
+<form name="listForm" action="<c:url value='/uss/umt/user/kakaoat/EgovGnrlselectedUserKakaoDataDetailListAjax.do'/>" method="post">
+	<input type="hidden" name="detailType" value="${searchVO.detailType}" />
+	<input type="hidden" name="msgGroupId" value="${searchVO.msgGroupId}" />
+	<input type="hidden" name="userId" id="userId" value="<c:out value='${searchVO.userId}'/>" />
+
+	<div class="contWrap" style="width:100%;position:relative;left:inherit;top:inherit;min-height:auto;padding:40px;">
+		<div class="pageTitle">
+			<h2 class="titType1 c_222222 fwBold">카톡 전송내역 상세</h2>
+		</div>
+		<div class="pageCont">
+			<table class="tbType2">
+				<colgroup>
+					<col style="width: 20%">
+					<col style="width: 80%">
+				</colgroup>
+				<tbody>
+				<tr class="no_modi">
+					<th><span class="reqArea">아이디</span></th>
+					<td colspan="3">
+						<c:out value="${mjonKakaoATDetailVO.userId}"/>
+					</td>
+				</tr>
+
+				<tr>
+					<th><span class="reqArea">전송사구분</span></th>
+					<td colspan="3">
+						<ec:code codeId="ITN019" code="${mjonKakaoATDetailVO.agentCode}" />
+					</td>
+				</tr>
+				<tr>
+					<th><span class="reqArea">채널ID</span></th>
+					<td colspan="3">
+						<a href="/uss/ion/kakaoat/KakaoATChannelIDList.do" ><c:out value="${mjonKakaoATDetailVO.yellowId}"/></a>
+					</td>
+				</tr>
+				<tr>
+					<th><span class="reqArea">템플릿명</span></th>
+					<td colspan="3">
+						<div class="btnWrap">
+							<input type="button" class="btnType2" style="padding:5px 10px" onclick="fnTemplateDetail('<c:out value="${mjonKakaoATDetailVO.msgNoticetalkTmpKey}"/>'); return false;" value="템플릿 상세보기">
+						</div>
+					</td>
+				</tr>
+				<tr>
+					<th><span class="reqArea">수신번호</span></th>
+					<td colspan="3">
+						<c:out value="${mjonKakaoATDetailVO.callTo}" />
+					</td>
+				</tr>
+				<tr>
+					<th><span class="reqArea">메세지타입</span></th>
+					<td colspan="3">
+						<c:out value="${mjonKakaoATDetailVO.msgTypeName}"/>
+					</td>
+				</tr>
+				<tr>
+					<th><span class="reqArea">내용</span></th>
+					<td colspan="3">
+						<c:out value="${fn:replace(fn:replace(mjonKakaoATDetailVO.smsTxt, newLineChar, '<br/>'), newLineChar2, '<br/>')}" escapeXml="false"/>
+						<br><br>
+					</td>
+				</tr>
+				<tr>
+					<th><span class="reqArea">전송 요청 시간</span></th>
+					<td colspan="3">
+						<c:out value="${mjonKakaoATDetailVO.reqDate}"/>
+					</td>
+				</tr>
+				<tr>
+					<th><span class="reqArea">전송 완료 시간</span></th>
+					<td colspan="3">
+						<c:out value="${mjonKakaoATDetailVO.rsltDate}"/>
+					</td>
+				</tr>
+				<tr>
+					<th><span class="reqArea">현재상태</span></th>
+					<td colspan="3">
+						<c:choose>
+							<c:when test="${mjonKakaoATDetailVO.reserveCYn == 'Y'}">
+								예약 취소(<c:out value="${mjonKakaoATDetailVO.cancelDate}"/>)
+							</c:when>
+							<c:otherwise>
+								<c:out value="${mjonKakaoATDetailVO.curStateTxt}"/>
+							</c:otherwise>
+						</c:choose>
+					</td>
+				</tr>
+				<tr>
+					<th><span class="reqArea">알림톡 처리결과</span></th>
+					<td colspan="3">
+						(
+						<c:if test="${not empty mjonKakaoATDetailVO.rsltCode}">
+							<c:out value="${mjonKakaoATDetailVO.rsltCode}"/>
+						</c:if>
+						)
+						<c:choose>
+							<c:when test="${mjonKakaoATDetailVO.resultCodeTxt eq 'S'}">
+								발송 성공
+							</c:when>
+							<c:when test="${mjonKakaoATDetailVO.resultCodeTxt eq 'W'}">
+								발송 대기
+							</c:when>
+							<c:otherwise>
+								발송 실패
+							</c:otherwise>
+						</c:choose>
+					</td>
+				</tr>
+				<c:if test="${mjonKakaoATDetailVO.resultCodeTxt eq 'F'}">
+					<tr>
+						<th><span class="reqArea">발송실패 사유</span></th>
+						<td colspan="3">
+							<c:out value="${mjonKakaoATDetailVO.agentCodeTxt}"/>
+						</td>
+					</tr>
+				</c:if>
+				<c:choose>
+					<c:when test="${mjonKakaoATDetailVO.resultCodeTxt eq 'F'}">
+						<tr>
+							<th><span class="reqArea">알림톡 환불결과(전송실패시)</span></th>
+							<td colspan="3">
+								<c:choose>
+									<c:when test="${mjonKakaoATDetailVO.refundYn == 'N'}">
+										미환불
+									</c:when>
+									<c:otherwise>
+										환불 완료
+									</c:otherwise>
+								</c:choose>
+							</td>
+						</tr>
+					</c:when>
+					<c:otherwise>
+					</c:otherwise>
+				</c:choose>
+				<tr>
+					<th><span class="reqArea">대체문자 사용여부</span></th>
+					<td colspan="3">
+						<c:out value="${mjonKakaoATDetailVO.subMsgSendYn}"/>(<c:out value="${mjonKakaoATDetailVO.subMsgType}"/>)
+					</td>
+				</tr>
+				<!-- 대체문자 발송으로 선택한 경우에만 표시됨 -->
+				<c:if test="${mjonKakaoATDetailVO.subMsgSendYn eq '대체문자 발송'}">
+					<tr>
+						<th><span class="reqArea">대체문자 내용</span></th>
+						<td colspan="3">
+							<c:out value="${fn:replace(fn:replace(mjonKakaoATDetailVO.subMsgTxt, newLineChar, '<br/>'), newLineChar2, '<br/>')}" escapeXml="false"/>
+						</td>
+					</tr>
+					<tr>
+						<th><span class="reqArea">대체문자 성공여부</span></th>
+						<td colspan="3">
+							<c:choose>
+								<c:when test="${mjonKakaoATDetailVO.resultCodeTxt eq 'F'}">
+									<c:choose>
+										<c:when test="${mjonKakaoATDetailVO.bizLogCallStatusCode eq 'S'}">
+											대체문자 발송 성공
+										</c:when>
+										<c:when test="${mjonKakaoATDetailVO.bizLogCallStatusCode eq 'W'}">
+											대체문자 발송 대기
+										</c:when>
+										<c:otherwise>
+											대체문자 발송 실패
+										</c:otherwise>
+									</c:choose>
+								</c:when>
+								<c:otherwise>
+									대체문자 미발송
+								</c:otherwise>
+							</c:choose>
+							<c:if test="${not empty mjonKakaoATDetailVO.bizLogCallStatus}">
+								(<c:out value="${mjonKakaoATDetailVO.bizLogCallStatus}"/>)
+							</c:if>
+						</td>
+					</tr>
+					<c:if test="${mjonKakaoATDetailVO.bizLogCallStatusCode eq 'F'}">
+						<tr>
+							<th><span class="reqArea">대체문자 발송실패 사유</span></th>
+							<td colspan="3">
+								<c:choose>
+									<c:when test="${not empty mjonKakaoATDetailVO.bizLogCallStatusTxt}">
+										<c:out value="${mjonKakaoATDetailVO.bizLogCallStatusTxt}"/>
+									</c:when>
+									<c:otherwise>
+										-
+									</c:otherwise>
+								</c:choose>
+							</td>
+						</tr>
+					</c:if>
+				</c:if>
+				<tr>
+					<th><span class="reqArea">접속기기</span></th>
+					<td colspan="3">
+						<c:out value="${mjonKakaoATDetailVO.conectMthdTxt}"/>
+					</td>
+				</tr>
+				<tr>
+					<th><span class="reqArea">전송사</span></th>
+					<td colspan="3">
+						<ec:code codeId="ITN019" code="${mjonKakaoATDetailVO.agentCode}" />
+					</td>
+				</tr>
+
+				<tr>
+					<th><span class="reqArea">통신사</span></th>
+					<td colspan="3">
+						<c:out value="${mjonKakaoATDetailVO.rsltNet}"/>
+					</td>
+				</tr>
+
+				<tr>
+					<th><span class="reqArea">삭제여부</span></th>
+					<td colspan="3">
+						${mjonKakaoATDetailVO.delFlag}
+					</td>
+				</tr>
+				</tbody>
+			</table>
+			<div class="btnWrap">
+				<input type="button" class="btnType1" value="목록" onclick="goList(); return false;" >
+			</div>
+		</div>
+	</div>
+</form>
+
+<form id="templateForm" name="templateForm" method="post">
+	<input type="hidden" name="SenderKey" value="<c:out value="${mjonKakaoATDetailVO.msgNoticetalkSenderKey }"/>">
+	<input type="hidden" id="templateCode" name="templateCode" value="">
+	<input type="hidden" id="userId" name="userId" value="<c:out value="${mjonKakaoATDetailVO.userId}"/>">
+</form>
+<form id="fTTemplateForm" name="fTTemplateForm" method="post">
+	<input type="hidden" id="msgGroupId" name="msgGroupId" value="<c:out value="${mjonKakaoATDetailVO.msgGroupId}"/>">
+	<input type="hidden" id="userId" name="userId" value="<c:out value="${mjonKakaoATDetailVO.userId}"/>">
+	<input type="hidden" name="senderKey" value="<c:out value="${mjonKakaoATDetailVO.msgNoticetalkSenderKey }"/>">
+	<input type="hidden" name="yellowId" value="<c:out value="${mjonKakaoATDetailVO.yellowId }"/>">
+</form>
+
+</body>
+</html>
src/main/webapp/WEB-INF/jsp/cmm/uss/umt/kakao/EgovGnrlUserSelectKakaoDataListPop.jsp
--- src/main/webapp/WEB-INF/jsp/cmm/uss/umt/kakao/EgovGnrlUserSelectKakaoDataListPop.jsp
+++ src/main/webapp/WEB-INF/jsp/cmm/uss/umt/kakao/EgovGnrlUserSelectKakaoDataListPop.jsp
@@ -122,6 +122,13 @@
 	$('#ntceEndde').val('');
 }
 
+function fn_detailList(msgGroupId, userId){
+	var form = document.modiForm;
+	form.msgGroupId.value = msgGroupId;
+	form.userId.value = userId;
+	form.action="/uss/umt/user/kakaoat/EgovGnrlselectedUserKakaoDataDetailListAjax.do";
+	form.submit();
+}
 
 //엑셀 다운로드
 function sendMsgExcelDownload(){
@@ -504,7 +511,7 @@
 									</c:otherwise>
 								</c:choose>
 							</td>							
-							<td class="sms_detail left">
+							<td class="sms_detail left" onclick="fn_detailList('<c:out value="${result.msgGroupId}"/>', '<c:out value="${result.userId}"/>'); return false;" style="cursor:pointer;" <c:if test="${result.atSmishingYn eq 'Y'}">class="smishing"</c:if>>
 								<p><c:out value="${result.smsTxt}"/></p>
 								<div class="sms_detail_hover">
 									<c:out value="${fn:replace(fn:replace(result.smsTxt, newLineChar, '<br/>'), newLineChar2, '<br/>')}" escapeXml="false"/>
@@ -540,6 +547,7 @@
 	<input name="userId" type="hidden" value="<c:out value='${searchVO.userId}'/>"/>
 	<input name="msgGroupId" type="hidden" />
 	<input name="detailType" type="hidden" value="sendMsgList" />
+	<input type="hidden" name="reserveType" id="reserveType"  value="${searchVO.reserveType}">
 </form>
 </body>
 </html>
src/main/webapp/WEB-INF/jsp/cop/bbs/EgovBoardContentsList.jsp
--- src/main/webapp/WEB-INF/jsp/cop/bbs/EgovBoardContentsList.jsp
+++ src/main/webapp/WEB-INF/jsp/cop/bbs/EgovBoardContentsList.jsp
@@ -57,15 +57,61 @@
     document.modiForm.submit();
 }
 
+function sendBbsListExcelDownload(){
+	var $excelDownForm = $("#excelDownForm");
+
+	$excelDownForm.empty();
+
+	var searchStartDate = $("#searchStartDate").val();
+	var searchEndDate = $("#searchEndDate").val();
+	var searchCnd = $("#searchCnd").val();
+	var searchWrd = $("#searchWrd").val();
+
+	if(searchStartDate) {
+		$excelDownForm.append($('<input>', {type: 'hidden', name: 'searchStartDate', value: searchStartDate}));
+	}
+	if(searchEndDate) {
+		$excelDownForm.append($('<input>', {type: 'hidden', name: 'searchEndDate', value: searchEndDate}));
+	}
+	if(searchCnd) {
+		$excelDownForm.append($('<input>', {type: 'hidden', name: 'searchCnd', value: searchCnd}));
+	}
+	if(searchWrd) {
+		$excelDownForm.append($('<input>', {type: 'hidden', name: 'searchWrd', value: searchWrd}));
+	}
+
+	$excelDownForm.attr("method", "post");
+	$excelDownForm.attr("action", "<c:url value='/cop/bbs/SelectBbsListExcelDownload.do'/>");
+	$excelDownForm.submit();
+}
+
+//기간선택 select
+function fnSetCalMonth(val) {
+	var form = document.listForm;
+	var today = new Date();
+
+	var year = today.getFullYear();
+	var month = ("0" + (today.getMonth() + 1)).slice(-2);
+	var date = ("0" + today.getDate()).slice(-2);
+
+	var sDate = new Date(today.setMonth(today.getMonth() - val));
+
+	var sYear = sDate.getFullYear();
+	var sMonth = ("0" + (sDate.getMonth() + 1)).slice(-2);
+	var sDate = ("0" + sDate.getDate()).slice(-2);
+
+	form.searchStartDate.value = sYear + "-" + sMonth + "-" + sDate;
+	form.searchEndDate.value = year + "-" + month + "-" + date;
+}
+
+
 </script>
 
 
 </head>
 <body>
-<form name="listForm" action="<c:url value='/cop/bbs/SelectBbsContentsList.do'/>" method="post">
+<form name="listForm" id="listForm" action="<c:url value='/cop/bbs/SelectBbsContentsList.do'/>" method="post">
 	<input name="pageIndex" type="hidden" />
-	<input name="searchSortCnd" id="searchSortCnd" type="hidden"  value="<c:out value="${searchVO.searchSortCnd}" />" />
-	<input name="searchSortOrd" id="searchSortOrd" type="hidden" value="<c:out value="${searchVO.searchSortOrd}" />" />
 		
 	<div class="contWrap">
 		<div class="pageTitle">
@@ -75,19 +121,42 @@
 		</div>
 	<div class="pageCont">
 		<div class="listSerch">
+			<div class="calendar_wrap">
+				<select name="setCalMonth" onchange="fnSetCalMonth(this.value)">
+					<option value="0">전체</option>
+					<option value="1">1개월</option>
+					<option value="3">3개월</option>
+					<option value="6">6개월</option>
+				</select>
+				<input type="hidden" name="cal_url" id="cal_url" value="/sym/cmm/EgovNormalCalPopup.do">
+				<div class="calendar_box" onclick="javascript:fn_egov_NormalCalendar(document.forms.listForm, document.forms.listForm.searchStartDate);">
+					<input style="width:auto;min-width: 83px;" type="text" class="date_format" name="searchStartDate" id="searchStartDate" size="4" maxlength="4" readonly="" value="<c:out value='${searchVO.searchStartDate}'/>">
+					<input type="button" class="calBtn">
+				</div>
+				<span class="line">~</span>
+				<div class="calendar_box" onclick="javascript:fn_egov_NormalCalendar(document.forms.listForm, document.forms.listForm.searchEndDate);">
+					<input style="width:auto;min-width: 83px;" type="text" class="date_format" name="searchEndDate" id="searchEndDate" size="4" maxlength="4" readonly="" value="<c:out value='${searchVO.searchEndDate}'/>">
+					<input type="button" class="calBtn">
+				</div>
+			</div>
 			<select name="searchCnd" id="searchCnd" title="검색조건2-검색어구분">
 				<option value="1" <c:if test="${searchVO.searchCnd == '1'}">selected="selected"</c:if> >제목+내용</option>
+				<option value="2" <c:if test="${searchVO.searchCnd == '2'}">selected="selected"</c:if> >등록ID</option>
+				<option value="3" <c:if test="${searchVO.searchCnd == '3'}">selected="selected"</c:if> >댓글 작성자</option>
 			</select>
 			<input type="text" name="searchWrd" id="searchWrd" class="recentSearch" title="검색어" type="text" value="<c:out value="${searchVO.searchWrd}"/>" maxlength="300" size="40"/>
 			<input type="button" class="btnType1" onclick="fn_search(); return false;" value="검색">
+
 		</div>
 		<div class="listTop">
 			<p class="tType5">총 <span class="tType4 c_456ded fwBold"> <fmt:formatNumber value="${paginationInfo.totalRecordCount}" pattern="#,###" /></span>건</p>
 			<p class="rightWrap">
+				<input type="button" class="excelBtn" onclick="sendBbsListExcelDownload();">
 				<select name="pageUnit" id="pageUnit" class="select" title="검색조건선택" onchange="linkPage(1);">
 					<option value='10' <c:if test="${searchVO.pageUnit == '10' or searchVO.pageUnit == ''}">selected</c:if>>10줄</option>
 					<option value='20' <c:if test="${searchVO.pageUnit == '20'}">selected</c:if>>20줄</option>
 					<option value='30' <c:if test="${searchVO.pageUnit == '30'}">selected</c:if>>30줄</option>
+					<option value='100' <c:if test="${searchVO.pageUnit == '100'}">selected</c:if>>100줄</option>
 				</select>
 			</p> 
 		</div>
@@ -100,7 +169,8 @@
 						<col style="width: 11%">
 						<col style="width: 11%">
 						<col style="width: 11%">
-						<col style="width: 15%">
+						<col style="width: 10%">
+						<col style="width: 10%">
 				</colgroup>
 				<thead>
 					<tr>
@@ -109,6 +179,7 @@
 						<th>처리상태</th>
 						<th>등록ID</th>
 						<th>등록자</th>
+						<th>댓글 작성 관리자</th>
 						<th>등록일<input type="button" class="sort sortBtn" id="sort_frstRegistPnttm"></th>
 					</tr>
 				</thead>
@@ -131,9 +202,11 @@
 							</td>
 				            <td>
 			            		<c:set var="commentChk" value="false"/>
+								<c:set var="commentAdminUser" value=""/>
 		                        <c:forEach var="comment" items="${commentList}" varStatus="status">
 									<c:if test="${comment.nttId == result.nttId}">
 										<c:set var="commentChk" value="true"/>
+										<c:set var="commentAdminUser" value="${comment.frstRegisterNm}"/>
 									</c:if>
 		                        </c:forEach>
 		                       	<c:if test="${!not commentChk}">
@@ -145,6 +218,7 @@
 		            		</td>
 		            		<td><a href="#" onclick="javascript:fnSelectMber('<c:out value="${result.ntcrId}"/>'); return false;"><c:out value="${result.ntcrId}"/></a></td>
 		            		<td><c:out value="${result.ntcrNm}"/></td>
+							<td><c:out value="${commentAdminUser}"/></td>
 							<td title="<c:out value="${result.frstRegisterPnttm}"/>">
 								<fmt:parseDate value="${result.frstRegisterPnttm}" var="frstRegisterPnttmValue" pattern="yyyy-MM-dd HH:mm"/>
 								<fmt:formatDate value="${frstRegisterPnttmValue}" pattern="MM-dd HH:mm"/>																													
@@ -153,7 +227,7 @@
 					</c:forEach>
 				</tbody>   
 				<c:if test="${empty adminBoardList}">
-         			<tr><td colspan="3"><spring:message code="common.nodata.msg" /></td></tr>
+         			<tr><td colspan="7"><spring:message code="common.nodata.msg" /></td></tr>
          		</c:if>
 			</table>
 		</div>
@@ -172,12 +246,15 @@
 		    <!-- //페이지 네비게이션 끝 --> 
 		
 		</div>
-	</div>	
+	</div>
 </form>
 
 <form name="modiForm" id="modiForm" method="post">
 <input name="mberId" type="hidden" />
 </form>
 
+<form name="excelDownForm" id="excelDownForm" method="post">
+</form>
+
 </body>
 </html>
(No newline at end of file)
 
src/main/webapp/WEB-INF/jsp/sym/log/access/UserAccessLog.jsp (added)
+++ src/main/webapp/WEB-INF/jsp/sym/log/access/UserAccessLog.jsp
@@ -0,0 +1,32 @@
+<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="ui" uri="http://egovframework.gov/ctl/ui"%>
+<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
+<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
+<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
+<!DOCTYPE html>
+<html>
+<body>
+<%@include file="include/_context.jspf"%>
+<form name="listForm" id="listForm" action ="<c:url value='/uss/umt/user/UserAccessLog.do'/>" method="post">
+    <input name="pageIndex" type="hidden" value="<c:out value='${searchVO.pageIndex}'/>"/>
+    <input type="hidden" name="searchSortCnd" value="<c:out value="${searchVO.searchSortCnd}" />" />
+    <input type="hidden" name="searchSortOrd" value="<c:out value="${searchVO.searchSortOrd}" />" />
+    <div class="contWrap">
+        <div class="pageTitle">
+            <div class="pageIcon"><img src="/pb/img/pageTitIcon4.png" alt=""></div>
+            <h2 class="titType1 c_222222 fwBold">회원 접속 기록 로그 정보</h2>
+            <p class="tType6 c_999999">사용자 메뉴 접속 및 페이지 이동 로그 리스트입니다.</p>
+        </div>
+        <div class="pageCont">
+            <%@include file="include/_search.jspf"%>
+            <%@include file="include/_table.jspf"%>
+            <%@include file="include/_paging.jspf"%>
+        </div>
+    </div>
+</form>
+<form name="modiForm" id="modiForm" method="post">
+    <input name="mberId" type="hidden" />
+</form>
+</body>
+</html>(No newline at end of file)
 
src/main/webapp/WEB-INF/jsp/sym/log/access/include/_context.jspf (added)
+++ src/main/webapp/WEB-INF/jsp/sym/log/access/include/_context.jspf
@@ -0,0 +1,8 @@
+<%@ page pageEncoding="UTF-8" %>
+<script>
+    function linkPage(pageNo){
+        var listForm = document.listForm ;
+        listForm.pageIndex.value = pageNo ;
+        listForm.submit();
+    }
+</script>
 
src/main/webapp/WEB-INF/jsp/sym/log/access/include/_paging.jspf (added)
+++ src/main/webapp/WEB-INF/jsp/sym/log/access/include/_paging.jspf
@@ -0,0 +1,9 @@
+<%@ page pageEncoding="UTF-8" %>
+<div class="btnWrap"></div>
+<c:if test="${!empty resultList}">
+    <div class="page">
+        <ul class="inline">
+            <ui:pagination paginationInfo = "${paginationInfo}"  type="image" jsFunction="linkPage" />
+        </ul>
+    </div>
+</c:if>(No newline at end of file)
 
src/main/webapp/WEB-INF/jsp/sym/log/access/include/_search.jspf (added)
+++ src/main/webapp/WEB-INF/jsp/sym/log/access/include/_search.jspf
@@ -0,0 +1,78 @@
+<%@ page pageEncoding="UTF-8" %>
+<div class="listSerch">
+
+    <div class="calendar_wrap">
+        <input type="hidden" name="cal_url" id="cal_url" value="/sym/cmm/EgovNormalCalPopup.do">
+
+        <div class="calendar_box" onclick="fn_egov_NormalCalendar(document.forms.listForm, document.forms.listForm.searchStartDate);">
+            <input type="text"
+                   class="date_format"
+                   name="searchStartDate"
+                   id="searchStartDate"
+                   size="10"
+                   maxlength="10"
+                   readonly
+                   value="<c:out value='${searchVO.searchStartDate}'/>"/>
+            <input type="button" class="calBtn">
+        </div>
+
+        <span class="line">~</span>
+
+        <div class="calendar_box"
+             onclick="fn_egov_NormalCalendar(document.forms.listForm, document.forms.listForm.searchEndDate);">
+            <input type="text"
+                   class="date_format"
+                   name="searchEndDate"
+                   id="searchEndDate"
+                   size="10"
+                   maxlength="10"
+                   readonly
+                   value="<c:out value='${searchVO.searchEndDate}'/>">
+            <input type="button" class="calBtn">
+        </div>
+    </div>
+
+    <!-- 상태 필터 -->
+    <select name="result" id="result" class="select" title="상태 선택">
+        <option value="">상태 전체</option>
+        <option value="SUCCESS"
+                <c:if test="${searchVO.result == 'SUCCESS'}">selected</c:if>>
+            성공
+        </option>
+        <option value="FAIL"
+                <c:if test="${searchVO.result == 'FAIL'}">selected</c:if>>
+            실패
+        </option>
+    </select>
+
+    <!-- 접속 ID/IP 검색 -->
+    <select name="searchCondition"
+            id="searchCondition"
+            class="select"
+            title="검색조건 선택">
+
+        <option value="" <c:if test="${empty searchVO.searchCondition}">selected</c:if>>전체</option>
+        <option value="userId" <c:if test="${searchVO.searchCondition == 'userId'}">selected</c:if>>접속 ID</option>
+        <option value="accessIp" <c:if test="${searchVO.searchCondition == 'accessIp'}">selected</c:if>>접속 IP</option>
+        <option value="menuNm" <c:if test="${searchVO.searchCondition == 'uri'}">selected</c:if>>메뉴</option>
+    </select>
+
+    <input id="searchKeyword"
+           name="searchKeyword"
+           class="recentSearch"
+           type="text"
+           value="<c:out value='${searchVO.searchKeyword}'/>"
+           size="25"
+           title="검색"
+           maxlength="50">
+
+    <input type="button"
+           class="btnType1"
+           onclick="fn_search(); return false;"
+           value="검색">
+
+    <input type="button"
+           class="btnType1"
+           onclick="fn_searchReset(); return false;"
+           value="초기화">
+</div>(No newline at end of file)
 
src/main/webapp/WEB-INF/jsp/sym/log/access/include/_table.jspf (added)
+++ src/main/webapp/WEB-INF/jsp/sym/log/access/include/_table.jspf
@@ -0,0 +1,116 @@
+<%@ page pageEncoding="UTF-8" %>
+
+<div class="tableWrap">
+    <table class="tbType1">
+        <colgroup>
+            <col style="width: 7%">
+            <col style="width: 12%">
+            <col style="width: 8%">
+            <col style="width: 12%">
+            <col style="width: 12%">
+            <col style="width: auto">
+            <col style="width: 15%">
+        </colgroup>
+
+        <thead>
+        <tr>
+            <th>
+                번호
+                <input type="button" class="sortBtn sort" id="sort_LOG_ID"/>
+            </th>
+            <th>
+                메뉴
+                <input type="button" class="sortBtn sort" id="sort_MENU_NM"/>
+            </th>
+            <th>
+                상태
+                <input type="button" class="sortBtn sort" id="sort_RESULT"/>
+            </th>
+            <th>
+                시도한 아이디
+                <input type="button" class="sortBtn sort" id="sort_USER_ID"/>
+            </th>
+            <th>
+                시도한 IP
+                <input type="button" class="sortBtn sort" id="sort_ACCESS_IP"/>
+            </th>
+            <th>
+                URI
+                <input type="button" class="sortBtn sort" id="sort_URI"/>
+            </th>
+            <th>
+                생성날짜
+                <input type="button" class="sortBtn sort" id="sort_FRST_REGIST_PNTTM"/>
+            </th>
+        </tr>
+        </thead>
+
+        <tbody>
+        <c:forEach var="vo" items="${resultList}" varStatus="status">
+            <tr>
+                <td>
+                    <c:choose>
+                        <c:when test="${searchVO.searchSortOrd eq 'asc'}">
+                            <c:out value="${
+                                paginationInfo.totalRecordCount
+                                - ((paginationInfo.currentPageNo - 1)
+                                * paginationInfo.recordCountPerPage)
+                                - status.index
+                            }"/>
+                        </c:when>
+                        <c:otherwise>
+                            <c:out value="${
+                                (paginationInfo.currentPageNo - 1)
+                                * paginationInfo.recordCountPerPage
+                                + status.count
+                            }"/>
+                        </c:otherwise>
+                    </c:choose>
+                </td>
+
+                <td>
+                    <c:out value="${vo.menuNm}"/>
+                </td>
+
+                <td>
+                    <c:choose>
+                        <c:when test="${vo.result eq 'SUCCESS'}">
+                            성공
+                        </c:when>
+                        <c:when test="${vo.result eq 'FAIL'}">
+                            실패
+                        </c:when>
+                        <c:otherwise>
+                            <c:out value="${vo.result}"/>
+                        </c:otherwise>
+                    </c:choose>
+                </td>
+
+                <td>
+                    <c:out value="${vo.userId}"/>
+                </td>
+
+                <td>
+                    <c:out value="${vo.accessIp}"/>
+                </td>
+
+                <td title="<c:out value='${vo.uri}'/>">
+                    <c:out value="${vo.uri}"/>
+                </td>
+
+                <td>
+                    <c:out value="${vo.frstRegistPnttm}"/>
+                </td>
+            </tr>
+        </c:forEach>
+
+        <c:if test="${empty resultList}">
+            <tr>
+                <td colspan="7">
+                    <spring:message code="common.nodata.msg"/>
+                </td>
+            </tr>
+        </c:if>
+        </tbody>
+    </table>
+</div>(No newline at end of file)
 
src/main/webapp/WEB-INF/jsp/sym/log/second/SecondAuthLog.jsp (added)
+++ src/main/webapp/WEB-INF/jsp/sym/log/second/SecondAuthLog.jsp
@@ -0,0 +1,32 @@
+<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="ui" uri="http://egovframework.gov/ctl/ui"%>
+<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
+<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
+<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
+<!DOCTYPE html>
+<html>
+<body>
+<%@include file="include/_context.jspf"%>
+<form name="listForm" id="listForm" action ="<c:url value='/uss/umt/user/SecondAuthLog.do'/>" method="post">
+    <input name="pageIndex" type="hidden" value="<c:out value='${searchVO.pageIndex}'/>"/>
+    <input type="hidden" name="searchSortCnd" value="<c:out value="${searchVO.searchSortCnd}" />" />
+    <input type="hidden" name="searchSortOrd" value="<c:out value="${searchVO.searchSortOrd}" />" />
+    <div class="contWrap">
+        <div class="pageTitle">
+            <div class="pageIcon"><img src="/pb/img/pageTitIcon4.png" alt=""></div>
+            <h2 class="titType1 c_222222 fwBold">회원 2차 인증 정보</h2>
+            <p class="tType6 c_999999">사용자 2차 로그인 시도 관련 로그 리스트입니다.</p>
+        </div>
+        <div class="pageCont">
+            <%@include file="include/_search.jspf"%>
+            <%@include file="include/_table.jspf"%>
+            <%@include file="include/_paging.jspf"%>
+        </div>
+    </div>
+</form>
+<form name="modiForm" id="modiForm" method="post">
+    <input name="mberId" type="hidden" />
+</form>
+</body>
+</html>(No newline at end of file)
 
src/main/webapp/WEB-INF/jsp/sym/log/second/include/_context.jspf (added)
+++ src/main/webapp/WEB-INF/jsp/sym/log/second/include/_context.jspf
@@ -0,0 +1,55 @@
+<%@ page pageEncoding="UTF-8" %>
+<script>
+    $().ready(() => {
+        document.querySelectorAll(".user-agent").forEach(element => {
+            const userAgent = element.dataset.userAgent;
+            console.log(userAgent);
+            element.textContent = parseUserAgent(userAgent);
+        });
+    })
+
+    function linkPage(pageNo){
+        var listForm = document.listForm ;
+        listForm.pageIndex.value = pageNo ;
+        listForm.submit();
+    }
+
+    function parseUserAgent(userAgent) {
+        if (!userAgent) {
+            return "-";
+        }
+
+        let os = "Unknown";
+        let browser = "Unknown";
+
+        // OS
+        if (/Windows/i.test(userAgent)) {
+            os = "Windows";
+        } else if (/Android/i.test(userAgent)) {
+            os = "Android";
+        } else if (/iPhone|iPad|iPod/i.test(userAgent)) {
+            os = "iOS";
+        } else if (/Macintosh|Mac OS X/i.test(userAgent)) {
+            os = "macOS";
+        } else if (/Linux/i.test(userAgent)) {
+            os = "Linux";
+        }
+
+        // 브라우저: 순서 중요
+        if (/Edg\//i.test(userAgent)) {
+            browser = "Edge";
+        } else if (/SamsungBrowser\//i.test(userAgent)) {
+            browser = "Samsung Internet";
+        } else if (/OPR\/|Opera/i.test(userAgent)) {
+            browser = "Opera";
+        } else if (/Chrome\/|CriOS\//i.test(userAgent)) {
+            browser = "Chrome";
+        } else if (/Firefox\/|FxiOS\//i.test(userAgent)) {
+            browser = "Firefox";
+        } else if (/Safari\//i.test(userAgent)) {
+            browser = "Safari";
+        }
+
+        return os + "(" + browser + ")";
+    }
+</script>
 
src/main/webapp/WEB-INF/jsp/sym/log/second/include/_paging.jspf (added)
+++ src/main/webapp/WEB-INF/jsp/sym/log/second/include/_paging.jspf
@@ -0,0 +1,11 @@
+<%@ page pageEncoding="UTF-8" %>
+<div class="btnWrap"></div>
+<c:if test="${!empty resultList}">
+    <div class="page">
+        <!-- 페이지 네비게이션 시작 -->
+        <ul class="inline">
+            <ui:pagination paginationInfo = "${paginationInfo}"  type="image" jsFunction="linkPage" />
+        </ul>
+        <!-- //페이지 네비게이션 끝 -->
+    </div>
+</c:if>(No newline at end of file)
 
src/main/webapp/WEB-INF/jsp/sym/log/second/include/_search.jspf (added)
+++ src/main/webapp/WEB-INF/jsp/sym/log/second/include/_search.jspf
@@ -0,0 +1,78 @@
+<%@ page pageEncoding="UTF-8" %>
+<div class="listSerch">
+
+    <div class="calendar_wrap">
+        <input type="hidden" name="cal_url" id="cal_url" value="/sym/cmm/EgovNormalCalPopup.do">
+
+        <div class="calendar_box" onclick="fn_egov_NormalCalendar(document.forms.listForm, document.forms.listForm.searchStartDate);">
+            <input type="text"
+                   class="date_format"
+                   name="searchStartDate"
+                   id="searchStartDate"
+                   size="10"
+                   maxlength="10"
+                   readonly
+                   value="<c:out value='${searchVO.searchStartDate}'/>"/>
+            <input type="button" class="calBtn">
+        </div>
+
+        <span class="line">~</span>
+
+        <div class="calendar_box"
+             onclick="fn_egov_NormalCalendar(document.forms.listForm, document.forms.listForm.searchEndDate);">
+            <input type="text"
+                   class="date_format"
+                   name="searchEndDate"
+                   id="searchEndDate"
+                   size="10"
+                   maxlength="10"
+                   readonly
+                   value="<c:out value='${searchVO.searchEndDate}'/>">
+            <input type="button" class="calBtn">
+        </div>
+    </div>
+
+    <!-- 상태 필터 -->
+    <select name="loginResult" id="loginResult" class="select" title="상태 선택">
+        <option value="">상태 전체</option>
+        <option value="SUCCESS"
+                <c:if test="${searchVO.loginResult == 'SUCCESS'}">selected</c:if>>
+            성공
+        </option>
+        <option value="FAIL"
+                <c:if test="${searchVO.loginResult == 'FAIL'}">selected</c:if>>
+            실패
+        </option>
+    </select>
+
+    <!-- 접속 ID/IP 검색 -->
+    <select name="searchCondition"
+            id="searchCondition"
+            class="select"
+            title="검색조건 선택">
+
+        <option value="" <c:if test="${empty searchVO.searchCondition}">selected</c:if>>전체</option>
+        <option value="tryLoginId" <c:if test="${searchVO.searchCondition == 'tryLoginId'}">selected</c:if>>접속 ID</option>
+        <option value="accessIp" <c:if test="${searchVO.searchCondition == 'accessIp'}">selected</c:if>>접속 IP</option>
+        <option value="receive" <c:if test="${searchVO.searchCondition == 'receive'}">selected</c:if>>전화번호</option>
+    </select>
+
+    <input id="searchKeyword"
+           name="searchKeyword"
+           class="recentSearch"
+           type="text"
+           value="<c:out value='${searchVO.searchKeyword}'/>"
+           size="25"
+           title="검색"
+           maxlength="50">
+
+    <input type="button"
+           class="btnType1"
+           onclick="fn_search(); return false;"
+           value="검색">
+
+    <input type="button"
+           class="btnType1"
+           onclick="fn_searchReset(); return false;"
+           value="초기화">
+</div>(No newline at end of file)
 
src/main/webapp/WEB-INF/jsp/sym/log/second/include/_table.jspf (added)
+++ src/main/webapp/WEB-INF/jsp/sym/log/second/include/_table.jspf
@@ -0,0 +1,67 @@
+<%@ page pageEncoding="UTF-8" %>
+
+<div class="tableWrap">
+    <table class="tbType1">
+        <colgroup>
+            <col style="width: 8%">
+            <col style="width: 8%">
+            <col style="width: 8%">
+            <col style="width: auto">
+        </colgroup>
+        <thead>
+        <tr>
+            <th>번호 <input type="button" class="sortBtn sort" id="sort_LOG_ID"></th>
+            <th>상태 <input type="button" class="sortBtn sort" id="sort_LOGIN_RESULT"></th>
+            <th>시도한 아이디 <input type="button" class="sortBtn sort" id="sort_TRY_LOGIN_ID"></th>
+            <th>전화번호 <input type="button" class="sortBtn sort" id="sort_RECEIVE"></th>
+            <th>성공/실패 사유 <input type="button" class="sortBtn sort" id="sort_REASON"></th>
+            <th>시도한 IP <input type="button" class="sortBtn sort" id="sort_ACCESS_IP"></th>
+            <th>시도한 기기 <input type="button" class="sortBtn sort" id="sort_USER_AGENT"></th>
+            <th>사용자 입력번호 <input type="button" class="sortBtn sort" id="sort_RESULT_CODE"></th>
+            <th>생성날짜 <input type="button" class="sortBtn sort" id="sort_FRST_REGIST_PNTTM"></th>
+        </tr>
+        </thead>
+        <tbody>
+        <c:forEach var="result" items="${resultList}" varStatus="status">
+            <tr>
+                <td>
+                    <c:choose>
+                        <c:when test="${searchVO.searchSortOrd eq 'asc'}">
+                            <c:out value="${paginationInfo.totalRecordCount - ((paginationInfo.currentPageNo - 1)* paginationInfo.recordCountPerPage)- status.index}"/>
+                        </c:when>
+
+                        <c:otherwise>
+                            <c:out value="${(paginationInfo.currentPageNo - 1) * paginationInfo.recordCountPerPage + status.count}"/>
+                        </c:otherwise>
+                    </c:choose>
+                </td>
+                <td>
+                    <c:choose>
+                        <c:when test="${result.loginResult eq 'SUCCESS'}">
+                            성공
+                        </c:when>
+                        <c:when test="${result.loginResult eq 'FAIL'}">
+                            실패
+                        </c:when>
+                        <c:otherwise>
+                            <c:out value="${result.loginResult}"/>
+                        </c:otherwise>
+                    </c:choose>
+                </td>
+                <td><c:out value="${result.tryLoginId}"/></td>
+                <td>${result.receive}</td>
+                <td title="${result.reason}"><c:out value="${result.reason}"/></td>
+                <td><c:out value="${result.accessIp}"/></td>
+                <td class="user-agent" data-user-agent="<c:out value='${result.userAgent}'/>"></td>
+                <td><c:out value="${result.resultCode}"/></td>
+                <td><c:out value="${result.frstRegistPnttm}"/></td>
+            </tr>
+        </c:forEach>
+        <c:if test="${empty resultList}">
+            <tr>
+                <td colspan="8"><spring:message code="common.nodata.msg"/></td>
+            </tr>
+        </c:if>
+        </tbody>
+    </table>
+</div>(No newline at end of file)
src/main/webapp/WEB-INF/jsp/sym/mnu/mpm/EgovMenuCreatSelectJtree.jsp
--- src/main/webapp/WEB-INF/jsp/sym/mnu/mpm/EgovMenuCreatSelectJtree.jsp
+++ src/main/webapp/WEB-INF/jsp/sym/mnu/mpm/EgovMenuCreatSelectJtree.jsp
@@ -19,789 +19,789 @@
 <!DOCTYPE html>
 <html>
 <head>
-<meta http-equiv="Content-Language" content="ko">
-<link href="<c:url value='/'/>css/jstree/themes/default/style.min.css" rel="stylesheet" type="text/css">
-<style>
-.jstree_orgChart {
-	overflow: auto;
-	border: 1px solid silver;
-	min-height: 100px;
-	width: 290px;
-}
-</style>
-<script src="<c:url value='/js/jquery-1.12.4.min.js' />"></script> 
-<script src="<c:url value='/js/jstree.min.js' />"></script>
-<script src="<c:url value='/js/EgovCmmUtl.js' />"></script>
-<script>
-/*********************************
- * jstree
- *********************************
- */
-var newNodeId = "";
-function jstreeInit() {
-	$('#kopost_organization').jstree({
-		"core" : {
-			"animation" : 0,
-			"multiple" : false,
-			"check_callback" : true, 
-			"themes" : { "stripes" : true },
-			"data" : {
-				"url" : "<c:url value='/sym/mnu/mcm/EgovMenuCreatSelectJtreeAjax.do'/>",
-				"dataType" : "json",
-				"data" : function (node) {
-					return {'id' : node.id,  'authorCode' : $('#authorCode').val() };
-				}
-			}
-		},
-		"types" : {
-			"#" : {
-				/* "max_children" : 4, */
-				"max_depth" : 5,
-				"valid_children" : ["root"]
-			},
-			"root" : {
-				"icon" : "glyphicon glyphicon-flash",
-				"valid_children" : ["default"]
-			},
-		    "default" : {
-				"valid_children" : ["default","file"]
-		    },
-		    "file" : {
-				"icon" : "jstree-file",
-				"valid_children" : []
-			}
-		},
-		"plugins" : [
-			"contextmenu", "dnd", "search",
-			"types"
-		]
-	})
-	.bind('loaded.jstree', function(e, data) {
-		$('#kopost_organization').jstree('open_node' , $('#0') )
-	})
-	.on('select_node.jstree', function (e, data) {
-		if(!$('.organ_rightbox').is(":visible")){
-			$(".organ_rightbox").show();
+	<meta http-equiv="Content-Language" content="ko">
+	<link href="<c:url value='/'/>css/jstree/themes/default/style.min.css" rel="stylesheet" type="text/css">
+	<style>
+		.jstree_orgChart {
+			overflow: auto;
+			border: 1px solid silver;
+			min-height: 100px;
+			width: 290px;
 		}
-		/*  매뉴  선택 */
-		var menuNo = data.node.id;
-		var upperMenuId = data.node.parent;
-		//하위 매뉴가 있으면 매뉴코드 변경못하게
-		if(data.node.children.length > 0){
-			$('#menuNo').attr("readonly",true);
-			$('#existChildNode').val("Y"); 
-		}else{
-			$('#menuNo').attr("readonly",false);
-			$('#existChildNode').val("N"); 
-		}
-		
-		/*  메뉴  선택 */
-		var menuNo = data.node.id;
-		//메뉴 추가시 자동 선택되게
-		if(newNodeId !=""){
-			menuNo = newNodeId ;
-			newNodeId = "";
-			$('#'+data.instance.get_node(menuNo).a_attr.id).trigger("click") //클릭 이벤트 발생
-		}
-		
-		$("#menuTopNm").text(data.node.text);
-		
-		$.ajax({
-			type:"POST",
-			url:"<c:url value='/sym/mnu/mcm/EgovMenuInfoAjax.do' />",
-			data:{ "menuNo" : menuNo , "authorCode" : $('#authorCode').val()},
-			dataType:'json',
-			//timeout:(1000*30),
-			success : function(returnData, status) {
-				if (status == "success") {
-					var menuManageVO = returnData.menuManageVO;
-					var menuUserTypeList = returnData.menuUserTypeList;
-					fn_select_menuNo(menuManageVO, menuUserTypeList);
-				} else { alert("ERROR"); return;} 
-			},
-			error : function(request , status, error) {
-			},
-			complete : function () {
-				deleteLodingBar();
-			}
-		});
-	})
-	.on('rename_node.jstree', function (e, data) { //메뉴명 변경
-		var nodeId = data.node.id; 
-		var oldText = data.old;
-		var newText = data.text;
-		
-		if (nodeId > 0) {
-			/* 부서명 변경 */
-			if (oldText != newText) {
-				if (confirm("메뉴명을  변경하시겠습니까?" )) {
-					$.ajax({
-						type:"POST",
-						url:"<c:url value='/sym/mnu/mcm/EgovMenuInfoNmUpdateAjax.do' />",
-						data:{ "menuNo" : nodeId, "menuNm" :  newText },
-						dataType:'json',
-						success : function(returnData, status) {
-							if (status == "success") {
-								alert("메뉴명이 변경되었습니다.");
-							} else { alert("ERROR"); return;} 
-						},
-						error : function(request , status, error) {
-							alert("메뉴명이 변경이 실패되었습니다.");
-						},
-						complete : function () {
-							data.instance.refresh();
-							deleteLodingBar();
+	</style>
+	<script src="<c:url value='/js/jquery-1.12.4.min.js' />"></script>
+	<script src="<c:url value='/js/jstree.min.js' />"></script>
+	<script src="<c:url value='/js/EgovCmmUtl.js' />"></script>
+	<script>
+		/*********************************
+		 * jstree
+		 *********************************
+		 */
+		var newNodeId = "";
+		function jstreeInit() {
+			$('#kopost_organization').jstree({
+				"core" : {
+					"animation" : 0,
+					"multiple" : false,
+					"check_callback" : true,
+					"themes" : { "stripes" : true },
+					"data" : {
+						"url" : "<c:url value='/sym/mnu/mcm/EgovMenuCreatSelectJtreeAjax.do'/>",
+						"dataType" : "json",
+						"data" : function (node) {
+							return {'id' : node.id,  'authorCode' : $('#authorCode').val() };
 						}
-					});
-				} else {
-					data.instance.refresh();
+					}
+				},
+				"types" : {
+					"#" : {
+						/* "max_children" : 4, */
+						"max_depth" : 5,
+						"valid_children" : ["root"]
+					},
+					"root" : {
+						"icon" : "glyphicon glyphicon-flash",
+						"valid_children" : ["default"]
+					},
+					"default" : {
+						"valid_children" : ["default","file"]
+					},
+					"file" : {
+						"icon" : "jstree-file",
+						"valid_children" : []
+					}
+				},
+				"plugins" : [
+					"contextmenu", "dnd", "search",
+					"types"
+				]
+			})
+					.bind('loaded.jstree', function(e, data) {
+						$('#kopost_organization').jstree('open_node' , $('#0') )
+					})
+					.on('select_node.jstree', function (e, data) {
+						if(!$('.organ_rightbox').is(":visible")){
+							$(".organ_rightbox").show();
+						}
+						/*  매뉴  선택 */
+						var menuNo = data.node.id;
+						var upperMenuId = data.node.parent;
+						//하위 매뉴가 있으면 매뉴코드 변경못하게
+						if(data.node.children.length > 0){
+							$('#menuNo').attr("readonly",true);
+							$('#existChildNode').val("Y");
+						}else{
+							$('#menuNo').attr("readonly",false);
+							$('#existChildNode').val("N");
+						}
+
+						/*  메뉴  선택 */
+						var menuNo = data.node.id;
+						//메뉴 추가시 자동 선택되게
+						if(newNodeId !=""){
+							menuNo = newNodeId ;
+							newNodeId = "";
+							$('#'+data.instance.get_node(menuNo).a_attr.id).trigger("click") //클릭 이벤트 발생
+						}
+
+						$("#menuTopNm").text(data.node.text);
+
+						$.ajax({
+							type:"POST",
+							url:"<c:url value='/sym/mnu/mcm/EgovMenuInfoAjax.do' />",
+							data:{ "menuNo" : menuNo , "authorCode" : $('#authorCode').val()},
+							dataType:'json',
+							//timeout:(1000*30),
+							success : function(returnData, status) {
+								if (status == "success") {
+									var menuManageVO = returnData.menuManageVO;
+									var menuUserTypeList = returnData.menuUserTypeList;
+									fn_select_menuNo(menuManageVO, menuUserTypeList);
+								} else { alert("ERROR"); return;}
+							},
+							error : function(request , status, error) {
+							},
+							complete : function () {
+								deleteLodingBar();
+							}
+						});
+					})
+					.on('rename_node.jstree', function (e, data) { //메뉴명 변경
+						var nodeId = data.node.id;
+						var oldText = data.old;
+						var newText = data.text;
+
+						if (nodeId > 0) {
+							/* 부서명 변경 */
+							if (oldText != newText) {
+								if (confirm("메뉴명을  변경하시겠습니까?" )) {
+									$.ajax({
+										type:"POST",
+										url:"<c:url value='/sym/mnu/mcm/EgovMenuInfoNmUpdateAjax.do' />",
+										data:{ "menuNo" : nodeId, "menuNm" :  newText },
+										dataType:'json',
+										success : function(returnData, status) {
+											if (status == "success") {
+												alert("메뉴명이 변경되었습니다.");
+											} else { alert("ERROR"); return;}
+										},
+										error : function(request , status, error) {
+											alert("메뉴명이 변경이 실패되었습니다.");
+										},
+										complete : function () {
+											data.instance.refresh();
+											deleteLodingBar();
+										}
+									});
+								} else {
+									data.instance.refresh();
+								}
+							}
+						} else {/* 메뉴 추가 */
+
+						}
+					})
+					.on('delete_node.jstree', function (e, data) {
+						/* 메뉴 삭제  */
+						if(data.node.children.length != 0){
+							alert("하위 메뉴를 먼저 삭제 후 메뉴를 삭제해 주세요.");
+							data.instance.refresh();
+						}else{
+							if (confirm("[" + data.node.text + "]" + " 메뉴를 삭제하시겠습니까?")){
+								$.ajax({
+									type:"POST",
+									url:"<c:url value='/sym/mnu/mcm/EgovMenuInfoDeleteAjax.do' />",
+									data:{ "menuNo" : data.node.id , "authorCode" : $('#authorCode').val() },
+									dataType:'json',
+									//timeout:(1000*30),
+									success : function(returnData, status) {
+										if (status == "success") {
+											alert("메뉴 정보가 삭제되었습니다.");
+											fn_init_menuInfo();
+										} else { alert("ERROR"); return;}
+									},
+									error : function(request , status, error) {
+										alert("메뉴 정보 삭제가 실패되었습니다.");
+										//alert("code:"+request.status+"\n"+"message:"+request.responseText+"\n"+"error:"+error);
+									},
+									complete : function () {
+										data.instance.refresh();
+										deleteLodingBar();
+									}
+								});
+							} else {
+								data.instance.refresh();
+							}
+						}
+
+					})
+					.on('create_node.jstree', function(e, data) {
+						if (confirm("메뉴를 추가하시겠습니까?")){
+							var instance = data.instance;
+							var menuNm = data.text;
+							var upperMenuId = data.node.parent;
+							var menuOrdr = 1;
+							var childrenNodes = instance.get_node(upperMenuId).children;
+
+							// 하위 메뉴 있을 시 마지막 부서 sort_ord + 1
+							if (childrenNodes.length > 1) {
+								//var lastChildrenNode = instance.get_node(childrenNodes[childrenNodes.length - 2]);
+								//sortOrd = lastChildrenNode.li_attr.sortOrd + 1;
+								menuOrdr = childrenNodes.length ;
+							}
+
+							$.ajax({
+								type:"POST",
+								url:"<c:url value='/sym/mnu/mcm/EgovMenuInfoInsertAjax.do' />",
+								data:{ "menuNm" : menuNm, "upperMenuId" :  upperMenuId,  "menuOrdr" : menuOrdr , "authorCode" : $('#authorCode').val() },
+								dataType:'json',
+								//timeout:(1000*30),
+								success : function(returnData, status) {
+									if (returnData.status == "success") {
+										alert("메뉴가 추가 되었습니다.");
+										//fn_select_menuNo(returnData.menuManageVO, returnData.menuManageVO.menuUserType);
+										newNodeId = returnData.menuManageVO.menuNo ;
+									}else if(returnData.status == "dupl"){
+										alert("중복된 아이디가 있습니다.\n 중복된 아이디변경/삭제후 다시 추가해 주세요\n"+ "("+returnData.menuManageResultVO.menuCours+")");
+										return;
+									}else{
+										alert("메뉴 추가가 실패하였습니다.");
+										return;
+									}
+								},
+								error : function(request , status, error) {
+									alert("메뉴 추가가 실패되었습니다.")
+								},
+								complete : function () {
+									data.instance.refresh();
+									deleteLodingBar();
+								}
+							});
+						}else{
+							data.instance.refresh();
+						}
+					})
+					.on('move_node.jstree', function (e, data) {
+						/* 메뉴 위치 변경 */
+						var instance = data.instance;
+						var menuNo = data.node.id;
+						var childrenNodes = instance.get_node(menuNo).children;
+
+						if (confirm("메뉴 위치를 변경하시겠습니까?" )){
+							//var partIdx = data.node.id;
+							var upperMenuId = data.parent;
+							var menuOrdr = data.position + 1;
+							var sortOver = "A" ;
+							$.ajax({
+								type:"POST",
+								url:"<c:url value='/sym/mnu/mcm/EgovMenuInfoMoveAjax.do' />",
+								data:{ "menuNo" : menuNo, "upperMenuId" :  upperMenuId,  "menuOrdr" : menuOrdr , "authorCode" : $('#authorCode').val()},
+								dataType:'json',
+								success : function(returnData, status) {
+									if (status == "success") {
+										alert("메뉴 위치가 변경되었습니다.");
+									} else { alert("ERROR"); return;}
+								},
+								error : function(request , status, error) {
+									alert("메뉴 위치 변경이 실패되었습니다.");
+								},
+								complete : function () {
+									data.instance.refresh();
+									deleteLodingBar();
+								}
+							});
+						} else {
+							data.instance.refresh();
+						}
+					})	;
+
+
+		}
+
+		$( document ).ready(function() {
+			jstreeInit();
+		});
+
+		//직원 상세 초기화
+		function fn_add_emp() {
+			var partIdx =$("#selectPartIdx").val();
+			var upperIdxs = $("#selectPartParents").val();
+
+			// 직원 상세 초기화
+			document.empInfForm.reset();
+			$("#empFormTitle").text("메뉴 추가등록 상세");
+			$("input[name='paIdx']").val("");
+
+			fn_set_emp_part(partIdx, upperIdxs);
+		}
+
+
+		//메뉴 정보 세팅
+		function fn_select_menuNo(menuManageVO, menuUserTypeList){
+			var tmpHtml = "";
+			if(menuManageVO!=null){
+				$('#menuNo').val(menuManageVO.menuNo);
+				$('#tmp_Id').val(menuManageVO.menuNo);
+				$('#menuCours').text(menuManageVO.menuCours);
+				$('#menuOrdr').val(menuManageVO.menuOrdr);
+				$('#menuNm').val(menuManageVO.menuNm);
+				$('#menuDc').val(menuManageVO.menuDc);
+				$('#upperMenuIdText').text(menuManageVO.upperMenuId);
+				$('#upperMenuId').val(menuManageVO.upperMenuId);
+				$('#progrmFileNm').val(menuManageVO.progrmFileNm);
+				/* $('#progrmFileNmText').text(menuManageVO.progrmFileNm); */
+				$('#tmp_Name').val(menuManageVO.progrmFileNm);
+				$('#relateImageNm').val(menuManageVO.relateImageNm);
+				$('#relateImagePath').val(menuManageVO.relateImagePath);
+				$('#userType').val(menuManageVO.userType);
+				$('#url').val(menuManageVO.url);
+				$('#useYn').val(menuManageVO.useYn);
+				$('#satisYn').val(menuManageVO.satisYn);
+				if(""!=menuManageVO.emplyrId) $('#emplyrId').val(menuManageVO.emplyrId); //담당자 세팅
+				if(""!=menuManageVO.emplyrIdTxt) $('#emplyrIdTxt').val(menuManageVO.emplyrIdTxt); //담당자 세팅
+
+				if(menuManageVO.satisYn == null){
+					$('#satisYn').val('N')
+				}
+				$("#menuTopNm").text( menuManageVO.menuNm );
+				$("#progrmHtmlFileId").val( menuManageVO.progrmHtmlFileId );
+				$("#progrmBbsId").val(menuManageVO.progrmBbsId);
+				$('#progrmFileNm_tmp').val(menuManageVO.progrmFileNm);
+				var menuType = menuManageVO.menuType ;
+
+				if(menuType == "M"){
+					$("#satisTr").css("display", "none");
+				}else{
+					$("#satisTr").css("display", "");
+				}
+				if(menuManageVO.progrmFileNm == 'dir' || menuType == 'M'){
+					$("#menuType").val("M"); //메뉴로 세팅
+					$('#progrmFileNm').attr("readonly", true);
+					$('#progrmFileNm_tmp').val("");
+					$('#url_tmp').val("");
+				}else{
+					$("#menuType").val(menuType);
+					//$('#progrmFileNm').attr("readonly", false);
+					$('#url_tmp').val(menuManageVO.url);
+				}
+
+				//메뉴타입 설정
+				initShowUrl('Y');
+				$('#url').val(menuManageVO.url);
+				$(".main1_delete_btn").removeAttr("onclick");
+				$(".main1_delete_btn").attr("onclick", "fn_delete_menuInfo('"+menuManageVO.menuNo+"' , '"+menuManageVO.progrmFileNm+"' );return false;");
+				$(".main1_save_btn").removeAttr("onclick");
+				$(".main1_save_btn").attr("onclick", "fn_save_menuInfo('"+menuManageVO.menuNo+"');return false;");
+
+				$('.tr_item').remove();
+				if( ( "P" == $('#menuType').val() || "C" == $('#menuType').val()) && "ROLE_ANONYMOUS"==$('#authorCode').val() ){ //추가 게시판 조회(프로그램/사용자 화면만 조회)
+					$('#tr_add_bbs').show();
+					set_bbs();
+				}else{
+					$('#tr_add_bbs').hide();
+				}
+
+				$('#htmlComfirm').hide();
+				if(""!=menuManageVO.progrmHtmlFileId){
+					$('#htmlComfirm').show();
+					$('#a_contentLink').attr("onclick" , "htmlComfirm('"+menuManageVO.progrmHtmlFileId+"');")
 				}
 			}
-		} else {/* 메뉴 추가 */
-			
 		}
-	})
-	.on('delete_node.jstree', function (e, data) {
-		/* 메뉴 삭제  */
-		if(data.node.children.length != 0){
-			alert("하위 메뉴를 먼저 삭제 후 메뉴를 삭제해 주세요.");
-			data.instance.refresh();
-		}else{
-			if (confirm("[" + data.node.text + "]" + " 메뉴를 삭제하시겠습니까?")){
+
+		//메뉴  정보 삭제
+		function fn_delete_menuInfo(menuNo , progrmFileNm ) {
+			if(menuNo == null || "undefined"== menuNo){
+				alert("삭제 하려는 메뉴를 먼저 선택해주세요.");
+				return ;
+			}
+
+			var instance = $('#kopost_organization').jstree(true);
+			if(instance.get_node(menuNo).children.length != 0){
+				alert("하위 메뉴를 먼저 삭제 후 메뉴를 삭제해 주세요.");
+				return;
+			}
+
+			if (confirm("메뉴를 삭제 하시겠습니까?")){
 				$.ajax({
 					type:"POST",
-					url:"<c:url value='/sym/mnu/mcm/EgovMenuInfoDeleteAjax.do' />",
-					data:{ "menuNo" : data.node.id , "authorCode" : $('#authorCode').val() },
+					"url" : "<c:url value='/sym/mnu/mcm/EgovMenuInfoDeleteAjax.do'/>",
+					data:{ "menuNo" : menuNo , "progrmFileNm" : progrmFileNm , "authorCode" : $('#authorCode').val() },
 					dataType:'json',
 					//timeout:(1000*30),
 					success : function(returnData, status) {
-						if (status == "success") {
-							alert("메뉴 정보가 삭제되었습니다.");
+						if (returnData.status == "success") {
+							// 직원 목록 갱신
+							var instance = $('#kopost_organization').jstree(true);
+							//$("#" + instance.get_node(partIdx).a_attr.id).trigger("click");
+							alert("메뉴 정보가 삭제 되었습니다.");
+							$("#kopost_organization").jstree("refresh");
 							fn_init_menuInfo();
-						} else { alert("ERROR"); return;} 
+						} else if(returnData.status == "duplPk"){
+							alert("삭제하려는 메뉴를 참조하고 있는 메뉴가 있습니다.\n 참조하는 메뉴를 삭제후 다시 시도해 주세요\n"+ "("+returnData.menuManageResultVO.menuCours+")");
+							return;
+						}
+						else {
+							alert("메뉴 삭제가 실패되었습니다.");
+							return;
+						}
 					},
 					error : function(request , status, error) {
-						alert("메뉴 정보 삭제가 실패되었습니다.");
-						//alert("code:"+request.status+"\n"+"message:"+request.responseText+"\n"+"error:"+error);
+						alert("메뉴 삭제가 실패되었습니다..");
 					},
-					complete : function () {
-						data.instance.refresh();
+					complete : function (){
 						deleteLodingBar();
 					}
 				});
-			} else {
-				data.instance.refresh();
 			}
 		}
-		
-	})
-	.on('create_node.jstree', function(e, data) {
-		if (confirm("메뉴를 추가하시겠습니까?")){
-			var instance = data.instance;
-			var menuNm = data.text;
-			var upperMenuId = data.node.parent;
-			var menuOrdr = 1;
-			var childrenNodes = instance.get_node(upperMenuId).children;
-			
-			// 하위 메뉴 있을 시 마지막 부서 sort_ord + 1
-			if (childrenNodes.length > 1) {
-				//var lastChildrenNode = instance.get_node(childrenNodes[childrenNodes.length - 2]);
-				//sortOrd = lastChildrenNode.li_attr.sortOrd + 1;
-				menuOrdr = childrenNodes.length ;
+
+		//메뉴정보 init(메뉴 초기화)
+		function fn_init_menuInfo() {
+			$("#menuTopNm").text("메뉴선택");
+			$("#menuForm input[type=text]").val("")
+			$('#menuCours').text("");
+			$('#upperMenuIdText').text("");
+			/* $('#progrmFileNmText').text(""); */
+		}
+
+		//메뉴 초기화
+		function jstreeRefresh() {
+			var searchForm = document.searchForm ;
+			searchForm.authorCode.value = $('#authorCode').val();
+			searchForm.submit();
+		}
+
+
+		//메뉴 정보 저장. 등록/수정
+		function fn_save_menuInfo(menuNo) {
+			if(menuNo == null || "undefined"== menuNo){
+				alert("저장 하려는 메뉴를 먼저 메뉴트리에서 생성해 주세요."); return ;
 			}
-			
+
+			var menuForm = document.menuForm;
+			if(""==menuForm.menuNo.value){
+				alert("메뉴번호는 필수 값입니다"); return;
+			}
+
+			if(!$.isNumeric(menuForm.menuNo.value)){
+				alert("메뉴번호는 숫자만 가능합니다."); return;
+			}
+
+			if(!$.isNumeric(menuForm.menuOrdr.value)){
+				alert("메뉴순서는 숫자만 가능합니다."); return;
+			}
+
+			var menuType = $("#menuType option:selected").val();
+			if(menuType !="M"){
+				if($("#progrmFileNm").val() == ""){
+					alert("프로그램 파일명은 필수 값입니다");
+					return;
+				}
+			}
+
+			if(!confirm("저장하시겠습니까?")) return;
+
+			//추가 게시판 저장후 메뉴 정보 저장
+			//if( $('#tr_bbs').length > 0 ){
+			if(!save_line()){
+				console.log();
+				return;
+			}
+			//}
+
+			var url = "";
+			url = "<c:url value='/sym/mnu/mcm/EgovMenuInfoUpdateAjax.do'/>";
+			var params = $(menuForm).serialize();
 			$.ajax({
 				type:"POST",
-				url:"<c:url value='/sym/mnu/mcm/EgovMenuInfoInsertAjax.do' />",
-				data:{ "menuNm" : menuNm, "upperMenuId" :  upperMenuId,  "menuOrdr" : menuOrdr , "authorCode" : $('#authorCode').val() },
+				"url":url,
+				data:params,
 				dataType:'json',
-				//timeout:(1000*30),
 				success : function(returnData, status) {
 					if (returnData.status == "success") {
-						alert("메뉴가 추가 되었습니다.");
-						//fn_select_menuNo(returnData.menuManageVO, returnData.menuManageVO.menuUserType);
-						newNodeId = returnData.menuManageVO.menuNo ;
-					}else if(returnData.status == "dupl"){ 
-						alert("중복된 아이디가 있습니다.\n 중복된 아이디변경/삭제후 다시 추가해 주세요\n"+ "("+returnData.menuManageResultVO.menuCours+")"); 
+						alert("메뉴 정보가 저장 되었습니다.");
+						var instance = $('#kopost_organization').jstree(true);
+						$('#'+instance.get_node($('#tmp_Id').val()).a_attr.id).trigger("click");//이전 메뉴id선택되게
+						$('#tmp_Id').val($('#menuNo').val());
+					} else if(returnData.status == "upperDupl"){
+						alert("상위 메뉴 번호가 있습니다.");
+						return;
+					}else if(returnData.status == "dupl"){
+						alert("이미 사용하고 있는 메뉴 번호가 있습니다.");
+						return;
+					}else if(returnData.status == "duplProNm"){
+						alert("이미 사용하고 있는 프로그램파일명이 있습니다.");
 						return;
 					}else{
-						alert("메뉴 추가가 실패하였습니다.");
-						return;
+						alert("ERROR"); return;
 					}
 				},
 				error : function(request , status, error) {
-					alert("메뉴 추가가 실패되었습니다.")
+					alert("메뉴 정보 저장이 실패되었습니다.");
 				},
 				complete : function () {
-					data.instance.refresh();  
-					deleteLodingBar();
-				}
-			});                                              
-		}else{
-			data.instance.refresh();
-		}
-  	})
-  	.on('move_node.jstree', function (e, data) {
-		/* 메뉴 위치 변경 */
-		var instance = data.instance;
-		var menuNo = data.node.id;
-		var childrenNodes = instance.get_node(menuNo).children;
-		
-		if (confirm("메뉴 위치를 변경하시겠습니까?" )){
-			//var partIdx = data.node.id;
-			var upperMenuId = data.parent;
-			var menuOrdr = data.position + 1;
-			var sortOver = "A" ;
-			$.ajax({
-				type:"POST",
-				url:"<c:url value='/sym/mnu/mcm/EgovMenuInfoMoveAjax.do' />",
-				data:{ "menuNo" : menuNo, "upperMenuId" :  upperMenuId,  "menuOrdr" : menuOrdr , "authorCode" : $('#authorCode').val()},
-				dataType:'json',
-				success : function(returnData, status) {
-					if (status == "success") {
-						alert("메뉴 위치가 변경되었습니다.");
-					} else { alert("ERROR"); return;}
-				},
-				error : function(request , status, error) {
-					alert("메뉴 위치 변경이 실패되었습니다.");
-				},
-				complete : function () {
-					data.instance.refresh();
+					$("#kopost_organization").jstree("refresh");
 					deleteLodingBar();
 				}
 			});
-		} else {
-			data.instance.refresh();
 		}
-	})	;
-  	
-	
-}
-	
-$( document ).ready(function() {
-	jstreeInit();
-});
 
-//직원 상세 초기화
-function fn_add_emp() {
-	var partIdx =$("#selectPartIdx").val();
-	var upperIdxs = $("#selectPartParents").val();
+		//메뉴 초기화
+		function initShowUrl(init){
+			var menuType = $("#menuType option:selected").val();
 
-	// 직원 상세 초기화
-	document.empInfForm.reset();
-	$("#empFormTitle").text("메뉴 추가등록 상세");
-	$("input[name='paIdx']").val("");
-	
-	fn_set_emp_part(partIdx, upperIdxs);
-}
+			$("#url").val("");
+			$("#showUrl").hide();
+			$("#btnContent").hide();
+			$("#btnBBS").hide();
+			$('#htmlComfirm').hide();
+			$('#BBSNameSpan').text("");
+			if("M" == menuType){ //메뉴
+				$("#progrmFileNm").val("dir");
+				$("#url").val("");
+				$('#progrmFileNm').attr("readonly", true);
+			}else{
+				$("#progrmFileNm").val($("#progrmFileNm_tmp").val());
+				$("#url").val($("#url_tmp").val());
 
-
-//메뉴 정보 세팅
-function fn_select_menuNo(menuManageVO, menuUserTypeList){
-	var tmpHtml = "";
-	if(menuManageVO!=null){
-		$('#menuNo').val(menuManageVO.menuNo);
-		$('#tmp_Id').val(menuManageVO.menuNo);
-		$('#menuCours').text(menuManageVO.menuCours);
-		$('#menuOrdr').val(menuManageVO.menuOrdr);
-		$('#menuNm').val(menuManageVO.menuNm);                                                                         
-		$('#menuDc').val(menuManageVO.menuDc);
-		$('#upperMenuIdText').text(menuManageVO.upperMenuId);
-		$('#upperMenuId').val(menuManageVO.upperMenuId);
-		$('#progrmFileNm').val(menuManageVO.progrmFileNm);
-		/* $('#progrmFileNmText').text(menuManageVO.progrmFileNm); */
-		$('#tmp_Name').val(menuManageVO.progrmFileNm);
-		$('#relateImageNm').val(menuManageVO.relateImageNm);
-		$('#relateImagePath').val(menuManageVO.relateImagePath);
-		$('#userType').val(menuManageVO.userType);
-		$('#url').val(menuManageVO.url);
-		$('#useYn').val(menuManageVO.useYn);
-		$('#satisYn').val(menuManageVO.satisYn);
-		if(""!=menuManageVO.emplyrId) $('#emplyrId').val(menuManageVO.emplyrId); //담당자 세팅
-		if(""!=menuManageVO.emplyrIdTxt) $('#emplyrIdTxt').val(menuManageVO.emplyrIdTxt); //담당자 세팅
-		
-		if(menuManageVO.satisYn == null){
-			$('#satisYn').val('N')
-		}
-		$("#menuTopNm").text( menuManageVO.menuNm );
-		$("#progrmHtmlFileId").val( menuManageVO.progrmHtmlFileId );
-		$("#progrmBbsId").val(menuManageVO.progrmBbsId);
-		$('#progrmFileNm_tmp').val(menuManageVO.progrmFileNm);
-		var menuType = menuManageVO.menuType ;
-		
-		if(menuType == "M"){
-			$("#satisTr").css("display", "none");
-		}else{
-			$("#satisTr").css("display", "");
-		}
-		if(menuManageVO.progrmFileNm == 'dir' || menuType == 'M'){
-			$("#menuType").val("M"); //메뉴로 세팅
-			$('#progrmFileNm').attr("readonly", true);
-			$('#progrmFileNm_tmp').val("");
-			$('#url_tmp').val("");
-		}else{
-			$("#menuType").val(menuType);
-			//$('#progrmFileNm').attr("readonly", false);
-			$('#url_tmp').val(menuManageVO.url);
-		}
-		
-		//메뉴타입 설정
-		initShowUrl('Y');
-		$('#url').val(menuManageVO.url);
-		$(".main1_delete_btn").removeAttr("onclick");
-		$(".main1_delete_btn").attr("onclick", "fn_delete_menuInfo('"+menuManageVO.menuNo+"' , '"+menuManageVO.progrmFileNm+"' );return false;");
-		$(".main1_save_btn").removeAttr("onclick");
-		$(".main1_save_btn").attr("onclick", "fn_save_menuInfo('"+menuManageVO.menuNo+"');return false;");
-		
-		$('.tr_item').remove();
-		if( ( "P" == $('#menuType').val() || "C" == $('#menuType').val()) && "ROLE_ANONYMOUS"==$('#authorCode').val() ){ //추가 게시판 조회(프로그램/사용자 화면만 조회)
-			$('#tr_add_bbs').show();
-			set_bbs();
-		}else{
-			$('#tr_add_bbs').hide();
-		}
-		
-		$('#htmlComfirm').hide();
-		if(""!=menuManageVO.progrmHtmlFileId){
-			$('#htmlComfirm').show();
-			$('#a_contentLink').attr("onclick" , "htmlComfirm('"+menuManageVO.progrmHtmlFileId+"');")
-		}	
-	}
-}
-
-//메뉴  정보 삭제
-function fn_delete_menuInfo(menuNo , progrmFileNm ) {
-	if(menuNo == null || "undefined"== menuNo){
-		alert("삭제 하려는 메뉴를 먼저 선택해주세요.");
-		return ;
-	}
-	
-	var instance = $('#kopost_organization').jstree(true);
-	if(instance.get_node(menuNo).children.length != 0){
-		alert("하위 메뉴를 먼저 삭제 후 메뉴를 삭제해 주세요.");
-		return;
-	}
-	
-	if (confirm("메뉴를 삭제 하시겠습니까?")){
-		$.ajax({
-			type:"POST",
-			"url" : "<c:url value='/sym/mnu/mcm/EgovMenuInfoDeleteAjax.do'/>",
-			data:{ "menuNo" : menuNo , "progrmFileNm" : progrmFileNm , "authorCode" : $('#authorCode').val() },
-			dataType:'json',
-			//timeout:(1000*30),
-			success : function(returnData, status) {
-				if (returnData.status == "success") {
-					// 직원 목록 갱신
+				if("P" == menuType){ //프로그램
+					$('#progrmFileNm').attr("readonly", false);
+					$("#url").attr("readonly", false);
+				}else if("C" == menuType ){ //컨텐츠
+					$('#progrmFileNm').attr("readonly", false);
+					$("#url").attr("readonly", false);
+				}else if("B" == menuType){ //게시판
+					$('#progrmFileNm').attr("readonly", false);
+					$("#url").attr("readonly", false);
+				}else if("O" == menuType){ //게시판
+					$('#progrmFileNm').attr("readonly", false);
+					$("#url").attr("readonly", false);
+				}
+				if(init=='N'){
 					var instance = $('#kopost_organization').jstree(true);
-					//$("#" + instance.get_node(partIdx).a_attr.id).trigger("click");
-					alert("메뉴 정보가 삭제 되었습니다.");
-					$("#kopost_organization").jstree("refresh");
-					fn_init_menuInfo();
-				} else if(returnData.status == "duplPk"){
-					alert("삭제하려는 메뉴를 참조하고 있는 메뉴가 있습니다.\n 참조하는 메뉴를 삭제후 다시 시도해 주세요\n"+ "("+returnData.menuManageResultVO.menuCours+")");
-					return;
-				}					
-				else { 
-					alert("메뉴 삭제가 실패되었습니다."); 
-					return;
-				} 
-			},
-			error : function(request , status, error) {
-				alert("메뉴 삭제가 실패되었습니다..");
-			},
-			complete : function (){
-				deleteLodingBar();
-			}
-		});
-	}
-}
+					if($('#kopost_organization').jstree('get_selected')[0] != null){
+						if(instance.get_node($('#kopost_organization').jstree('get_selected')[0]).children.length != 0){
+							alert("하위 메뉴가 있을경우는 다른타입으로 변경할수 없습니다.");
+							return;
+						}
+					}
+				}
 
-//메뉴정보 init(메뉴 초기화)
-function fn_init_menuInfo() {
-	$("#menuTopNm").text("메뉴선택");
-	$("#menuForm input[type=text]").val("")
-	$('#menuCours').text("");
-	$('#upperMenuIdText').text("");
-	/* $('#progrmFileNmText').text(""); */
-}
-
-//메뉴 초기화
-function jstreeRefresh() {
-	var searchForm = document.searchForm ;
-	searchForm.authorCode.value = $('#authorCode').val();
-	searchForm.submit();
-}
-
-
-//메뉴 정보 저장. 등록/수정
-function fn_save_menuInfo(menuNo) {
-	if(menuNo == null || "undefined"== menuNo){
-		alert("저장 하려는 메뉴를 먼저 메뉴트리에서 생성해 주세요."); return ;
-	}
-	
-	var menuForm = document.menuForm;
-	if(""==menuForm.menuNo.value){
-		alert("메뉴번호는 필수 값입니다"); return;
-	}
-	
-	if(!$.isNumeric(menuForm.menuNo.value)){
-		alert("메뉴번호는 숫자만 가능합니다."); return;
-	}
-	
-	if(!$.isNumeric(menuForm.menuOrdr.value)){
-		alert("메뉴순서는 숫자만 가능합니다."); return;
-	}
-	
-	var menuType = $("#menuType option:selected").val();
-	if(menuType !="M"){
-		if($("#progrmFileNm").val() == ""){
-			alert("프로그램 파일명은 필수 값입니다");
-			return;
-		}
-	}
-	
-	if(!confirm("저장하시겠습니까?")) return;
-	
-	//추가 게시판 저장후 메뉴 정보 저장
-	//if( $('#tr_bbs').length > 0 ){
-		if(!save_line()){
-			console.log();
-			return;
-		}
-	//}
-	
- 	var url = "";
-	url = "<c:url value='/sym/mnu/mcm/EgovMenuInfoUpdateAjax.do'/>";
-	var params = $(menuForm).serialize();
-	$.ajax({
-		type:"POST",
-		"url":url,
-		data:params,
-		dataType:'json',
-		success : function(returnData, status) {
-			if (returnData.status == "success") {
-				alert("메뉴 정보가 저장 되었습니다.");
-				var instance = $('#kopost_organization').jstree(true);
-				$('#'+instance.get_node($('#tmp_Id').val()).a_attr.id).trigger("click");//이전 메뉴id선택되게
-				$('#tmp_Id').val($('#menuNo').val());
-			} else if(returnData.status == "upperDupl"){
-				alert("상위 메뉴 번호가 있습니다.");
-				return;
-			}else if(returnData.status == "dupl"){
-				alert("이미 사용하고 있는 메뉴 번호가 있습니다.");
-				return;
-			}else if(returnData.status == "duplProNm"){
-				alert("이미 사용하고 있는 프로그램파일명이 있습니다.");
-				return;
-			}else{ 
-				alert("ERROR"); return;
-			} 
-		},
-		error : function(request , status, error) {
-			alert("메뉴 정보 저장이 실패되었습니다.");
-		},
-		complete : function () {
-			$("#kopost_organization").jstree("refresh");
-			deleteLodingBar();
-		}
-	});
-}
-
-//메뉴 초기화
-function initShowUrl(init){
-	var menuType = $("#menuType option:selected").val();
-	
-	$("#url").val("");
-	$("#showUrl").hide();
-	$("#btnContent").hide();
-	$("#btnBBS").hide();
-	$('#htmlComfirm').hide();
-	$('#BBSNameSpan').text("");
-	if("M" == menuType){ //메뉴
-		$("#progrmFileNm").val("dir");
-		$("#url").val("");
-		$('#progrmFileNm').attr("readonly", true);
-	}else{
-		$("#progrmFileNm").val($("#progrmFileNm_tmp").val());
-		$("#url").val($("#url_tmp").val());
-		
-		if("P" == menuType){ //프로그램
-			$('#progrmFileNm').attr("readonly", false);
-			$("#url").attr("readonly", false);
-		}else if("C" == menuType ){ //컨텐츠
-			$('#progrmFileNm').attr("readonly", false);
-			$("#url").attr("readonly", false);
-		}else if("B" == menuType){ //게시판
-			$('#progrmFileNm').attr("readonly", false);	
-			$("#url").attr("readonly", false);
-		}else if("O" == menuType){ //게시판
-			$('#progrmFileNm').attr("readonly", false);	
-			$("#url").attr("readonly", false);
-		}
-		if(init=='N'){
-			var instance = $('#kopost_organization').jstree(true);
-			if($('#kopost_organization').jstree('get_selected')[0] != null){
-				if(instance.get_node($('#kopost_organization').jstree('get_selected')[0]).children.length != 0){
-					alert("하위 메뉴가 있을경우는 다른타입으로 변경할수 없습니다.");
-					return;
-				}	
+				$("#showUrl").show();
+				if("C" == menuType){
+					$("#btnContent").show();
+					$("#url").attr("readonly", false);
+				}else if("B" == menuType){
+					$("#btnBBS").show();
+					$("#url").attr("readonly", false);
+				}
 			}
 		}
-		
-		$("#showUrl").show();
-		if("C" == menuType){
-			$("#btnContent").show();
-			$("#url").attr("readonly", false);
-		}else if("B" == menuType){
-			$("#btnBBS").show();
-			$("#url").attr("readonly", false);
+
+
+		var docWidth = screen.availWidth;
+		var docHeight = screen.availHeight;
+		var scX = window.screenX||window.screenLeft||0;
+		var scY = window.screenY||window.screenTop||0;
+		/* ********************************************************
+         * 게시판목록조회  함수
+         ******************************************************** */
+		function searchBBSId(obj) {
+			var popupX = scX + (docWidth - 185) / 2;
+			var popupY = scY + (docHeight - 195) / 2;
+
+			memuPopup = window.open('', 'memuPopup', "width=800, height=730, left="+popupX+", top="+popupY, "location = no","status= no","toolbars= no");
+			document.searchForm.method = "post";
+			if("menuAdd"==$(obj).attr('id')){  //추가게시판 버튼 클릭시
+				document.searchForm.seCd.value = $(obj).attr('id');
+				document.searchForm.searchNm.value = $(obj).attr('value');
+			}
+			document.searchForm.action = "/cop/bbs/EgovBBSIdListSearch.do";
+			document.searchForm.target = "memuPopup" ;
+			document.searchForm.submit();
+			document.searchForm.target = "_self" ;
+			document.searchForm.action= "/sym/mnu/mcm/EgovMenuCreatSelectJtree.do";
 		}
-	}
-}
 
+		/* ********************************************************
+         * 화면컨텐츠ID 검색 팝업
+         ******************************************************** */
+		var memuPopup ="";
+		function searchContentList() {
+			var popupX = scX + (docWidth - 185) / 2;
+			var popupY = scY + (docHeight - 195) / 2;
 
-var docWidth = screen.availWidth;
-var docHeight = screen.availHeight;
-var scX = window.screenX||window.screenLeft||0;
-var scY = window.screenY||window.screenTop||0;
-/* ********************************************************
- * 게시판목록조회  함수
- ******************************************************** */
-function searchBBSId(obj) {
-	var popupX = scX + (docWidth - 185) / 2;
-	var popupY = scY + (docHeight - 195) / 2;
-	
-	memuPopup = window.open('', 'memuPopup', "width=800, height=730, left="+popupX+", top="+popupY, "location = no","status= no","toolbars= no");
-	document.searchForm.method = "post";
-	if("menuAdd"==$(obj).attr('id')){  //추가게시판 버튼 클릭시 
-		document.searchForm.seCd.value = $(obj).attr('id');
-		document.searchForm.searchNm.value = $(obj).attr('value');
-	}
-	document.searchForm.action = "/cop/bbs/EgovBBSIdListSearch.do";
-	document.searchForm.target = "memuPopup" ;
-	document.searchForm.submit();
-	document.searchForm.target = "_self" ;
-	document.searchForm.action= "/sym/mnu/mcm/EgovMenuCreatSelectJtree.do";
-}
-
-/* ********************************************************
- * 화면컨텐츠ID 검색 팝업
- ******************************************************** */
-var memuPopup ="";
-function searchContentList() {
-	var popupX = scX + (docWidth - 185) / 2;
-	var popupY = scY + (docHeight - 195) / 2;
-	
-	memuPopup = window.open('', 'memuPopup', "width=800, height=730, left="+popupX+", top="+popupY, "location = no","status= no","toolbars= no");
-	document.searchForm.method = "post";
-	document.searchForm.action = "/uss/ion/cnt/contentListPopup.do";
-	document.searchForm.target = "memuPopup" ;
-	document.searchForm.submit();
-	document.searchForm.target = "_self" ;
-	document.searchForm.action= "/sym/mnu/mcm/EgovMenuCreatSelectJtree.do";
-}
-
-/* ********************************************************
- * 사용자 매뉴 담당자 조회 함수
- ******************************************************** */
-function searchManageMenuList() {
-	var popupX = scX + (docWidth - 185) / 2;
-	var popupY = scY + (docHeight - 195) / 2;
-	
-	memuPopup = window.open('', 'memuPopup', "width=800, height=730, left="+popupX+", top="+popupY, "location = no","status= no","toolbars= no");
-	document.searchForm.method = "post";
-	document.searchForm.action = "/uss/umt/user/EgovUserManageMenuAjax.do";
-	document.searchForm.target = "memuPopup" ;
-	document.searchForm.submit();
-	document.searchForm.target = "_self" ;
-	document.searchForm.action= "/sym/mnu/mcm/EgovMenuCreatSelectJtree.do";
-}
-
-
-function onkeyContentName(event){
-	var tempContentUrl = "/web/content.do?proFn=" ; 
-	if($("#menuType option:selected").val()=="C"){
-	   $("#url").val(tempContentUrl + $("#progrmFileNm").val()) ;
-	}
-}
-
-
-
-//행추가
-function add_line(bbsInfo){
-	var eva_temp_tr = $('#temp_tr').clone();
-	$('#tbl_bbsId').append(eva_temp_tr);
-	eva_temp_tr.attr('id' , 'tr_bbs').attr('class' , 'tr_item');
-	{ //변수 변경
-		var tr_item_length = $('.tr_item').size()-1 ;
-		eva_temp_tr.find("#temp_bbsTxt").attr('name', eva_temp_tr.find("#temp_bbsTxt").attr('name').replace('[]' , '['+tr_item_length+']' ))   ;
-		eva_temp_tr.find("#temp_bbsTxt").attr('id' , 'bbsTxt_'+tr_item_length) ; 
-		eva_temp_tr.find("#temp_bbsIds").attr('name', eva_temp_tr.find("#temp_bbsIds").attr('name').replace('[]' , '['+tr_item_length+']' ))   ;
-		eva_temp_tr.find("#temp_bbsIds").attr('id' , 'menuAdd_'+tr_item_length) ;
-		eva_temp_tr.find("#temp_bbsSorts").attr('name' , eva_temp_tr.find("#temp_bbsSorts").attr('name').replace('[]' , '['+tr_item_length+']' ) ) ;
-		eva_temp_tr.find("#temp_bbsSorts").attr('id' , 'bbsSorts_'+tr_item_length) ; 
-		eva_temp_tr.find("#menuAdd").attr('value' ,  'menuAdd_'+tr_item_length ) ;
-	}
-	if(null != bbsInfo){
-		$('#bbsTxt_'+tr_item_length).val(bbsInfo.bbsNm);
-		$('#bbsSorts_'+tr_item_length).val(bbsInfo.bbsSort);
-		$('#menuAdd_'+tr_item_length).val(bbsInfo.bbsId);
-		
-	}
-}
-
-//삭제시 배열 초기화
-var arrCd = new Array();
-function set_count(){  //tr 세팅
-	$('.tr_item').each(function(index, item){
-		$(this).find('input[name^=bbsTxt]').attr('name', 'bbsTxt['+index+']' ).attr('id' , 'bbsTxt_'+index ) ;
-		$(this).find('input[name^=bbsSorts]').attr('name', 'bbsSorts['+index+']' );
-		$(this).find('input[name^=bbsIds]').attr('name', 'bbsIds['+index+']' ).attr('id' , 'menuAdd_'+index ) ;
-		$(this).find('#menuAdd').attr('value' , 'menuAdd_'+index) ;
-	});
-}
-
-var arrDel = new Array; //1차배열
-function delete_line(obj){
-	$(obj).parent().parent().remove();
-	set_count();
-}
-
-function save_line() {
-	/* if(0== $('.tr_item').size()){
-		alert("선택된 게시판이 없습니다.");
-		return;
-	} */
-	
-	//빈 게시판 방지
-	var blank_tr = false;
-	var blank_sort = false;
-	$('.tr_item').each(function() {
-		if(""==$(this).find('input[name^=bbsTxt]').val()){
-			blank_tr = true;
+			memuPopup = window.open('', 'memuPopup', "width=800, height=730, left="+popupX+", top="+popupY, "location = no","status= no","toolbars= no");
+			document.searchForm.method = "post";
+			document.searchForm.action = "/uss/ion/cnt/contentListPopup.do";
+			document.searchForm.target = "memuPopup" ;
+			document.searchForm.submit();
+			document.searchForm.target = "_self" ;
+			document.searchForm.action= "/sym/mnu/mcm/EgovMenuCreatSelectJtree.do";
 		}
-		
-		if(""==$(this).find('input[name^=bbsSort]').val()){
-			blank_sort = true;
+
+		/* ********************************************************
+         * 사용자 매뉴 담당자 조회 함수
+         ******************************************************** */
+		function searchManageMenuList() {
+			var popupX = scX + (docWidth - 185) / 2;
+			var popupY = scY + (docHeight - 195) / 2;
+
+			memuPopup = window.open('', 'memuPopup', "width=800, height=730, left="+popupX+", top="+popupY, "location = no","status= no","toolbars= no");
+			document.searchForm.method = "post";
+			document.searchForm.action = "/uss/umt/user/EgovUserManageMenuAjax.do";
+			document.searchForm.target = "memuPopup" ;
+			document.searchForm.submit();
+			document.searchForm.target = "_self" ;
+			document.searchForm.action= "/sym/mnu/mcm/EgovMenuCreatSelectJtree.do";
 		}
-		
-	});
-	if(blank_tr) {
-		alert("비어 있는 게시판이 있습니다.");
-		return false;
-	}
-	if(blank_sort) {
-		alert("게시판 순서를 넣어주세요.");
-		return false;
-	}
-	
-	var save_line_return = false;
-	var frm = document.menuForm;
-   	var data = new FormData(frm);
-   	$.ajax({
-       type: "POST",
-       url: "/sym/mnu/mcm/MenuBbsInsertAjax.do",
-       data: data,
-       dataType:'json',
-       processData: false,
-       contentType: false,
-       async: false, 
-       cache: false,
-       timeout: 600000,
-       success: function (returnData, status) {
-           if(status == 'success'){
-	           	if(returnData.status == 'fail'){
-	           		alert("게시판 등록 실패하였습니다.");
-	           	}else if(returnData.status == 'auth_fail'){
-	           		alert("세션이 종료되었습니다.");
-	           	}else if(returnData.status =='success'){
-					//alert("등록되었습니다.");
-	           		save_line_return = true;
-	           	}
-           }else{
-           	alert("등록에 실패하였습니다.");
-           	return false;
-           }
-       },
-       error: function (e) {
-           console.log("ERROR : ", e);
-           alert("등록에 실패하였습니다.");
-       }
-   	});
-   	return save_line_return;
-}
 
-function htmlComfirm(progrmHtmlFileId) {
-   	$.ajax({
-       type: "POST",
-       url: "/sym/mnu/mcm/HtmlComfirmAjax.do",
-       data:{
-			"cntId": progrmHtmlFileId		
-		},
-       dataType:'json',
-       timeout: 600000,
-       success: function (returnData, status) {
-           if(status == 'success'){
-	          console.log("sdfsdf");
-	          window.open("/uss/ion/cnt/cntManageInsert.do?cntId="+returnData.cntManageVO.cntId+"&cntDtId="+returnData.cntManageVO.cntDtId);
-           }else{
-           	 //alert("등록에 실패하였습니다.");
-           	return false;
-           }
-       },
-       error: function (e) {
-           console.log("ERROR : ", e);
-           alert("등록에 실패하였습니다.");
-       }
-   	});
-}
 
-function set_bbs(){
-	var frm = document.menuForm;
-   	var data = new FormData(frm);
-   	$.ajax({
-       type: "POST",
-       url: "/sym/mnu/mcm/MenuBbsSelectAjax.do",
-       data: data,
-       dataType:'json',
-       processData: false,
-       contentType: false,
-       cache: false,
-       timeout: 600000,
-       success: function (returnData, status) {
-           if(status == 'success'){
-	       		for(var i = 0 ; i < returnData.boardMasterList.length ; i++){
-					add_line(returnData.boardMasterList[i]);
-	       		}				
-           }else{
-           	alert("등록에 실패하였습니다.");
-           }
-       },
-       error: function (e) {
-           console.log("ERROR : ", e);
-           alert("등록에 실패하였습니다.");
-       }
-   	});
-   	
-	
-	
-}
+		function onkeyContentName(event){
+			var tempContentUrl = "/web/content.do?proFn=" ;
+			if($("#menuType option:selected").val()=="C"){
+				$("#url").val(tempContentUrl + $("#progrmFileNm").val()) ;
+			}
+		}
 
-</script>
-<title>메뉴관리</title>
+
+
+		//행추가
+		function add_line(bbsInfo){
+			var eva_temp_tr = $('#temp_tr').clone();
+			$('#tbl_bbsId').append(eva_temp_tr);
+			eva_temp_tr.attr('id' , 'tr_bbs').attr('class' , 'tr_item');
+			{ //변수 변경
+				var tr_item_length = $('.tr_item').size()-1 ;
+				eva_temp_tr.find("#temp_bbsTxt").attr('name', eva_temp_tr.find("#temp_bbsTxt").attr('name').replace('[]' , '['+tr_item_length+']' ))   ;
+				eva_temp_tr.find("#temp_bbsTxt").attr('id' , 'bbsTxt_'+tr_item_length) ;
+				eva_temp_tr.find("#temp_bbsIds").attr('name', eva_temp_tr.find("#temp_bbsIds").attr('name').replace('[]' , '['+tr_item_length+']' ))   ;
+				eva_temp_tr.find("#temp_bbsIds").attr('id' , 'menuAdd_'+tr_item_length) ;
+				eva_temp_tr.find("#temp_bbsSorts").attr('name' , eva_temp_tr.find("#temp_bbsSorts").attr('name').replace('[]' , '['+tr_item_length+']' ) ) ;
+				eva_temp_tr.find("#temp_bbsSorts").attr('id' , 'bbsSorts_'+tr_item_length) ;
+				eva_temp_tr.find("#menuAdd").attr('value' ,  'menuAdd_'+tr_item_length ) ;
+			}
+			if(null != bbsInfo){
+				$('#bbsTxt_'+tr_item_length).val(bbsInfo.bbsNm);
+				$('#bbsSorts_'+tr_item_length).val(bbsInfo.bbsSort);
+				$('#menuAdd_'+tr_item_length).val(bbsInfo.bbsId);
+
+			}
+		}
+
+		//삭제시 배열 초기화
+		var arrCd = new Array();
+		function set_count(){  //tr 세팅
+			$('.tr_item').each(function(index, item){
+				$(this).find('input[name^=bbsTxt]').attr('name', 'bbsTxt['+index+']' ).attr('id' , 'bbsTxt_'+index ) ;
+				$(this).find('input[name^=bbsSorts]').attr('name', 'bbsSorts['+index+']' );
+				$(this).find('input[name^=bbsIds]').attr('name', 'bbsIds['+index+']' ).attr('id' , 'menuAdd_'+index ) ;
+				$(this).find('#menuAdd').attr('value' , 'menuAdd_'+index) ;
+			});
+		}
+
+		var arrDel = new Array; //1차배열
+		function delete_line(obj){
+			$(obj).parent().parent().remove();
+			set_count();
+		}
+
+		function save_line() {
+			/* if(0== $('.tr_item').size()){
+                alert("선택된 게시판이 없습니다.");
+                return;
+            } */
+
+			//빈 게시판 방지
+			var blank_tr = false;
+			var blank_sort = false;
+			$('.tr_item').each(function() {
+				if(""==$(this).find('input[name^=bbsTxt]').val()){
+					blank_tr = true;
+				}
+
+				if(""==$(this).find('input[name^=bbsSort]').val()){
+					blank_sort = true;
+				}
+
+			});
+			if(blank_tr) {
+				alert("비어 있는 게시판이 있습니다.");
+				return false;
+			}
+			if(blank_sort) {
+				alert("게시판 순서를 넣어주세요.");
+				return false;
+			}
+
+			var save_line_return = false;
+			var frm = document.menuForm;
+			var data = new FormData(frm);
+			$.ajax({
+				type: "POST",
+				url: "/sym/mnu/mcm/MenuBbsInsertAjax.do",
+				data: data,
+				dataType:'json',
+				processData: false,
+				contentType: false,
+				async: false,
+				cache: false,
+				timeout: 600000,
+				success: function (returnData, status) {
+					if(status == 'success'){
+						if(returnData.status == 'fail'){
+							alert("게시판 등록 실패하였습니다.");
+						}else if(returnData.status == 'auth_fail'){
+							alert("세션이 종료되었습니다.");
+						}else if(returnData.status =='success'){
+							//alert("등록되었습니다.");
+							save_line_return = true;
+						}
+					}else{
+						alert("등록에 실패하였습니다.");
+						return false;
+					}
+				},
+				error: function (e) {
+					console.log("ERROR : ", e);
+					alert("등록에 실패하였습니다.");
+				}
+			});
+			return save_line_return;
+		}
+
+		function htmlComfirm(progrmHtmlFileId) {
+			$.ajax({
+				type: "POST",
+				url: "/sym/mnu/mcm/HtmlComfirmAjax.do",
+				data:{
+					"cntId": progrmHtmlFileId
+				},
+				dataType:'json',
+				timeout: 600000,
+				success: function (returnData, status) {
+					if(status == 'success'){
+						console.log("sdfsdf");
+						window.open("/uss/ion/cnt/cntManageInsert.do?cntId="+returnData.cntManageVO.cntId+"&cntDtId="+returnData.cntManageVO.cntDtId);
+					}else{
+						//alert("등록에 실패하였습니다.");
+						return false;
+					}
+				},
+				error: function (e) {
+					console.log("ERROR : ", e);
+					alert("등록에 실패하였습니다.");
+				}
+			});
+		}
+
+		function set_bbs(){
+			var frm = document.menuForm;
+			var data = new FormData(frm);
+			$.ajax({
+				type: "POST",
+				url: "/sym/mnu/mcm/MenuBbsSelectAjax.do",
+				data: data,
+				dataType:'json',
+				processData: false,
+				contentType: false,
+				cache: false,
+				timeout: 600000,
+				success: function (returnData, status) {
+					if(status == 'success'){
+						for(var i = 0 ; i < returnData.boardMasterList.length ; i++){
+							add_line(returnData.boardMasterList[i]);
+						}
+					}else{
+						alert("등록에 실패하였습니다.");
+					}
+				},
+				error: function (e) {
+					console.log("ERROR : ", e);
+					alert("등록에 실패하였습니다.");
+				}
+			});
+
+
+
+		}
+
+	</script>
+	<title>메뉴관리</title>
 </head>
 <body>
-	<div class="contWrap">
-		<form name="searchForm" method="get" action="<c:url value='/sym/mnu/mcm/EgovMenuCreatSelectJtree.do'/>" >
-			<input name="authorCode" type="hidden" value="ROLE_ADMIN" />
-			<input name="seCd" type="hidden" value="" />
-			<input name="searchNm" type="hidden" value="" />
-		</form>
-		<form name="menuForm" id="menuForm" >
-		
+<div class="contWrap">
+	<form name="searchForm" method="get" action="<c:url value='/sym/mnu/mcm/EgovMenuCreatSelectJtree.do'/>" >
+		<input name="authorCode" type="hidden" value="ROLE_ADMIN" />
+		<input name="seCd" type="hidden" value="" />
+		<input name="searchNm" type="hidden" value="" />
+	</form>
+	<form name="menuForm" id="menuForm" >
+
 		<input type="hidden" id="existChildNode" name="existChildNode" value="N" />
 		<input type="hidden" name="emplyrId" id="emplyrId" /><!-- 담당자ID -->
-		 
+
 		<div class="pageTitle">
 			<div class="pageIcon"><img src="/pb/img/pageTitIcon4.png" alt=""></div>
 			<h2 class="titType1 c_222222 fwBold">메뉴관리</h2>
@@ -812,10 +812,10 @@
 		</div>
 		<div class="pageCont">
 			<div class="selectWrap">
-			    <select name="authorCode" id="authorCode" class="select" onchange="jstreeRefresh();  return false;" title="검색조건선택">
-				   <option value='ROLE_ANONYMOUS' <c:if test="${menuCreatVO.authorCode == 'ROLE_ANONYMOUS' || empty menuCreatVO.authorCode }">selected</c:if>>사용자</option>
-				   <option value='ROLE_ADMIN' <c:if test="${menuCreatVO.authorCode == 'ROLE_ADMIN'  }">selected</c:if>>관리자</option>
-			    </select>
+				<select name="authorCode" id="authorCode" class="select" onchange="jstreeRefresh();  return false;" title="검색조건선택">
+					<option value='ROLE_ANONYMOUS' <c:if test="${menuCreatVO.authorCode == 'ROLE_ANONYMOUS' || empty menuCreatVO.authorCode }">selected</c:if>>사용자</option>
+					<option value='ROLE_ADMIN' <c:if test="${menuCreatVO.authorCode == 'ROLE_ADMIN'  }">selected</c:if>>관리자</option>
+				</select>
 			</div>
 
 			<div class="orgWrap">
@@ -836,48 +836,48 @@
 						<col style="width: 80%">
 					</colgroup>
 					<tbody>
-						<tr>
-							<th><span>메뉴번호</span></th>
-							<td>
-								<div id="select_part">
-									<input type="text" name="menuNo" id="menuNo" />
-									<input type="hidden" id="tmp_Id" name="tmp_Id"/><!-- 이전메뉴 No --> 
-								</div>
-							</td>
-						</tr>
-						<tr>
-							<th><span>메뉴명</span></th>
-							<td>
-								<input type="text" name="menuNm" id="menuNm" />
-								<input type="hidden" id="tmp_Name" name="tmp_Name"/><!-- 이전메뉴 이름 -->
-							</td>
-						</tr>
-						<tr>
-							<th><span>타입</span></th>
-							<td>
-								<select name="menuType" id="menuType" title="" onchange="initShowUrl('N'); return false;">
-				                	<option value="M" <c:if test="${userSearchVO.menuType == 'M'}">selected="selected"</c:if> >메뉴</option>
-				                    <option value="P" <c:if test="${userSearchVO.menuType == 'P'}">selected="selected"</c:if> >프로그램</option>
-				                    <option value="C" <c:if test="${userSearchVO.menuType == 'C'}">selected="selected"</c:if> >HTML컨텐츠</option>
-				                    <option value="B" <c:if test="${userSearchVO.menuType == 'B'}">selected="selected"</c:if> >게시판</option>
-				                    <option value="O" <c:if test="${userSearchVO.menuType == 'O'}">selected="selected"</c:if> >외부링크</option>
-								</select>
-								<span>
-								 
+					<tr>
+						<th><span>메뉴번호</span></th>
+						<td>
+							<div id="select_part">
+								<input type="text" name="menuNo" id="menuNo" />
+								<input type="hidden" id="tmp_Id" name="tmp_Id"/><!-- 이전메뉴 No -->
+							</div>
+						</td>
+					</tr>
+					<tr>
+						<th><span>메뉴명</span></th>
+						<td>
+							<input type="text" name="menuNm" id="menuNm" />
+							<input type="hidden" id="tmp_Name" name="tmp_Name"/><!-- 이전메뉴 이름 -->
+						</td>
+					</tr>
+					<tr>
+						<th><span>타입</span></th>
+						<td>
+							<select name="menuType" id="menuType" title="" onchange="initShowUrl('N'); return false;">
+								<option value="M" <c:if test="${userSearchVO.menuType == 'M'}">selected="selected"</c:if> >메뉴</option>
+								<option value="P" <c:if test="${userSearchVO.menuType == 'P'}">selected="selected"</c:if> >프로그램</option>
+								<option value="C" <c:if test="${userSearchVO.menuType == 'C'}">selected="selected"</c:if> >HTML컨텐츠</option>
+								<option value="B" <c:if test="${userSearchVO.menuType == 'B'}">selected="selected"</c:if> >게시판</option>
+								<option value="O" <c:if test="${userSearchVO.menuType == 'O'}">selected="selected"</c:if> >외부링크</option>
+							</select>
+							<span>
+
 								<a style="display: none;cursor:pointer;" id="btnContent"
-						        	target="_blank" title="새창으로" onclick="javascript:searchContentList(); return false;"
-									style="selector-dummy:expression(this.hideFocus=false);" >
+								   target="_blank" title="새창으로" onclick="javascript:searchContentList(); return false;"
+								   style="selector-dummy:expression(this.hideFocus=false);" >
 						        	<img src="<c:url value='/img/post/serch_img.png' />" alt='컨텐츠ID 검색' width="15" height="15" />
 						        	<span style="vertical-align: middle;">(화면컨텐츠ID 검색)</span>
 						        </a>
 						        <span style="display: none;cursor:pointer;padding-left:30px;vertical-align:middle;" id="htmlComfirm">
 						        	<a href="#" onclick="htmlComfirm();" id="a_contentLink">확인</a>
 						        </span>
-						        
+
 				        		<span id="contentNameSpan" style="color: blue"></span>
-								<a style="display: none;cursor:pointer;" id="btnBBS" 
-						        	target="_blank" title="새창으로" onclick="javascript:searchBBSId(); return false;"
-									style="selector-dummy:expression(this.hideFocus=false);" >
+								<a style="display: none;cursor:pointer;" id="btnBBS"
+								   target="_blank" title="새창으로" onclick="javascript:searchBBSId(); return false;"
+								   style="selector-dummy:expression(this.hideFocus=false);" >
 						        	<img src="<c:url value='/img/post/serch_img.png' />" alt='게시판ID 검색' width="15" height="15" />
 						        	<span style="vertical-align: middle;">(게시판ID 검색)</span>
 						        </a>
@@ -887,82 +887,82 @@
 									URL <input type="text" name="url" id="url"/>
 									<input type="hidden" id="url_tmp" name="url_tmp"/>
 								</span>
-							</td>
-						</tr>
-						<tr>
-							<th><span>상위메뉴번호</span></th>
-							<td>
-								<span id="upperMenuIdText"></span>
-								<input type="hidden" id="upperMenuId" name="upperMenuId"/>
-							</td>
-						</tr>
-						<tr>
-							<th><span>프로그램파일명</span></th>
-							<td>
-								<input type="text" name="progrmFileNm" id="progrmFileNm" readonly="readonly" onkeyup="onkeyContentName(event);" />
-								<input type="hidden" name="progrmHtmlFileId" id="progrmHtmlFileId" />
-								<input type="hidden" name="progrmBbsId" id="progrmBbsId" />
-								<input type="hidden" name="progrmFileNm_tmp" id="progrmFileNm_tmp" />
-							</td>
-						</tr>
-						<tr>
-							<th><span>메뉴경로</span></th>
-							<td>
+						</td>
+					</tr>
+					<tr>
+						<th><span>상위메뉴번호</span></th>
+						<td>
+							<span id="upperMenuIdText"></span>
+							<input type="hidden" id="upperMenuId" name="upperMenuId"/>
+						</td>
+					</tr>
+					<tr>
+						<th><span>프로그램파일명</span></th>
+						<td>
+							<input type="text" name="progrmFileNm" id="progrmFileNm" readonly="readonly" onkeyup="onkeyContentName(event);" />
+							<input type="hidden" name="progrmHtmlFileId" id="progrmHtmlFileId" />
+							<input type="hidden" name="progrmBbsId" id="progrmBbsId" />
+							<input type="hidden" name="progrmFileNm_tmp" id="progrmFileNm_tmp" />
+						</td>
+					</tr>
+					<tr>
+						<th><span>메뉴경로</span></th>
+						<td>
 								<span id="menuCours">
 								</span>
-							</td>
-						</tr>
-						<tr>
-							<th><span>메뉴순서</span></th>
-							<td>
-								<input type="text" name="menuOrdr" id="menuOrdr" />
-							</td>
-						</tr>
-						<tr>
-							<th><span>매뉴노출</span></th>
-							<td>
-								<select name="useYn" id="useYn" title="" >
-				                	<option value="Y" <c:if test="${userSearchVO.useYn == 'Y'}">selected="selected"</c:if> >사용</option>
-				                    <option value="N" <c:if test="${userSearchVO.useYn == 'N'}">selected="selected"</c:if> >미사용</option>
-								</select>
-							</td>
-						</tr>
-						<c:if test="${menuManageVO.authorCode == 'ROLE_ANONYMOUS'}">
+						</td>
+					</tr>
+					<tr>
+						<th><span>메뉴순서</span></th>
+						<td>
+							<input type="text" name="menuOrdr" id="menuOrdr" />
+						</td>
+					</tr>
+					<tr>
+						<th><span>매뉴노출</span></th>
+						<td>
+							<select name="useYn" id="useYn" title="" >
+								<option value="Y" <c:if test="${userSearchVO.useYn == 'Y'}">selected="selected"</c:if> >사용</option>
+								<option value="N" <c:if test="${userSearchVO.useYn == 'N'}">selected="selected"</c:if> >미사용</option>
+							</select>
+						</td>
+					</tr>
+					<c:if test="${menuManageVO.authorCode == 'ROLE_ANONYMOUS'}">
 						<tr id="satisTr">
 							<th><span>만족도 평가</span></th>
 							<td>
 								<select name="satisYn" id="satisYn" title="" >
-				                	<option value="Y" <c:if test="${userSearchVO.satisYn == 'Y'}">selected="selected"</c:if> >사용</option>
-				                    <option value="N" <c:if test="${userSearchVO.satisYn == 'N'}">selected="selected"</c:if> >미사용</option>
+									<option value="Y" <c:if test="${userSearchVO.satisYn == 'Y'}">selected="selected"</c:if> >사용</option>
+									<option value="N" <c:if test="${userSearchVO.satisYn == 'N'}">selected="selected"</c:if> >미사용</option>
 								</select>
 							</td>
 						</tr>
-						</c:if>
-						
-						<%-- <tr>
-							<th><span>담당자</span></th>
-							<td>
-								<input type="text" name="emplyrIdTxt" id="emplyrIdTxt" style="width:4%;" readonly="readonly"/>
-								<a id="btnContent" style="cursor:pointer;"
-						        	target="_blank" title="새창으로" onclick="javascript:searchManageMenuList(); return false;"
-									style="selector-dummy:expression(this.hideFocus=false);" >
-						        	<img src="<c:url value='/img/post/serch_img.png' />" alt='게시판ID 검색' width="15" height="15" />
-						        	<span style="vertical-align: middle;">담당자 검색</span>
-						        </a>
-							</td>
-						</tr> --%>
-						
-						<tr id="tr_add_bbs" style="display:none;">
-							<th><span>추가게시판</span></th>
-							<td>
-								<div class="add_line">
-									<input type="button" value="추가" onclick="add_line();">
-								</div>
-								<table id="tbl_bbsId">
-								</table>
-							</td>
-						</tr>
-						
+					</c:if>
+
+					<%-- <tr>
+                        <th><span>담당자</span></th>
+                        <td>
+                            <input type="text" name="emplyrIdTxt" id="emplyrIdTxt" style="width:4%;" readonly="readonly"/>
+                            <a id="btnContent" style="cursor:pointer;"
+                                target="_blank" title="새창으로" onclick="javascript:searchManageMenuList(); return false;"
+                                style="selector-dummy:expression(this.hideFocus=false);" >
+                                <img src="<c:url value='/img/post/serch_img.png' />" alt='게시판ID 검색' width="15" height="15" />
+                                <span style="vertical-align: middle;">담당자 검색</span>
+                            </a>
+                        </td>
+                    </tr> --%>
+
+					<tr id="tr_add_bbs" style="display:none;">
+						<th><span>추가게시판</span></th>
+						<td>
+							<div class="add_line">
+								<input type="button" value="추가" onclick="add_line();">
+							</div>
+							<table id="tbl_bbsId">
+							</table>
+						</td>
+					</tr>
+
 					</tbody>
 				</table>
 			</div>
@@ -972,22 +972,22 @@
 				
 			</div>
 		</div>
-		</form>
-	</div>
-	
-	<table id="eva_temp_table" style="display:none">
-		<tr id="temp_tr">
-			<td>
-				게시판<input type="text" name="bbsTxt[]" id="temp_bbsTxt" style="width:4%;" readonly="readonly">
-				순서<input type="text" name="bbsSorts[]" id="temp_bbsSorts" style="width:1%;" >
-				<input type="hidden" name="bbsIds[]" id="temp_bbsIds" style="width:4%;" readonly="readonly">
-				<input type="button" value="삭제" onclick="delete_line(this);">
-				<a id="menuAdd" value="bbsIds[]" style="cursor:pointer;" target="_blank" title="새창으로" onclick="javascript:searchBBSId(this); return false;">
-					<img src="/img/post/serch_img.png" alt="게시판ID 검색" width="15" height="15">
-					<span style="vertical-align: middle;">게시판 검색</span>
-				</a>
-			</td>
-		</tr>
-	</table>
+	</form>
+</div>
+
+<table id="eva_temp_table" style="display:none">
+	<tr id="temp_tr">
+		<td>
+			게시판<input type="text" name="bbsTxt[]" id="temp_bbsTxt" style="width:4%;" readonly="readonly">
+			순서<input type="text" name="bbsSorts[]" id="temp_bbsSorts" style="width:1%;" >
+			<input type="hidden" name="bbsIds[]" id="temp_bbsIds" style="width:4%;" readonly="readonly">
+			<input type="button" value="삭제" onclick="delete_line(this);">
+			<a id="menuAdd" value="bbsIds[]" style="cursor:pointer;" target="_blank" title="새창으로" onclick="javascript:searchBBSId(this); return false;">
+				<img src="/img/post/serch_img.png" alt="게시판ID 검색" width="15" height="15">
+				<span style="vertical-align: middle;">게시판 검색</span>
+			</a>
+		</td>
+	</tr>
+</table>
 </body>
 </html>
(No newline at end of file)
 
src/main/webapp/WEB-INF/jsp/sym/site/authValidityTimeMng.jsp (added)
+++ src/main/webapp/WEB-INF/jsp/sym/site/authValidityTimeMng.jsp
@@ -0,0 +1,78 @@
+<%@ page contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="ui" uri="http://egovframework.gov/ctl/ui"%>
+<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
+<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
+<%@ page import="itn.com.cmm.LoginVO"%>
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Language" content="ko">
+
+<title>로그인정책 목록조회</title>
+<script type="text/javaScript" language="javascript" defer="defer">
+function fnUpdate(){
+ let authValidtyTime = $('#selectAuthValidtyTime option:selected').val();
+	$.ajax({
+		url :"/sym/site/sessionTimeUpdateAjax.do"
+		,type:"post"
+		,data:{"sessionTimeCd":authValidtyTime}
+		,dataType:"json"
+		,success:function(data){
+			alert("정상적으로 저장되었습니다.");
+			location.reload();
+		}
+		,error: function(){
+			alert("에러발생");
+		}
+	});
+}
+
+</script>
+</head>
+<body>
+<noscript>자바스크립트를 지원하지 않는 브라우저에서는 일부 기능을 사용하실 수 없습니다.</noscript>
+<form name="listForm" action="<c:url value='/sym/site/selectSiteManagerList.do'/>" method="post">
+	<!-- cont -->
+	<div class="contWrap">
+		<div class="pageTitle">
+			<div class="pageIcon"><img src="/pb/img/pageTitIcon4.png" alt=""></div>
+			<h2 class="titType1 c_222222 fwBold">추가인증 유효시간 관리</h2>
+			<p class="tType6 c_999999">발신번호 추가인증의 유효시간을 설정할 수 있습니다.</p>
+		</div>
+		<div class="pageCont">
+			<div class="tableWrap">
+				<table class="tbType2">
+					<colgroup>
+						<col width="20%">
+						<col width="*">
+					</colgroup>
+					<tbody>
+					<tr>
+						<th>추가인증 유효시간</th>
+						<td>
+							<c:forEach var="result" items="${sessionTimeList}" varStatus="status">
+							<select name="selectAuthValidtyTime" id="selectAuthValidtyTime">
+								<c:forEach var="sessionTimeCdList" items="${sessionTimeCdList}" varStatus="status">
+									<option value="${sessionTimeCdList.code}"
+											<c:if test="${result.sessionTimeCd eq sessionTimeCdList.code}">
+												selected
+											</c:if>>${sessionTimeCdList.codeNm}</option>
+								</c:forEach>
+							</select> ※ 권장 <span style="color: #0000FF;">4~8시간</span> (일과시간 기준)
+							<p class="tType7 c_999999" style="padding-top: 10px;">발신번호별 인증 시각을 기준으로 적용되며, 로그아웃·세션 만료 후 재로그인 시에는 다시 인증해야 합니다.</p>
+							</c:forEach>
+						</td>
+					</tr>
+					</tbody>
+				</table>
+				<div class="btnWrap">
+					<input type="button" class="btnType1" value="수정" onclick="fnUpdate()">
+				</div>
+			</div>
+		</div>
+	</div>
+	<!-- //cont -->
+</form>
+</body>
+</html>(No newline at end of file)
src/main/webapp/WEB-INF/jsp/uss/ion/kakaoat/SendKakaoATModify.jsp
--- src/main/webapp/WEB-INF/jsp/uss/ion/kakaoat/SendKakaoATModify.jsp
+++ src/main/webapp/WEB-INF/jsp/uss/ion/kakaoat/SendKakaoATModify.jsp
@@ -362,9 +362,17 @@
 						</td>
 					</tr>
 					<tr>
+						<th><span class="reqArea">아이디</span></th>
+						<td colspan="3">
+							<a href="#"  onclick="javascript:fnSelectMber('<c:out value="${mjonKakaoATDetailVO.userId}"/>'); return false;">
+								<c:out value="${mjonKakaoATDetailVO.userId}"/>
+							</a>
+						</td>
+					</tr>
+					<tr>
 						<th><span class="reqArea">채널ID</span></th>
 						<td colspan="3">
-							<c:out value="${mjonKakaoATDetailVO.yellowId}"/>
+							<a href="/uss/ion/kakaoat/KakaoATChannelIDList.do" ><c:out value="${mjonKakaoATDetailVO.yellowId}"/></a>
 						</td>
 					</tr>
 						<!-- 알림톡,친구톡 템플릿 상세 팝업 호출 -->
 
src/main/webapp/WEB-INF/jsp/uss/ion/msg/EmpPdfView.jsp (added)
+++ src/main/webapp/WEB-INF/jsp/uss/ion/msg/EmpPdfView.jsp
@@ -0,0 +1,351 @@
+<%@ page contentType="text/html; charset=utf-8" pageEncoding="utf-8" %>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%
+    response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
+    response.setHeader("Pragma", "no-cache");
+    response.setDateHeader("Expires", 0);
+%>
+<!DOCTYPE html>
+<html lang="ko">
+<head>
+    <meta charset="utf-8">
+    <title>종사자 수 인증 증빙서류 미리보기</title>
+    <link rel="stylesheet" href="/pb/css/reset.css">
+    <link rel="stylesheet" href="/pb/css/common.css">
+    <link rel="stylesheet" href="/pb/css/content.css?date=202301160001">
+    <link rel="stylesheet" href="/pb/css/popup.css">
+    <script src="/pb/js/jquery-3.5.0.js"></script>
+    <script src="/js/pdfjs-3.11.174/build/pdf.js"></script>
+    <script>pdfjsLib.GlobalWorkerOptions.workerSrc = '/js/pdfjs-3.11.174/build/pdf.worker.js';</script>
+    <style>html {
+        overflow-x: hidden;
+        overflow-y: auto;
+    }</style>
+</head>
+<body>
+<div class="pageCont" style="text-align: center; width: 1000px;">
+    <div class="listTop" style="float: left; margin-top: 0; padding-top: 0;">
+        <p class="tType5">종사자 수 인증 신청 정보</p>
+    </div>
+    <div class="tableWrap">
+        <table class="tbType1">
+            <colgroup>
+                <col style="width: 18%">
+                <col style="width: 22%">
+                <col style="width: 18%">
+                <col style="width: 14%">
+                <col style="width: 14%">
+                <col style="width: 14%">
+            </colgroup>
+            <thead>
+            <tr>
+                <th>아이디</th>
+                <th>기업명</th>
+                <th>사업자번호</th>
+                <th>대표자</th>
+                <th>신청 종사자 수</th>
+                <th>다운로드</th>
+            </tr>
+            </thead>
+            <tbody>
+            <tr>
+                <td><c:out value="${employeeCertVO.mberId}"/></td>
+                <td><c:out value="${employeeCertVO.mberNm}"/></td>
+                <td><c:out value="${employeeCertVO.bizNo}"/></td>
+                <td><c:out value="${employeeCertVO.managerNm}"/></td>
+                <td><c:out value="${empty employeeCertVO.applyCnt ? '-' : employeeCertVO.applyCnt}"/><c:if
+                        test="${not empty employeeCertVO.applyCnt}">명</c:if>
+                </td>
+                <td>
+                    <c:choose>
+                        <c:when test="${not empty atchFileId}">
+                            <c:import url="/cmm/fms/selectMberFileInfs.do" charEncoding="utf-8">
+                                <c:param name="param_atchFileId" value="${atchFileId}"/>
+                            </c:import>
+                        </c:when>
+                        <c:otherwise>-</c:otherwise>
+                    </c:choose>
+                </td>
+            </tr>
+            </tbody>
+        </table>
+    </div>
+
+    <br><br>
+    <div class="listTop" style="float: left; margin-top: 0; padding-top: 0;">
+        <p class="tType5">승인에 필요한 서류</p>
+    </div>
+    <div class="tableWrap">
+        <table class="tbType1">
+            <colgroup>
+                <col style="width: 75%">
+                <col style="width: 25%">
+            </colgroup>
+            <tbody>
+            <tr>
+                <td class="left" style="padding: 10px 0; line-height: 1.8em;">
+                    법인(기업) : 4대보험 사업장 가입자 명부, 임직원 명부, 조직도 중 1종<br>
+                    ※ 사업장 전체 인원 수를 확인할 수 있어야 하며, 불필요한 개인정보는 마스킹 필요
+                </td>
+                <td style="padding: 10px 0; vertical-align: middle;">
+                    <c:choose>
+                        <c:when test="${employeeCertVO.authYn eq 'N' or employeeCertVO.authYn eq 'H'}">
+                            <button type="button" class="btnType1" style="background-color: #246ee9;"
+                                    onclick="return fnEmployeeCertApprove();">인증완료</button>
+                            <button type="button" class="btnType1" id="btnReject"
+                                    onclick="return fnRejectAreaToggle();">반려 OPEN</button>
+                        </c:when>
+                        <c:when test="${employeeCertVO.authYn eq 'Y'}">인증완료</c:when>
+                        <c:when test="${employeeCertVO.authYn eq 'C'}">반려</c:when>
+                    </c:choose>
+                </td>
+            </tr>
+            </tbody>
+        </table>
+    </div>
+
+    <div id="rejectArea" style="display: none;">
+        <br><br>
+        <div class="listTop" style="float: left; margin-top: 0; padding-top: 0;">
+            <p class="tType5">반려</p>
+        </div>
+        <div class="tableWrap">
+            <form id="employeeCertRejectForm" method="post">
+                <input type="hidden" name="employeeCertHstrySeq"
+                       value="<c:out value='${employeeCertVO.employeeCertHstrySeq}'/>"/>
+                <input type="hidden" name="authYn" value="C"/>
+                <table class="tbType3">
+                    <colgroup>
+                        <col style="width: 15%">
+                        <col style="width: 85%">
+                    </colgroup>
+                    <tbody>
+                    <tr>
+                        <th>반려문구</th>
+                        <td class="left">
+                            <select id="rejectCode" name="rejectCode" style="width: 89%;"
+                                    onchange="fnRejectReasonChange();">
+                                <option value="">선택</option>
+                                <c:forEach var="code" items="${rejectCodeList}">
+                                    <option value="<c:out value='${code.code}'/>"
+                                            data-reason="<c:out value='${code.codeDc}'/>">
+                                        <c:out value="${code.codeNm}"/>
+                                    </option>
+                                </c:forEach>
+                            </select>
+                        </td>
+                    </tr>
+                    <tr>
+                        <th>반려사유</th>
+                        <td class="left">
+                            <textarea id="rejectReason" name="rejectReason" maxlength="1000"
+                                      style="width: 87%; height: 160px;"></textarea>
+                        </td>
+                    </tr>
+                    </tbody>
+                </table>
+                <div class="button_box" style="margin-top: 15px;">
+                    <button type="button" class="btnType btnType20" style="background-color: #246ee9;"
+                            onclick="return fnEmployeeCertReject();">반려</button>
+                    <button type="button" class="btnType btnType20"
+                            onclick="return fnRejectAreaHide();">취소</button>
+                </div>
+            </form>
+        </div>
+    </div>
+
+    <c:if test="${not empty fileList}">
+        <div style="width: 100%; text-align: center; margin: 30px 0;">
+            <c:forEach var="file" items="${fileList}" varStatus="status">
+                <c:set var="buttonClass" value="btnType1"/>
+                <c:if test="${file.fileSn eq fileSn}"><c:set var="buttonClass" value="btnType2"/></c:if>
+                <button type="button"
+                        class="<c:out value='${buttonClass}'/>"
+                        onclick="return fnChangeFile('<c:out value='${file.atchFileId}'/>', '<c:out
+                                value='${file.fileSn}'/>');">
+                    첨부파일 <c:out value="${status.count}"/>
+                </button>
+            </c:forEach>
+        </div>
+    </c:if>
+
+    <c:choose>
+        <c:when test="${empty selectedFile}">
+            <div style="margin: 30px 0; color: red;">미리보기할 첨부파일을 찾을 수 없습니다.</div>
+        </c:when>
+        <c:otherwise>
+            <c:if test="${fileType eq 'etc'}">
+                <div style="width: 100%; text-align: center; margin: 30px 0; color: red;">PDF 뷰어에서 지원하지 않는 형식의 파일입니다.
+                    첨부파일 다운로드 후 확인해 주세요.
+                </div>
+            </c:if>
+            <canvas id="the-canvas"
+                    style="min-width: 600px; max-width: 1000px; margin-top: 25px; margin-bottom: 25px;"></canvas>
+            <div>
+                <button type="button" class="btnType" id="prev">Previous</button>
+                &nbsp;<span>Page: <span id="page_num"></span> / <span id="page_count"></span></span>&nbsp;
+                <button type="button" class="btnType" id="next">Next</button>
+                <a class="btnType"
+                   href="<c:url value='/cmm/fms/FileDown.do'><c:param name='atchFileId' value='${selectedFile.atchFileId}'/><c:param name='fileSn' value='${selectedFile.fileSn}'/></c:url>">다운로드</a>
+                <div style="float: right; margin-right: 10px;">
+                    <button type="button" class="btnType" onclick="window.close();">CLOSE</button>
+                </div>
+            </div>
+        </c:otherwise>
+    </c:choose>
+</div>
+
+<form id="pdfForm" method="post" action="<c:url value='/uss/ion/msg/EmpPdfView.do'/>">
+    <input type="hidden" name="atchFileId" value="<c:out value='${atchFileId}'/>"/>
+    <input type="hidden" name="fileSn" value="<c:out value='${fileSn}'/>"/>
+    <input type="hidden" name="employeeCertHstrySeq" value="<c:out value='${employeeCertHstrySeq}'/>"/>
+</form>
+
+<script>
+    function fnEmployeeCertApprove() {
+        if (!confirm('종사자 수 인증을 완료하시겠습니까?')) return false;
+
+        $.ajax({
+            type: 'POST',
+            url: '/uss/ion/msg/updateEmployeeAuth.do',
+            data: {
+                employeeCertHstrySeq: '<c:out value="${employeeCertVO.employeeCertHstrySeq}"/>',
+                authYn: 'Y'
+            },
+            dataType: 'json',
+            success: function (data) {
+                alert(data.message || (data.success ? '처리되었습니다.' : '처리에 실패했습니다.'));
+                if (data.success) {
+                    if (window.opener && !window.opener.closed) window.opener.location.reload();
+                    window.close();
+                }
+            },
+            error: function () {
+                alert('저장에 실패했습니다.');
+            }
+        });
+        return false;
+    }
+
+    function fnRejectAreaToggle() {
+        if ($('#rejectArea').is(':visible')) return fnRejectAreaHide();
+        $('#rejectArea').show();
+        $('#btnReject').text('반려 CLOSE').removeClass('btnType1').addClass('btnType2');
+        return false;
+    }
+
+    function fnRejectAreaHide() {
+        $('#rejectArea').hide();
+        $('#btnReject').text('반려 OPEN').removeClass('btnType2').addClass('btnType1');
+        return false;
+    }
+
+    function fnRejectReasonChange() {
+        var option = $('#rejectCode option:selected');
+        $('#rejectReason').val(option.data('reason') || '');
+    }
+
+    function fnEmployeeCertReject() {
+        var rejectCode = $('#rejectCode');
+        var rejectReason = $.trim($('#rejectReason').val());
+
+        if (!rejectCode.val()) {
+            alert('반려문구를 선택해 주세요.');
+            rejectCode.focus();
+            return false;
+        }
+        if (!rejectReason) {
+            alert('반려사유를 입력해 주세요.');
+            $('#rejectReason').focus();
+            return false;
+        }
+        if (!confirm('반려하시겠습니까?')) return false;
+
+        $.ajax({
+            type: 'POST',
+            url: '/uss/ion/msg/updateEmployeeAuth.do',
+            data: $('#employeeCertRejectForm').serialize(),
+            dataType: 'json',
+            success: function (data) {
+                alert(data.message || (data.success ? '처리되었습니다.' : '처리에 실패했습니다.'));
+                if (data.success) {
+                    if (window.opener && !window.opener.closed) window.opener.location.reload();
+                    window.close();
+                }
+            },
+            error: function () {
+                alert('저장에 실패했습니다.');
+            }
+        });
+        return false;
+    }
+
+    function fnChangeFile(atchFileId, fileSn) {
+        var form = document.getElementById('pdfForm');
+        form.atchFileId.value = atchFileId;
+        form.fileSn.value = fileSn;
+        form.submit();
+        return false;
+    }
+
+    <c:if test="${not empty selectedFile}">
+    (function () {
+        var pdfDoc = null;
+        var pageNum = 1;
+        var pageRendering = false;
+        var pageNumPending = null;
+        var scale = 1.4;
+        var canvas = document.getElementById('the-canvas');
+        var context = canvas.getContext('2d');
+
+        function renderPage(num) {
+            pageRendering = true;
+            pdfDoc.getPage(num).then(function (page) {
+                var viewport = page.getViewport({scale: scale});
+                canvas.height = viewport.height;
+                canvas.width = viewport.width;
+                return page.render({canvasContext: context, viewport: viewport}).promise;
+            }).then(function () {
+                pageRendering = false;
+                if (pageNumPending !== null) {
+                    renderPage(pageNumPending);
+                    pageNumPending = null;
+                }
+            });
+            document.getElementById('page_num').textContent = num;
+        }
+
+        function queueRenderPage(num) {
+            if (pageRendering) pageNumPending = num;
+            else renderPage(num);
+        }
+
+        document.getElementById('prev').addEventListener('click', function () {
+            if (pageNum <= 1) return;
+            pageNum--;
+            queueRenderPage(pageNum);
+        });
+
+        document.getElementById('next').addEventListener('click', function () {
+            if (pageNum >= pdfDoc.numPages) return;
+            pageNum++;
+            queueRenderPage(pageNum);
+        });
+
+        var url = '${pdfPath}';
+        pdfjsLib.getDocument(url).promise.then(function (loadedPdf) {
+            pdfDoc = loadedPdf;
+            document.getElementById('page_count').textContent = pdfDoc.numPages;
+            renderPage(pageNum);
+        }).catch(function () {
+            // canvas.style.display = 'none';
+            // var message = document.createElement('div');
+            // message.style.cssText = 'margin:30px 0;color:red;';
+            // message.textContent = '파일을 미리 볼 수 없습니다. 다운로드해 확인해 주세요.';
+            // canvas.parentNode.insertBefore(message, canvas);
+        });
+    }());
+    </c:if>
+</script>
+</body>
+</html>
 
src/main/webapp/WEB-INF/jsp/uss/ion/msg/EmployeeCertDetail.jsp (added)
+++ src/main/webapp/WEB-INF/jsp/uss/ion/msg/EmployeeCertDetail.jsp
@@ -0,0 +1,313 @@
+<%@ page contentType="text/html; charset=utf-8" pageEncoding="utf-8" %>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
+<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
+<body>
+<script>
+    $(function () {
+        var rejectMessages = {
+            '02': '[문자온] 종사자 수 인증이 반려되었습니다. 첨부하신 서류로는 사업장 전체 인원 수를 확인할 수 없습니다. 인원이 확인되는 자료를 첨부(문자온 로그인-마이페이지-발신번호 관리-종사자 수 등록)하여 재신청해 주시면 빠른 심사 도와드리겠습니다.',
+            '03': '[문자온] 종사자 수 인증이 반려되었습니다. 첨부하신 서류는 인원 확인 자료로 인정되지 않습니다. “4대보험 사업장 가입자 명부”, “임직원 명부”, “조직도” 중 1종을 첨부(문자온 로그인-마이페이지-발신번호 관리-종사자 수 등록)하여 재신청해 주시면 빠른 심사 도와드리겠습니다.',
+            '04': '[문자온] 종사자 수 인증이 반려되었습니다. 신청하신 종사자 수와 증빙서류상 인원이 일치하지 않습니다. 증빙서류 기준 인원으로 재신청(문자온 로그인-마이페이지-발신번호 관리-종사자 수 등록)해 주시면 빠른 심사 도와드리겠습니다.',
+            '05': '[문자온] 종사자 수 인증이 반려되었습니다. 증빙서류의 사업자번호가 회원정보와 일치하지 않습니다. 가입하신 사업자번호 기준 서류를 첨부하여 재신청해 주시면 빠른 심사 도와드리겠습니다.'
+        };
+
+        toggleRejectArea();
+
+        $('#authYn').on('change', function () {
+            toggleRejectArea();
+        });
+
+        $('#rejectCode').on('change', function () {
+            var rejectCode = $(this).val();
+
+            if (rejectCode === '01') {
+                $('#rejectReason').val('').focus();
+                return;
+            }
+
+            $('#rejectReason').val(rejectMessages[rejectCode] || '');
+        });
+    });
+
+    function toggleRejectArea() {
+        var isReject = $('#authYn').val() === 'C';
+
+        $('#rejectCode').prop('disabled', !isReject);
+        $('#rejectReason').prop('disabled', !isReject);
+
+        if (!isReject) {
+            $('#rejectCode').val('');
+            $('#rejectReason').val('');
+        }
+    }
+
+    function fnEmployeeCertUpdate() {
+        var authYn = $('#authYn').val();
+        var rejectCode = $('#rejectCode').val();
+        var rejectReason = $.trim($('#rejectReason').val());
+
+        if (authYn === 'C') {
+            if (!rejectCode) {
+                alert('반려문구를 선택해 주세요.');
+                $('#rejectCode').focus();
+                return false;
+            }
+
+            if (!rejectReason) {
+                alert('반려사유를 입력해 주세요.');
+                $('#rejectReason').focus();
+                return false;
+            }
+        }
+
+        if (!confirm('심사 내용을 수정하시겠습니까?')) return false;
+
+        $.ajax({
+            type: 'POST',
+            url: '/uss/ion/msg/updateEmployeeAuth.do',
+            data: {
+                employeeCertHstrySeq: "<c:out value='${employeeCertVO.employeeCertHstrySeq}'/>",
+                authYn: authYn,
+                rejectCode: rejectCode,
+                rejectReason: rejectReason
+            },
+            dataType: 'json',
+            success: function (data) {
+                alert(data.message || (data.success ? '처리되었습니다.' : '처리에 실패했습니다.'));
+                if (data.success) location.reload();
+            },
+            error: function () {
+                alert('저장에 실패했습니다.');
+            }
+        });
+
+        return false;
+    }
+</script>
+<div class="contWrap">
+    <div class="pageTitle">
+        <div class="pageIcon"><img src="/pb/img/pageTitIcon4.png" alt=""></div>
+        <h2 class="titType1 c_222222 fwBold">종사자 수 인증 심사 (상세)</h2>
+        <p class="tType6 c_999999">신청 내용과 증빙서류 및 기존 심사 이력을 확인할 수 있습니다.</p>
+    </div>
+    <div class="pageCont">
+        <table class="tbType2">
+            <tbody>
+            <tr>
+                <th>아이디</th>
+                <td><c:out value="${employeeCertVO.mberId}"/></td>
+            </tr>
+            <tr>
+                <th>기업명</th>
+                <td><c:out value="${employeeCertVO.mberNm}"/></td>
+            </tr>
+            <tr>
+                <th>사업자번호</th>
+                <td><c:out value="${employeeCertVO.bizNo}"/></td>
+            </tr>
+            <tr>
+                <th>대표자</th>
+                <td><c:out value="${employeeCertVO.managerNm}"/></td>
+            </tr>
+            <tr>
+                <th>현재 종사자 수</th>
+                <td>
+                    <c:choose>
+                        <c:when test="${empty employeeCertVO.certCnt}">-</c:when>
+                        <c:otherwise><fmt:formatNumber value="${employeeCertVO.certCnt}"
+                                                       pattern="#,###"/>명</c:otherwise>
+                    </c:choose>
+                </td>
+            </tr>
+            <tr>
+                <th>신청 종사자 수</th>
+                <td><fmt:formatNumber value="${employeeCertVO.applyCnt}" pattern="#,###"/>명</td>
+            </tr>
+            <tr>
+                <th>심사상태</th>
+                <td>
+                    <select name="authYn" id="authYn">
+                        <option value="Y" <c:if test="${employeeCertVO.authYn eq 'Y'}">selected</c:if>>인증완료</option>
+                        <option value="C" <c:if test="${employeeCertVO.authYn eq 'C'}">selected</c:if>>반려</option>
+                    </select>
+                </td>
+            </tr>
+            <tr>
+                <th>반려문구</th>
+                <td>
+                    <select name="rejectCode" id="rejectCode" style="width: 20%">
+                        <option value="01" <c:if test="${employeeCertVO.rejectCode eq '01'}">selected</c:if>>직접입력</option>
+                        <option value="02" <c:if test="${employeeCertVO.rejectCode eq '02'}">selected</c:if>>종사자 수 확인
+                            불가
+                        </option>
+                        <option value="03" <c:if test="${employeeCertVO.rejectCode eq '03'}">selected</c:if>>증빙서류 유형
+                            부적합
+                        </option>
+                        <option value="04" <c:if test="${employeeCertVO.rejectCode eq '04'}">selected</c:if>>신청 인원/증빙
+                            불일치
+                        </option>
+                        <option value="05" <c:if test="${employeeCertVO.rejectCode eq '05'}">selected</c:if>>사업자번호 불일치
+                        </option>
+                    </select>
+                </td>
+            </tr>
+            <tr>
+                <th>반려사유</th>
+                <td>
+                    <textarea style="width: 84% ; height: 250px" id="rejectReason" name="rejectReason"><c:out
+                            value="${employeeCertVO.rejectReason}"/></textarea>
+                </td>
+            </tr>
+
+            <tr>
+                <th>첨부파일</th>
+                <td class="upload_area">
+                    <div class="file_upload_box no_img_box fileWrap">
+                        <table>
+                            <colgroup>
+                                <col style="width:60%">
+                                <col style="width:10%">
+                                <col style="width:20%">
+                                <col style="width:10%">
+                            </colgroup>
+                            <thead>
+                            <tr>
+                                <th>파일명</th>
+                                <th>크기</th>
+                                <th>등록일시</th>
+                                <th>삭제</th>
+                            </tr>
+                            </thead>
+                        </table>
+                    </div>
+                    <div class="fileWrap fileAfter file_list_div">
+                        <table>
+                            <colgroup>
+                                <col style="width:60%">
+                                <col style="width:20%">
+                                <col style="width:20%">
+                            </colgroup>
+                            <thead>
+                            <tr>
+                                <th>파일명</th>
+                                <th>크기</th>
+                                <th>등록일시</th>
+                            </tr>
+                            </thead>
+                            <tbody id="tbody_fiielist">
+                            <c:if test="${not empty fileList}">
+                                <c:forEach var="file" items="${fileList}">
+                                    <tr class="item_${file.atchFileId}_${file.fileSn} uploaded_obj">
+                                        <input type="hidden" name="fileSize" class="item_file_size"
+                                               value="<c:out value='${file.fileMg}'/>"/>
+                                        <td class="file_name">
+                                            <img src="/direct/img/upload_hwp_img.png" alt=""/>
+                                            <a href="/cmm/fms/FileDown.do?atchFileId=${file.atchFileId}&amp;fileSn=${file.fileSn}">
+                                                <span class="file_name_text"><c:out
+                                                        value="${file.orignlFileNm}"/></span>
+                                            </a>
+                                        </td>
+                                        <td>
+                                            <span class="file_size_text" value="<c:out value='${file.fileMg}'/>"></span>
+                                        </td>
+                                        <td>
+                                            <c:out value="${file.creatDt}"/>
+                                        </td>
+                                    </tr>
+                                </c:forEach>
+                            </c:if>
+                            </tbody>
+                        </table>
+                    </div>
+                    <div class="fileInfo file_list_div">
+                        <ul class="inline">
+                            <li>
+                                <p>최대 <span class="c_e40000 fwBold limitcount_li">5</span>개 | <span
+                                        class="c_e40000 fwBold upload_number">50MB</span>제한</p>
+                            </li>
+                            <li>
+                                <p><span class="c_456ded fwBold totalfileCount">1</span>개 | <span
+                                        class="c_456ded fwBold totalfileSize">72.01KB</span></p>
+                            </li>
+                        </ul>
+                    </div>
+                </td>
+            </tr>
+
+            <tr>
+                <th>수집ㆍ이용ㆍ동의</th>
+                <td><c:out value="${employeeCertVO.agreePnttm}"/></td>
+            </tr>
+            <tr>
+                <th>신청일시</th>
+                <td><c:out value="${employeeCertVO.frstRegistPnttm}"/></td>
+            </tr>
+            <tr>
+                <th>관리자 / 처리일시</th>
+                <td><c:out value="${employeeCertVO.lastUpdusrNm}"/> / <c:out
+                        value="${employeeCertVO.lastUpdtPnttm}"/></td>
+            </tr>
+            <tr>
+                <th>심사 이력</th>
+                <td>
+                    <div class="tableWrap">
+                        <table class="tbType1">
+                            <colgroup>
+                                <col style="width:20%">
+                                <col style="width:12%">
+                                <col style="width:12%">
+                                <col style="width:18%">
+                                <col style="width:20%">
+                                <col style="width:14%">
+                            </colgroup>
+                            <thead>
+                            <tr>
+                                <th style="text-align: center">신청일시</th>
+                                <th style="text-align: center">신청 인원</th>
+                                <th style="text-align: center">처리결과</th>
+                                <th style="text-align: center">관리자</th>
+                                <th style="text-align: center">처리일시</th>
+                                <th style="text-align: center">사유</th>
+                            </tr>
+                            </thead>
+                            <tbody>
+                            <c:forEach var="history" items="${historyList}">
+                                <tr>
+                                    <td style="padding: 20px 25px;"><c:out value="${history.frstRegistPnttm}"/></td>
+                                    <td style="padding: 20px 25px;"><fmt:formatNumber value="${history.applyCnt}"
+                                                                                      pattern="#,###"/>명
+                                    </td>
+                                    <td style="padding: 20px 25px;"><c:out value="${history.authYnTxt}"/></td>
+                                    <td style="padding: 20px 25px;"><c:out value="${history.lastUpdusrNm}"/></td>
+                                    <td style="padding: 20px 25px;"><c:out value="${history.lastUpdtPnttm}"/></td>
+                                    <td style="padding: 20px 25px;" title="<c:out value='${history.rejectReason}'/>">
+                                        <c:out value="${history.rejectReason}"/></td>
+                                </tr>
+                            </c:forEach>
+                            <c:if test="${empty historyList}">
+                                <tr>
+                                    <td colspan="6"><spring:message code="common.nodata.msg"/></td>
+                                </tr>
+                            </c:if>
+                            </tbody>
+                        </table>
+                    </div>
+                </td>
+            </tr>
+            </tbody>
+            <colgroup>
+                <col style="width:20%">
+                <col style="width:80%">
+            </colgroup>
+        </table>
+
+        <div class="btnWrap">
+            <input type="button" class="btnType1 bg_888888" value="목 록"
+                   onclick="location.href='/uss/ion/msg/EmployeeCertList.do'; return false;">
+            <input type="button" class="btnType1" value="수 정"
+                   onclick="fnEmployeeCertUpdate(); return false;">
+        </div>
+    </div>
+</div>
+</body>
 
src/main/webapp/WEB-INF/jsp/uss/ion/msg/EmployeeCertList.jsp (added)
+++ src/main/webapp/WEB-INF/jsp/uss/ion/msg/EmployeeCertList.jsp
@@ -0,0 +1,44 @@
+<%@ page contentType="text/html; charset=utf-8"%>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="ui" uri="http://egovframework.gov/ctl/ui"%>
+<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>
+<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
+<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
+<%@ taglib prefix="ec" uri="/WEB-INF/tld/ecnet_tld.tld"%>
+<body>
+<%@ include file="include/employee/list/_context.jspf"%>
+<form name="listForm" action="<c:url value='/uss/ion/msg/EmployeeCertList.do'/>" method="post">
+	<input type="hidden" name="delFlag" value="Y" />
+	<input type="hidden" name="pageType" />
+	<input type="hidden" name="pageIndex" value="<c:out value='${searchVO.pageIndex}'/>" />
+	<input type="hidden" name="searchSortCnd" value="<c:out value="${searchVO.searchSortCnd}" />" />
+	<input type="hidden" name="searchSortOrd" value="<c:out value="${searchVO.searchSortOrd}" />" />
+	<div class="contWrap">
+		<div class="pageTitle">
+			<div class="pageIcon"><img src="/pb/img/pageTitIcon4.png" alt=""></div>
+			<h2 class="titType1 c_222222 fwBold">종사자 수 인증 심사</h2>
+			<p class="tType6 c_999999">기업회원이 신청한 종사자 수 인증을 심사할 수 있습니다.</p>
+		</div>
+		<div class="pageCont">
+			<%@include file="include/employee/list/_search.jspf"%>
+			<%@include file="include/employee/list/_table.jspf"%>
+			<%@include file="include/employee/list/_paging.jspf"%>
+		</div>
+	</div>
+</form>
+
+<form name="modiForm" id="modiForm" method="post">
+	<input name="mberId" type="hidden" />
+</form>
+
+<form name="popupForm" id="popupForm" method="post">
+	<input name="phmId" type="hidden" />
+</form>
+
+<form name="empPdfForm" method="post">
+	<input name="atchFileId" type="hidden" />
+	<input name="fileSn" type="hidden" />
+	<input name="employeeCertHstrySeq" type="hidden" />
+</form>
+
+</body>
 
src/main/webapp/WEB-INF/jsp/uss/ion/msg/EmployeeCertRejectPop.jsp (added)
+++ src/main/webapp/WEB-INF/jsp/uss/ion/msg/EmployeeCertRejectPop.jsp
@@ -0,0 +1,101 @@
+<%@ page contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<!DOCTYPE html>
+<html lang="ko">
+<head>
+    <meta charset="utf-8">
+    <title>종사자 수 인증 반려</title>
+    <link rel="stylesheet" href="/publish/testcss/css/reset.css">
+    <link rel="stylesheet" href="/publish/testcss/css/font.css">
+    <link rel="stylesheet" href="/publish/testcss/css/sample.css">
+    <script src="/publish/js/jquery-3.5.0.js"></script>
+    <script>
+        function fnRejectReasonChange() {
+            var option = document.querySelector("#rejectCode option:checked");
+            document.getElementById("rejectReason").value = option ? option.getAttribute("data-reason") || "" : "";
+        }
+
+        function fnEmployeeCertReject() {
+            var rejectCode = document.getElementById("rejectCode");
+            var rejectReason = document.getElementById("rejectReason");
+            if (!rejectCode.value) {
+                alert("반려문구를 선택해 주세요.");
+                rejectCode.focus();
+                return;
+            }
+            if (!rejectReason.value.trim()) {
+                alert("반려사유를 입력해 주세요.");
+                rejectReason.focus();
+                return;
+            }
+            if (!confirm("반려하시겠습니까?")) return;
+
+            $.ajax({
+                type: "POST",
+                url: "/uss/ion/msg/updateEmployeeAuth.do",
+                data: $("#employeeCertRejectForm").serialize(),
+                dataType: "json",
+                success: function(data) {
+                    alert(data.message || (data.success ? "처리되었습니다." : "처리에 실패했습니다."));
+                    if (data.success) {
+                        if (window.opener && !window.opener.closed) window.opener.location.reload();
+                        window.close();
+                    }
+                },
+                error: function() {
+                    alert("저장에 실패했습니다.");
+                }
+            });
+        }
+    </script>
+</head>
+<body>
+<form id="employeeCertRejectForm" method="post">
+    <input type="hidden" name="employeeCertHstrySeq" value="<c:out value='${employeeCertVO.employeeCertHstrySeq}'/>"/>
+    <input type="hidden" name="authYn" value="C"/>
+    <div class="layer_popup active" style="width:90%">
+        <div class="layer_content" style="padding:0;">
+            <table>
+                <colgroup>
+                    <col style="width:100px;">
+                    <col style="width:auto;">
+                </colgroup>
+                <tbody>
+                <tr>
+                    <th>반려문구</th>
+                    <td>
+                        <c:choose>
+                            <c:when test="${employeeCertVO.authYn eq 'N' or employeeCertVO.authYn eq 'H'}">
+                                <select id="rejectCode" name="rejectCode" onchange="fnRejectReasonChange();">
+                                    <option value="">선택</option>
+                                    <c:forEach var="code" items="${rejectCodeList}">
+                                        <option value="<c:out value='${code.code}'/>" data-reason="<c:out value='${code.codeDc}'/>">
+                                            <c:out value="${code.codeNm}"/>
+                                        </option>
+                                    </c:forEach>
+                                </select>
+                            </c:when>
+                            <c:otherwise><c:out value="${employeeCertVO.rejectCodeTxt}"/></c:otherwise>
+                        </c:choose>
+                    </td>
+                </tr>
+                <tr>
+                    <th>반려사유</th>
+                    <td>
+                        <textarea id="rejectReason" name="rejectReason" maxlength="1000" style="height:130px"
+                                  <c:if test="${employeeCertVO.authYn eq 'C'}">readonly="readonly"</c:if>><c:out value="${employeeCertVO.rejectReason}"/></textarea>
+                    </td>
+                </tr>
+                </tbody>
+            </table>
+            <div class="button_box">
+                <c:if test="${employeeCertVO.authYn eq 'N' or employeeCertVO.authYn eq 'H'}">
+                    <button type="button" onclick="fnEmployeeCertReject();">반려</button>
+                </c:if>
+                <button type="button" style="color:#8595b0;border:1px solid #8595b0;background:#fff;" onclick="window.close();">취소</button>
+            </div>
+        </div>
+    </div>
+</form>
+</body>
+</html>
src/main/webapp/WEB-INF/jsp/uss/ion/msg/SendMsgList.jsp
--- src/main/webapp/WEB-INF/jsp/uss/ion/msg/SendMsgList.jsp
+++ src/main/webapp/WEB-INF/jsp/uss/ion/msg/SendMsgList.jsp
@@ -753,7 +753,7 @@
 									<c:otherwise>
 										<span style="color: #0000FF;">
 											<c:out value="${result.msgGroupCnt}"/>(<fmt:formatNumber value="${(result.successCount / result.msgGroupCnt) * 100}" pattern="#,###" />%)
-											<c:if test="${result.msgGroupCnt eq result.callRejectionCount && result.callbackYn eq 'N' && result.userCallbackYn eq 'N' }">
+											<c:if test="${ result.callbackYn eq 'N' && result.userCallbackYn eq 'N' }">
 					                			<input type="button" style="margin-left:3px;margin-right:0;vertical-align:top;color:#ffffff !important;" class="btnType1" onclick="fn_sendMsgData('<c:out value="${result.msgGroupId}"/>','<c:out value="${result.callFrom}"/>','<c:out value="${result.userId}"/>');" value="문자" />	
 						                	</c:if>
 											<c:if test="${result.callbackYn eq 'Y' }">
 
src/main/webapp/WEB-INF/jsp/uss/ion/msg/include/employee/list/_action.jspx (added)
+++ src/main/webapp/WEB-INF/jsp/uss/ion/msg/include/employee/list/_action.jspx
@@ -0,0 +1,4 @@
+<div class="btnWrap">
+  <input type="button" class="btnType2" value="삭제" onclick="fn_delete(); return false;"/>
+  <input type="button" class="btnType1" value="등록" onclick="location.href='/uss/ion/msg/SendNumberModify.do'; return false;" value="등록" />
+</div>
 
src/main/webapp/WEB-INF/jsp/uss/ion/msg/include/employee/list/_context.jspf (added)
+++ src/main/webapp/WEB-INF/jsp/uss/ion/msg/include/employee/list/_context.jspf
@@ -0,0 +1,90 @@
+<%@ page pageEncoding="UTF-8" %>
+<script>
+    function linkPage(pageNo){
+        var listForm = document.listForm ;
+        listForm.pageIndex.value = pageNo ;
+        listForm.submit();
+    }
+
+    function fnSelectMber(mberId) {
+        document.modiForm.mberId.value = mberId;
+        window.open("about:blank", 'popupSelectMber', 'width=900, height=1800, top=100, left=100, fullscreen=no, menubar=no, status=no, toolbar=no, titlebar=yes, location=no, scrollbar=no');
+        document.modiForm.action = "<c:url value='/uss/umt/user/EgovGnrlselectedUserView.do'/>";
+        document.modiForm.target = "popupSelectMber";
+        document.modiForm.submit();
+    }
+
+    function fn_employeeCertApprove(employeeCertHstrySeq) {
+        if (!confirm("종사자 수 인증을 완료하시겠습니까?")) return false;
+        $.ajax({
+            type: "POST",
+            url: "/uss/ion/msg/updateEmployeeAuth.do",
+            data: {
+                employeeCertHstrySeq: employeeCertHstrySeq,
+                authYn: "Y"
+            },
+            dataType: "json",
+            success: function(data) {
+                alert(data.message || (data.success ? "처리되었습니다." : "처리에 실패했습니다."));
+                if (data.success) location.reload();
+            },
+            error: function() {
+                alert("저장에 실패했습니다.");
+            }
+        });
+        return false;
+    }
+
+    function fn_employeeCertReject(employeeCertHstrySeq) {
+        return fn_employeeCertRejectPopup(employeeCertHstrySeq);
+    }
+
+    function fn_employeeCertRejectReason(employeeCertHstrySeq) {
+        return fn_employeeCertRejectPopup(employeeCertHstrySeq);
+    }
+
+    function fn_employeeCertRejectPopup(employeeCertHstrySeq) {
+        var url = "/uss/ion/msg/EmployeeCertRejectPop.do?employeeCertHstrySeq=" + encodeURIComponent(employeeCertHstrySeq);
+        window.open(url, 'employeeCertRejectPop', 'width=600, height=310, top=400, left=650, fullscreen=no, menubar=no, status=no, toolbar=no, titlebar=yes, location=no, scrollbar=no');
+        return false;
+    }
+
+    function fn_empPdfView(atchFileId, employeeCertHstrySeq) {
+        var form = document.empPdfForm;
+        form.atchFileId.value = atchFileId;
+        form.fileSn.value = 0;
+        form.employeeCertHstrySeq.value = employeeCertHstrySeq;
+
+        window.open("about:blank", "empPdfViewPopup", "width=1020,height=800,top=100,left=0,fullscreen=no,menubar=no,status=no,toolbar=no,titlebar=no,location=no,scrollbars=no");
+        form.action = "<c:url value='/uss/ion/msg/EmpPdfView.do'/>";
+        form.target = "empPdfViewPopup";
+        form.submit();
+        return false;
+    }
+    //
+    // $("#rejectCode").on("change", function() {
+    //     var rejectCode = $(this).val();
+    //     var rejectReason = getRejectReasonText(rejectCode);
+    //     $("#rejectReason").val(rejectReason);
+    // });
+    //
+    // function getRejectReasonText(rejectCode) {
+    //     switch (rejectCode) {
+    //         case "01":
+    //             return "";
+    //         case "02":
+    //             return "[문자온] 종사자 수 인증이 반려되었습니다. 첨부하신 서류로는 사업장 전체 인원 수를 확인할 수 없습니다. 인원이 확인되는 자료를 첨부하여 재신청해 주세요.";
+    //
+    //         case "03":
+    //             return "[문자온] 종사자 수 인증이 반려되었습니다. 첨부하신 서류는 인원 확인 자료로 인정되지 않습니다. 인정 가능한 증빙서류를 첨부하여 재신청해 주세요.";
+    //
+    //         case "04":
+    //             return "[문자온] 종사자 수 인증이 반려되었습니다. 신청하신 종사자 수와 증빙서류상 인원이 일치하지 않습니다. 증빙서류 기준 인원으로 재신청해 주세요.";
+    //
+    //         case "05":
+    //             return "[문자온] 종사자 수 인증이 반려되었습니다. 증빙서류의 사업자번호가 회원정보와 일치하지 않습니다. 가입하신 사업자번호 기준 서류를 첨부하여 재신청해 주세요.";
+    //         default:
+    //             return "";
+    //     }
+    // }
+</script>
 
src/main/webapp/WEB-INF/jsp/uss/ion/msg/include/employee/list/_paging.jspf (added)
+++ src/main/webapp/WEB-INF/jsp/uss/ion/msg/include/employee/list/_paging.jspf
@@ -0,0 +1,9 @@
+<%@ page pageEncoding="UTF-8" %>
+<div class="btnWrap"></div>
+<c:if test="${!empty resultList}">
+    <div class="page">
+        <ul class="inline">
+            <ui:pagination paginationInfo = "${paginationInfo}"  type="image" jsFunction="linkPage" />
+        </ul>
+    </div>
+</c:if>(No newline at end of file)
 
src/main/webapp/WEB-INF/jsp/uss/ion/msg/include/employee/list/_search.jspf (added)
+++ src/main/webapp/WEB-INF/jsp/uss/ion/msg/include/employee/list/_search.jspf
@@ -0,0 +1,59 @@
+<%@ page pageEncoding="UTF-8" %>
+<div class="listSerch">
+    <div class="calendar_wrap">
+        <select name="setCalMonth" onchange="fnSetCalMonth(this.value)">
+            <option value="0">전체</option>
+            <option value="1">1개월</option>
+            <option value="3">3개월</option>
+            <option value="6">6개월</option>
+        </select>
+        <input type="hidden" name="cal_url" id="cal_url" value="/sym/cmm/EgovNormalCalPopup.do">
+        <div class="calendar_box"
+             onclick="javascript:fn_egov_NormalCalendar(document.forms.listForm, document.forms.listForm.searchStartDate);">
+            <input style="width:auto;min-width: 83px;" type="text" class="date_format" name="searchStartDate"
+                   id="searchStartDate" size="4" maxlength="4" readonly=""
+                   value="<c:out value='${searchVO.searchStartDate}'/>">
+            <input type="button" class="calBtn">
+        </div>
+        <span class="line">~</span>
+        <div class="calendar_box"
+             onclick="javascript:fn_egov_NormalCalendar(document.forms.listForm, document.forms.listForm.searchEndDate);">
+            <input style="width:auto;min-width: 83px;" type="text" class="date_format" name="searchEndDate"
+                   id="searchEndDate" size="4" maxlength="4" readonly=""
+                   value="<c:out value='${searchVO.searchEndDate}'/>">
+            <input type="button" class="calBtn">
+        </div>
+    </div>
+    <br/><br/>
+    <!-- <br /><br />
+    <div style="width: 100%; height: 3px;"></div> -->
+    <select name="searchCondition2" class="select" title="검색조건 선택">
+        <option value="" <c:if test="${searchVO.searchCondition2 == ''}">selected="selected"</c:if>>심사상태(전체)</option>
+        <option value="N" <c:if test="${searchVO.searchCondition2 == 'N'}">selected="selected"</c:if>>심사중</option>
+        <option value="Y" <c:if test="${searchVO.searchCondition2 == 'Y'}">selected="selected"</c:if>>인증완료</option>
+        <option value="C" <c:if test="${searchVO.searchCondition2 == 'C'}">selected="selected"</c:if>>반려</option>
+    </select>
+    <select name="searchCondition" class="select" title="검색조건 선택">
+        <option value="" <c:if test="${searchVO.searchCondition == ''}">selected="selected"</c:if>>전체</option>
+        <option value="1" <c:if test="${searchVO.searchCondition == '1'}">selected="selected"</c:if>>사용자ID</option>
+        <option value="2" <c:if test="${searchVO.searchCondition == '2'}">selected="selected"</c:if>>기업명</option>
+        <option value="3" <c:if test="${searchVO.searchCondition == '3'}">selected="selected"</c:if>>사업자번호</option>
+    </select>
+    <input id="searchKeyword" name="searchKeyword" class="recentSearch" type="text"
+           value="<c:out value='${searchVO.searchKeyword}'/>" size="15" title="검색" maxlength="100"/>
+    <input type="button" class="btnType1" value="검색" onclick="fn_search(); return false;">
+    <input type="button" class="btnType1" onclick="fn_searchReset(); return false;" value="초기화">
+</div>
+<div class="listTop">
+    <p class="tType5">총 <span class="tType4 c_456ded fwBold"><fmt:formatNumber
+            value="${paginationInfo.totalRecordCount}" pattern="#,###"/></span>건</p>
+    <div class="rightWrap">
+        <select name="pageUnit" id="pageUnit" class="select" title="검색조건선택" onchange="linkPage(1);">
+            <option value='10' <c:if test="${searchVO.pageUnit == '10' or searchVO.pageUnit == ''}">selected</c:if>>
+                10줄
+            </option>
+            <option value='20' <c:if test="${searchVO.pageUnit == '20'}">selected</c:if>>20줄</option>
+            <option value='30' <c:if test="${searchVO.pageUnit == '30'}">selected</c:if>>30줄</option>
+        </select>
+    </div>
+</div>
 
src/main/webapp/WEB-INF/jsp/uss/ion/msg/include/employee/list/_table.jspf (added)
+++ src/main/webapp/WEB-INF/jsp/uss/ion/msg/include/employee/list/_table.jspf
@@ -0,0 +1,121 @@
+<%@ page pageEncoding="UTF-8" %>
+<div class="tableWrap">
+    <table class="tbType1">
+        <colgroup>
+            <col style="width: 5%">
+            <col style="width: 8%">
+            <col style="width: 13%">
+            <col style="width: 10%">
+            <col style="width: 7%">
+            <col style="width: 7%">
+            <col style="width: 7%">
+            <col style="width: 7%">
+            <col style="width: 8%">
+            <col style="width: 2%">
+            <col style="width: 7%">
+            <col style="width: 9%">
+            <col style="width: 12%">
+            <col style="width: 12%">
+        </colgroup>
+        <thead>
+        <tr>
+            <th>번호</th>
+            <th>아이디</th>
+            <th>기업명</th>
+            <th>사업자번호</th>
+            <th>대표자</th>
+            <th>현재<br>종사자 수</th>
+            <th>신청<br>종사자 수</th>
+            <th>심사상태</th>
+            <th>첨부파일</th>
+            <th></th>
+            <th>관리자</th>
+            <th>관리</th>
+            <th>신청일시</th>
+            <th>처리일시</th>
+        </tr>
+        </thead>
+        <tbody>
+        <c:forEach var="result" items="${resultList}" varStatus="status">
+        <tr>
+            <td>
+                <c:out value="${paginationInfo.totalRecordCount - ((paginationInfo.currentPageNo - 1) * paginationInfo.recordCountPerPage) - status.index}"/>
+            </td>
+            <td title="<c:out value='${result.mberId}'/>">
+                <a href="#"  onclick="javascript:fnSelectMber('<c:out value="${result.mberId}"/>'); return false;">
+                    <c:out value="${result.mberId}"/>
+                </a>
+            </td>
+            <td class="tl" title="<c:out value='${result.mberNm}'/>">
+                <a href="/uss/ion/msg/EmployeeCertDetail.do?employeeCertHstrySeq=<c:out value='${result.employeeCertHstrySeq}'/>">
+                    <c:out value="${result.mberNm}"/>
+                </a>
+            </td>
+            <td title="<c:out value='${result.bizNo}'/>">
+                <a href="/uss/ion/msg/EmployeeCertDetail.do?employeeCertHstrySeq=<c:out value='${result.employeeCertHstrySeq}'/>">
+                    <c:out value="${result.bizNo}"/>
+                </a>
+            </td>
+            <td><c:out value="${result.managerNm}"/></td>
+            <td>${empty result.certCnt ? '-' : result.certCnt += '명'}</td>
+            <td>${empty result.applyCnt ? '-' : result.applyCnt += '명'}</td>
+            <td>
+                <c:choose>
+                        <c:when test="${result.authYn eq 'N' or result.authYn eq 'H'}">심사중</c:when>
+                        <c:when test="${result.authYn eq 'Y'}">인증완료</c:when>
+                        <c:when test="${result.authYn eq 'C'}">반려</c:when>
+                        <c:otherwise>-</c:otherwise>
+                </c:choose>
+            </td>
+            <td class="brRm">
+                <c:choose>
+                    <c:when test="${not empty result.atchFileId}">
+                        <c:import url="/cmm/fms/selectAddrAgencyFileInfs.do" charEncoding="utf-8">
+                            <c:param name="param_atchFileId" value="${result.atchFileId}"/>
+                        </c:import>
+                    </td>
+                    <td>
+                        <a href="#" onclick="fn_empPdfView('<c:out value='${result.atchFileId}'/>', '<c:out value='${result.employeeCertHstrySeq}'/>'); return false;">
+                            <img src="/publish/images/content/file_view.png" style="vertical-align:middle;" alt="미리보기"/>
+                        </a>
+
+                    </c:when>
+                    <c:otherwise>-</c:otherwise>
+                </c:choose>
+            </td>
+            <td>
+                <c:choose>
+                    <c:when test="${empty result.lastUpdusrNm}">-</c:when>
+                    <c:otherwise><c:out value="${result.lastUpdusrNm}"/></c:otherwise>
+                </c:choose>
+            </td>
+            <td>
+                <c:choose>
+                    <c:when test="${result.authYn eq 'N' or result.authYn eq 'H'}">
+                        <button type="button" class="btnType btnType20" onclick="fn_employeeCertApprove('<c:out value='${result.employeeCertHstrySeq}'/>'); return false;" style="padding:0 5px;">인증완료</button>
+                        <button type="button" class="btnType btnType20" onclick="fn_employeeCertReject('<c:out value='${result.employeeCertHstrySeq}'/>'); return false;" style="padding:0 5px;">반려</button>
+                    </c:when>
+                    <c:when test="${result.authYn eq 'C'}">
+                        <button type="button" class="btnType btnType20" onclick="fn_employeeCertRejectReason('<c:out value='${result.employeeCertHstrySeq}'/>'); return false;" style="padding:0 5px;">반려사유</button>
+                    </c:when>
+                    <c:otherwise>-</c:otherwise>
+                </c:choose>
+            </td>
+            <td><c:out value="${result.frstRegistPnttm}"/></td>
+            <td>
+                <c:choose>
+                    <c:when test="${result.authYn eq 'N' or result.authYn eq 'H'}">-</c:when>
+                    <c:when test="${empty result.lastUpdtPnttm}">-</c:when>
+                    <c:otherwise><c:out value="${result.lastUpdtPnttm}"/></c:otherwise>
+                </c:choose>
+            </td>
+        </tr>
+            </c:forEach>
+        <c:if test="${empty resultList}">
+            <tr>
+                <td colspan="13"><spring:message code="common.nodata.msg"/></td>
+            </tr>
+        </c:if>
+        </tbody>
+    </table>
+</div>
 
src/main/webapp/WEB-INF/jsp/uss/olp/hpc/ForeignAccessBlockList.jsp (added)
+++ src/main/webapp/WEB-INF/jsp/uss/olp/hpc/ForeignAccessBlockList.jsp
@@ -0,0 +1,291 @@
+<%@ page contentType="text/html; charset=utf-8"%>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="ui" uri="http://egovframework.gov/ctl/ui"%>
+<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>
+<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
+<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
+<%@ taglib prefix="ec" uri="/WEB-INF/tld/ecnet_tld.tld"%>
+<%
+	response.setHeader("Cache-Control","no-store");
+	response.setHeader("Pragma","no-cache");
+	response.setDateHeader("Expires",0);
+	if (request.getProtocol().equals("HTTP/1.1")) response.setHeader("Cache-Control", "no-cache");
+%>
+<!DOCTYPE html>
+<html lang="ko">
+<head>
+<title>운영관리 > 국외접속 차단</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" >
+<meta http-equiv="content-language" content="ko">
+<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@300;400;500;700&display=swap" rel="stylesheet">
+<link rel="stylesheet" href="/pb/css/reset.css">
+<link rel="stylesheet" href="/pb/css/common.css">
+<link rel="stylesheet" href="/pb/css/content.css">
+<link rel="stylesheet" href="/pb/css/popup.css">
+<%--
+<script src="/pb/js/jquery-3.5.0.js"></script>
+<script src="/pb/js/common.js"></script>
+<script type="text/javascript" src="<c:url value='/js/EgovMultiFile.js'/>"></script>--%>
+<style>
+	/* 검색 영역 강제 스타일 교정 (기존 CSS 충돌 방지) */
+	.custom-search-box {
+		width: 100% !important;
+		background-color: #f7f8f9 !important;
+		border: 1px solid #e1e4e7 !important;
+		border-radius: 6px !important;
+		padding: 15px 20px !important;
+		box-sizing: border-box !important;
+		margin: 15px 0 25px 0 !important;
+		display: flex !important;
+		flex-wrap: wrap !important;
+		gap: 12px 15px !important;
+		align-items: center !important;
+	}
+
+	.custom-search-box .search-group {
+		display: flex !important;
+		align-items: center !important;
+		gap: 8px !important;
+	}
+
+	.custom-search-box select {
+		height: 36px !important;
+		border: 1px solid #ccc !important;
+		border-radius: 4px !important;
+		padding: 0 25px 0 10px !important;
+		background-color: #fff !important;
+		font-size: 14px !important;
+	}
+
+	.custom-search-box input[type="text"] {
+		height: 36px !important;
+		border: 1px solid #ccc !important;
+		border-radius: 4px !important;
+		padding: 0 10px !important;
+		background-color: #fff !important;
+		font-size: 14px !important;
+		box-sizing: border-box !important;
+	}
+
+	.custom-search-box .calendar_wrap {
+		display: flex !important;
+		align-items: center !important;
+		gap: 5px !important;
+	}
+
+	.custom-search-box .calendar_box {
+		display: inline-flex !important;
+		align-items: center !important;
+	}
+
+	.custom-search-box .btn-search {
+		height: 36px !important;
+		padding: 0 18px !important;
+		background-color: #3b82f6 !important;
+		color: #fff !important;
+		border: none !important;
+		border-radius: 4px !important;
+		font-weight: 500 !important;
+		cursor: pointer !important;
+		font-size: 14px !important;
+	}
+
+	.custom-search-box .btn-search:hover {
+		background-color: #2563eb !important;
+	}
+</style>
+<script type="text/javaScript" language="javascript">
+function fn_search(){
+	linkPage(1);
+}
+
+function linkPage(pageNo){
+	var listForm = document.listForm ;
+	listForm.pageIndex.value = pageNo ;
+	listForm.submit();
+}
+
+//기간선택 select
+function fnSetCalMonth(val) {
+	var form = document.listForm;
+	var today = new Date();
+
+	var year = today.getFullYear();
+	var month = ("0"+(today.getMonth()+1)).slice(-2);
+	var date = ("0"+today.getDate()).slice(-2);
+
+	var sDate = new Date(today.setMonth(today.getMonth() - val));
+
+	var sYear = sDate.getFullYear();
+	var sMonth = ("0"+(sDate.getMonth()+1)).slice(-2);
+	var sDate = ("0"+sDate.getDate()).slice(-2);
+
+	form.searchStartDate.value = sYear + "-" + sMonth + "-" + sDate;
+	form.searchEndDate.value = year + "-" + month + "-" + date;
+
+}
+
+function fnChangeBlockYn(){
+
+	if(confirm("사용여부를 수정하시겠습니까?")){
+		var blockYn = $('#changeBlockYn option:selected').val();
+		$.ajax({
+			type: "POST",
+			url: "/uss/olp/hak/updateAccessBlockYn.do",
+			data : {"blockYn" : blockYn},
+			dataType:'json',
+			async: false,
+			success: function (response) {
+				if (response.result === "success") {
+					alert("수정하였습니다.");
+				}
+			},
+			error: function (e) {
+				alert("ERROR : " + JSON.stringify(e));
+			}
+		});
+	}
+
+}
+</script>
+</head>
+<body>
+<div class="contWrap blocked_cont">
+	<div class="pageTitle">
+		<div class="pageIcon"><img src="/pb/img/pageTitIcon4.png" alt=""></div>
+		<h2 class="titType1 c_222222 fwBold">국외접속 차단</h2>
+		<p class="tType6 c_999999">국외 IP 접속 차단 설정 현황을 파악할 수 있으며, 차단 이력을 조회할 수 있습니다.</p>
+	</div>
+
+	<div class="pageCont">
+		<form name="listForm" action="<c:url value='/uss/olp/hak/ForeignAccessBlock.do'/>" method="post">
+			<input name="pageIndex" type="hidden" value="<c:out value='${searchVO.pageIndex}'/>"/>
+
+			<span class="tbTit">국외접속 차단 설정 - 사용자 로그인 시 국외 IP 접속 차단</span>
+
+			<div class="tableWrap">
+				<table class="tbType2">
+					<colgroup>
+						<col style="width: 15%">
+						<col style="width: 85%">
+					</colgroup>
+					<tbody>
+					<tr>
+						<th><span>국외접속 차단 사용여부</span></th>
+						<td>
+							<select name="changeBlockYn" id="changeBlockYn">
+								<option value="Y" <c:if test="${accessBlockYn == 'Y'}">selected="selected"</c:if>>사용</option>
+								<option value="N" <c:if test="${accessBlockYn == 'N'}">selected="selected"</c:if>>미사용</option>
+							</select>
+							<button type="button" class="btnType bluebor" onclick="fnChangeBlockYn()">수정</button>
+						</td>
+					</tr>
+					<tr>
+						<th><span>차단 대상</span></th>
+						<td>대한민국 외 전체 국가</td>
+					</tr>
+					<tr>
+						<th><span>국가 판별 기준</span></th>
+						<td>
+							<b class="fwMd">[MaxMind/GeoLite2]</b> <small class="tType7 c_999999 fwBold">최종 갱신 2026-08-30</small>
+						</td>
+					</tr>
+					</tbody>
+				</table>
+			</div>
+			<br>
+			<span class="tbTit">국외접속 차단 이력 - 국외 IP 로그인 차단 기록 조회</span>
+
+			<div class="custom-search-box">
+				<div class="search-group">
+					<select  name="setCalMonth" onchange="fnSetCalMonth(this.value)">
+						<option value="0">전체</option>
+						<option value="1">1개월</option>
+						<option value="3">3개월</option>
+						<option value="6">6개월</option>
+					</select>
+					<div class="calendar_wrap">
+						<input type="hidden" name="cal_url" id="cal_url" value="/sym/cmm/EgovNormalCalPopup.do" >
+						<div class="calendar_box" onclick="javascript:fn_egov_NormalCalendar(document.forms.listForm, document.forms.listForm.searchStartDate);">
+							<input style="min-width: 133px;" type="text" class="date_format" name="searchStartDate" id="searchStartDate" size="4" maxlength="4" readonly="" value="">
+							<input type="button" class="calBtn">
+						</div>
+						<span class="line">~</span>
+						<div class="calendar_box" onclick="javascript:fn_egov_NormalCalendar(document.forms.listForm, document.forms.listForm.searchEndDate);">
+							<input style="min-width: 133px;" type="text" class="date_format" name="searchEndDate" id="searchEndDate" size="4" maxlength="4" readonly="" value="">
+							<input type="button" class="calBtn">
+						</div>
+					</div>
+				</div>
+				<div class="search-group">
+					<select id="searchCondition" name="searchCondition" title="조회조건" style="min-width: 170px;" >
+						<%--<option value="" <c:if test="${empty searchVO.searchCondition }">selected="selected"</c:if> >계정ID/접속 IP(전체)</option>
+						<option value="1" <c:if test="${searchVO.searchCondition == '1'}">selected="selected"</c:if> >계정ID</option>--%>
+						<option value="1" <c:if test="${searchVO.searchCondition == '1'}">selected="selected"</c:if> >접속 IP</option>
+					</select>
+					<input id="searchKeyword" name="searchKeyword" class="recentSearch" type="text" value="<c:out value='${searchVO.searchKeyword}'/>" size="15" title="검색" maxlength="100" />
+					<input type="button" class="btnType1" value="검색" onclick="fn_search();" style="background-color: #456ded">
+				</div>
+			</div>
+
+			<div class="listTop">
+				<p class="tType5">총<span class="tType4 c_456ded fwBold"><fmt:formatNumber value="${paginationInfo.totalRecordCount}" pattern="#,###" /></span>건</p>
+			</div>
+
+			<div class="tableWrap">
+				<table class="tbType1">
+					<colgroup>
+						<col style="width:80px;"/>
+						<col style="width:auto;"/>
+						<col style="width:15%;"/>
+						<col style="width:auto;"/>
+						<col style="width:10%;"/>
+					</colgroup>
+					<thead>
+					<tr>
+						<th>번호</th>
+						<th>차단일시</th>
+						<th>접속 IP</th>
+						<th>판별 국가</th>
+						<th>차단 결과</th>
+					</tr>
+					</thead>
+					<tbody>
+						<c:forEach var="result" items="${resultList}" varStatus="status">
+						<tr>
+							<td><c:out value="${(result.pageIndex - 1) * result.pageSize + status.count}"/></td>
+							<td>${result.blockDt}</td>
+							<td>${result.accessIp}</td>
+							<td>${result.countryCode}(${result.countryName})</td>
+							<td style="color: #e40000 !important;">차단</td>
+						</tr>
+						</c:forEach>
+						<c:if test="${empty resultList}">
+							<tr><td colspan="5">자료가 없습니다.</td></tr>
+						</c:if>
+					</tbody>
+				</table>
+			</div>
+			<div class="page">
+				<ul class="inline">
+					<c:if test="${!empty resultList}">
+						<ui:pagination paginationInfo="${paginationInfo}" type="image" jsFunction="linkPage" />
+					</c:if>
+					<c:if test="${empty resultList}">
+						<li><input type="button" class="pageFirst"></li>
+						<li><input type="button" class="pageBefore"></li>
+						<li>1</li>
+						<li><input type="button" class="pageNext"></li>
+						<li><input type="button" class="pageLast"></li>
+					</c:if>
+				</ul>
+			</div>
+			<!-- //페이지 네비게이션 끝 -->
+		</form>
+	</div>
+</div>
+<!-- 페이지 네비게이션 시작 -->
+</div>
+</body>
+</html>
Add a comment
List