986 lines
54 KiB
HTML
986 lines
54 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="ko">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>GUARDiA ITSM — AI 기반 레거시 인프라 자율 운영 플랫폼</title>
|
||
<link rel="icon" type="image/x-icon" href="/static/favicon.ico">
|
||
<link rel="stylesheet" href="/static/style.css">
|
||
<!-- Chart.js — 대시보드 차트 (CDN 실패 시 로컬 폴백) -->
|
||
<script>
|
||
(function() {
|
||
var s = document.createElement('script');
|
||
s.src = 'https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js';
|
||
s.crossOrigin = 'anonymous';
|
||
s.onerror = function() {
|
||
// 폐쇄망 폴백: /static/chart.umd.min.js (오프라인 설치 시 복사됨)
|
||
var local = document.createElement('script');
|
||
local.src = '/static/chart.umd.min.js';
|
||
local.onerror = function() { window._chartjsUnavailable = true; };
|
||
document.head.appendChild(local);
|
||
};
|
||
document.head.appendChild(s);
|
||
})();
|
||
</script>
|
||
<!-- F-4: PWA -->
|
||
<link rel="manifest" href="/static/manifest.json">
|
||
<meta name="theme-color" content="#4f8ef7">
|
||
<meta name="mobile-web-app-capable" content="yes">
|
||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
||
<meta name="apple-mobile-web-app-title" content="GUARDiA">
|
||
<link rel="apple-touch-icon" href="/static/icons/icon-192.png">
|
||
</head>
|
||
<body>
|
||
<!-- FOUC 방지: body 첫 번째 자식으로 테마를 즉시 적용 -->
|
||
<script>document.body.dataset.theme = localStorage.getItem("guardia_theme") || "dark";</script>
|
||
<div id="app">
|
||
|
||
<!-- ── Sidebar ───────────────────────────────────── -->
|
||
<aside id="sidebar">
|
||
<div id="sidebar-logo">
|
||
<img src="/static/icons/logo.png" alt="GUARDiA 로고"
|
||
style="height:36px;width:auto;object-fit:contain;margin-right:10px"
|
||
onerror="this.style.display='none';document.getElementById('logo-fallback').style.display='flex'">
|
||
<div id="logo-fallback" style="display:none;align-items:center;gap:8px">
|
||
<div class="logo-icon">G</div>
|
||
</div>
|
||
<div>
|
||
<div class="logo-title">GUARDiA ITSM</div>
|
||
<div class="logo-sub">인프라 자동화 플랫폼</div>
|
||
</div>
|
||
</div>
|
||
|
||
<nav id="sidebar-nav">
|
||
<!-- 대시보드 -->
|
||
<div class="nav-item active" data-view="dashboard">
|
||
<span class="nav-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="18" y="3" width="4" height="18"/><rect x="10" y="8" width="4" height="13"/><rect x="2" y="13" width="4" height="8"/></svg></span> 대시보드
|
||
</div>
|
||
|
||
<!-- SR 관리 -->
|
||
<div class="nav-group-header" onclick="toggleNavGroup(this)" aria-expanded="false">
|
||
<span class="nav-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="3" width="16" height="18" rx="2"/><path d="M9 3a3 3 0 006 0"/><path d="M8 10h8M8 14h6M8 18h4"/></svg></span><span>SR 관리</span>
|
||
<span class="nav-arrow" aria-hidden="true">▾</span>
|
||
</div>
|
||
<div class="nav-group-body" role="group">
|
||
<div class="nav-sub-item" data-view="board">칸반 보드</div>
|
||
<div class="nav-sub-item" data-view="list">SR 목록</div>
|
||
<div class="nav-sub-item" data-view="audit">감사 로그</div>
|
||
</div>
|
||
|
||
<!-- PMS 프로젝트 관리 -->
|
||
<div class="nav-group-header" onclick="toggleNavGroup(this)" aria-expanded="false">
|
||
<span class="nav-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18M9 21V9"/></svg></span><span>PMS 프로젝트</span>
|
||
<span class="nav-arrow" aria-hidden="true">▾</span>
|
||
</div>
|
||
<div class="nav-group-body" role="group">
|
||
<a class="nav-sub-item" href="/si">프로젝트 목록</a>
|
||
<a class="nav-sub-item" href="/si?tab=wbs">WBS 관리</a>
|
||
<a class="nav-sub-item" href="/si?tab=deliverables">산출물 관리</a>
|
||
<a class="nav-sub-item" href="/si?tab=issues">이슈 관리</a>
|
||
<a class="nav-sub-item" href="/si?tab=risks">위험 관리</a>
|
||
<a class="nav-sub-item" href="/si?tab=report">보고서 (일/주/월)</a>
|
||
</div>
|
||
|
||
<!-- 인프라 -->
|
||
<div class="nav-group-header" onclick="toggleNavGroup(this)" aria-expanded="false">
|
||
<span class="nav-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="2" width="20" height="8" rx="2"/><rect x="2" y="14" width="20" height="8" rx="2"/><circle cx="6" cy="6" r="1" fill="currentColor"/><circle cx="6" cy="18" r="1" fill="currentColor"/><path d="M10 6h8M10 18h8"/></svg></span><span>인프라</span>
|
||
<span class="nav-arrow" aria-hidden="true">▾</span>
|
||
</div>
|
||
<div class="nav-group-body" role="group">
|
||
<div class="nav-sub-item" data-view="cmdb">CMDB</div>
|
||
<div class="nav-sub-item" data-view="kb">기술 문서 KB</div>
|
||
<div class="nav-sub-item" data-view="institutions">기관/사이트</div>
|
||
</div>
|
||
|
||
<div class="nav-separator"></div>
|
||
<a class="nav-item nav-link-ext" href="/incidents">
|
||
<span class="nav-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M10.3 3.1L2 20h20L13.7 3.1a2 2 0 00-3.4 0z"/><line x1="12" y1="9" x2="12" y2="13"/><circle cx="12" cy="17" r="1" fill="currentColor"/></svg></span> 장애 관리
|
||
</a>
|
||
<a class="nav-item nav-link-ext" href="/ssl">
|
||
<span class="nav-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="8" cy="15" r="4"/><path d="M12 11l8-8M17 6l3 3"/></svg></span> SSL 관리
|
||
</a>
|
||
<a class="nav-item nav-link-ext" href="/pm">
|
||
<span class="nav-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M14.7 6.3a1 1 0 000 1.4l1.6 1.6a1 1 0 001.4 0l3.77-3.77a6 6 0 01-7.94 7.94L5.37 18.6a2.12 2.12 0 01-3-3L7.5 12a6 6 0 017.2-5.7z"/></svg></span> PM 점검
|
||
</a>
|
||
<a class="nav-item nav-link-ext" href="/oncall">
|
||
<span class="nav-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M22 16.9v3a2 2 0 01-2.2 2 19.8 19.8 0 01-8.6-3.1 19.5 19.5 0 01-6-6A19.8 19.8 0 012.1 4.2 2 2 0 014.1 2h3a2 2 0 012 1.7c.1.8.4 1.8.7 2.8a2 2 0 01-.5 2.1L8.1 9.9a16 16 0 006 6l1.3-1.3a2 2 0 012.1-.4c1 .3 2 .6 2.8.7 1 .1 1.7 1 1.7 2z"/></svg></span> 온콜 관리
|
||
</a>
|
||
<a class="nav-item nav-link-ext" href="/batch">
|
||
<span class="nav-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M20 12a8 8 0 01-.5 2.8l1.8 1a10 10 0 010-7.6l-1.8 1A8 8 0 0120 12zM4 12a8 8 0 01.5-2.8l-1.8-1a10 10 0 000 7.6l1.8-1A8 8 0 014 12z"/></svg></span> 배치 작업
|
||
</a>
|
||
<a class="nav-item nav-link-ext" href="/vibe">
|
||
<span class="nav-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></svg></span> 바이브 코딩
|
||
</a>
|
||
<a class="nav-item nav-link-ext" href="/si">
|
||
<span class="nav-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><polygon points="12 2 2 7 12 12 22 7 12 2"/><polyline points="2 17 12 22 22 17"/><polyline points="2 12 12 17 22 12"/></svg></span> SI 프로젝트
|
||
</a>
|
||
<a class="nav-item nav-link-ext" href="/agents">
|
||
<span class="nav-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="6" width="18" height="12" rx="2"/><circle cx="8" cy="12" r="1.5"/><circle cx="12" cy="12" r="1.5"/><circle cx="16" cy="12" r="1.5"/><path d="M8 6V4M12 6V4M16 6V4M8 18v2M12 18v2M16 18v2"/></svg></span> AI 에이전트
|
||
</a>
|
||
<div class="nav-separator"></div>
|
||
<div class="nav-item" data-view="institutions">
|
||
<span class="nav-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M3 21h18M3 7l9-4 9 4M4 7v14M20 7v14M9 21v-4h6v4M9 11h1M14 11h1M9 15h1M14 15h1"/></svg></span> 기관 관리
|
||
</div>
|
||
<div class="nav-item" data-view="scripts">
|
||
<span class="nav-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><polyline points="4 17 10 11 4 5"/><line x1="12" y1="19" x2="20" y2="19"/></svg></span> 스크립트 관리
|
||
</div>
|
||
<div class="nav-item" data-view="timetable">
|
||
<span class="nav-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="18" rx="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg></span> 작업 타임테이블
|
||
</div>
|
||
<!-- ── Upstage OCR ───────────────────────────── -->
|
||
<div class="nav-separator"></div>
|
||
<div class="nav-group-header" onclick="toggleNavGroup(this)" aria-expanded="false">
|
||
<span class="nav-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"/><polyline points="14 2 14 8 20 8"/><path d="M8 13h8M8 17h5"/></svg></span><span>문서 AI (OCR)</span>
|
||
<span class="nav-arrow" aria-hidden="true">▾</span>
|
||
</div>
|
||
<div class="nav-group-body" role="group">
|
||
<div class="nav-sub-item" data-view="ocr_parse">문서 파싱 (Parse)</div>
|
||
<div class="nav-sub-item" data-view="ocr_contract">계약서 자동 처리</div>
|
||
<div class="nav-sub-item" data-view="ocr_brand_contract">브랜드 계약서</div>
|
||
<div class="nav-sub-item" data-view="ocr_server_spec">납품서 → CMDB</div>
|
||
<div class="nav-sub-item" data-view="ocr_invoice">청구서 처리</div>
|
||
<div class="nav-sub-item" data-view="ocr_incident">장애보고서 → SR</div>
|
||
<div class="nav-sub-item" data-view="ocr_meeting">회의록 → 액션</div>
|
||
<div class="nav-sub-item" data-view="ocr_history">OCR 이력</div>
|
||
<div class="nav-sub-item" data-view="doc_templates">추출 템플릿</div>
|
||
</div>
|
||
<!-- ── GUARDiA 확장 v3 ─────────────────────── -->
|
||
<div class="nav-separator"></div>
|
||
|
||
<!-- AI 플랫폼 -->
|
||
<div class="nav-group-header" onclick="toggleNavGroup(this)" aria-expanded="false">
|
||
<span class="nav-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M12 5a3 3 0 10-3 3H12"/><path d="M12 5a3 3 0 113 3H12"/><path d="M6 8a4 4 0 000 8h.5"/><path d="M18 8a4 4 0 010 8h-.5"/><path d="M8 16a4 4 0 008 0v-4H8v4z"/></svg></span><span>AI 플랫폼</span>
|
||
<span class="nav-arrow" aria-hidden="true">▾</span>
|
||
</div>
|
||
<div class="nav-group-body" role="group">
|
||
<div class="nav-sub-item" data-view="rag_search">RAG 하이브리드 검색</div>
|
||
<div class="nav-sub-item" data-view="ai_insights">AI 운영 인사이트</div>
|
||
<div class="nav-sub-item" data-view="ai_workflow">자율 워크플로우</div>
|
||
<div class="nav-sub-item" data-view="learning_loop">Learning Loop</div>
|
||
<div class="nav-sub-item" data-view="multimodal">멀티모달 분석</div>
|
||
</div>
|
||
|
||
<!-- 분석·KPI -->
|
||
<div class="nav-group-header" onclick="toggleNavGroup(this)" aria-expanded="false">
|
||
<span class="nav-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><polyline points="23 6 13.5 15.5 8.5 10.5 1 18"/><polyline points="17 6 23 6 23 12"/></svg></span><span>분석 · KPI</span>
|
||
<span class="nav-arrow" aria-hidden="true">▾</span>
|
||
</div>
|
||
<div class="nav-group-body" role="group">
|
||
<div class="nav-sub-item" data-view="kpi_dashboard">KPI 대시보드</div>
|
||
<div class="nav-sub-item" data-view="bi_dashboard">BI 대시보드</div>
|
||
<div class="nav-sub-item" data-view="predictive">예측 분석</div>
|
||
<div class="nav-sub-item" data-view="benchmark">벤치마킹</div>
|
||
<div class="nav-sub-item" data-view="auto_report">자동 보고서</div>
|
||
<div class="nav-sub-item" data-view="cohort">코호트 분석</div>
|
||
</div>
|
||
|
||
<!-- 클라우드 -->
|
||
<div class="nav-group-header" onclick="toggleNavGroup(this)" aria-expanded="false">
|
||
<span class="nav-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M18 10h-1.3A7 7 0 106 19h12a4 4 0 000-8v-1z"/></svg></span><span>클라우드 · 컨테이너</span>
|
||
<span class="nav-arrow" aria-hidden="true">▾</span>
|
||
</div>
|
||
<div class="nav-group-body" role="group">
|
||
<div class="nav-sub-item" data-view="kubernetes">Kubernetes</div>
|
||
<div class="nav-sub-item" data-view="container_alerts">컨테이너 알림</div>
|
||
<div class="nav-sub-item" data-view="ncloud">NCloud 관리</div>
|
||
</div>
|
||
|
||
<!-- 외부 연동 -->
|
||
<div class="nav-group-header" onclick="toggleNavGroup(this)" aria-expanded="false">
|
||
<span class="nav-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M10 13a5 5 0 007.5.5l3-3a5 5 0 00-7-7l-1.5 1.5"/><path d="M14 11a5 5 0 00-7.5-.5l-3 3a5 5 0 007 7l1.5-1.5"/></svg></span><span>외부 연동</span>
|
||
<span class="nav-arrow" aria-hidden="true">▾</span>
|
||
</div>
|
||
<div class="nav-group-body" role="group">
|
||
<div class="nav-sub-item" data-view="jira_sync">Jira 동기화</div>
|
||
<div class="nav-sub-item" data-view="servicenow">ServiceNow</div>
|
||
<div class="nav-sub-item" data-view="slack_config">Slack 설정</div>
|
||
<div class="nav-sub-item" data-view="sso_config">SSO 인증</div>
|
||
<div class="nav-sub-item" data-view="erp_config">ERP 연동</div>
|
||
<div class="nav-sub-item" data-view="kakao_config">카카오 알림톡</div>
|
||
</div>
|
||
|
||
<!-- SaaS 관리 -->
|
||
<div class="nav-group-header" onclick="toggleNavGroup(this)" aria-expanded="false">
|
||
<span class="nav-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="7" width="20" height="14" rx="2"/><path d="M16 7V5a2 2 0 00-2-2h-4a2 2 0 00-2 2v2"/><line x1="12" y1="12" x2="12" y2="12" stroke-width="3"/><path d="M2 13h20"/></svg></span><span>SaaS 관리</span>
|
||
<span class="nav-arrow" aria-hidden="true">▾</span>
|
||
</div>
|
||
<div class="nav-group-body" role="group">
|
||
<div class="nav-sub-item" data-view="tenant_portal">테넌트 포털</div>
|
||
<div class="nav-sub-item" data-view="billing">구독 · 과금</div>
|
||
<div class="nav-sub-item" data-view="white_label">브랜딩 설정</div>
|
||
</div>
|
||
|
||
<!-- ── 디자인 AI + 스마트 UX ────────────────────── -->
|
||
<div class="nav-separator"></div>
|
||
|
||
<div class="nav-group-header" onclick="toggleNavGroup(this)" aria-expanded="true">
|
||
<span class="nav-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><circle cx="8" cy="10" r="1.5" fill="currentColor" stroke="none"/><circle cx="13" cy="8" r="1.5" fill="currentColor" stroke="none"/><circle cx="16" cy="12" r="1.5" fill="currentColor" stroke="none"/><path d="M12 22c0-2.5-2-4-4-4h-2a2 2 0 010-4"/></svg></span><span>디자인 AI</span>
|
||
<span class="nav-arrow" aria-hidden="true">▾</span>
|
||
</div>
|
||
<div class="nav-group-body" role="group" style="display:block">
|
||
<div class="nav-sub-item" data-view="design_dashboard">디자인 SR 대시보드</div>
|
||
<div class="nav-sub-item" data-view="design_icon">아이콘 생성</div>
|
||
<div class="nav-sub-item" data-view="design_css">CSS 자동 생성</div>
|
||
<div class="nav-sub-item" data-view="design_review">스크린샷 분석</div>
|
||
</div>
|
||
|
||
<!-- ── GUARDiA Brain — AI 지능화 엔진 ──────────── -->
|
||
<div class="nav-separator"></div>
|
||
|
||
<div class="nav-group-header" onclick="toggleNavGroup(this)" aria-expanded="true">
|
||
<span class="nav-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M12 5a3 3 0 10-3 3H12"/><path d="M12 5a3 3 0 113 3H12"/><path d="M6 8a4 4 0 000 8h.5"/><path d="M18 8a4 4 0 010 8h-.5"/><path d="M8 16a4 4 0 008 0v-4H8v4z"/><path d="M9 12v-1M15 12v-1"/></svg></span><span>AI 뇌 엔진</span>
|
||
<span class="nav-arrow" aria-hidden="true">▾</span>
|
||
</div>
|
||
<div class="nav-group-body" role="group" style="display:block">
|
||
<div class="nav-sub-item" data-view="brain_dashboard">AI 엔진 대시보드</div>
|
||
<div class="nav-sub-item" data-view="ai_memory">영구 메모리</div>
|
||
<div class="nav-sub-item" data-view="knowledge_graph_view">지식 그래프</div>
|
||
<div class="nav-sub-item" data-view="skill_registry_view">스킬 레지스트리</div>
|
||
<div class="nav-sub-item" data-view="skill_miner_view">자동 스킬 발굴</div>
|
||
<div class="nav-sub-item" data-view="finetune_view">LoRA 파인튜닝</div>
|
||
<div class="nav-sub-item" data-view="brain_plugins">플러그인 관리</div>
|
||
</div>
|
||
|
||
<!-- ── GUARDiA 차세대 확장 ───────────────────── -->
|
||
<div class="nav-separator"></div>
|
||
|
||
<!-- AIOps 2.0 -->
|
||
<div class="nav-group-header" onclick="toggleNavGroup(this)" aria-expanded="false">
|
||
<span class="nav-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="6" width="18" height="12" rx="2"/><circle cx="8" cy="12" r="1.5"/><circle cx="12" cy="12" r="1.5"/><circle cx="16" cy="12" r="1.5"/><path d="M8 6V4M12 6V4M16 6V4M8 18v2M12 18v2M16 18v2"/></svg></span><span>AIOps 2.0</span>
|
||
<span class="nav-arrow" aria-hidden="true">▾</span>
|
||
</div>
|
||
<div class="nav-group-body" role="group">
|
||
<div class="nav-sub-item" data-view="agentic_aiops">에이전트 태스크 실행</div>
|
||
<div class="nav-sub-item" data-view="auto_remediation_v2">자율 교정 루프</div>
|
||
<div class="nav-sub-item" data-view="otel_tracing">분산 트레이싱 (OTLP)</div>
|
||
<div class="nav-sub-item" data-view="mlsecops">AI 모델 보안</div>
|
||
</div>
|
||
|
||
<!-- Zero Trust + Supply Chain -->
|
||
<div class="nav-group-header" onclick="toggleNavGroup(this)" aria-expanded="false">
|
||
<span class="nav-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2l9 4v5c0 5.2-3.9 10-9 11C6.9 21 3 16.2 3 11V6l9-4z"/></svg></span><span>Zero Trust + SBOM</span>
|
||
<span class="nav-arrow" aria-hidden="true">▾</span>
|
||
</div>
|
||
<div class="nav-group-body" role="group">
|
||
<div class="nav-sub-item" data-view="ztna">ZTNA 정책 관리</div>
|
||
<div class="nav-sub-item" data-view="sbom">SBOM 생성·관리</div>
|
||
<div class="nav-sub-item" data-view="n2sf">N²SF 보안체계</div>
|
||
</div>
|
||
|
||
<!-- IDP -->
|
||
<div class="nav-group-header" onclick="toggleNavGroup(this)" aria-expanded="false">
|
||
<span class="nav-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><polygon points="12 2 2 7 12 12 22 7 12 2"/><polyline points="2 17 12 22 22 17"/><polyline points="2 12 12 17 22 12"/></svg></span><span>개발자 플랫폼 (IDP)</span>
|
||
<span class="nav-arrow" aria-hidden="true">▾</span>
|
||
</div>
|
||
<div class="nav-group-body" role="group">
|
||
<div class="nav-sub-item" data-view="idp_catalog">서비스 카탈로그</div>
|
||
<div class="nav-sub-item" data-view="idp_template">Golden Path 템플릿</div>
|
||
<div class="nav-sub-item" data-view="idp_portal">셀프서비스 포털</div>
|
||
</div>
|
||
|
||
<!-- GreenOps + Edge -->
|
||
<div class="nav-group-header" onclick="toggleNavGroup(this)" aria-expanded="false">
|
||
<span class="nav-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M2 22c4-4 6-8 6-12A8 8 0 0122 2c0 4-2 8-4 10s-6 4-10 4H2z"/><path d="M2 22l8-8"/></svg></span><span>GreenOps + Edge/IoT</span>
|
||
<span class="nav-arrow" aria-hidden="true">▾</span>
|
||
</div>
|
||
<div class="nav-group-body" role="group">
|
||
<div class="nav-sub-item" data-view="greenops">탄소 대시보드</div>
|
||
<div class="nav-sub-item" data-view="edge_monitor">Edge/IoT 디바이스</div>
|
||
<div class="nav-sub-item" data-view="energy_optimizer">에너지 최적화</div>
|
||
</div>
|
||
|
||
<!-- ── GUARDiA 기능 개선 v4 ─────────────────── -->
|
||
<div class="nav-separator"></div>
|
||
|
||
<!-- 앱 배포 -->
|
||
<div class="nav-group-header" onclick="toggleNavGroup(this)" aria-expanded="false">
|
||
<span class="nav-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="5" y="2" width="14" height="20" rx="2"/><line x1="12" y1="18" x2="12.01" y2="18" stroke-width="3"/></svg></span><span>모바일 앱 배포</span>
|
||
<span class="nav-arrow" aria-hidden="true">▾</span>
|
||
</div>
|
||
<div class="nav-group-body" role="group">
|
||
<div class="nav-sub-item" data-view="app_deploy">APK 업로드 · QR</div>
|
||
<div class="nav-sub-item" data-view="app_versions">버전 이력</div>
|
||
<div class="nav-sub-item" data-view="app_stats">다운로드 통계</div>
|
||
</div>
|
||
|
||
<!-- 배치 SSH -->
|
||
<div class="nav-item" data-view="batch_ssh" onclick="showPage('batch_ssh')">
|
||
<span class="nav-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg></span> 배치 SSH 실행
|
||
</div>
|
||
|
||
<!-- 자산 QR -->
|
||
<div class="nav-item" data-view="asset_qr" onclick="showPage('asset_qr')">
|
||
<span class="nav-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/><rect x="5" y="5" width="3" height="3" fill="currentColor" stroke="none"/><rect x="16" y="5" width="3" height="3" fill="currentColor" stroke="none"/><rect x="5" y="16" width="3" height="3" fill="currentColor" stroke="none"/><path d="M14 14h3v3M17 14v7M14 21h7"/></svg></span> 자산 QR 태그
|
||
</div>
|
||
|
||
<!-- 스마트 알림 -->
|
||
<div class="nav-item" data-view="notification_rules" onclick="showPage('notification_rules')">
|
||
<span class="nav-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M18 8A6 6 0 006 8c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.7 21a2 2 0 01-3.4 0"/></svg></span> 스마트 알림 규칙
|
||
</div>
|
||
|
||
<div class="nav-separator"></div>
|
||
<a class="nav-item nav-link-ext" href="/license" id="nav-license">
|
||
<span class="nav-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0110 0v4"/><circle cx="12" cy="16" r="1" fill="currentColor"/></svg></span> 라이선스 관리
|
||
</a>
|
||
</nav>
|
||
|
||
<div id="sidebar-footer">
|
||
<div class="status-dot online"></div>
|
||
<span>시스템 정상</span>
|
||
</div>
|
||
<div style="padding:8px 16px;font-size:10px;color:var(--text-muted);line-height:1.5;border-top:1px solid rgba(255,255,255,.06)">
|
||
<img src="/static/icons/logo.png" alt="" style="height:18px;vertical-align:middle;margin-right:4px;opacity:.6"
|
||
onerror="this.style.display='none'">
|
||
Copyright © 2026 GUARDiA<br>
|
||
All Rights Reserved.
|
||
</div>
|
||
|
||
<!-- 사용자 정보 + 로그아웃 -->
|
||
<div id="sidebar-user">
|
||
<div id="sidebar-user-info">
|
||
<div id="user-display-name" style="font-size:13px;color:var(--text-bright);font-weight:600"></div>
|
||
<div id="user-role-badge"></div>
|
||
</div>
|
||
<button class="btn-logout" onclick="logout()" title="로그아웃">⏏</button>
|
||
</div>
|
||
<!-- 테마 전환 -->
|
||
<div id="theme-switcher">
|
||
<div class="theme-switcher-label">테마</div>
|
||
<div class="theme-swatches">
|
||
<button class="theme-swatch" data-theme="dark" onclick="applyTheme('dark')">
|
||
<span class="theme-swatch-icon">🌑</span>
|
||
<span class="theme-swatch-name">다크</span>
|
||
</button>
|
||
<button class="theme-swatch" data-theme="light" onclick="applyTheme('light')">
|
||
<span class="theme-swatch-icon">☀️</span>
|
||
<span class="theme-swatch-name">라이트</span>
|
||
</button>
|
||
<button class="theme-swatch" data-theme="midnight" onclick="applyTheme('midnight')">
|
||
<span class="theme-swatch-icon">🌌</span>
|
||
<span class="theme-swatch-name">미드나잇</span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<!-- SSE 연결 상태 표시 -->
|
||
<div id="sse-status" title="실시간 연결 상태">
|
||
<span id="sse-dot" class="sse-dot grey"></span>
|
||
<span id="sse-label" style="font-size:10px;color:var(--text-muted)">연결 중…</span>
|
||
</div>
|
||
</aside>
|
||
|
||
<!-- ── Main ──────────────────────────────────────── -->
|
||
<main id="main">
|
||
|
||
<!-- Top bar -->
|
||
<header id="topbar">
|
||
<h1 id="page-title">대시보드</h1>
|
||
<div id="topbar-actions">
|
||
<div id="topbar-refresh-indicator" class="refresh-indicator hidden">
|
||
<span class="refresh-dot"></span><span style="font-size:11px">데이터 갱신됨</span>
|
||
</div>
|
||
<button class="btn btn-primary" id="btn-new-sr">+ 새 SR</button>
|
||
</div>
|
||
</header>
|
||
|
||
<!-- Views -->
|
||
<div id="view-dashboard" class="view active">
|
||
<!-- KPI 카드 행 -->
|
||
<div class="stats-row" id="stats-row"><!-- filled by JS --></div>
|
||
|
||
<!-- ── 대시보드 탭 ── -->
|
||
<div class="dash-tab-nav" id="dash-tab-nav">
|
||
<button class="dash-tab active" data-tab="ops" onclick="switchDashTab('ops')">📊 운영 현황</button>
|
||
<button class="dash-tab" data-tab="infra" onclick="switchDashTab('infra')">🖥️ 인프라</button>
|
||
<button class="dash-tab" data-tab="security" onclick="switchDashTab('security')">🔒 보안</button>
|
||
<button class="dash-tab" data-tab="ai" onclick="switchDashTab('ai')">🤖 AI 인사이트</button>
|
||
</div>
|
||
|
||
<!-- ═══ 탭 1: 운영 현황 ═══ -->
|
||
<div class="dash-tab-panel active" id="dash-panel-ops">
|
||
<div class="chart-grid-2">
|
||
<!-- SR 상태 도넛 -->
|
||
<div class="card chart-card">
|
||
<div class="card-header">SR 상태 분포</div>
|
||
<div class="card-body chart-body">
|
||
<canvas id="chart-sr-status"></canvas>
|
||
</div>
|
||
</div>
|
||
<!-- 우선순위 바 -->
|
||
<div class="card chart-card">
|
||
<div class="card-header">우선순위별 SR</div>
|
||
<div class="card-body chart-body">
|
||
<canvas id="chart-sr-priority"></canvas>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<!-- 7일 SR 추이 -->
|
||
<div class="card" style="margin-top:14px">
|
||
<div class="card-header" style="display:flex;align-items:center;justify-content:space-between">
|
||
<span>📈 최근 7일 SR 추이</span>
|
||
<button class="btn btn-secondary" style="font-size:11px;padding:3px 8px"
|
||
onclick="loadDashboardCharts()">새로고침</button>
|
||
</div>
|
||
<div class="card-body" style="padding:14px 16px">
|
||
<canvas id="chart-sr-trend" style="max-height:200px"></canvas>
|
||
</div>
|
||
</div>
|
||
<!-- 엔지니어 워크로드 + 최근 SR -->
|
||
<div class="chart-grid-2" style="margin-top:14px">
|
||
<div class="card chart-card">
|
||
<div class="card-header">👷 엔지니어 워크로드</div>
|
||
<div class="card-body" id="workload-body">
|
||
<div style="color:var(--text-muted);font-size:13px;padding:8px">로딩 중…</div>
|
||
</div>
|
||
</div>
|
||
<div class="card chart-card">
|
||
<div class="card-header">최근 SR</div>
|
||
<div class="card-body" id="recent-list" style="overflow-y:auto;max-height:260px"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══ 탭 2: 인프라 ═══ -->
|
||
<div class="dash-tab-panel" id="dash-panel-infra">
|
||
<div class="chart-grid-2">
|
||
<!-- 기관별 SR 수평 바 -->
|
||
<div class="card chart-card">
|
||
<div class="card-header">기관별 SR 현황 (Top 10)</div>
|
||
<div class="card-body chart-body">
|
||
<canvas id="chart-inst-sr"></canvas>
|
||
</div>
|
||
</div>
|
||
<!-- 서버 OS 분포 -->
|
||
<div class="card chart-card">
|
||
<div class="card-header">서버 OS 분포</div>
|
||
<div class="card-body chart-body">
|
||
<canvas id="chart-os-dist"></canvas>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<!-- CMDB 서버 상태 그리드 -->
|
||
<div class="card" style="margin-top:14px">
|
||
<div class="card-header">서버 헬스 현황</div>
|
||
<div class="card-body" id="server-health-grid"
|
||
style="display:flex;flex-wrap:wrap;gap:8px;padding:14px 16px">
|
||
<div style="color:var(--text-muted);font-size:13px">로딩 중…</div>
|
||
</div>
|
||
</div>
|
||
<!-- SSL 만료 현황 -->
|
||
<div class="card" style="margin-top:14px">
|
||
<div class="card-header">🔐 SSL 인증서 만료 현황</div>
|
||
<div class="card-body chart-body" style="max-height:220px">
|
||
<canvas id="chart-ssl-expiry"></canvas>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══ 탭 3: 보안 ═══ -->
|
||
<div class="dash-tab-panel" id="dash-panel-security">
|
||
<div class="chart-grid-2">
|
||
<!-- 취약점 심각도 바 -->
|
||
<div class="card chart-card">
|
||
<div class="card-header">취약점 심각도 분포</div>
|
||
<div class="card-body chart-body">
|
||
<canvas id="chart-vuln-severity"></canvas>
|
||
</div>
|
||
</div>
|
||
<!-- 패치율 도넛 -->
|
||
<div class="card chart-card">
|
||
<div class="card-header">패치 적용 현황</div>
|
||
<div class="card-body chart-body">
|
||
<canvas id="chart-patch-rate"></canvas>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<!-- PAM 세션 + 감사 로그 -->
|
||
<div class="chart-grid-2" style="margin-top:14px">
|
||
<div class="card chart-card">
|
||
<div class="card-header">🔑 PAM 세션 현황</div>
|
||
<div class="card-body" id="pam-status-body"
|
||
style="padding:14px 16px;font-size:13px">로딩 중…</div>
|
||
</div>
|
||
<div class="card chart-card">
|
||
<div class="card-header">📋 최근 감사 로그</div>
|
||
<div class="card-body" id="audit-body"
|
||
style="overflow-y:auto;max-height:260px"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══ 탭 4: AI 인사이트 ═══ -->
|
||
<div class="dash-tab-panel" id="dash-panel-ai">
|
||
<div class="chart-grid-2">
|
||
<!-- AI 티켓 분류 분포 -->
|
||
<div class="card chart-card">
|
||
<div class="card-header">🤖 AI 티켓 분류 현황</div>
|
||
<div class="card-body chart-body">
|
||
<canvas id="chart-ai-category"></canvas>
|
||
</div>
|
||
</div>
|
||
<!-- 이상 탐지 추이 -->
|
||
<div class="card chart-card">
|
||
<div class="card-header">⚡ 이상 탐지 추이 (7일)</div>
|
||
<div class="card-body chart-body">
|
||
<canvas id="chart-anomaly-trend"></canvas>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<!-- 예측 유지보수 + 학습 루프 -->
|
||
<div class="chart-grid-2" style="margin-top:14px">
|
||
<div class="card chart-card">
|
||
<div class="card-header">🔧 예측 유지보수 위험 서버</div>
|
||
<div class="card-body" id="predictive-body"
|
||
style="padding:14px 16px;font-size:13px">로딩 중…</div>
|
||
</div>
|
||
<div class="card chart-card">
|
||
<div class="card-header">📚 학습 루프 현황</div>
|
||
<div class="card-body" id="learning-body"
|
||
style="padding:14px 16px;font-size:13px">로딩 중…</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div><!-- /view-dashboard -->
|
||
|
||
<div id="view-board" class="view">
|
||
<div id="kanban-board">
|
||
<!-- columns rendered by JS -->
|
||
</div>
|
||
</div>
|
||
|
||
<div id="view-list" class="view">
|
||
<div class="list-toolbar">
|
||
<input type="text" id="search-input" placeholder="SR 제목 검색…" class="search-box">
|
||
<select id="filter-status" class="filter-select">
|
||
<option value="">전체 상태</option>
|
||
<option value="RECEIVED">접수</option>
|
||
<option value="PARSED">파싱 완료</option>
|
||
<option value="PENDING_APPROVAL">승인 대기</option>
|
||
<option value="APPROVED">승인됨</option>
|
||
<option value="IN_PROGRESS">진행 중</option>
|
||
<option value="PENDING_PM_VALIDATION">PM 검증 대기</option>
|
||
<option value="COMPLETED">완료</option>
|
||
<option value="FAILED_ROLLBACK">롤백 실패</option>
|
||
<option value="REJECTED">반려</option>
|
||
</select>
|
||
<select id="filter-type" class="filter-select">
|
||
<option value="">전체 유형</option>
|
||
<option value="DEPLOY">배포</option>
|
||
<option value="RESTART">재기동</option>
|
||
<option value="LOG">로그</option>
|
||
<option value="INQUIRY">문의</option>
|
||
<option value="OTHER">기타</option>
|
||
</select>
|
||
</div>
|
||
<table class="sr-table" id="sr-table">
|
||
<thead>
|
||
<tr>
|
||
<th>SR ID</th><th>유형</th><th>제목</th>
|
||
<th>상태</th><th>우선순위</th><th>담당자</th><th>요청자</th><th>생성일</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="sr-tbody"></tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<div id="view-audit" class="view">
|
||
<div class="audit-header-row">
|
||
<span class="audit-title">감사 로그 (SHA-256 해시 체인)</span>
|
||
<button class="btn btn-secondary" id="btn-verify">체인 무결성 검증</button>
|
||
<span id="verify-result"></span>
|
||
</div>
|
||
<table class="sr-table" id="audit-table">
|
||
<thead>
|
||
<tr>
|
||
<th>#</th><th>SR</th><th>행위자</th><th>액션</th><th>내용</th>
|
||
<th>해시 (앞 12자)</th><th>시각</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="audit-tbody"></tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<div id="view-cmdb" class="view">
|
||
<div class="cmdb-grid" id="cmdb-grid"><!-- filled by JS --></div>
|
||
</div>
|
||
|
||
<!-- KB 뷰 -->
|
||
<div id="view-kb" class="view">
|
||
<div class="list-toolbar" style="gap:10px">
|
||
<input type="text" id="kb-search-input" placeholder="증상 또는 키워드 검색… (예: OOM, SSL, connection pool)"
|
||
class="search-box" style="flex:1">
|
||
<select id="kb-category-filter" class="filter-select">
|
||
<option value="">전체 카테고리</option>
|
||
<option value="JAVA">JAVA</option>
|
||
<option value="MIDDLEWARE">MIDDLEWARE</option>
|
||
<option value="DB">DB</option>
|
||
<option value="WEB">WEB</option>
|
||
<option value="OS">OS</option>
|
||
<option value="SECURITY">SECURITY</option>
|
||
</select>
|
||
<button class="btn btn-primary" onclick="searchKB()">검색</button>
|
||
</div>
|
||
<div id="kb-results"><!-- filled by JS --></div>
|
||
</div>
|
||
|
||
<!-- 기관 관리 뷰 -->
|
||
<div id="view-institutions" class="view">
|
||
<div class="list-toolbar">
|
||
<input type="text" id="inst-search" placeholder="기관명 검색…" class="search-box" oninput="filterInstitutions()">
|
||
<select id="inst-region-filter" class="filter-select" onchange="filterInstitutions()">
|
||
<option value="">전체 지역</option>
|
||
<option value="서울">서울</option>
|
||
<option value="세종">세종</option>
|
||
<option value="부산">부산</option>
|
||
<option value="대전">대전</option>
|
||
<option value="기타">기타</option>
|
||
</select>
|
||
<button class="btn btn-primary" id="btn-new-inst" onclick="openInstModal()">+ 기관 등록</button>
|
||
</div>
|
||
<table class="sr-table" id="inst-table">
|
||
<thead>
|
||
<tr>
|
||
<th>기관코드</th><th>기관명</th><th>지역</th><th>계약 만료</th>
|
||
<th>SLA</th><th>서버</th><th>담당자</th><th>상태</th><th>관리</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="inst-tbody"></tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<!-- 스크립트 관리 뷰 -->
|
||
<div id="view-scripts" class="view">
|
||
<div class="list-toolbar">
|
||
<input type="text" id="script-search" placeholder="스크립트명·설명·태그 검색…" class="search-box" oninput="filterScripts()">
|
||
<select id="script-category-filter" class="filter-select" onchange="filterScripts()">
|
||
<option value="">전체 카테고리</option>
|
||
<option value="SM">SM (일상운영)</option>
|
||
<option value="REGULAR">정기점검</option>
|
||
<option value="ADHOC">수시점검</option>
|
||
<option value="DEPLOY">배포</option>
|
||
<option value="SECURITY">보안</option>
|
||
<option value="MONITORING">모니터링</option>
|
||
</select>
|
||
<select id="script-layer-filter" class="filter-select" onchange="filterScripts()">
|
||
<option value="">전체 레이어</option>
|
||
<option value="WEB">WEB</option>
|
||
<option value="WAS">WAS</option>
|
||
<option value="DB">DB</option>
|
||
<option value="ALL">공통</option>
|
||
</select>
|
||
<button class="btn btn-primary" onclick="openScriptModal()">+ 스크립트 등록</button>
|
||
</div>
|
||
<div id="script-list-body"></div>
|
||
</div>
|
||
|
||
<!-- 작업 타임테이블 뷰 -->
|
||
<div id="view-timetable" class="view">
|
||
<div class="list-toolbar">
|
||
<input type="text" id="tt-search" placeholder="제목·내용 검색…" class="search-box" oninput="filterTimetable()">
|
||
<select id="tt-type-filter" class="filter-select" onchange="filterTimetable()">
|
||
<option value="">전체 유형</option>
|
||
<option value="REGULAR_CHECK">정기점검</option>
|
||
<option value="PM">예방정비</option>
|
||
<option value="SR">SR작업</option>
|
||
<option value="ADHOC">수시점검</option>
|
||
<option value="DEPLOY">배포</option>
|
||
<option value="EMERGENCY">긴급대응</option>
|
||
</select>
|
||
<select id="tt-status-filter" class="filter-select" onchange="filterTimetable()">
|
||
<option value="">전체 결과</option>
|
||
<option value="PENDING">예정</option>
|
||
<option value="SUCCESS">완료</option>
|
||
<option value="FAILED">실패</option>
|
||
<option value="PARTIAL">부분완료</option>
|
||
<option value="CANCELLED">취소</option>
|
||
</select>
|
||
<button class="btn btn-primary" onclick="openTimetableModal()">+ 작업 등록</button>
|
||
<button class="btn btn-secondary" onclick="exportTimetableExcel()" title="Excel 다운로드">📥 Excel</button>
|
||
</div>
|
||
<table class="sr-table" id="tt-table">
|
||
<thead>
|
||
<tr>
|
||
<th>유형</th><th>제목</th><th>기관</th><th>처리예정</th>
|
||
<th>완료</th><th>결과상태</th><th>담당자</th><th>SR</th><th>관리</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="tt-tbody"></tbody>
|
||
</table>
|
||
</div>
|
||
|
||
</main>
|
||
</div>
|
||
|
||
<!-- ── SR Detail Modal ────────────────────────────── -->
|
||
<div id="modal-overlay" class="hidden">
|
||
<div id="modal">
|
||
<button class="modal-close" id="modal-close-btn">×</button>
|
||
<div id="modal-body"><!-- filled by JS --></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ── New SR Modal ───────────────────────────────── -->
|
||
<div id="new-sr-overlay" class="hidden">
|
||
<div id="new-sr-modal">
|
||
<button class="modal-close" id="new-sr-close">×</button>
|
||
<h2>새 SR 생성</h2>
|
||
<form id="new-sr-form">
|
||
<label>제목 <input type="text" name="title" required></label>
|
||
<label>설명 <textarea name="description" rows="3"></textarea></label>
|
||
<div class="form-row">
|
||
<label>유형
|
||
<select name="sr_type">
|
||
<option value="OTHER">기타</option>
|
||
<option value="DEPLOY">배포</option>
|
||
<option value="RESTART">재기동</option>
|
||
<option value="LOG">로그</option>
|
||
<option value="INQUIRY">문의</option>
|
||
</select>
|
||
</label>
|
||
<label>우선순위
|
||
<select name="priority">
|
||
<option value="MEDIUM">보통</option>
|
||
<option value="CRITICAL">긴급</option>
|
||
<option value="HIGH">높음</option>
|
||
<option value="LOW">낮음</option>
|
||
</select>
|
||
</label>
|
||
</div>
|
||
<div class="form-row">
|
||
<label>요청자 <input type="text" name="requested_by" required></label>
|
||
<label>기관코드 <input type="text" name="inst_code" placeholder="MOF / MOIS / MSS"></label>
|
||
</div>
|
||
<label>대상 서버 <input type="text" name="target_server" placeholder="예: MOF-WAS-01"></label>
|
||
<div class="file-upload-area">
|
||
<label class="file-upload-label">
|
||
<span class="file-upload-icon">📎</span>
|
||
<span id="file-upload-text">첨부파일 선택 (선택사항, 최대 10개 · 파일당 20 MB)</span>
|
||
<input type="file" id="sr-file-input" multiple accept=".pdf,.txt,.log,.csv,.png,.jpg,.jpeg,.xlsx,.docx,.zip,.sh,.sql,.json,.yaml,.md" style="display:none">
|
||
</label>
|
||
<div id="file-preview-list"></div>
|
||
</div>
|
||
<button type="submit" class="btn btn-primary" style="width:100%;margin-top:8px">생성</button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ── AI 명령 채팅 패널 ──────────────────────────── -->
|
||
<div id="ai-chat-panel" class="hidden">
|
||
<div id="ai-chat-header">
|
||
<span>🤖 GUARDiA AI 어시스턴트</span>
|
||
<button id="ai-chat-close" title="닫기">×</button>
|
||
</div>
|
||
<div id="ai-chat-messages"></div>
|
||
<div id="ai-chat-suggestions"></div>
|
||
<div id="ai-chat-input-row">
|
||
<input type="text" id="ai-chat-input"
|
||
placeholder="자연어로 명령하세요… 예: 승인 대기 SR 목록 보여줘">
|
||
<button id="ai-chat-send">전송</button>
|
||
</div>
|
||
</div>
|
||
<button id="ai-chat-fab" title="AI 명령 어시스턴트">🤖</button>
|
||
|
||
<!-- ── 기관 등록/수정 모달 ────────────────────────── -->
|
||
<div id="inst-modal-overlay" class="hidden">
|
||
<div id="inst-modal" class="modal-wide">
|
||
<button class="modal-close" onclick="closeInstModal()">×</button>
|
||
<h2 id="inst-modal-title">기관 등록</h2>
|
||
<form id="inst-form" onsubmit="submitInstForm(event)">
|
||
<div class="form-row">
|
||
<label>기관코드 <input type="text" name="inst_code" placeholder="MOF" required></label>
|
||
<label>기관명 <input type="text" name="inst_name" required></label>
|
||
</div>
|
||
<div class="form-row">
|
||
<label>기관유형 <input type="text" name="org_type" placeholder="중앙행정기관"></label>
|
||
<label>지역
|
||
<select name="region">
|
||
<option value="">선택</option>
|
||
<option value="서울">서울</option>
|
||
<option value="세종">세종</option>
|
||
<option value="부산">부산</option>
|
||
<option value="대전">대전</option>
|
||
<option value="기타">기타</option>
|
||
</select>
|
||
</label>
|
||
</div>
|
||
<label>주소 <input type="text" name="address"></label>
|
||
<div class="form-row">
|
||
<label>대표 전화 <input type="text" name="phone" placeholder="044-000-0000"></label>
|
||
<label>SLA (시간) <input type="number" name="sla_hours" value="4" min="1" max="72"></label>
|
||
</div>
|
||
<div class="form-row">
|
||
<label>계약 시작 <input type="date" name="contract_start"></label>
|
||
<label>계약 만료 <input type="date" name="contract_end"></label>
|
||
</div>
|
||
<label>담당 PM <input type="text" name="contact_pm"></label>
|
||
<label>메모 <textarea name="note" rows="2"></textarea></label>
|
||
<button type="submit" class="btn btn-primary" style="width:100%;margin-top:8px">저장</button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ── 담당자 등록/수정 모달 ──────────────────────── -->
|
||
<div id="contact-modal-overlay" class="hidden">
|
||
<div id="contact-modal">
|
||
<button class="modal-close" onclick="closeContactModal()">×</button>
|
||
<h2 id="contact-modal-title">담당자 등록</h2>
|
||
<form id="contact-form" onsubmit="submitContactForm(event)">
|
||
<div class="form-row">
|
||
<label>이름 <input type="text" name="contact_name" required></label>
|
||
<label>역할
|
||
<select name="role">
|
||
<option value="MANAGER">담당자(관리)</option>
|
||
<option value="ENGINEER">엔지니어</option>
|
||
<option value="PM">PM</option>
|
||
<option value="SECURITY">보안담당</option>
|
||
<option value="HELPDESK">헬프데스크</option>
|
||
</select>
|
||
</label>
|
||
</div>
|
||
<div class="form-row">
|
||
<label>부서 <input type="text" name="dept"></label>
|
||
<label>직책 <input type="text" name="position"></label>
|
||
</div>
|
||
<div class="form-row">
|
||
<label>이메일 <input type="email" name="email" placeholder="user@agency.go.kr"></label>
|
||
<label>직통 전화 <input type="text" name="phone"></label>
|
||
</div>
|
||
<div class="form-row">
|
||
<label>휴대폰 <input type="text" name="mobile" placeholder="010-0000-0000"></label>
|
||
<label style="align-items:center;gap:8px">
|
||
주 담당자
|
||
<input type="checkbox" name="is_primary" style="width:auto;margin-top:4px">
|
||
</label>
|
||
</div>
|
||
<label>메모 <textarea name="note" rows="2"></textarea></label>
|
||
<button type="submit" class="btn btn-primary" style="width:100%;margin-top:8px">저장</button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ── 스크립트 등록/수정 모달 ───────────────────── -->
|
||
<div id="script-modal-overlay" class="hidden">
|
||
<div id="script-modal" class="modal-wide modal-xlarge">
|
||
<button class="modal-close" onclick="closeScriptModal()">×</button>
|
||
<h2 id="script-modal-title">스크립트 등록</h2>
|
||
<form id="script-form" onsubmit="submitScriptForm(event)">
|
||
<label>스크립트명 <input type="text" name="script_name" required></label>
|
||
<div class="form-row">
|
||
<label>카테고리
|
||
<select name="category">
|
||
<option value="SM">SM (일상운영)</option>
|
||
<option value="REGULAR">정기점검</option>
|
||
<option value="ADHOC">수시점검</option>
|
||
<option value="DEPLOY">배포</option>
|
||
<option value="SECURITY">보안</option>
|
||
<option value="MONITORING">모니터링</option>
|
||
</select>
|
||
</label>
|
||
<label>세부분류 <input type="text" name="sub_category" placeholder="DISK_CHECK"></label>
|
||
</div>
|
||
<div class="form-row">
|
||
<label>대상 레이어
|
||
<select name="target_layer">
|
||
<option value="ALL">전체 (ALL)</option>
|
||
<option value="WEB">WEB</option>
|
||
<option value="WAS">WAS</option>
|
||
<option value="DB">DB</option>
|
||
<option value="ESB">ESB</option>
|
||
</select>
|
||
</label>
|
||
<label>OS 유형
|
||
<select name="os_type">
|
||
<option value="LINUX">LINUX</option>
|
||
<option value="WINDOWS">WINDOWS</option>
|
||
<option value="ALL">ALL</option>
|
||
</select>
|
||
</label>
|
||
</div>
|
||
<label>설명 <textarea name="description" rows="2" required></textarea></label>
|
||
<label>스크립트 내용
|
||
<textarea name="script_body" rows="10" class="code-textarea" placeholder="#!/bin/bash # 스크립트 내용 입력" required></textarea>
|
||
</label>
|
||
<label>태그 (쉼표 구분) <input type="text" name="tags" placeholder="health,check,linux"></label>
|
||
<div class="form-row" style="align-items:center">
|
||
<label style="flex-direction:row;align-items:center;gap:8px">
|
||
<input type="checkbox" name="is_dangerous" style="width:auto"> 위험 명령 포함
|
||
</label>
|
||
<label style="flex-direction:row;align-items:center;gap:8px">
|
||
<input type="checkbox" name="requires_approval" style="width:auto"> 실행 전 승인 필요
|
||
</label>
|
||
</div>
|
||
<button type="submit" class="btn btn-primary" style="width:100%;margin-top:8px">저장</button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ── 타임테이블 등록/수정 모달 ─────────────────── -->
|
||
<div id="tt-modal-overlay" class="hidden">
|
||
<div id="tt-modal" class="modal-wide">
|
||
<button class="modal-close" onclick="closeTimetableModal()">×</button>
|
||
<h2 id="tt-modal-title">작업 등록</h2>
|
||
<form id="tt-form" onsubmit="submitTimetableForm(event)">
|
||
<div class="form-row">
|
||
<label>작업유형
|
||
<select name="work_type" required>
|
||
<option value="REGULAR_CHECK">정기점검</option>
|
||
<option value="PM">예방정비</option>
|
||
<option value="SR">SR작업</option>
|
||
<option value="ADHOC">수시점검</option>
|
||
<option value="DEPLOY">배포</option>
|
||
<option value="EMERGENCY">긴급대응</option>
|
||
</select>
|
||
</label>
|
||
<label>기관
|
||
<select name="inst_id" id="tt-inst-select">
|
||
<option value="">선택 안 함</option>
|
||
</select>
|
||
</label>
|
||
</div>
|
||
<label>제목 <input type="text" name="title" required></label>
|
||
<div class="form-row">
|
||
<label>처리예정 <input type="datetime-local" name="scheduled_at" required></label>
|
||
<label>SR번호 <input type="text" name="sr_id" placeholder="SR-YYYYMMDD-XXXXXX"></label>
|
||
</div>
|
||
<div class="form-row">
|
||
<label>시작일시 <input type="datetime-local" name="started_at"></label>
|
||
<label>완료일시 <input type="datetime-local" name="completed_at"></label>
|
||
</div>
|
||
<label>처리내용 <textarea name="content" rows="3" required></textarea></label>
|
||
<label>명령어/쉘 스크립트
|
||
<select name="script_id" id="tt-script-select" onchange="fillScriptBody(this)">
|
||
<option value="">직접 입력</option>
|
||
</select>
|
||
</label>
|
||
<label>명령어 직접 입력 <textarea name="command_or_shell" rows="3" class="code-textarea"></textarea></label>
|
||
<label>처리결과 <textarea name="result" rows="3"></textarea></label>
|
||
<div class="form-row">
|
||
<label>결과상태
|
||
<select name="result_status">
|
||
<option value="PENDING">예정</option>
|
||
<option value="SUCCESS">완료</option>
|
||
<option value="FAILED">실패</option>
|
||
<option value="PARTIAL">부분완료</option>
|
||
<option value="CANCELLED">취소</option>
|
||
</select>
|
||
</label>
|
||
<label>담당자 <input type="text" name="assignee" placeholder="사번 또는 이름"></label>
|
||
</div>
|
||
<div class="form-row">
|
||
<label>검토자 <input type="text" name="reviewer" placeholder="PM 사번 또는 이름"></label>
|
||
<label>비고 <input type="text" name="note"></label>
|
||
</div>
|
||
<button type="submit" class="btn btn-primary" style="width:100%;margin-top:8px">저장</button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
|
||
<script src="/static/app.js"></script>
|
||
<!-- 온보딩 가이드 챗봇 — 설치 완료 후 자동 실행 -->
|
||
<script src="/static/onboarding.js"></script>
|
||
<!-- 화면별 도움말 시스템 (GS인증 사용성 요구사항 F1/? 버튼) -->
|
||
<script src="/static/help.js"></script>
|
||
</body>
|
||
</html>
|