guardia-itsm/static/index.html
2026-06-03 20:13:36 +09:00

986 lines
54 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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 &copy; 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&#10;# 스크립트 내용 입력" 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>