/**
* GUARDiA ITSM 화면별 도움말 시스템 (GS인증 사용성 요구사항)
* - 각 화면/기능의 ? 버튼 → 팝업 도움말
* - F1 키 → 현재 화면 도움말
* - 검색 가능한 도움말 DB
*/
(function GUARDiAHelp() {
'use strict';
// ── 도움말 데이터베이스 ────────────────────────────────────
const HELP_DB = {
'dashboard': {
title: '대시보드',
icon: '📊',
content: `
통합 대시보드
GUARDiA ITSM의 모든 운영 현황을 한눈에 확인할 수 있는 화면입니다.
탭 구성
- 운영 현황: SR 상태·SLA·7일 추이 차트
- 인프라: 서버 헬스·기관별 현황
- 보안: 취약점·패치 현황
- AI 인사이트: 이상탐지·예측 현황
KPI 카드
상단 숫자 카드를 클릭하면 해당 상세 목록으로 이동합니다.
단축키
`,
},
'tasks': {
title: 'SR 서비스 요청',
icon: '📋',
content: `
SR 서비스 요청 관리
IT 서비스 요청(SR)을 접수·처리·추적하는 화면입니다.
SR 상태 흐름
접수 → 파싱 → 승인대기 → 승인 → 진행중 → PM검증 → 완료
주요 기능
- AI 자동 분류: SR 생성 시 우선순위·카테고리 자동 제안
- SLA 타이머: 우선순위별 처리 기한 자동 계산
- 대량 처리: 여러 SR을 한 번에 상태 변경
봇 명령어
/sr <제목> - 메신저에서 즉시 접수
/sla - SLA 위반 목록 조회
`,
},
'cmdb': {
title: 'CMDB 형상관리',
icon: '🖥️',
content: `
CMDB (Configuration Management Database)
관리하는 모든 IT 자산(서버·소프트웨어·네트워크)을 등록·관리합니다.
서버 등록 방법
- 서버 관리 → 서버 등록 버튼 클릭
- 서버명, IP, OS, SSH 계정 입력
- SSH 비밀번호는 AES-256 암호화 저장
CI 의존관계
서버 간 의존관계를 등록하면 배포 영향도 자동 분석에 활용됩니다.
보안 주의사항
⚠️ root 계정 SSH 직접 접속 금지 — opsagent 계정 사용
`,
},
'incidents': {
title: '인시던트 관리',
icon: '🚨',
content: `
인시던트(장애) 관리
IT 서비스 장애를 신속하게 탐지·대응·복구하는 프로세스입니다.
장애 등급
- P1 🚨: 전체 서비스 중단 — 즉시 대응, MTTR 1시간
- P2 🔴: 주요 기능 장애 — MTTR 4시간
- P3 🟠: 부분 영향 — MTTR 24시간
- P4 🟡: 경미 — MTTR 72시간
AI 자동 RCA
인시던트 종료 시 Ollama AI가 근본원인 초안을 자동 생성합니다.
봇 명령어
/incident <제목> P1 - 즉시 P1 인시던트 등록
/rca INC-XXXX - AI RCA 분석 요청
`,
},
'si': {
title: 'PMS 프로젝트 관리',
icon: '🏗️',
content: `
PMS (Project Management System)
SI 프로젝트의 전체 생명주기를 관리합니다.
관리 항목
- WBS: 작업 분류 체계, 진척률 입력
- 산출물: 문서 제출·검토·승인 워크플로우
- 이슈: 프로젝트 이슈 → SR 자동 연결
- 위험: 리스크 매트릭스 관리
- 보고서: 일간/주간/월간 자동 생성
자동 보고서
매일 18:00 일일 보고서, 매주 금요일 주간 보고서가 운영팀에 자동 발송됩니다.
`,
},
'license': {
title: '라이선스 관리',
icon: '🔏',
content: `
라이선스 관리
에디션 비교
| 에디션 | 기관 | 사용자 | 기능 |
| COMMUNITY | 1 | 10 | 기본 |
| STANDARD | 50 | 200 | 전체 |
| ENTERPRISE | 무제한 | 무제한 | 전체+APM |
체험판
무료 체험 시작 버튼으로 30일 체험판을 즉시 활성화할 수 있습니다.
라이선스 갱신
만료 30일 전부터 알림이 발송됩니다. 갱신 키를 입력하여 연장하세요.
`,
},
'agents': {
title: 'AI 에이전트',
icon: '🤖',
content: `
AI 에이전트 시스템
GUARDiA의 AI 에이전트는 온프레미스 Ollama LLM을 사용합니다. 외부 API 호출 없음.
에이전트 역할
- SR 매니저: SR 자동 분류·배정
- 코드 리뷰어: 배포 전 코드 품질 검토
- SLA 가디언: SLA 위반 모니터링·에스컬레이션
- KB 큐레이터: 해결된 SR → KB 자동 생성
Ollama 상태 확인
상단 Ollama 상태 표시가 🟢이면 AI 기능 사용 가능합니다.
`,
},
'default': {
title: 'GUARDiA ITSM 도움말',
icon: '❓',
content: `
GUARDiA ITSM v2.0
AI 기반 레거시 인프라 자율 운영 플랫폼
빠른 시작
- 좌측 메뉴에서 원하는 기능을 선택하세요
- 각 화면에서 ? 버튼을 누르면 상세 도움말이 표시됩니다
- F1로 언제든 도움말을 열 수 있습니다
메신저 봇 명령어
/help - 전체 명령어 목록
/sr <제목> - SR 접수
/status - 시스템 현황
기술 지원
📧 support@zioinfo.co.kr | 📞 02-000-0000
`,
},
};
// ── 현재 뷰 감지 ───────────────────────────────────────────
function getCurrentView() {
const path = location.pathname;
const viewEl = document.querySelector('[data-view].active');
const viewId = viewEl?.dataset?.view;
if (viewId) return viewId;
if (path.includes('/si')) return 'si';
if (path.includes('/incidents')) return 'incidents';
if (path.includes('/license')) return 'license';
if (path.includes('/agents')) return 'agents';
return 'default';
}
// ── 팝업 HTML 빌드 ─────────────────────────────────────────
function buildPopup() {
if (document.getElementById('grd-help-popup')) return;
const overlay = document.createElement('div');
overlay.id = 'grd-help-overlay';
overlay.innerHTML = `
`;
const style = document.createElement('style');
style.id = 'grd-help-style';
style.textContent = `
#grd-help-overlay {
position: fixed; inset: 0; z-index: 10000;
background: rgba(0,0,0,.6); backdrop-filter: blur(4px);
display: flex; align-items: center; justify-content: center;
animation: fadeIn .15s ease;
}
@keyframes fadeIn { from{opacity:0} to{opacity:1} }
#grd-help-popup {
background: var(--surface, #1e2333);
border: 1px solid var(--border, rgba(255,255,255,.1));
border-radius: 16px;
width: min(680px, 95vw);
max-height: 80vh;
display: flex; flex-direction: column;
box-shadow: 0 24px 80px rgba(0,0,0,.5);
animation: slideUp .2s ease;
}
@keyframes slideUp { from{transform:translateY(20px);opacity:0} to{transform:translateY(0);opacity:1} }
#grd-help-header {
display: flex; align-items: center; gap: 12px;
padding: 18px 20px; border-bottom: 1px solid var(--border, rgba(255,255,255,.08));
flex-shrink: 0;
}
#grd-help-icon { font-size: 24px; }
#grd-help-title {
flex: 1; font-size: 18px; font-weight: 700;
color: var(--text-bright, #f1f5f9); margin: 0;
}
#grd-help-close {
width: 32px; height: 32px; border-radius: 8px;
background: rgba(255,255,255,.08); border: none;
color: var(--text-muted, #64748b); cursor: pointer;
font-size: 16px; display: flex; align-items: center; justify-content: center;
transition: all .15s;
}
#grd-help-close:hover { background: rgba(255,255,255,.15); color: #fff; }
#grd-help-search-area {
padding: 12px 20px; border-bottom: 1px solid var(--border, rgba(255,255,255,.08));
flex-shrink: 0;
}
#grd-help-search {
width: 100%; padding: 8px 14px;
background: rgba(255,255,255,.06); border: 1px solid rgba(255,255,255,.1);
border-radius: 8px; color: var(--text-bright, #f1f5f9);
font-size: 14px; outline: none; box-sizing: border-box;
}
#grd-help-search:focus { border-color: #818cf8; }
#grd-help-body {
flex: 1; overflow-y: auto; padding: 20px;
color: var(--text-bright, #e2e8f0); line-height: 1.7; font-size: 14px;
scrollbar-width: thin;
}
#grd-help-body h3 { font-size: 18px; color: #818cf8; margin: 0 0 12px; }
#grd-help-body h4 { font-size: 14px; font-weight: 700; color: #a5b4fc; margin: 16px 0 6px; }
#grd-help-body ul,ol { padding-left: 20px; margin: 6px 0; }
#grd-help-body li { margin: 4px 0; }
#grd-help-body code {
background: rgba(255,255,255,.1); padding: 2px 6px;
border-radius: 4px; font-family: monospace; font-size: 13px;
}
#grd-help-body kbd {
background: rgba(255,255,255,.15); padding: 1px 6px;
border-radius: 4px; font-size: 12px; border: 1px solid rgba(255,255,255,.2);
}
.help-flow {
background: rgba(129,140,248,.1); border-left: 3px solid #818cf8;
padding: 10px 14px; border-radius: 0 8px 8px 0; margin: 8px 0;
font-family: monospace; font-size: 13px;
}
.help-table { border-collapse: collapse; width: 100%; margin: 8px 0; font-size: 13px; }
.help-table th { background: rgba(255,255,255,.08); padding: 6px 10px; text-align: left; }
.help-table td { padding: 5px 10px; border-bottom: 1px solid rgba(255,255,255,.05); }
#grd-help-nav {
display: flex; flex-wrap: wrap; gap: 6px;
padding: 12px 20px; border-top: 1px solid rgba(255,255,255,.08);
flex-shrink: 0;
}
.grd-help-topic {
padding: 5px 12px; border-radius: 20px; font-size: 12px;
background: rgba(255,255,255,.06); border: 1px solid rgba(255,255,255,.1);
color: var(--text-muted, #64748b); cursor: pointer; transition: all .15s;
}
.grd-help-topic:hover, .grd-help-topic.active {
background: rgba(129,140,248,.2); border-color: #818cf8; color: #818cf8;
}
#grd-help-footer {
display: flex; justify-content: space-between; align-items: center;
padding: 10px 20px; border-top: 1px solid rgba(255,255,255,.05);
font-size: 11px; color: var(--text-muted, #64748b); flex-shrink: 0;
}
#grd-help-footer a { color: #818cf8; }
/* 화면별 ? 버튼 */
.grd-help-btn {
width: 28px; height: 28px; border-radius: 50%;
background: rgba(129,140,248,.15); border: 1px solid rgba(129,140,248,.3);
color: #818cf8; cursor: pointer; font-size: 14px; font-weight: 700;
display: inline-flex; align-items: center; justify-content: center;
transition: all .15s; line-height: 1;
}
.grd-help-btn:hover { background: rgba(129,140,248,.3); transform: scale(1.1); }
`;
document.head.appendChild(style);
document.body.appendChild(overlay);
// 이벤트
overlay.addEventListener('click', e => { if (e.target === overlay) closeHelp(); });
document.getElementById('grd-help-close').onclick = closeHelp;
document.getElementById('grd-help-search').oninput = searchHelp;
document.querySelectorAll('.grd-help-topic').forEach(btn => {
btn.onclick = () => showTopic(btn.dataset.topic);
});
}
// ── 도움말 표시 ────────────────────────────────────────────
function showHelp(topicId) {
buildPopup();
const topic = topicId || getCurrentView();
showTopic(topic);
document.getElementById('grd-help-overlay').style.display = 'flex';
document.getElementById('grd-help-search').focus();
}
function showTopic(topicId) {
const data = HELP_DB[topicId] || HELP_DB['default'];
document.getElementById('grd-help-icon').textContent = data.icon;
document.getElementById('grd-help-title').textContent = data.title;
document.getElementById('grd-help-body').innerHTML = data.content;
document.querySelectorAll('.grd-help-topic').forEach(b =>
b.classList.toggle('active', b.dataset.topic === topicId));
}
function closeHelp() {
const ol = document.getElementById('grd-help-overlay');
if (ol) { ol.style.display = 'none'; }
document.getElementById('grd-help-search').value = '';
}
function searchHelp() {
const q = this.value.toLowerCase();
if (!q) { showTopic(getCurrentView()); return; }
let results = '';
for (const [id, data] of Object.entries(HELP_DB)) {
if (id === 'default') continue;
const text = data.content.replace(/<[^>]+>/g, '').toLowerCase();
if (text.includes(q) || data.title.toLowerCase().includes(q)) {
results += `
${data.icon} ${data.title}
${data.content.replace(/<[^>]+>/g,'').substring(0,150)}...
`;
}
}
document.getElementById('grd-help-body').innerHTML =
results || `"${q}"에 대한 결과가 없습니다.
`;
}
// ── ? 버튼 자동 삽입 ───────────────────────────────────────
function injectHelpButtons() {
const targets = [
{ selector: '.card-header', topic: null },
{ selector: '.section-header', topic: null },
{ selector: '.page-hero-title', topic: null },
{ selector: '#grd-ob-header', topic: 'default', skip: true },
];
targets.forEach(({ selector, topic, skip }) => {
if (skip) return;
document.querySelectorAll(selector).forEach(el => {
if (el.querySelector('.grd-help-btn')) return;
const btn = document.createElement('button');
btn.className = 'grd-help-btn';
btn.textContent = '?';
btn.title = '도움말 (F1)';
btn.setAttribute('aria-label', '도움말');
btn.onclick = e => { e.stopPropagation(); showHelp(topic); };
el.style.position = 'relative';
el.appendChild(btn);
});
});
}
// ── 전역 ? 도움말 버튼 ─────────────────────────────────────
function buildGlobalHelpBtn() {
if (document.getElementById('grd-global-help')) return;
const btn = document.createElement('button');
btn.id = 'grd-global-help';
btn.textContent = '?';
btn.title = 'GUARDiA 도움말 (F1)';
btn.setAttribute('aria-label', '도움말');
btn.style.cssText = `
position:fixed; right:70px; bottom:20px; z-index:8999;
width:44px; height:44px; border-radius:50%;
background:#4f46e5; color:#fff; border:none;
font-size:18px; font-weight:700; cursor:pointer;
box-shadow:0 4px 16px rgba(79,70,229,.4);
display:flex; align-items:center; justify-content:center;
transition:transform .2s;
`;
btn.onmouseover = () => btn.style.transform = 'scale(1.1)';
btn.onmouseout = () => btn.style.transform = '';
btn.onclick = () => showHelp();
document.body.appendChild(btn);
}
// ── 키보드 단축키 ──────────────────────────────────────────
document.addEventListener('keydown', e => {
if (e.key === 'F1') { e.preventDefault(); showHelp(); }
if (e.key === 'Escape') {
const ol = document.getElementById('grd-help-overlay');
if (ol && ol.style.display !== 'none') closeHelp();
}
});
// ── 초기화 ─────────────────────────────────────────────────
function init() {
buildGlobalHelpBtn();
injectHelpButtons();
// SPA 뷰 변화 시 버튼 재삽입
new MutationObserver(() => injectHelpButtons())
.observe(document.body, { childList: true, subtree: true });
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
setTimeout(init, 300);
}
// 전역 노출
window.GUARDiAHelp = { show: showHelp, close: closeHelp };
})();