import axios from 'axios' import * as SecureStore from 'expo-secure-store' import { API_BASE } from '../constants/Config' const client = axios.create({ baseURL: API_BASE, timeout: 15000, // 자체서명 인증서 허용 (개발/테스트) }) client.interceptors.request.use(async (cfg) => { const token = await SecureStore.getItemAsync('grd_token') if (token) cfg.headers.Authorization = `Bearer ${token}` return cfg }) client.interceptors.response.use( (r) => r, async (err) => { if (err.response?.status === 401) { await SecureStore.deleteItemAsync('grd_token') await SecureStore.deleteItemAsync('grd_user') } return Promise.reject(err) } ) /* ── 인증 ── */ export const login = (username: string, password: string) => client.post('/api/auth/login', { username, password }) export const getMe = () => client.get('/api/auth/me') /* ── 인증·보안 (#33 #34 #37 #38) ── */ /* 등록 디바이스 관리 */ export const getDevices = () => client.get('/api/auth/devices') export const deleteDevice = (id: string | number) => client.delete(`/api/auth/devices/${id}`) /* 보안 이벤트 로그 */ export const getSecurityEvents = () => client.get('/api/auth/events') /* Zero Trust 네트워크 상태 */ export const getNetworkStatus = () => client.get('/api/auth/network-status') /* 멀티기관 전환 */ export const getInstitutions = () => client.get('/api/institutions/') export const switchTenant = (tenantId: string | number) => client.post('/api/auth/switch-tenant', { tenant_id: tenantId }) /* ── 대시보드 ── */ export const getDashboard = () => client.get('/api/dashboard') /* ── SR ── */ export const getSRList = (page = 0, size = 20) => client.get(`/api/tasks?page=${page}&size=${size}`) export const getSRDetail = (id: number) => client.get(`/api/tasks/${id}`) export const createSR = (data: { title: string; description: string; priority: string; sr_type: string }) => client.post('/api/tasks', data) export const updateSRStatus = (id: number, status: string) => client.patch(`/api/tasks/${id}/status`, { status }) /* SR 부분 수정 (스와이프 상태 전환 등) */ export const patchSR = (id: number, data: Record) => client.patch(`/api/tasks/${id}`, data) /* 빠른 SR 등록 (FormData 또는 JSON) */ export const createSRRaw = (data: Record) => client.post('/api/tasks', data) /* 일괄 상태 변경 */ export const batchUpdateSR = (ids: number[], status: string) => client.patch('/api/tasks/batch', { ids, status }) /* 에스컬레이션 */ export const escalateSR = (id: number, reason?: string) => client.post(`/api/tasks/${id}/escalate`, { reason: reason ?? '' }) /* 구독 / 팔로우 토글 */ export const subscribeSR = (id: number, subscribe: boolean) => client.post(`/api/tasks/${id}/subscribe`, { subscribe }) /* 만족도 평가 */ export const rateSR = (id: number, score: number, comment?: string) => client.post(`/api/tasks/${id}/rating`, { score, comment: comment ?? '' }) /* 코멘트 작성 (내부/외부) */ export const addSRComment = (id: number, content: string, isInternal: boolean) => client.post(`/api/tasks/${id}/comments`, { content, is_internal: isInternal }) export const getSRComments = (id: number) => client.get(`/api/tasks/${id}/comments`) /* 인시던트 타임라인 */ export const getSRTimeline = (id: number) => client.get(`/api/tasks/${id}/timeline`) /* 관련 SR */ export const getRelatedSR = (id: number) => client.get(`/api/tasks`, { params: { related_to: id } }) /* 중복 SR 감지 */ export const findSimilarSR = (title: string, limit = 3) => client.get(`/api/tasks`, { params: { title_similar: title, status: 'open', limit } }) /* SR 템플릿 */ export const getSRTemplates = () => client.get('/api/tasks/templates') /* 미처리 SR 카운트 (뱃지용) */ export const getOpenSRCount = () => client.get('/api/tasks', { params: { status: 'open', assigned_to: 'me', size: 1 } }) /* ── AI 챗봇 ── */ export const sendAIMessage = (message: string) => client.post('/api/chatbot/message', { message }) /* ── 라이선스 ── */ export const getLicenseStatus = () => client.get('/api/license/status') /* ── 알림 ── */ export const getNotifications = () => client.get('/api/notifications?size=30') export const markNotificationRead = (id: number) => client.patch(`/api/notifications/${id}/read`) /* ── DR 자동화 ── */ export const getDRDashboard = () => client.get('/api/dr/dashboard') export const getDRRtoRpo = () => client.get('/api/dr/rto-rpo') export const getDRScenarios = () => client.get('/api/dr/scenarios') export const runDRTest = (scenarioId: number) => client.post('/api/dr/test', { scenario_id: scenarioId, test_type: 'RECOVERY' }) /* ── 네트워크 장비 ── */ export const getNetworkDevices = (instId?: number) => client.get('/api/network/devices', { params: instId ? { inst_id: instId } : {} }) export const getNetworkTopology = () => client.get('/api/network/topology') export const backupNetworkDevice = (id: number) => client.post(`/api/network/devices/${id}/backup`) export const getNetworkDiff = (id: number) => client.get(`/api/network/devices/${id}/diff`) /* ── CSAP 점검 ── */ export const getCSAPDashboard = () => client.get('/api/compliance/csap/dashboard') export const getCSAPItems = () => client.get('/api/compliance/csap/items') export const getCSAPResults = () => client.get('/api/compliance/csap/results') /* ── 모니터링·알림 (#39~#50) ── */ /* #39 서버 상태 대시보드 — 이름/상태/리소스 수치만 (IP·계정·PW 노출 금지) */ export const getServerStatus = () => client.get('/api/servers/status') /* #42 서버 부하 히트맵 (status 재활용 가능, 별도 엔드포인트 우선 시도) */ export const getServerHeatmap = () => client.get('/api/servers/status') /* #47 서버 메트릭 시계열 (range: 1h/6h/24h) */ export const getServerMetrics = (id: string | number, range = '1h') => client.get(`/api/servers/${id}/metrics`, { params: { range } }) /* #43 SLA 위반 예측 */ export const getSLAPrediction = () => client.get('/api/sla/prediction') /* #44 서비스 상태 */ export const getServiceStatus = () => client.get('/api/service-status') /* #45 알림 규칙 노코드 편집기 */ export const getAlertRules = () => client.get('/api/alert-rules/') export const createAlertRule = (data: Record) => client.post('/api/alert-rules/', data) export const updateAlertRule = (id: string | number, data: Record) => client.put(`/api/alert-rules/${id}`, data) export const deleteAlertRule = (id: string | number) => client.delete(`/api/alert-rules/${id}`) export const toggleAlertRule = (id: string | number) => client.patch(`/api/alert-rules/${id}/toggle`) /* #46 온콜 스케줄 */ export const getOncallSchedule = () => client.get('/api/oncall/schedule') /* #48 임계값 초과 이력 */ export const getThresholdHistory = (page = 0, size = 30) => client.get('/api/threshold-history', { params: { page, size } }) /* #49 커스텀 대시보드 위젯 */ export const getCustomDashboard = () => client.get('/api/custom-dashboard') export const saveCustomDashboard = (widgets: unknown[]) => client.put('/api/custom-dashboard', { widgets }) /* #50 글로벌 통합 검색 */ export const globalSearch = (q: string, types = 'sr,server,kb,institution') => client.get('/api/search/', { params: { q, types } }) /* ────────────────────────────────────────────── * 승인·워크플로우 (#63~#70) * ────────────────────────────────────────────── */ /* #63 승인 요청 목록 (기본: 대기 상태) */ export const getApprovals = (status = 'pending') => client.get('/api/approvals/', { params: { status } }) /* #64 승인 / 반려 */ export const approveRequest = (id: string | number, comment = '') => client.post(`/api/approvals/${id}/approve`, { comment }) export const rejectRequest = (id: string | number, reason: string) => client.post(`/api/approvals/${id}/reject`, { reason }) /* #64 언두 — 3초 내 실행취소 */ export const cancelApproval = (id: string | number) => client.patch(`/api/approvals/${id}/cancel`) /* #65 다단계 승인 진행 단계 */ export const getApprovalStages = (id: string | number) => client.get(`/api/approvals/${id}/stages`) /* #67 대리결재 설정 */ export const getDelegation = () => client.get('/api/approvals/delegate') export const setDelegation = (data: { delegate_to: string | number start_date: string end_date: string reason: string }) => client.post('/api/approvals/delegate', data) export const cancelDelegation = (id: string | number) => client.delete(`/api/approvals/delegate/${id}`) /* #67 사용자 검색 (대리인 지정용) */ export const searchUsers = (q: string) => client.get('/api/auth/users', { params: { q } }) /* #68 변경 관리 캘린더 */ export const getChangeCalendar = (month: string) => client.get('/api/changes/calendar', { params: { month } }) /* #69 자동화 규칙 조회 (워크플로우 엔진) */ export const getAutomationRules = () => client.get('/api/automation-rules/') /* #70 SLA 예외 승인 */ export const getSLAExceptionPending = () => client.get('/api/tasks', { params: { sla_exception_pending: true } }) export const requestSLAException = ( id: string | number, data: { reason: string; new_deadline: string } ) => client.post(`/api/tasks/${id}/sla-exception`, data) /* ────────────────────────────────────────────── * 지식베이스·문서 (#71~#77) * ────────────────────────────────────────────── */ export const getKBList = (q = '', category = '', page = 0, size = 20) => client.get('/api/kb/', { params: { q, category, page, size } }) export const getKBDetail = (id: string | number) => client.get(`/api/kb/${id}`) export const getKBBookmarks = () => client.get('/api/kb/bookmarks') export const toggleKBBookmark = (id: string | number) => client.post(`/api/kb/${id}/bookmark`) export const ocrScanDocument = (formData: FormData) => client.post('/api/ocr/parse', formData, { headers: { 'Content-Type': 'multipart/form-data' } }) export const getMeetingMinutes = (page = 0) => client.get('/api/meetings/', { params: { page, size: 20 } }) export const getMeetingMinuteDetail = (id: string | number) => client.get(`/api/meetings/${id}`) export const getReleaseNotes = () => client.get('/api/system/release-notes') /* ────────────────────────────────────────────── * 준수·거버넌스 (#78~#84) * ────────────────────────────────────────────── */ export const getCSAPScore = () => client.get('/api/compliance/csap/dashboard') export const getCSAPNonCompliant = () => client.get('/api/compliance/csap/items', { params: { status: 'fail' } }) export const createCSAPSR = (itemId: string | number) => client.post('/api/tasks', { title: `CSAP 미준수 즉시 조치: 항목 ${itemId}`, description: `CSAP 점검 항목 ${itemId} 미준수 즉시 조치`, priority: 'HIGH', sr_type: 'CHANGE', csap_item_id: itemId }) export const getAuditLogs = (page = 0, size = 30) => client.get('/api/audit/', { params: { page, size } }) export const getLicenseExpired = () => client.get('/api/license/status') export const getPatchStatus = () => client.get('/api/patches/status') export const getPIITypes = () => client.get('/api/patches/pii-types') export const applyPatch = (cveId: string) => client.post(`/api/patches/${cveId}/apply`) export const getAISOCEvents = (page = 0) => client.get('/api/ai-soc/events', { params: { page, size: 20 } }) /* ────────────────────────────────────────────── * 통계·보고 (#93~#97) * ────────────────────────────────────────────── */ export const getMyStats = () => client.get('/api/stats/my') export const getInstitutionStats = () => client.get('/api/stats/institutions') export const getDeployHistory = () => client.get('/api/stats/deploy-history') export const getKPIDashboard = () => client.get('/api/stats/kpi') export const getReportData = () => client.get('/api/stats/export-pdf') /* ────────────────────────────────────────────── * 협업·연동 (#98~#100) * ────────────────────────────────────────────── */ export const getSRChat = (srId: number, page = 0) => client.get(`/api/sr-chat/${srId}/messages`, { params: { page, size: 50 } }) export const sendSRChat = (srId: number, content: string, msgType = 'text') => client.post(`/api/sr-chat/${srId}/messages`, { content, msg_type: msgType }) export const getAPKQRCode = () => client.get('/api/cicd/status') export const getBuilds = () => client.get('/api/cicd/builds') export const triggerBuild = (project: string) => client.post('/api/cicd/builds/trigger', { project }) /* ────────────────────────────────────────────── * 2세대 확장 API (#101~#200) * ────────────────────────────────────────────── */ /* AIOps / 예측 */ export const getFailurePredictions = () => client.get('/api/predictive/failure') export const getCapacityPredictions = (days: 30 | 60 | 90) => client.get('/api/capacity/predictions', { params: { days } }) /* GreenOps */ export const getGreenopsEnergy = () => client.get('/api/greenops/energy') export const getGreenopsCarbon = () => client.get('/api/greenops/carbon') /* 비용 최적화 */ export const getCostRecommendations = () => client.get('/api/cost-optimizer/recommendations') export const getSavingsDashboard = () => client.get('/api/mobile2/savings-dashboard') /* 서비스 의존성 */ export const getServiceDependencyMap = () => client.get('/api/knowledge-graph/service-map') /* 정책 위반 */ export const getPolicyViolations = () => client.get('/api/policy/violations') /* 전자서명 */ export const getPendingDocs = () => client.get('/api/approvals/pending-docs') export const signDocument = (id: string | number, pinHash: string) => client.post(`/api/approvals/${id}/sign`, { pin_hash: pinHash }) /* 하드웨어 보증 */ export const getHWWarranty = () => client.get('/api/cmdb/warranty') /* NFC / 자산 */ export const getAssetById = (id: string | number) => client.get(`/api/cmdb/assets/${id}`) export const nfcCheckin = (serverId: string | number) => client.post('/api/servers/field-checkin', { server_id: serverId, source: 'nfc', method: 'nfc_tag' }) /* CVE / 위협 */ export const getCVEList = () => client.get('/api/patches/cve') export const getThreatFeed = () => client.get('/api/ai-soc/threats') export const searchIOC = (q: string) => client.get('/api/ai-soc/ioc/search', { params: { q } }) export const getSecurityScore = () => client.get('/api/ai-soc/security-score') /* AI 이력 / 브리핑 */ export const getChatbotHistory = (page = 0) => client.get('/api/mobile2/chatbot-history', { params: { page, size: 20 } }) export const getAIBriefing = () => client.get('/api/ai-insights/briefing') export const getOllamaStatus = () => client.get('/api/ai-insights/ollama-status') export const pullOllamaModel = (model: string) => client.post('/api/ai-insights/ollama-pull', { model }) /* 캘린더 / 유지보수 */ export const getWorkCalendar = (year: number, month: number) => client.get('/api/mobile2/work-calendar', { params: { year, month } }) export const getMaintenanceWindows = () => client.get('/api/cmdb/maintenance') export const cancelMaintenanceWindow = (id: string | number) => client.delete(`/api/cmdb/maintenance/${id}`) /* VM */ export const getVMs = () => client.get('/api/cloud/vms') export const vmAction = (id: string | number, action: 'start' | 'stop' | 'reboot') => client.post(`/api/cloud/vms/${id}/${action}`) /* SSL / EOL */ export const getSSLCerts = () => client.get('/api/cmdb/ssl-certs') export const getEOLSoftware = () => client.get('/api/cmdb/eol-software') /* 리더보드 / 히트맵 */ export const getTeamLeaderboard = () => client.get('/api/mobile2/team-leaderboard') export const getSRHourlyPattern = () => client.get('/api/mobile2/hourly-pattern') /* 나라장터 / 시민 */ export const getG2BContracts = () => client.get('/api/public-sector/g2b-contracts') export const getCitizenRequests = () => client.get('/api/citizen/requests') /* Ollama 브리핑 보조 */ export const getHourlyPattern = () => client.get('/api/mobile2/hourly-pattern') export const getIncidentPatterns = () => client.get('/api/mobile2/incident-patterns') export const getHandoverChecklist = () => client.get('/api/mobile2/handover-checklist') export const getTeamPresence = () => client.get('/api/mobile2/team-presence') export const getAppVersion = () => client.get('/api/mobile2/app-version') export const getAnnouncements = () => client.get('/api/mobile2/announcements') export default client