# 메인 대시보드 차트 구성 가이드
> 관리자 시스템 메인화면은 대시보드 차트로 구성한다.
> 네이버 클라우드 콘솔의 "서비스 사용 현황" 및 "리소스 모니터링" 화면을 참조한다.
## 메인 대시보드 레이아웃
```
┌─────────────────────────────────────────────────────────────────────────┐
│ GUARDiA Manager — 통합 운영 대시보드 마지막 갱신: 2분 전 [↺ 새로고침] │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌── 핵심 지표 카드 (4개) ─────────────────────────────────────────────┐ │
│ │ [SR 현황] [인시던트] [서버 가용률] [SLA 달성률] │ │
│ │ 24건 긴급 2건 91.7% 98.7% │ │
│ │ 진행중 8↗ 해결중 3 11/12대 실행 ▲ 0.3% │ │
│ └──────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌── SR 추이 꺾은선 차트 ─────────┐ ┌── 서버 상태 도넛 차트 ──────────┐ │
│ │ 7일간 SR 생성 vs 완료 │ │ │ │
│ │ │ │ 실행중 10 │ │
│ │ ╭──╮ │ │ ●────────── │ │
│ │ │ ╰──╮ ╭─── │ │ ○ 중지 1 │ │
│ │ │ ╰────╯ │ │ ● 오류 1 │ │
│ │ └────────────────────────── │ │ │ │
│ │ 월 화 수 목 금 토 일 │ │ 12대 서버 │ │
│ └────────────────────────────────┘ └──────────────────────────────┘ │
│ │
│ ┌── 리소스 모니터링 막대 차트 ──────────────────────────────────────────┐ │
│ │ CPU ██████████░░ 62% 메모리 ████████████░ 78% 디스크 ████░ 16% │ │
│ └──────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌── 최근 배포 이력 타임라인 ────────┐ ┌── AI/LLM 사용 현황 ───────────┐ │
│ │ 5분전 ✅ zioinfo-web v1.2.1 │ │ llama3:8b 응답시간 2.3s │ │
│ │ 1시간 ✅ guardia-itsm v2.0.4 │ │ 요청 124건/오늘 │ │
│ │ 3시간 ❌ zioinfo-web (실패) │ │ [████████░░] 메모리 4.7GB │ │
│ └────────────────────────────────┘ └──────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
```
---
## 차트 라이브러리 선택: Recharts
```bash
npm install recharts
```
**선택 이유:** NCloud 콘솔과 유사한 심플한 차트 스타일, React 친화적, 번들 크기 적당.
---
## 1. SR 추이 꺾은선 차트 (SRTrendChart)
```tsx
// components/dashboard/SRTrendChart.tsx
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts';
interface SRTrendData {
date: string; // 'MM/DD'
created: number;
completed: number;
}
export function SRTrendChart({ data }: { data: SRTrendData[] }) {
return (
SR 생성/완료 추이 (7일)
);
}
```
---
## 2. 서버 상태 도넛 차트 (ServerStatusDonut)
```tsx
// components/dashboard/ServerStatusDonut.tsx
import { PieChart, Pie, Cell, Tooltip, Legend, ResponsiveContainer } from 'recharts';
const COLORS = {
running: '#22c55e',
stopped: '#94a3b8',
error: '#ef4444',
pending: '#f59e0b',
};
export function ServerStatusDonut({ servers }: { servers: { status: string }[] }) {
const counts = servers.reduce((acc, s) => {
acc[s.status] = (acc[s.status] ?? 0) + 1; return acc;
}, {} as Record);
const data = Object.entries(counts).map(([status, value]) => ({
name: { running: '실행중', stopped: '중지', error: '오류', pending: '진행중' }[status] ?? status,
value,
status,
}));
return (
서버 상태 ({servers.length}대)
{data.map((entry) => (
|
))}
[`${value}대`, name]} />
);
}
```
---
## 3. 리소스 모니터링 바 차트 (ResourceGauge)
```tsx
// components/dashboard/ResourceGauge.tsx
// NCloud 콘솔의 리소스 게이지 UI 참조
interface GaugeProps {
label: string;
percent: number;
detail?: string;
}
function Gauge({ label, percent, detail }: GaugeProps) {
const color = percent > 90 ? '#ef4444' : percent > 70 ? '#f59e0b' : '#22c55e';
return (
{label}
{percent}%
{detail &&
{detail}
}
);
}
export function ResourceGauge({ resources }: { resources: SystemResources }) {
return (
);
}
```
---
## 4. 배포 이력 타임라인 (DeployTimeline)
```tsx
// components/dashboard/DeployTimeline.tsx
import { useGuardiaApi } from '../../hooks/useGuardiaApi';
function timeAgo(ts: string) {
const diff = Date.now() - new Date(ts).getTime();
if (diff < 60000) return '방금 전';
if (diff < 3600000) return `${Math.floor(diff/60000)}분 전`;
return `${Math.floor(diff/3600000)}시간 전`;
}
export function DeployTimeline() {
const { data: logs } = useGuardiaApi('/api/deploy/history');
const parsed = (logs ?? []).slice(-5).reverse().map(line => ({
time: line.match(/\d{4}-\d{2}-\d{2} \d{2}:\d{2}/)?.[0] ?? '',
ok: line.includes('완료') || line.includes('success'),
msg: line.replace(/^\d{4}.*?INFO\s+/, '').trim().slice(0, 60),
}));
return (
최근 배포 이력
{parsed.map((item, i) => (
-
{item.ok ? '✅' : '❌'}
{item.msg}
{item.time}
))}
{!parsed.length && (
- 배포 이력이 없습니다.
)}
);
}
```
---
## Dashboard.tsx 전체 조합
```tsx
// pages/Dashboard.tsx
import { StatCard } from '../components/common/StatCard';
import { SRTrendChart } from '../components/dashboard/SRTrendChart';
import { ServerStatusDonut } from '../components/dashboard/ServerStatusDonut';
import { ResourceGauge } from '../components/dashboard/ResourceGauge';
import { DeployTimeline } from '../components/dashboard/DeployTimeline';
import { useGuardiaApi } from '../hooks/useGuardiaApi';
import { useManagerApi } from '../hooks/useManagerApi';
export function Dashboard() {
const { data: stats } = useGuardiaApi('/api/dashboard');
const { data: resources } = useManagerApi('/api/system/resources');
const { data: servers } = useGuardiaApi('/api/cmdb/servers?limit=100');
return (
{/* 핵심 지표 카드 */}
s.status==='running').length / servers.length)*100).toFixed(1)}%` : '-'}
icon="🖥️" color="#f0fdf4" />
{/* 차트 행 1: SR 추이 + 서버 상태 */}
{/* 리소스 게이지 */}
{resources &&
}
{/* 차트 행 2: 배포 이력 + LLM */}
{/* LLM 상태 카드 추가 가능 */}
);
}
```