Compare commits
2 Commits
efcc771263
...
91a573c504
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
91a573c504 | ||
|
|
77024af42e |
93
CLAUDE.md
93
CLAUDE.md
@ -1,17 +1,86 @@
|
||||
# GUARDiA Manager
|
||||
# GUARDiA 관리자 시스템 (Manager)
|
||||
|
||||
**저장소**: http://101.79.17.164:3000/zio/guardia-manager
|
||||
**배포**: git push origin main → Gitea webhook → 자동 배포
|
||||
**라이브**: https://zioinfo.co.kr:8090
|
||||
**서버 경로**: /opt/manager/
|
||||
> **Claude Code용 프로젝트 마스터 컨텍스트**
|
||||
|
||||
---
|
||||
|
||||
## 프로젝트 비전
|
||||
|
||||
GUARDiA ITSM·홈페이지·서버 인프라·CI/CD를 단일 화면에서 통합 관제하는
|
||||
**경량 관리자 포털**. GUARDiA ITSM API를 허브로 삼아 별도 DB 없이 운영한다.
|
||||
|
||||
---
|
||||
|
||||
## 기술 스택
|
||||
- Frontend: React 18 + TypeScript + Vite (Variant 디자인)
|
||||
- Backend: Python FastAPI (포트 8002)
|
||||
|
||||
## 로그인
|
||||
- ITSM과 동일 계정 사용 (admin / 1111)
|
||||
- JWT 공유 secret: GUARDIA_JWT_SECRET
|
||||
| 레이어 | 기술 | 비고 |
|
||||
|--------|------|------|
|
||||
| Frontend | React 18 + TypeScript + Vite | 독립 SPA |
|
||||
| Backend | Python FastAPI (경량) | 시스템 수준 작업 전용 |
|
||||
| 인증 | GUARDiA ITSM JWT 공유 | 별도 DB 없음 |
|
||||
| 연동 | GUARDiA ITSM REST API | http://zioinfo.co.kr:8001 |
|
||||
| 배포 | Gitea + Deploy Webhook | 포트 9999 |
|
||||
|
||||
## 하네스
|
||||
- Manager UI: `manager-orchestrator` 스킬
|
||||
---
|
||||
|
||||
## 제안 기능 목록 (M-01 ~ M-08)
|
||||
|
||||
| 코드 | 기능 | 우선순위 | 연동 대상 |
|
||||
|------|------|---------|---------|
|
||||
| **M-01** | 통합 운영 대시보드 (**메인화면 — 차트 중심**) | ⭐ 필수 | ITSM API, 서버 SSH |
|
||||
| **M-02** | 테넌트/사용자 관리 | ⭐ 필수 | ITSM /api/auth, /api/tenant |
|
||||
| **M-03** | CMDB/서버 자산 관리 | ⭐ 필수 | ITSM /api/cmdb, /api/ssh |
|
||||
| **M-04** | 배포/CI-CD 관리 | ⭐ 필수 | Gitea API, Deploy Webhook |
|
||||
| **M-05** | 보안/API Key 관리 | ⭐ 필수 | ITSM /api/external/keys, /api/audit |
|
||||
| **M-06** | LLM/AI 엔진 관리 | 🔵 권장 | Ollama API (localhost:11434) |
|
||||
| **M-07** | 시스템 설정 관리 | 🔵 권장 | .env 편집, Nginx 리로드 |
|
||||
| **M-08** | 알림/리포트 | 🟡 선택 | ITSM /api/report, 이메일 |
|
||||
|
||||
---
|
||||
|
||||
## 디렉터리 구조
|
||||
|
||||
```
|
||||
C:\GUARDiA\manager\
|
||||
├── CLAUDE.md ← 이 파일
|
||||
├── frontend/ ← React SPA
|
||||
│ ├── src/
|
||||
│ │ ├── pages/ ← 각 기능 페이지
|
||||
│ │ ├── components/ ← 공통 컴포넌트
|
||||
│ │ ├── hooks/ ← 커스텀 훅
|
||||
│ │ └── api/ ← API 클라이언트
|
||||
│ └── package.json
|
||||
├── backend/ ← FastAPI (시스템 작업 전용)
|
||||
│ ├── main.py
|
||||
│ ├── routers/
|
||||
│ │ ├── system.py ← 서버 상태, 서비스 제어
|
||||
│ │ ├── deploy.py ← 배포 트리거, 이력
|
||||
│ │ └── config.py ← 설정 관리
|
||||
│ └── requirements.txt
|
||||
└── .claude/
|
||||
├── agents/ ← 에이전트 정의
|
||||
└── skills/ ← 스킬 파일
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 하네스: GUARDiA Manager
|
||||
|
||||
**목표:** 관리자 시스템 전체 구현 — UI 설계 → API 연동 → 보안 → 배포까지 자동화
|
||||
|
||||
**UI 참조:** 네이버 클라우드 콘솔(console.ncloud.com) 디자인 패턴 적용 필수.
|
||||
좌측 사이드바 서비스 트리 + 상단 GNB 레이아웃, 리소스 상태 배지, NCloud 스타일 테이블.
|
||||
|
||||
**메인화면:** 대시보드 차트 중심 구성 — SR 추이(꺾은선), 서버 상태(도넛), 리소스(게이지), 배포 이력(타임라인).
|
||||
→ `references/dashboard-charts.md` 참조.
|
||||
|
||||
**트리거:** 관리자 시스템 관련 작업 요청 시 `manager-orchestrator` 스킬을 사용하라.
|
||||
`M-01 대시보드 만들어줘`, `M-03 CMDB 페이지 구현`, `배포 관리 기능 추가` 등.
|
||||
다시 실행, 재실행, 업데이트, 수정, 보완 요청 시에도 이 스킬을 사용하라.
|
||||
|
||||
**변경 이력:**
|
||||
| 날짜 | 변경 내용 | 대상 | 사유 |
|
||||
|------|----------|------|------|
|
||||
| 2026-05-30 | 초기 하네스 구성 | 전체 | GUARDiA Manager 신규 구축 |
|
||||
| 2026-05-30 | M-01~M-08 전체 구현 + 서버 배포 | frontend/, backend/, deploy_server.py | 단계별 전체 구현 완료 |
|
||||
| 2026-05-31 | roadmap-planner 에이전트 + manager-roadmap 스킬 추가 | agents/, skills/ | MG-01~MG-09 추가 개발 제안 (DR·네트워크·CSAP 관제 연동) |
|
||||
|
||||
@ -1,7 +0,0 @@
|
||||
MANAGER_PORT=8002
|
||||
GUARDIA_API=http://localhost:8001
|
||||
GUARDIA_JWT_SECRET=guardia-jwt-production-secret-2026-please-change
|
||||
MANAGER_ALLOWED_ORIGINS=http://localhost:5175,http://localhost:5173,http://zioinfo.co.kr:8090
|
||||
DEPLOY_WEBHOOK=http://localhost:9999/
|
||||
DEPLOY_LOG=/var/log/zioinfo/deploy.log
|
||||
OLLAMA_URL=http://localhost:11434
|
||||
99
frontend/src/components/Icons.tsx
Normal file
99
frontend/src/components/Icons.tsx
Normal file
@ -0,0 +1,99 @@
|
||||
/**
|
||||
* GUARDiA Manager 라인 아이콘 라이브러리
|
||||
* stroke 기반, strokeLinecap/Join=round, fill=none
|
||||
* 원본: workspace/zioinfo-web/frontend/src/components/Icons.jsx 에서 파생
|
||||
*/
|
||||
|
||||
import React from 'react'
|
||||
|
||||
interface IcoProps {
|
||||
size?: number
|
||||
color?: string
|
||||
sw?: number
|
||||
style?: React.CSSProperties
|
||||
className?: string
|
||||
}
|
||||
|
||||
const D = { size: 18, sw: 1.8 }
|
||||
|
||||
const Ico: React.FC<IcoProps & { children: React.ReactNode }> = ({
|
||||
size = D.size, color = 'currentColor', sw = D.sw, children, ...p
|
||||
}) => (
|
||||
<svg width={size} height={size} viewBox="0 0 24 24" fill="none"
|
||||
stroke={color} strokeWidth={sw} strokeLinecap="round" strokeLinejoin="round" {...p}>
|
||||
{children}
|
||||
</svg>
|
||||
)
|
||||
|
||||
/* ── 대시보드 / 분석 ── */
|
||||
export const IconBarChart = (p: IcoProps) => <Ico {...p}><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"/></Ico>
|
||||
export const IconTrendUp = (p: IcoProps) => <Ico {...p}><polyline points="23 6 13.5 15.5 8.5 10.5 1 18"/><polyline points="17 6 23 6 23 12"/></Ico>
|
||||
export const IconPieChart = (p: IcoProps) => <Ico {...p}><path d="M21.2 15A9 9 0 118.8 2.8"/><path d="M12 2v10l7 4"/></Ico>
|
||||
export const IconActivity = (p: IcoProps) => <Ico {...p}><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></Ico>
|
||||
export const IconKpi = (p: IcoProps) => <Ico {...p}><circle cx="12" cy="12" r="10"/><circle cx="12" cy="12" r="6"/><circle cx="12" cy="12" r="2"/><path d="M12 2v4M12 18v4M2 12h4M18 12h4"/></Ico>
|
||||
|
||||
/* ── 인프라 / 서버 ── */
|
||||
export const IconServer = (p: IcoProps) => <Ico {...p}><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"/></Ico>
|
||||
export const IconDatabase = (p: IcoProps) => <Ico {...p}><ellipse cx="12" cy="5" rx="9" ry="3"/><path d="M21 12c0 1.7-4 3-9 3s-9-1.3-9-3"/><path d="M3 5v14c0 1.7 4 3 9 3s9-1.3 9-3V5"/></Ico>
|
||||
export const IconCpu = (p: IcoProps) => <Ico {...p}><rect x="4" y="4" width="16" height="16" rx="2"/><rect x="9" y="9" width="6" height="6"/><path d="M9 1v3M15 1v3M9 20v3M15 20v3M1 9h3M1 15h3M20 9h3M20 15h3"/></Ico>
|
||||
export const IconCloud = (p: IcoProps) => <Ico {...p}><path d="M18 10h-1.3A7 7 0 106 19h12a4 4 0 000-8v-1z"/></Ico>
|
||||
export const IconGlobe = (p: IcoProps) => <Ico {...p}><circle cx="12" cy="12" r="10"/><path d="M2 12h20M12 2a15 15 0 010 20M12 2a15 15 0 000 20"/></Ico>
|
||||
export const IconHardDrive = (p: IcoProps) => <Ico {...p}><rect x="2" y="6" width="20" height="12" rx="2"/><path d="M17 13h.01"/><path d="M6 13h8"/></Ico>
|
||||
|
||||
/* ── 배포 / CI-CD ── */
|
||||
export const IconRocket = (p: IcoProps) => <Ico {...p}><path d="M4.5 16.5c-1.5 1.5-1.5 3.5 0 3.5s3.5-1.5 3.5-3.5c0 0-1.5-.5-3.5 0z"/><path d="M12 2C8 2 5 8 5 13l2 2 4-2 4 2 2-2c0-5-3-11-5-11z"/><circle cx="12" cy="10" r="2"/></Ico>
|
||||
export const IconGitBranch = (p: IcoProps) => <Ico {...p}><line x1="6" y1="3" x2="6" y2="15"/><circle cx="18" cy="6" r="3"/><circle cx="6" cy="18" r="3"/><path d="M18 9a9 9 0 01-9 9"/></Ico>
|
||||
export const IconCode = (p: IcoProps) => <Ico {...p}><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></Ico>
|
||||
export const IconPackage = (p: IcoProps) => <Ico {...p}><line x1="16.5" y1="9.4" x2="7.5" y2="4.21"/><path d="M21 16V8a2 2 0 00-1-1.73l-7-4a2 2 0 00-2 0l-7 4A2 2 0 002 8v8a2 2 0 001 1.73l7 4a2 2 0 002 0l7-4A2 2 0 0021 16z"/><polyline points="3.27 6.96 12 12.01 20.73 6.96"/><line x1="12" y1="22.08" x2="12" y2="12"/></Ico>
|
||||
|
||||
/* ── 사용자 / 테넌트 ── */
|
||||
export const IconUsers = (p: IcoProps) => <Ico {...p}><circle cx="9" cy="8" r="3"/><path d="M2 20c0-3.3 2.9-6 7-6s7 2.7 7 6"/><circle cx="18" cy="9" r="2.5" opacity=".6"/><path d="M22 20c0-2.5-2-4.5-4-4.5" opacity=".6"/></Ico>
|
||||
export const IconUser = (p: IcoProps) => <Ico {...p}><circle cx="12" cy="8" r="4"/><path d="M4 20c0-4 3.6-7 8-7s8 3 8 7"/></Ico>
|
||||
export const IconBuilding = (p: IcoProps) => <Ico {...p}><path d="M3 21h18M3 7l9-4 9 4M4 7v14M20 7v14M9 21v-4h6v4M9 11h1M14 11h1M9 15h1M14 15h1"/></Ico>
|
||||
|
||||
/* ── 보안 ── */
|
||||
export const IconLock = (p: IcoProps) => <Ico {...p}><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"/></Ico>
|
||||
export const IconKey = (p: IcoProps) => <Ico {...p}><circle cx="8" cy="15" r="4"/><path d="M12 11l8-8M17 6l3 3"/></Ico>
|
||||
export const IconShield = (p: IcoProps) => <Ico {...p}><path d="M12 2l9 4v5c0 5.2-3.9 10-9 11C6.9 21 3 16.2 3 11V6l9-4z"/></Ico>
|
||||
export const IconEye = (p: IcoProps) => <Ico {...p}><path d="M1 12S5 4 12 4s11 8 11 8-4 8-11 8S1 12 1 12z"/><circle cx="12" cy="12" r="3"/></Ico>
|
||||
|
||||
/* ── AI / LLM ── */
|
||||
export const IconBrain = (p: IcoProps) => <Ico {...p}><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"/></Ico>
|
||||
export const IconZap = (p: IcoProps) => <Ico {...p}><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></Ico>
|
||||
export const IconAI = (p: IcoProps) => <Ico {...p}><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"/></Ico>
|
||||
|
||||
/* ── 시스템 설정 ── */
|
||||
export const IconSettings = (p: IcoProps) => <Ico {...p}><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"/><path d="M12 4a8 8 0 012.8.5l1-1.8a10 10 0 00-7.6 0l1 1.8A8 8 0 0112 4zM12 20a8 8 0 01-2.8-.5l-1 1.8a10 10 0 007.6 0l-1-1.8A8 8 0 0112 20z"/></Ico>
|
||||
export const IconFileText = (p: IcoProps) => <Ico {...p}><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"/></Ico>
|
||||
export const IconSliders = (p: IcoProps) => <Ico {...p}><line x1="4" y1="21" x2="4" y2="14"/><line x1="4" y1="10" x2="4" y2="3"/><line x1="12" y1="21" x2="12" y2="12"/><line x1="12" y1="8" x2="12" y2="3"/><line x1="20" y1="21" x2="20" y2="16"/><line x1="20" y1="12" x2="20" y2="3"/><line x1="1" y1="14" x2="7" y2="14"/><line x1="9" y1="8" x2="15" y2="8"/><line x1="17" y1="16" x2="23" y2="16"/></Ico>
|
||||
|
||||
/* ── 알림 ── */
|
||||
export const IconBell = (p: IcoProps) => <Ico {...p}><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"/></Ico>
|
||||
|
||||
/* ── 연동 / 외부 ── */
|
||||
export const IconLink = (p: IcoProps) => <Ico {...p}><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"/></Ico>
|
||||
export const IconRefresh = (p: IcoProps) => <Ico {...p}><polyline points="23 4 23 10 17 10"/><polyline points="1 20 1 14 7 14"/><path d="M3.5 9A9 9 0 0121 12M3 12a9 9 0 0017.5 3"/></Ico>
|
||||
|
||||
/* ── 운영 관제 ── */
|
||||
export const IconRadio = (p: IcoProps) => <Ico {...p}><circle cx="12" cy="12" r="2"/><path d="M16.2 7.8a5.5 5.5 0 010 8.4"/><path d="M7.8 7.8a5.5 5.5 0 000 8.4"/><path d="M19.1 4.9a9.5 9.5 0 010 14.2"/><path d="M4.9 4.9a9.5 9.5 0 000 14.2"/></Ico>
|
||||
export const IconNetwork = (p: IcoProps) => <Ico {...p}><circle cx="12" cy="5" r="2"/><circle cx="5" cy="19" r="2"/><circle cx="19" cy="19" r="2"/><path d="M12 7v5M12 12l-5.5 5M12 12l5.5 5"/></Ico>
|
||||
export const IconCheckCircle = (p: IcoProps) => <Ico {...p}><path d="M22 11.1V12a10 10 0 11-5.9-9.1"/><polyline points="22 4 12 14.1 9 11.1"/></Ico>
|
||||
|
||||
/* ── 과금 ── */
|
||||
export const IconMoney = (p: IcoProps) => <Ico {...p}><rect x="1" y="4" width="22" height="16" rx="2"/><circle cx="12" cy="12" r="3"/><path d="M1 9h4M19 9h4M1 15h4M19 15h4"/></Ico>
|
||||
export const IconCreditCard= (p: IcoProps) => <Ico {...p}><rect x="1" y="4" width="22" height="16" rx="2"/><line x1="1" y1="10" x2="23" y2="10"/></Ico>
|
||||
|
||||
/* ── 앱 배포 ── */
|
||||
export const IconMobile = (p: IcoProps) => <Ico {...p}><rect x="5" y="2" width="14" height="20" rx="2"/><line x1="12" y1="18" x2="12.01" y2="18" strokeWidth="3"/></Ico>
|
||||
export const IconDownload = (p: IcoProps) => <Ico {...p}><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></Ico>
|
||||
export const IconQrCode = (p: IcoProps) => <Ico {...p}><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"/></Ico>
|
||||
|
||||
/* ── 설치 가이드 ── */
|
||||
export const IconBook = (p: IcoProps) => <Ico {...p}><path d="M4 19.5A2.5 2.5 0 016.5 17H20V3H6.5A2.5 2.5 0 004 5.5v14z"/><path d="M6.5 17v4"/><path d="M8 7h8M8 11h6"/></Ico>
|
||||
|
||||
/* ── 스크래핑 ── */
|
||||
export const IconSpider = (p: IcoProps) => <Ico {...p}><circle cx="12" cy="12" r="4"/><path d="M2 12h3M19 12h3M12 2v3M12 19v3M4.9 4.9l2.1 2.1M16.9 16.9l2.1 2.1M4.9 19.1l2.1-2.1M16.9 7.1l2.1-2.1"/></Ico>
|
||||
|
||||
/* ── 라이선스 ── */
|
||||
export const IconBadge = (p: IcoProps) => <Ico {...p}><path d="M12 2l2.4 4.8 5.3.8-3.9 3.7.9 5.3L12 14l-4.7 2.6.9-5.3L4.3 7.6l5.3-.8z"/></Ico>
|
||||
export const IconTag = (p: IcoProps) => <Ico {...p}><path d="M20.6 11.4l-9-9A2 2 0 0010.2 2H4a2 2 0 00-2 2v6.2a2 2 0 00.6 1.4l9 9a2 2 0 002.8 0l6.2-6.2a2 2 0 000-2.8z"/><circle cx="7" cy="7" r="1" fill="currentColor" stroke="none"/></Ico>
|
||||
@ -1,52 +1,62 @@
|
||||
import { NavLink } from 'react-router-dom'
|
||||
import { useState } from 'react'
|
||||
import {
|
||||
IconBarChart, IconServer, IconDatabase, IconRocket, IconGitBranch,
|
||||
IconUsers, IconBuilding, IconLock, IconKey, IconBrain, IconSettings,
|
||||
IconFileText, IconSliders, IconBell, IconLink, IconRadio, IconNetwork,
|
||||
IconCheckCircle, IconMoney, IconMobile, IconTrendUp, IconBook,
|
||||
IconSpider, IconTag, IconRefresh,
|
||||
} from '../Icons'
|
||||
import type { FC, ReactElement } from 'react'
|
||||
|
||||
interface NavItem { label: string; path?: string; icon: string; children?: NavItem[] }
|
||||
type IconComp = (p: { size?: number; color?: string }) => ReactElement
|
||||
|
||||
interface NavItem { label: string; path?: string; icon: IconComp | null; children?: NavItem[] }
|
||||
|
||||
const NAV: NavItem[] = [
|
||||
{ label: '대시보드', icon: '📊', path: '/' },
|
||||
{ label: '인프라 관리', icon: '🖥️', children: [
|
||||
{ label: '서버 목록', icon: '', path: '/servers' },
|
||||
{ label: 'CMDB 현황', icon: '', path: '/cmdb' },
|
||||
{ label: '대시보드', icon: IconBarChart, path: '/' },
|
||||
{ label: '인프라 관리', icon: IconServer, children: [
|
||||
{ label: '서버 목록', icon: null, path: '/servers' },
|
||||
{ label: 'CMDB 현황', icon: null, path: '/cmdb' },
|
||||
]},
|
||||
{ label: '배포/CI-CD', icon: '🚀', children: [
|
||||
{ label: '배포 이력', icon: '', path: '/deployments' },
|
||||
{ label: '저장소 목록',icon: '', path: '/repos' },
|
||||
{ label: '배포/CI-CD', icon: IconRocket, children: [
|
||||
{ label: '배포 이력', icon: null, path: '/deployments' },
|
||||
{ label: '저장소 목록',icon: null, path: '/repos' },
|
||||
]},
|
||||
{ label: '사용자/테넌트',icon: '👥', children: [
|
||||
{ label: '사용자 관리',icon: '', path: '/users' },
|
||||
{ label: '기관 관리', icon: '', path: '/institutions' },
|
||||
{ label: '사용자/테넌트',icon: IconUsers, children: [
|
||||
{ label: '사용자 관리',icon: null, path: '/users' },
|
||||
{ label: '기관 관리', icon: null, path: '/institutions' },
|
||||
]},
|
||||
{ label: '보안', icon: '🔒', children: [
|
||||
{ label: 'API Key', icon: '', path: '/api-keys' },
|
||||
{ label: '감사 로그', icon: '', path: '/audit' },
|
||||
{ label: '보안', icon: IconLock, children: [
|
||||
{ label: 'API Key', icon: null, path: '/api-keys' },
|
||||
{ label: '감사 로그', icon: null, path: '/audit' },
|
||||
]},
|
||||
{ label: 'AI / LLM', icon: '🤖', path: '/llm' },
|
||||
{ label: '시스템 설정', icon: '⚙️', children: [
|
||||
{ label: '환경변수', icon: '', path: '/config/env' },
|
||||
{ label: 'Nginx 관리', icon: '', path: '/config/nginx' },
|
||||
{ label: 'AI / LLM', icon: IconBrain, path: '/llm' },
|
||||
{ label: '시스템 설정', icon: IconSettings, children: [
|
||||
{ label: '환경변수', icon: null, path: '/config/env' },
|
||||
{ label: 'Nginx 관리', icon: null, path: '/config/nginx' },
|
||||
]},
|
||||
{ label: '알림/리포트', icon: '🔔', path: '/notifications' },
|
||||
{ label: '스크랩핑 봇', icon: '🕷️', path: '/scraping' },
|
||||
{ label: '라이선스 관리',icon: '🪪', path: '/licenses' },
|
||||
{ label: '데이터 연동', icon: '🔄', path: '/export-import' },
|
||||
{ label: '운영 관제', icon: '🛰️', children: [
|
||||
{ label: 'DR 재해복구', icon: '', path: '/dr' },
|
||||
{ label: '네트워크 장비', icon: '', path: '/network' },
|
||||
{ label: 'CSAP 점검', icon: '', path: '/csap' },
|
||||
{ label: '알림/리포트', icon: IconBell, path: '/notifications' },
|
||||
{ label: '스크랩핑 봇', icon: IconSpider, path: '/scraping' },
|
||||
{ label: '라이선스 관리',icon: IconTag, path: '/licenses' },
|
||||
{ label: '데이터 연동', icon: IconRefresh, path: '/export-import' },
|
||||
{ label: '운영 관제', icon: IconRadio, children: [
|
||||
{ label: 'DR 재해복구', icon: null, path: '/dr' },
|
||||
{ label: '네트워크 장비', icon: null, path: '/network' },
|
||||
{ label: 'CSAP 점검', icon: null, path: '/csap' },
|
||||
]},
|
||||
// ── GUARDiA 확장 v3 ──
|
||||
{ label: '분석 · KPI', icon: '📈', children: [
|
||||
{ label: 'KPI 대시보드', icon: '', path: '/kpi' },
|
||||
{ label: 'BI 대시보드', icon: '', path: '/bi' },
|
||||
{ label: '분석 · KPI', icon: IconTrendUp, children: [
|
||||
{ label: 'KPI 대시보드', icon: null, path: '/kpi' },
|
||||
{ label: 'BI 대시보드', icon: null, path: '/bi' },
|
||||
]},
|
||||
{ label: 'AI 플랫폼', icon: '🧠', path: '/ai-platform' },
|
||||
{ label: '외부 연동', icon: '🔗', path: '/integrations' },
|
||||
{ label: '구독 · 과금', icon: '💰', path: '/billing' },
|
||||
{ label: 'AI 플랫폼', icon: IconBrain, path: '/ai-platform' },
|
||||
{ label: '외부 연동', icon: IconLink, path: '/integrations' },
|
||||
{ label: '구독 · 과금', icon: IconMoney, path: '/billing' },
|
||||
// ── GUARDiA 기능 개선 v4 ──
|
||||
{ label: '앱 배포', icon: '📱', path: '/app-distribution' },
|
||||
{ label: '알림 규칙', icon: '🔔', path: '/notification-rules' },
|
||||
{ label: '설치 가이드', icon: '📦', path: '/install-guide' },
|
||||
{ label: '앱 배포', icon: IconMobile, path: '/app-distribution' },
|
||||
{ label: '알림 규칙', icon: IconBell, path: '/notification-rules' },
|
||||
{ label: '설치 가이드', icon: IconBook, path: '/install-guide' },
|
||||
]
|
||||
|
||||
/* Variant 스타일 색상 상수 */
|
||||
@ -64,6 +74,7 @@ const V = {
|
||||
|
||||
function NavGroup({ item }: { item: NavItem }) {
|
||||
const [open, setOpen] = useState(true)
|
||||
const IcoComp = item.icon
|
||||
|
||||
if (!item.children) {
|
||||
return (
|
||||
@ -77,7 +88,9 @@ function NavGroup({ item }: { item: NavItem }) {
|
||||
transition: 'all .15s',
|
||||
textDecoration: 'none',
|
||||
})}>
|
||||
<span style={{ width: 18, textAlign: 'center' }}>{item.icon}</span>
|
||||
<span style={{ width: 18, height: 18, display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
|
||||
{IcoComp && <IcoComp size={16} />}
|
||||
</span>
|
||||
{item.label}
|
||||
</NavLink>
|
||||
)
|
||||
@ -91,7 +104,9 @@ function NavGroup({ item }: { item: NavItem }) {
|
||||
border: 'none', cursor: 'pointer', fontWeight: 700,
|
||||
letterSpacing: '-.01em',
|
||||
}}>
|
||||
<span style={{ width: 18, textAlign: 'center' }}>{item.icon}</span>
|
||||
<span style={{ width: 18, height: 18, display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0, color: V.cyan }}>
|
||||
{IcoComp && <IcoComp size={16} color={V.cyan} />}
|
||||
</span>
|
||||
{item.label}
|
||||
<span style={{
|
||||
marginLeft: 'auto', fontSize: 9, color: V.cyan,
|
||||
|
||||
@ -1 +1 @@
|
||||
{"root":["./src/app.tsx","./src/main.tsx","./src/api/clients.ts","./src/api/types.ts","./src/components/common/btn.tsx","./src/components/common/datatable.tsx","./src/components/common/protectedroute.tsx","./src/components/common/slidepanel.tsx","./src/components/common/statcard.tsx","./src/components/common/statusbadge.tsx","./src/components/layout/applayout.tsx","./src/components/layout/gnb.tsx","./src/components/layout/sidebar.tsx","./src/config/env.ts","./src/hooks/useapi.ts","./src/hooks/useauth.ts","./src/pages/aiplatform.tsx","./src/pages/apikeys.tsx","./src/pages/appdistribution.tsx","./src/pages/auditlog.tsx","./src/pages/bianalytics.tsx","./src/pages/billingmanage.tsx","./src/pages/cmdb.tsx","./src/pages/configenv.tsx","./src/pages/confignginx.tsx","./src/pages/csapconsole.tsx","./src/pages/dashboard.tsx","./src/pages/deployments.tsx","./src/pages/drconsole.tsx","./src/pages/exportimport.tsx","./src/pages/installguide.tsx","./src/pages/institutions.tsx","./src/pages/integrationhub.tsx","./src/pages/kpidashboard.tsx","./src/pages/llmmanager.tsx","./src/pages/licenses.tsx","./src/pages/login.tsx","./src/pages/networkconsole.tsx","./src/pages/notificationrules.tsx","./src/pages/notifications.tsx","./src/pages/repos.tsx","./src/pages/scrapingmanager.tsx","./src/pages/servers.tsx","./src/pages/users.tsx"],"version":"5.9.3"}
|
||||
{"root":["./src/app.tsx","./src/main.tsx","./src/api/clients.ts","./src/api/types.ts","./src/components/common/btn.tsx","./src/components/common/datatable.tsx","./src/components/common/protectedroute.tsx","./src/components/common/slidepanel.tsx","./src/components/common/statcard.tsx","./src/components/common/statusbadge.tsx","./src/components/layout/applayout.tsx","./src/components/layout/gnb.tsx","./src/components/layout/sidebar.tsx","./src/config/env.ts","./src/hooks/useapi.ts","./src/hooks/useauth.ts","./src/pages/aiplatform.tsx","./src/pages/apikeys.tsx","./src/pages/appdistribution.tsx","./src/pages/auditlog.tsx","./src/pages/bianalytics.tsx","./src/pages/billingmanage.tsx","./src/pages/cmdb.tsx","./src/pages/configenv.tsx","./src/pages/confignginx.tsx","./src/pages/csapconsole.tsx","./src/pages/dashboard.tsx","./src/pages/deployments.tsx","./src/pages/drconsole.tsx","./src/pages/exportimport.tsx","./src/pages/institutions.tsx","./src/pages/integrationhub.tsx","./src/pages/kpidashboard.tsx","./src/pages/llmmanager.tsx","./src/pages/licenses.tsx","./src/pages/login.tsx","./src/pages/networkconsole.tsx","./src/pages/notificationrules.tsx","./src/pages/notifications.tsx","./src/pages/repos.tsx","./src/pages/scrapingmanager.tsx","./src/pages/servers.tsx","./src/pages/users.tsx"],"version":"5.9.3"}
|
||||
Loading…
Reference in New Issue
Block a user