guardia-manager/.claude/skills/manager-integration/SKILL.md
DESKTOP-TKLFCPRython 10cc76d6e6 refactor: 101.79.17.164 → zioinfo.co.kr 전체 도메인 변환 + Manager UI 배포
- 37개 파일 IP → zioinfo.co.kr 치환 (소스/매뉴얼/설정/하네스)
- Manager DrConsole/NetworkConsole/CsapConsole 빌드 + /var/www/manager/ 배포
- 테스트: Manager HTTP 200, ITSM 신규 API 7개 전체 200

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 10:09:17 +09:00

5.6 KiB

name description
manager-integration GUARDiA Manager와 외부 시스템(GUARDiA ITSM, Gitea, Ollama) 연동 코드를 구현하는 스킬. API 클라이언트, TypeScript 타입, React 훅을 생성한다. 트리거: API 연동 구현, axios 클라이언트 작성, GUARDiA API 호출, Gitea 연동, Ollama 모델 조회, 데이터 페칭 훅 작성 요청 시.

GUARDiA Manager 연동 구현 스킬

연동 대상 API 목록

GUARDiA ITSM (http://zioinfo.co.kr:8001)

엔드포인트 용도 필요 권한
POST /api/auth/login 로그인 없음
GET /api/dashboard 대시보드 통계 로그인
GET /api/tasks SR 목록 로그인
GET /api/incidents 인시던트 목록 로그인
GET /api/cmdb/servers 서버 자산 목록 로그인
GET /api/tenant 테넌트 목록 admin
GET /api/external/keys API Key 목록 admin
GET /api/audit 감사 로그 admin
GET /api/metrics Prometheus 메트릭 로그인

Gitea (http://zioinfo.co.kr:3000/api/v1)

엔드포인트 용도
GET /repos/search 저장소 목록
GET /repos/{user}/{repo}/commits 최신 커밋
GET /repos/{user}/{repo}/hooks 웹훅 목록

Ollama (http://localhost:11434)

엔드포인트 용도
GET /api/tags 설치된 모델 목록
GET /api/ps 로드된 모델

API 클라이언트 구현

guardiaClient.ts

// frontend/src/api/guardiaClient.ts
import axios from 'axios';

const BASE = import.meta.env.VITE_GUARDIA_API ?? 'http://zioinfo.co.kr:8001';

export const guardiaApi = axios.create({ baseURL: BASE });

// 요청 인터셉터: JWT 자동 주입
guardiaApi.interceptors.request.use((config) => {
  const token = sessionStorage.getItem('guardia_token');
  if (token) config.headers.Authorization = `Bearer ${token}`;
  return config;
});

// 응답 인터셉터: 401 → 로그인 리다이렉트
guardiaApi.interceptors.response.use(
  res => res,
  err => {
    if (err.response?.status === 401) {
      sessionStorage.removeItem('guardia_token');
      window.location.href = '/login';
    }
    return Promise.reject(err);
  }
);

types.ts — 핵심 타입 정의

// frontend/src/api/types.ts

export interface User {
  id: number;
  username: string;
  display_name: string;
  role: 'admin' | 'pm' | 'engineer' | 'customer';
  is_active: boolean;
}

export interface Server {
  id: number;
  hostname: string;
  ip_addr: string;      // ServerOut 스키마에서 제외됨 — 실제 응답에 없을 수 있음
  os_type: string;
  status: 'running' | 'stopped' | 'error' | 'unknown';
  inst_id?: number;
}

export interface SRRequest {
  id: number;
  sr_id: string;
  title: string;
  status: string;
  priority: 'CRITICAL' | 'HIGH' | 'MEDIUM' | 'LOW';
  requested_by: string;
  created_at: string;
}

export interface DashboardStats {
  total_sr: number;
  open_sr: number;
  critical_incidents: number;
  sla_achievement: number;
  server_count: number;
  running_servers: number;
}

export interface APIKey {
  id: number;
  name: string;
  scopes: string;
  is_active: boolean;
  use_count: number;
  last_used_at: string | null;
  expires_at: string | null;
}

export interface AuditLog {
  id: number;
  action: string;
  entity_type: string;
  entity_id: string;
  username: string;
  ip_hash: string;
  created_at: string;
}

export interface SystemResources {
  cpu_percent: number;
  memory: { total_gb: number; used_gb: number; percent: number };
  disk: { total_gb: number; used_gb: number; percent: number };
}

export interface ServiceStatus {
  [serviceName: string]: 'active' | 'inactive' | 'failed' | 'unknown';
}

React 훅 — useGuardiaApi.ts

// frontend/src/hooks/useGuardiaApi.ts
import { useState, useEffect, useCallback } from 'react';
import { guardiaApi } from '../api/guardiaClient';

export function useGuardiaApi<T>(
  url: string,
  options: { immediate?: boolean; deps?: unknown[] } = {}
) {
  const { immediate = true, deps = [] } = options;
  const [data, setData] = useState<T | null>(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const fetch = useCallback(async () => {
    setLoading(true); setError(null);
    try {
      const res = await guardiaApi.get<T>(url);
      setData(res.data);
    } catch (e: any) {
      setError(e.response?.data?.detail ?? '오류가 발생했습니다.');
    } finally {
      setLoading(false);
    }
  }, [url]);

  useEffect(() => { if (immediate) fetch(); }, [fetch, immediate, ...deps]);

  return { data, loading, error, refetch: fetch };
}

환경변수 설정

// frontend/src/config/env.ts
export const ENV = {
  GUARDIA_API: import.meta.env.VITE_GUARDIA_API ?? 'http://zioinfo.co.kr:8001',
  MANAGER_API: import.meta.env.VITE_MANAGER_API ?? 'http://localhost:8002',
  GITEA_API:   import.meta.env.VITE_GITEA_API   ?? 'http://zioinfo.co.kr:3000/api/v1',
  GITEA_USER:  import.meta.env.VITE_GITEA_USER  ?? 'zio',
} as const;

주의사항

  • ServerOut 스키마: GUARDiA ITSM은 보안 정책으로 ip_addr, ssh_user, os_pw_enc 필드를 API 응답에서 제외한다. 이 필드를 프론트엔드에 표시하려면 ITSM 쪽에 별도 admin 엔드포인트가 필요하다.
  • 인증 토큰 저장: localStorage 금지. sessionStorage 또는 메모리 변수 사용.
  • Gitea CORS: Gitea API를 직접 호출하면 CORS 오류 발생 가능. Manager Backend의 프록시 라우터(/api/proxy/gitea) 를 거쳐 호출한다.