import { Response } from "express"; import { AuthenticatedRequest } from "../middleware/authMiddleware"; import { auditLogService, getClientIp, AuditAction, AuditResourceType } from "../services/auditLogService"; import { query } from "../database/db"; import logger from "../utils/logger"; export const getAuditLogs = async ( req: AuthenticatedRequest, res: Response ): Promise => { try { const userCompanyCode = req.user?.companyCode; const isSuperAdmin = req.user?.userType === "SUPER_ADMIN"; const { companyCode, userId, resourceType, action, tableName, dateFrom, dateTo, search, page, limit, } = req.query; const result = await auditLogService.queryLogs( { companyCode: (companyCode as string) || (isSuperAdmin ? undefined : userCompanyCode), userId: userId as string, resourceType: resourceType as string, action: action as string, tableName: tableName as string, dateFrom: dateFrom as string, dateTo: dateTo as string, search: search as string, page: page ? parseInt(page as string, 10) : 1, limit: limit ? parseInt(limit as string, 10) : 50, }, isSuperAdmin ); res.json({ success: true, data: result.data, total: result.total, page: page ? parseInt(page as string, 10) : 1, limit: limit ? parseInt(limit as string, 10) : 50, }); } catch (error: any) { logger.error("감사 로그 조회 실패", { error: error.message }); res.status(500).json({ success: false, message: "감사 로그 조회 중 오류가 발생했습니다.", }); } }; export const getAuditLogStats = async ( req: AuthenticatedRequest, res: Response ): Promise => { try { const userCompanyCode = req.user?.companyCode; const isSuperAdmin = req.user?.userType === "SUPER_ADMIN"; const { companyCode, days } = req.query; const targetCompany = isSuperAdmin ? (companyCode as string) || undefined : userCompanyCode; const stats = await auditLogService.getStats( targetCompany, days ? parseInt(days as string, 10) : 30 ); res.json({ success: true, data: stats }); } catch (error: any) { logger.error("감사 로그 통계 조회 실패", { error: error.message }); res.status(500).json({ success: false, message: "감사 로그 통계 조회 중 오류가 발생했습니다.", }); } }; export const getAuditLogUsers = async ( req: AuthenticatedRequest, res: Response ): Promise => { try { const userCompanyCode = req.user?.companyCode; const isSuperAdmin = req.user?.userType === "SUPER_ADMIN"; const { companyCode } = req.query; const conditions: string[] = ["LOWER(u.status) = 'active'"]; const params: any[] = []; let paramIndex = 1; if (!isSuperAdmin) { conditions.push(`u.company_code = $${paramIndex++}`); params.push(userCompanyCode); } else if (companyCode) { conditions.push(`u.company_code = $${paramIndex++}`); params.push(companyCode); } if (!isSuperAdmin) { conditions.push(`u.company_code != '*'`); } const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : ""; const users = await query<{ user_id: string; user_name: string; count: number }>( `SELECT u.user_id, u.user_name, COALESCE(sal.log_count, 0)::int as count FROM user_info u LEFT JOIN ( SELECT user_id, COUNT(*) as log_count FROM system_audit_log GROUP BY user_id ) sal ON u.user_id = sal.user_id ${whereClause} ORDER BY count DESC, u.user_name ASC`, params ); res.json({ success: true, data: users }); } catch (error: any) { logger.error("감사 로그 사용자 목록 조회 실패", { error: error.message }); res.status(500).json({ success: false, message: "사용자 목록 조회 중 오류가 발생했습니다.", }); } }; /** * 프론트엔드에서 직접 감사 로그 기록 (그룹 복제 등 프론트 오케스트레이션 작업용) */ export const createAuditLog = async ( req: AuthenticatedRequest, res: Response ): Promise => { try { const { action, resourceType, resourceId, resourceName, tableName, summary, changes } = req.body; if (!action || !resourceType) { res.status(400).json({ success: false, message: "action, resourceType은 필수입니다." }); return; } await auditLogService.log({ companyCode: req.user?.companyCode || "", userId: req.user?.userId || "", userName: req.user?.userName || "", action: action as AuditAction, resourceType: resourceType as AuditResourceType, resourceId: resourceId || undefined, resourceName: resourceName || undefined, tableName: tableName || undefined, summary: summary || undefined, changes: changes || undefined, ipAddress: getClientIp(req), requestPath: req.originalUrl, }); res.json({ success: true }); } catch (error: any) { logger.error("감사 로그 기록 실패", { error: error.message }); res.status(500).json({ success: false, message: "감사 로그 기록 실패" }); } };