From 6196c03e4667559215d1ec7e87aa49a56b772170 Mon Sep 17 00:00:00 2001 From: Hyoseong Jo Date: Sun, 28 Dec 2025 14:31:12 +0900 Subject: [PATCH] =?UTF-8?q?Docker=20=ED=8C=8C=EC=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/api/network/privnet/chart.get.ts | 33 +++----- backend/api/network/privnet/logs.get.ts | 15 ++-- backend/api/network/privnet/status.get.ts | 23 +++--- .../network/privnet/targets/[id].delete.ts | 7 +- .../api/network/privnet/targets/[id].put.ts | 11 ++- .../api/network/privnet/targets/index.get.ts | 10 +-- .../api/network/privnet/targets/index.post.ts | 12 +-- backend/api/network/pubnet/chart.get.ts | 33 +++----- backend/api/network/pubnet/logs.get.ts | 15 ++-- backend/api/network/pubnet/status.get.ts | 23 +++--- .../api/network/pubnet/targets/[id].delete.ts | 7 +- .../api/network/pubnet/targets/[id].put.ts | 11 ++- .../api/network/pubnet/targets/index.get.ts | 10 +-- .../api/network/pubnet/targets/index.post.ts | 12 +-- .../api/server/history/container-list.get.ts | 38 ++++----- backend/api/server/history/containers.get.ts | 77 ++++++++++--------- backend/api/server/history/disk-list.get.ts | 36 +++++---- backend/api/server/history/disks.get.ts | 71 +++++++++-------- backend/api/server/history/latest.get.ts | 31 ++++---- backend/api/server/history/networks.get.ts | 71 +++++++++-------- backend/api/server/history/snapshots.get.ts | 67 +++++++--------- backend/api/settings/thresholds.get.ts | 22 +++--- backend/api/settings/thresholds.put.ts | 22 +++--- 23 files changed, 302 insertions(+), 355 deletions(-) diff --git a/backend/api/network/privnet/chart.get.ts b/backend/api/network/privnet/chart.get.ts index ccadb88..2144c18 100644 --- a/backend/api/network/privnet/chart.get.ts +++ b/backend/api/network/privnet/chart.get.ts @@ -1,36 +1,29 @@ -import { getDb } from '../../../utils/db' +import { query } from '../../../utils/db' export default defineEventHandler(async (event) => { - const query = getQuery(event) - const { year, month, week } = query as { year?: string, month?: string, week?: string } + const queryParams = getQuery(event) + const { year, month, week } = queryParams as { year?: string, month?: string, week?: string } if (!year || !month || !week) { return { error: 'year, month, week are required' } } - // 해당 월의 첫날과 마지막날 const y = parseInt(year) const m = parseInt(month) const w = parseInt(week) - // 해당 월의 첫날 const firstDayOfMonth = new Date(y, m - 1, 1) - const firstDayWeekday = firstDayOfMonth.getDay() // 0=일, 1=월, ... + const firstDayWeekday = firstDayOfMonth.getDay() - // 주차의 시작일 계산 (월요일 기준) - // 1주차: 1일이 포함된 주 const mondayOffset = firstDayWeekday === 0 ? -6 : 1 - firstDayWeekday const firstMondayOfMonth = new Date(y, m - 1, 1 + mondayOffset) - // 선택한 주차의 월요일 const weekStart = new Date(firstMondayOfMonth) weekStart.setDate(weekStart.getDate() + (w - 1) * 7) - // 주차의 일요일 const weekEnd = new Date(weekStart) weekEnd.setDate(weekEnd.getDate() + 6) - // 해당 주의 날짜 목록 생성 const weekDates: string[] = [] for (let i = 0; i < 7; i++) { const d = new Date(weekStart) @@ -39,31 +32,23 @@ export default defineEventHandler(async (event) => { weekDates.push(dateStr) } - const db = getDb() - - // 시작/종료 날짜 const startDate = weekDates[0] const endDate = weekDates[6] - // 1시간 단위 성공률 조회 - const heatmapData = db.prepare(` + const heatmapData = await query(` SELECT - date(checked_at) as date, - strftime('%H', checked_at) || ':00' as time_slot, + TO_CHAR(checked_at::timestamp, 'YYYY-MM-DD') as date, + TO_CHAR(checked_at::timestamp, 'HH24:00') as time_slot, COUNT(*) as total_count, SUM(CASE WHEN is_success = 1 THEN 1 ELSE 0 END) as success_count, ROUND(SUM(CASE WHEN is_success = 1 THEN 1.0 ELSE 0.0 END) / COUNT(*) * 100, 1) as success_rate FROM privnet_logs - WHERE date(checked_at) >= ? AND date(checked_at) <= ? + WHERE checked_at::date >= $1 AND checked_at::date <= $2 GROUP BY date, time_slot ORDER BY date, time_slot - `).all(startDate, endDate) + `, [startDate, endDate]) - // 해당 월의 주차 수 계산 const lastDayOfMonth = new Date(y, m, 0) - const lastDate = lastDayOfMonth.getDate() - - // 마지막 날이 몇 주차인지 계산 const lastDayFromFirstMonday = Math.floor((lastDayOfMonth.getTime() - firstMondayOfMonth.getTime()) / (1000 * 60 * 60 * 24)) const totalWeeks = Math.ceil((lastDayFromFirstMonday + 1) / 7) diff --git a/backend/api/network/privnet/logs.get.ts b/backend/api/network/privnet/logs.get.ts index c3e3bb7..324a17c 100644 --- a/backend/api/network/privnet/logs.get.ts +++ b/backend/api/network/privnet/logs.get.ts @@ -1,8 +1,8 @@ -import { getDb } from '../../../utils/db' +import { query } from '../../../utils/db' export default defineEventHandler(async (event) => { - const query = getQuery(event) - const { year, month, day, hour } = query as { + const queryParams = getQuery(event) + const { year, month, day, hour } = queryParams as { year?: string, month?: string, day?: string, hour?: string } @@ -10,13 +10,10 @@ export default defineEventHandler(async (event) => { return { error: 'year, month, day, hour are required' } } - const db = getDb() - - // 해당 시간대 로그 조회 const startTime = `${year}-${month.padStart(2, '0')}-${day.padStart(2, '0')} ${hour.padStart(2, '0')}:00:00` const endTime = `${year}-${month.padStart(2, '0')}-${day.padStart(2, '0')} ${hour.padStart(2, '0')}:59:59` - const logs = db.prepare(` + const logs = await query(` SELECT l.id, l.checked_at, @@ -25,9 +22,9 @@ export default defineEventHandler(async (event) => { t.url as target_url FROM privnet_logs l JOIN privnet_targets t ON l.target_id = t.id - WHERE l.checked_at >= ? AND l.checked_at <= ? + WHERE l.checked_at >= $1 AND l.checked_at <= $2 ORDER BY l.checked_at DESC - `).all(startTime, endTime) + `, [startTime, endTime]) return { logs } }) diff --git a/backend/api/network/privnet/status.get.ts b/backend/api/network/privnet/status.get.ts index 28b1c74..d483d91 100644 --- a/backend/api/network/privnet/status.get.ts +++ b/backend/api/network/privnet/status.get.ts @@ -1,11 +1,8 @@ -import { getDb } from '../../../utils/db' +import { query, queryOne } from '../../../utils/db' import { privnetScheduler } from '../../../utils/privnet-scheduler' -export default defineEventHandler(() => { - const db = getDb() - - // 현재 상태 조회 - const status = db.prepare(` +export default defineEventHandler(async () => { + const status = await queryOne(` SELECT ps.*, pt.name as last_target_name, @@ -13,10 +10,9 @@ export default defineEventHandler(() => { FROM privnet_status ps LEFT JOIN privnet_targets pt ON ps.last_target_id = pt.id WHERE ps.id = 1 - `).get() + `) - // 최근 10개 로그 - const recentLogs = db.prepare(` + const recentLogs = await query(` SELECT pl.*, pt.name as target_name, @@ -25,17 +21,16 @@ export default defineEventHandler(() => { JOIN privnet_targets pt ON pl.target_id = pt.id ORDER BY pl.checked_at DESC LIMIT 10 - `).all() + `) - // 활성 타겟 수 - const targetCount = db.prepare(` + const targetCount = await queryOne<{ cnt: number }>(` SELECT COUNT(*) as cnt FROM privnet_targets WHERE is_active = 1 - `).get() as { cnt: number } + `) return { status, recentLogs, - targetCount: targetCount.cnt, + targetCount: targetCount?.cnt || 0, schedulerRunning: privnetScheduler.getIsRunning() } }) diff --git a/backend/api/network/privnet/targets/[id].delete.ts b/backend/api/network/privnet/targets/[id].delete.ts index b896b27..b33ec56 100644 --- a/backend/api/network/privnet/targets/[id].delete.ts +++ b/backend/api/network/privnet/targets/[id].delete.ts @@ -1,10 +1,9 @@ -import { getDb } from '../../../../utils/db' +import { execute } from '../../../../utils/db' -export default defineEventHandler((event) => { - const db = getDb() +export default defineEventHandler(async (event) => { const id = getRouterParam(event, 'id') - db.prepare(`DELETE FROM privnet_targets WHERE id = ?`).run(id) + await execute(`DELETE FROM privnet_targets WHERE id = $1`, [id]) return { success: true } }) diff --git a/backend/api/network/privnet/targets/[id].put.ts b/backend/api/network/privnet/targets/[id].put.ts index 90b1c6a..d2fe1b4 100644 --- a/backend/api/network/privnet/targets/[id].put.ts +++ b/backend/api/network/privnet/targets/[id].put.ts @@ -1,7 +1,6 @@ -import { getDb } from '../../../../utils/db' +import { execute } from '../../../../utils/db' export default defineEventHandler(async (event) => { - const db = getDb() const id = getRouterParam(event, 'id') const body = await readBody(event) @@ -14,11 +13,11 @@ export default defineEventHandler(async (event) => { }) } - db.prepare(` + await execute(` UPDATE privnet_targets - SET name = ?, url = ?, is_active = ?, updated_at = datetime('now', 'localtime') - WHERE id = ? - `).run(name, url, is_active ? 1 : 0, id) + SET name = $1, url = $2, is_active = $3, updated_at = TO_CHAR(NOW(), 'YYYY-MM-DD HH24:MI:SS') + WHERE id = $4 + `, [name, url, is_active ? 1 : 0, id]) return { id: Number(id), diff --git a/backend/api/network/privnet/targets/index.get.ts b/backend/api/network/privnet/targets/index.get.ts index 37a5005..a547b2d 100644 --- a/backend/api/network/privnet/targets/index.get.ts +++ b/backend/api/network/privnet/targets/index.get.ts @@ -1,12 +1,10 @@ -import { getDb } from '../../../../utils/db' +import { query } from '../../../../utils/db' -export default defineEventHandler(() => { - const db = getDb() - - const targets = db.prepare(` +export default defineEventHandler(async () => { + const targets = await query(` SELECT * FROM privnet_targets ORDER BY id ASC - `).all() + `) return targets }) diff --git a/backend/api/network/privnet/targets/index.post.ts b/backend/api/network/privnet/targets/index.post.ts index 93e1c7e..72ab098 100644 --- a/backend/api/network/privnet/targets/index.post.ts +++ b/backend/api/network/privnet/targets/index.post.ts @@ -1,7 +1,6 @@ -import { getDb } from '../../../../utils/db' +import { queryOne } from '../../../../utils/db' export default defineEventHandler(async (event) => { - const db = getDb() const body = await readBody(event) const { name, url, is_active } = body @@ -13,13 +12,14 @@ export default defineEventHandler(async (event) => { }) } - const result = db.prepare(` + const result = await queryOne<{ id: number }>(` INSERT INTO privnet_targets (name, url, is_active) - VALUES (?, ?, ?) - `).run(name, url, is_active ? 1 : 0) + VALUES ($1, $2, $3) + RETURNING id + `, [name, url, is_active ? 1 : 0]) return { - id: result.lastInsertRowid, + id: result?.id, name, url, is_active: is_active ? 1 : 0 diff --git a/backend/api/network/pubnet/chart.get.ts b/backend/api/network/pubnet/chart.get.ts index c500ce1..ec70199 100644 --- a/backend/api/network/pubnet/chart.get.ts +++ b/backend/api/network/pubnet/chart.get.ts @@ -1,36 +1,29 @@ -import { getDb } from '../../../utils/db' +import { query } from '../../../utils/db' export default defineEventHandler(async (event) => { - const query = getQuery(event) - const { year, month, week } = query as { year?: string, month?: string, week?: string } + const queryParams = getQuery(event) + const { year, month, week } = queryParams as { year?: string, month?: string, week?: string } if (!year || !month || !week) { return { error: 'year, month, week are required' } } - // 해당 월의 첫날과 마지막날 const y = parseInt(year) const m = parseInt(month) const w = parseInt(week) - // 해당 월의 첫날 const firstDayOfMonth = new Date(y, m - 1, 1) - const firstDayWeekday = firstDayOfMonth.getDay() // 0=일, 1=월, ... + const firstDayWeekday = firstDayOfMonth.getDay() - // 주차의 시작일 계산 (월요일 기준) - // 1주차: 1일이 포함된 주 const mondayOffset = firstDayWeekday === 0 ? -6 : 1 - firstDayWeekday const firstMondayOfMonth = new Date(y, m - 1, 1 + mondayOffset) - // 선택한 주차의 월요일 const weekStart = new Date(firstMondayOfMonth) weekStart.setDate(weekStart.getDate() + (w - 1) * 7) - // 주차의 일요일 const weekEnd = new Date(weekStart) weekEnd.setDate(weekEnd.getDate() + 6) - // 해당 주의 날짜 목록 생성 const weekDates: string[] = [] for (let i = 0; i < 7; i++) { const d = new Date(weekStart) @@ -39,31 +32,23 @@ export default defineEventHandler(async (event) => { weekDates.push(dateStr) } - const db = getDb() - - // 시작/종료 날짜 const startDate = weekDates[0] const endDate = weekDates[6] - // 1시간 단위 성공률 조회 - const heatmapData = db.prepare(` + const heatmapData = await query(` SELECT - date(checked_at) as date, - strftime('%H', checked_at) || ':00' as time_slot, + TO_CHAR(checked_at::timestamp, 'YYYY-MM-DD') as date, + TO_CHAR(checked_at::timestamp, 'HH24:00') as time_slot, COUNT(*) as total_count, SUM(CASE WHEN is_success = 1 THEN 1 ELSE 0 END) as success_count, ROUND(SUM(CASE WHEN is_success = 1 THEN 1.0 ELSE 0.0 END) / COUNT(*) * 100, 1) as success_rate FROM pubnet_logs - WHERE date(checked_at) >= ? AND date(checked_at) <= ? + WHERE checked_at::date >= $1 AND checked_at::date <= $2 GROUP BY date, time_slot ORDER BY date, time_slot - `).all(startDate, endDate) + `, [startDate, endDate]) - // 해당 월의 주차 수 계산 const lastDayOfMonth = new Date(y, m, 0) - const lastDate = lastDayOfMonth.getDate() - - // 마지막 날이 몇 주차인지 계산 const lastDayFromFirstMonday = Math.floor((lastDayOfMonth.getTime() - firstMondayOfMonth.getTime()) / (1000 * 60 * 60 * 24)) const totalWeeks = Math.ceil((lastDayFromFirstMonday + 1) / 7) diff --git a/backend/api/network/pubnet/logs.get.ts b/backend/api/network/pubnet/logs.get.ts index f57de49..d77c542 100644 --- a/backend/api/network/pubnet/logs.get.ts +++ b/backend/api/network/pubnet/logs.get.ts @@ -1,8 +1,8 @@ -import { getDb } from '../../../utils/db' +import { query } from '../../../utils/db' export default defineEventHandler(async (event) => { - const query = getQuery(event) - const { year, month, day, hour } = query as { + const queryParams = getQuery(event) + const { year, month, day, hour } = queryParams as { year?: string, month?: string, day?: string, hour?: string } @@ -10,13 +10,10 @@ export default defineEventHandler(async (event) => { return { error: 'year, month, day, hour are required' } } - const db = getDb() - - // 해당 시간대 로그 조회 const startTime = `${year}-${month.padStart(2, '0')}-${day.padStart(2, '0')} ${hour.padStart(2, '0')}:00:00` const endTime = `${year}-${month.padStart(2, '0')}-${day.padStart(2, '0')} ${hour.padStart(2, '0')}:59:59` - const logs = db.prepare(` + const logs = await query(` SELECT l.id, l.checked_at, @@ -25,9 +22,9 @@ export default defineEventHandler(async (event) => { t.url as target_url FROM pubnet_logs l JOIN pubnet_targets t ON l.target_id = t.id - WHERE l.checked_at >= ? AND l.checked_at <= ? + WHERE l.checked_at >= $1 AND l.checked_at <= $2 ORDER BY l.checked_at DESC - `).all(startTime, endTime) + `, [startTime, endTime]) return { logs } }) diff --git a/backend/api/network/pubnet/status.get.ts b/backend/api/network/pubnet/status.get.ts index 46096a5..fe59ee4 100644 --- a/backend/api/network/pubnet/status.get.ts +++ b/backend/api/network/pubnet/status.get.ts @@ -1,11 +1,8 @@ -import { getDb } from '../../../utils/db' +import { query, queryOne } from '../../../utils/db' import { pubnetScheduler } from '../../../utils/pubnet-scheduler' -export default defineEventHandler(() => { - const db = getDb() - - // 현재 상태 조회 - const status = db.prepare(` +export default defineEventHandler(async () => { + const status = await queryOne(` SELECT ps.*, pt.name as last_target_name, @@ -13,10 +10,9 @@ export default defineEventHandler(() => { FROM pubnet_status ps LEFT JOIN pubnet_targets pt ON ps.last_target_id = pt.id WHERE ps.id = 1 - `).get() + `) - // 최근 10개 로그 - const recentLogs = db.prepare(` + const recentLogs = await query(` SELECT pl.*, pt.name as target_name, @@ -25,17 +21,16 @@ export default defineEventHandler(() => { JOIN pubnet_targets pt ON pl.target_id = pt.id ORDER BY pl.checked_at DESC LIMIT 10 - `).all() + `) - // 활성 타겟 수 - const targetCount = db.prepare(` + const targetCount = await queryOne<{ cnt: number }>(` SELECT COUNT(*) as cnt FROM pubnet_targets WHERE is_active = 1 - `).get() as { cnt: number } + `) return { status, recentLogs, - targetCount: targetCount.cnt, + targetCount: targetCount?.cnt || 0, schedulerRunning: pubnetScheduler.getIsRunning() } }) diff --git a/backend/api/network/pubnet/targets/[id].delete.ts b/backend/api/network/pubnet/targets/[id].delete.ts index e48aee5..8163292 100644 --- a/backend/api/network/pubnet/targets/[id].delete.ts +++ b/backend/api/network/pubnet/targets/[id].delete.ts @@ -1,10 +1,9 @@ -import { getDb } from '../../../../utils/db' +import { execute } from '../../../../utils/db' -export default defineEventHandler((event) => { - const db = getDb() +export default defineEventHandler(async (event) => { const id = getRouterParam(event, 'id') - db.prepare(`DELETE FROM pubnet_targets WHERE id = ?`).run(id) + await execute(`DELETE FROM pubnet_targets WHERE id = $1`, [id]) return { success: true } }) diff --git a/backend/api/network/pubnet/targets/[id].put.ts b/backend/api/network/pubnet/targets/[id].put.ts index fcdf866..12a8707 100644 --- a/backend/api/network/pubnet/targets/[id].put.ts +++ b/backend/api/network/pubnet/targets/[id].put.ts @@ -1,7 +1,6 @@ -import { getDb } from '../../../../utils/db' +import { execute } from '../../../../utils/db' export default defineEventHandler(async (event) => { - const db = getDb() const id = getRouterParam(event, 'id') const body = await readBody(event) @@ -14,11 +13,11 @@ export default defineEventHandler(async (event) => { }) } - db.prepare(` + await execute(` UPDATE pubnet_targets - SET name = ?, url = ?, is_active = ?, updated_at = datetime('now', 'localtime') - WHERE id = ? - `).run(name, url, is_active ? 1 : 0, id) + SET name = $1, url = $2, is_active = $3, updated_at = TO_CHAR(NOW(), 'YYYY-MM-DD HH24:MI:SS') + WHERE id = $4 + `, [name, url, is_active ? 1 : 0, id]) return { id: Number(id), diff --git a/backend/api/network/pubnet/targets/index.get.ts b/backend/api/network/pubnet/targets/index.get.ts index 2092dd9..75c6a67 100644 --- a/backend/api/network/pubnet/targets/index.get.ts +++ b/backend/api/network/pubnet/targets/index.get.ts @@ -1,12 +1,10 @@ -import { getDb } from '../../../../utils/db' +import { query } from '../../../../utils/db' -export default defineEventHandler(() => { - const db = getDb() - - const targets = db.prepare(` +export default defineEventHandler(async () => { + const targets = await query(` SELECT * FROM pubnet_targets ORDER BY id ASC - `).all() + `) return targets }) diff --git a/backend/api/network/pubnet/targets/index.post.ts b/backend/api/network/pubnet/targets/index.post.ts index fa589e8..161fff8 100644 --- a/backend/api/network/pubnet/targets/index.post.ts +++ b/backend/api/network/pubnet/targets/index.post.ts @@ -1,7 +1,6 @@ -import { getDb } from '../../../../utils/db' +import { queryOne } from '../../../../utils/db' export default defineEventHandler(async (event) => { - const db = getDb() const body = await readBody(event) const { name, url, is_active } = body @@ -13,13 +12,14 @@ export default defineEventHandler(async (event) => { }) } - const result = db.prepare(` + const result = await queryOne<{ id: number }>(` INSERT INTO pubnet_targets (name, url, is_active) - VALUES (?, ?, ?) - `).run(name, url, is_active ? 1 : 0) + VALUES ($1, $2, $3) + RETURNING id + `, [name, url, is_active ? 1 : 0]) return { - id: result.lastInsertRowid, + id: result?.id, name, url, is_active: is_active ? 1 : 0 diff --git a/backend/api/server/history/container-list.get.ts b/backend/api/server/history/container-list.get.ts index 763bf4c..e5d4e03 100644 --- a/backend/api/server/history/container-list.get.ts +++ b/backend/api/server/history/container-list.get.ts @@ -1,8 +1,8 @@ -import { getDb } from '../../../utils/db' +import { query } from '../../../utils/db' -export default defineEventHandler((event) => { - const query = getQuery(event) - const targetId = query.target_id as string +export default defineEventHandler(async (event) => { + const queryParams = getQuery(event) + const targetId = queryParams.target_id as string if (!targetId) { throw createError({ @@ -11,20 +11,22 @@ export default defineEventHandler((event) => { }) } - const db = getDb() - - // 최신 수집 시간 기준 컨테이너 목록 - const containers = db.prepare(` - SELECT DISTINCT container_name - FROM server_containers - WHERE target_id = ? - AND collected_at = ( - SELECT MAX(collected_at) - FROM server_containers - WHERE target_id = ? - ) - ORDER BY container_name ASC - `).all(targetId, targetId) + let containers: any[] = [] + try { + containers = await query(` + SELECT DISTINCT container_name + FROM server_containers + WHERE target_id = $1 + AND collected_at = ( + SELECT MAX(collected_at) + FROM server_containers + WHERE target_id = $1 + ) + ORDER BY container_name ASC + `, [targetId]) + } catch (e) { + containers = [] + } return containers.map((c: any) => c.container_name) }) diff --git a/backend/api/server/history/containers.get.ts b/backend/api/server/history/containers.get.ts index f635130..8332829 100644 --- a/backend/api/server/history/containers.get.ts +++ b/backend/api/server/history/containers.get.ts @@ -1,9 +1,9 @@ -import { getDb } from '../../../utils/db' +import { query } from '../../../utils/db' -export default defineEventHandler((event) => { - const query = getQuery(event) - const targetId = query.target_id as string - const period = (query.period as string) || '1h' +export default defineEventHandler(async (event) => { + const queryParams = getQuery(event) + const targetId = queryParams.target_id as string + const period = (queryParams.period as string) || '1h' if (!targetId) { throw createError({ @@ -13,41 +13,44 @@ export default defineEventHandler((event) => { } const periodMap: Record = { - '1h': '-1 hour', - '2h': '-2 hours', - '3h': '-3 hours', - '4h': '-4 hours', - '5h': '-5 hours', - '6h': '-6 hours', - '12h': '-12 hours', - '18h': '-18 hours', - '24h': '-24 hours', - '7d': '-7 days', - '30d': '-30 days' + '1h': '1 hour', + '2h': '2 hours', + '3h': '3 hours', + '4h': '4 hours', + '5h': '5 hours', + '6h': '6 hours', + '12h': '12 hours', + '18h': '18 hours', + '24h': '24 hours', + '7d': '7 days', + '30d': '30 days' } - const timeOffset = periodMap[period] || '-1 hour' + const interval = periodMap[period] || '1 hour' - const db = getDb() - - const containers = db.prepare(` - SELECT - container_id, - container_name, - container_status, - cpu_percent, - memory_usage, - memory_limit, - memory_percent, - uptime, - network_rx, - network_tx, - collected_at - FROM server_containers - WHERE target_id = ? - AND collected_at >= datetime('now', 'localtime', ?) - ORDER BY collected_at ASC, container_name ASC - `).all(targetId, timeOffset) + let containers: any[] = [] + try { + containers = await query(` + SELECT + container_id, + container_name, + container_status, + cpu_percent, + memory_usage, + memory_limit, + memory_percent, + uptime, + network_rx, + network_tx, + collected_at + FROM server_containers + WHERE target_id = $1 + AND collected_at >= NOW() - INTERVAL '${interval}' + ORDER BY collected_at ASC, container_name ASC + `, [targetId]) + } catch (e) { + containers = [] + } return { target_id: targetId, diff --git a/backend/api/server/history/disk-list.get.ts b/backend/api/server/history/disk-list.get.ts index 49e8cd2..6991581 100644 --- a/backend/api/server/history/disk-list.get.ts +++ b/backend/api/server/history/disk-list.get.ts @@ -1,8 +1,8 @@ -import { getDb } from '../../../utils/db' +import { query } from '../../../utils/db' -export default defineEventHandler((event) => { - const query = getQuery(event) - const targetId = query.target_id as string +export default defineEventHandler(async (event) => { + const queryParams = getQuery(event) + const targetId = queryParams.target_id as string if (!targetId) { throw createError({ @@ -11,19 +11,21 @@ export default defineEventHandler((event) => { }) } - const db = getDb() - - // 최신 수집 시간 기준 디스크 목록 (물리 디스크만) - const disks = db.prepare(` - SELECT DISTINCT device_name, mount_point, fs_type, disk_total, disk_used, disk_percent - FROM server_disks - WHERE target_id = ? - AND collected_at = (SELECT MAX(collected_at) FROM server_disks WHERE target_id = ?) - AND device_name NOT LIKE '%loop%' - AND mount_point NOT LIKE '%/snap%' - AND fs_type NOT IN ('tmpfs', 'squashfs', 'overlay') - ORDER BY mount_point ASC - `).all(targetId, targetId) + let disks: any[] = [] + try { + disks = await query(` + SELECT DISTINCT device_name, mount_point, fs_type, disk_total, disk_used, disk_percent + FROM server_disks + WHERE target_id = $1 + AND collected_at = (SELECT MAX(collected_at) FROM server_disks WHERE target_id = $1) + AND device_name NOT LIKE '%loop%' + AND mount_point NOT LIKE '%/snap%' + AND fs_type NOT IN ('tmpfs', 'squashfs', 'overlay') + ORDER BY mount_point ASC + `, [targetId]) + } catch (e) { + disks = [] + } return disks }) diff --git a/backend/api/server/history/disks.get.ts b/backend/api/server/history/disks.get.ts index 2a3d1a0..029541e 100644 --- a/backend/api/server/history/disks.get.ts +++ b/backend/api/server/history/disks.get.ts @@ -1,9 +1,9 @@ -import { getDb } from '../../../utils/db' +import { query } from '../../../utils/db' -export default defineEventHandler((event) => { - const query = getQuery(event) - const targetId = query.target_id as string - const period = (query.period as string) || '1h' +export default defineEventHandler(async (event) => { + const queryParams = getQuery(event) + const targetId = queryParams.target_id as string + const period = (queryParams.period as string) || '1h' if (!targetId) { throw createError({ @@ -13,38 +13,41 @@ export default defineEventHandler((event) => { } const periodMap: Record = { - '1h': '-1 hour', - '2h': '-2 hours', - '3h': '-3 hours', - '4h': '-4 hours', - '5h': '-5 hours', - '6h': '-6 hours', - '12h': '-12 hours', - '18h': '-18 hours', - '24h': '-24 hours', - '7d': '-7 days', - '30d': '-30 days' + '1h': '1 hour', + '2h': '2 hours', + '3h': '3 hours', + '4h': '4 hours', + '5h': '5 hours', + '6h': '6 hours', + '12h': '12 hours', + '18h': '18 hours', + '24h': '24 hours', + '7d': '7 days', + '30d': '30 days' } - const timeOffset = periodMap[period] || '-1 hour' + const interval = periodMap[period] || '1 hour' - const db = getDb() - - const disks = db.prepare(` - SELECT - disk_id, - device_name, - mount_point, - fs_type, - disk_total, - disk_used, - disk_percent, - collected_at - FROM server_disks - WHERE target_id = ? - AND collected_at >= datetime('now', 'localtime', ?) - ORDER BY collected_at ASC, mount_point ASC - `).all(targetId, timeOffset) + let disks: any[] = [] + try { + disks = await query(` + SELECT + disk_id, + device_name, + mount_point, + fs_type, + disk_total, + disk_used, + disk_percent, + collected_at + FROM server_disks + WHERE target_id = $1 + AND collected_at >= NOW() - INTERVAL '${interval}' + ORDER BY collected_at ASC, mount_point ASC + `, [targetId]) + } catch (e) { + disks = [] + } return { target_id: targetId, diff --git a/backend/api/server/history/latest.get.ts b/backend/api/server/history/latest.get.ts index 771e56e..def0e28 100644 --- a/backend/api/server/history/latest.get.ts +++ b/backend/api/server/history/latest.get.ts @@ -1,8 +1,8 @@ -import { getDb } from '../../../utils/db' +import { queryOne } from '../../../utils/db' -export default defineEventHandler((event) => { - const query = getQuery(event) - const targetId = query.target_id as string +export default defineEventHandler(async (event) => { + const queryParams = getQuery(event) + const targetId = queryParams.target_id as string if (!targetId) { throw createError({ @@ -11,22 +11,17 @@ export default defineEventHandler((event) => { }) } - const db = getDb() - - // 최신 스냅샷 - const snapshot = db.prepare(` + const snapshot = await queryOne(` SELECT - s.*, - t.server_name, - t.server_ip, - t.glances_url, - t.collect_interval - FROM server_snapshots s - JOIN server_targets t ON s.target_id = t.target_id - WHERE s.target_id = ? - ORDER BY s.collected_at DESC + l.*, + t.name as server_name, + t.host as server_ip + FROM server_logs l + JOIN server_targets t ON l.target_id = t.target_id + WHERE l.target_id = $1 + ORDER BY l.checked_at DESC LIMIT 1 - `).get(targetId) + `, [targetId]) return snapshot || null }) diff --git a/backend/api/server/history/networks.get.ts b/backend/api/server/history/networks.get.ts index ecfa6b5..c47f7c0 100644 --- a/backend/api/server/history/networks.get.ts +++ b/backend/api/server/history/networks.get.ts @@ -1,9 +1,9 @@ -import { getDb } from '../../../utils/db' +import { query } from '../../../utils/db' -export default defineEventHandler((event) => { - const query = getQuery(event) - const targetId = query.target_id as string - const period = (query.period as string) || '1h' +export default defineEventHandler(async (event) => { + const queryParams = getQuery(event) + const targetId = queryParams.target_id as string + const period = (queryParams.period as string) || '1h' if (!targetId) { throw createError({ @@ -13,38 +13,41 @@ export default defineEventHandler((event) => { } const periodMap: Record = { - '1h': '-1 hour', - '2h': '-2 hours', - '3h': '-3 hours', - '4h': '-4 hours', - '5h': '-5 hours', - '6h': '-6 hours', - '12h': '-12 hours', - '18h': '-18 hours', - '24h': '-24 hours', - '7d': '-7 days', - '30d': '-30 days' + '1h': '1 hour', + '2h': '2 hours', + '3h': '3 hours', + '4h': '4 hours', + '5h': '5 hours', + '6h': '6 hours', + '12h': '12 hours', + '18h': '18 hours', + '24h': '24 hours', + '7d': '7 days', + '30d': '30 days' } - const timeOffset = periodMap[period] || '-1 hour' + const interval = periodMap[period] || '1 hour' - const db = getDb() - - const networks = db.prepare(` - SELECT - network_id, - interface_name, - bytes_recv, - bytes_sent, - speed_recv, - speed_sent, - is_up, - collected_at - FROM server_networks - WHERE target_id = ? - AND collected_at >= datetime('now', 'localtime', ?) - ORDER BY collected_at ASC, interface_name ASC - `).all(targetId, timeOffset) + let networks: any[] = [] + try { + networks = await query(` + SELECT + network_id, + interface_name, + bytes_recv, + bytes_sent, + speed_recv, + speed_sent, + is_up, + collected_at + FROM server_networks + WHERE target_id = $1 + AND collected_at >= NOW() - INTERVAL '${interval}' + ORDER BY collected_at ASC, interface_name ASC + `, [targetId]) + } catch (e) { + networks = [] + } return { target_id: targetId, diff --git a/backend/api/server/history/snapshots.get.ts b/backend/api/server/history/snapshots.get.ts index c1834aa..e12bb8d 100644 --- a/backend/api/server/history/snapshots.get.ts +++ b/backend/api/server/history/snapshots.get.ts @@ -1,9 +1,9 @@ -import { getDb } from '../../../utils/db' +import { query } from '../../../utils/db' -export default defineEventHandler((event) => { - const query = getQuery(event) - const targetId = query.target_id as string - const period = (query.period as string) || '1h' +export default defineEventHandler(async (event) => { + const queryParams = getQuery(event) + const targetId = queryParams.target_id as string + const period = (queryParams.period as string) || '1h' if (!targetId) { throw createError({ @@ -12,44 +12,35 @@ export default defineEventHandler((event) => { }) } - // 기간별 시간 계산 const periodMap: Record = { - '1h': '-1 hour', - '2h': '-2 hours', - '3h': '-3 hours', - '4h': '-4 hours', - '5h': '-5 hours', - '6h': '-6 hours', - '12h': '-12 hours', - '18h': '-18 hours', - '24h': '-24 hours', - '7d': '-7 days', - '30d': '-30 days' + '1h': '1 hour', + '2h': '2 hours', + '3h': '3 hours', + '4h': '4 hours', + '5h': '5 hours', + '6h': '6 hours', + '12h': '12 hours', + '18h': '18 hours', + '24h': '24 hours', + '7d': '7 days', + '30d': '30 days' } - const timeOffset = periodMap[period] || '-1 hour' + const interval = periodMap[period] || '1 hour' - const db = getDb() - - const snapshots = db.prepare(` + const snapshots = await query(` SELECT - snapshot_id, - cpu_percent, - cpu_temp, - load_percent, - memory_percent, - memory_used, - memory_total, - swap_percent, - swap_used, - swap_total, - is_online, - collected_at - FROM server_snapshots - WHERE target_id = ? - AND collected_at >= datetime('now', 'localtime', ?) - ORDER BY collected_at ASC - `).all(targetId, timeOffset) + log_id, + cpu_usage as cpu_percent, + memory_usage as memory_percent, + disk_usage as disk_percent, + is_success as is_online, + checked_at as collected_at + FROM server_logs + WHERE target_id = $1 + AND checked_at >= NOW() - INTERVAL '${interval}' + ORDER BY checked_at ASC + `, [targetId]) return { target_id: targetId, diff --git a/backend/api/settings/thresholds.get.ts b/backend/api/settings/thresholds.get.ts index 9aed0f6..0aec60e 100644 --- a/backend/api/settings/thresholds.get.ts +++ b/backend/api/settings/thresholds.get.ts @@ -1,15 +1,17 @@ -import { getDb } from '../../utils/db' +import { query } from '../../utils/db' -export default defineEventHandler(() => { - const db = getDb() +export default defineEventHandler(async () => { + let rows: any[] = [] + try { + rows = await query(` + SELECT category, metric, warning, critical, danger, updated_at + FROM thresholds + ORDER BY category, metric + `) + } catch (e) { + rows = [] + } - const rows = db.prepare(` - SELECT category, metric, warning, critical, danger, updated_at - FROM thresholds - ORDER BY category, metric - `).all() as any[] - - // 카테고리별로 그룹화 const result: Record> = {} for (const row of rows) { diff --git a/backend/api/settings/thresholds.put.ts b/backend/api/settings/thresholds.put.ts index b837437..3cf88ea 100644 --- a/backend/api/settings/thresholds.put.ts +++ b/backend/api/settings/thresholds.put.ts @@ -1,4 +1,4 @@ -import { getDb } from '../../utils/db' +import { execute } from '../../utils/db' export default defineEventHandler(async (event) => { const body = await readBody(event) @@ -10,15 +10,8 @@ export default defineEventHandler(async (event) => { }) } - const db = getDb() const now = new Date().toLocaleString('sv-SE', { timeZone: 'Asia/Seoul' }).replace('T', ' ') - const stmt = db.prepare(` - UPDATE thresholds - SET warning = ?, critical = ?, danger = ?, updated_at = ? - WHERE category = ? AND metric = ? - `) - let updated = 0 for (const [category, metrics] of Object.entries(body)) { @@ -29,7 +22,6 @@ export default defineEventHandler(async (event) => { const { warning, critical, danger } = values - // 유효성 검사 if (typeof warning !== 'number' || typeof critical !== 'number' || typeof danger !== 'number') { continue } @@ -45,8 +37,16 @@ export default defineEventHandler(async (event) => { }) } - const result = stmt.run(warning, critical, danger, now, category, metric) - if (result.changes > 0) updated++ + try { + const result = await execute(` + UPDATE thresholds + SET warning = $1, critical = $2, danger = $3, updated_at = $4 + WHERE category = $5 AND metric = $6 + `, [warning, critical, danger, now, category, metric]) + if (result > 0) updated++ + } catch (e) { + // 테이블이 없는 경우 무시 + } } }