feat: Enhance audit logging with client IP tracking

- Integrated client IP address retrieval in the audit logging functionality across multiple controllers, including admin, common code, department, flow, screen, and table management.
- Updated the `auditLogService` to include a new method for obtaining the client's IP address, ensuring accurate logging of user actions.
- This enhancement improves traceability and accountability by capturing the source of requests, thereby strengthening the overall logging mechanism within the application.
This commit is contained in:
kjs
2026-03-04 15:02:27 +09:00
parent 459777d5f0
commit 96637a9cb6
12 changed files with 268 additions and 154 deletions

View File

@@ -10,7 +10,7 @@ import { EncryptUtil } from "../utils/encryptUtil";
import { FileSystemManager } from "../utils/fileSystemManager";
import { validateBusinessNumber } from "../utils/businessNumberValidator";
import { MenuCopyService } from "../services/menuCopyService";
import { auditLogService } from "../services/auditLogService";
import { auditLogService, getClientIp } from "../services/auditLogService";
/**
* 관리자 메뉴 목록 조회
@@ -1199,7 +1199,7 @@ export async function saveMenu(
resourceName: savedMenu.menu_name_kor,
summary: `메뉴 "${savedMenu.menu_name_kor}" 생성`,
changes: { after: { menuNameKor: savedMenu.menu_name_kor, menuUrl: savedMenu.menu_url, status: savedMenu.status } },
ipAddress: (req as any).ip,
ipAddress: getClientIp(req),
requestPath: req.originalUrl,
});
@@ -1403,7 +1403,7 @@ export async function updateMenu(
before: { menuNameKor: currentMenu.menu_name_kor, menuUrl: currentMenu.menu_url, status: currentMenu.status },
after: { menuNameKor: updatedMenu.menu_name_kor, menuUrl: updatedMenu.menu_url, status: updatedMenu.status },
},
ipAddress: (req as any).ip,
ipAddress: getClientIp(req),
requestPath: req.originalUrl,
});
@@ -1596,7 +1596,7 @@ export async function deleteMenu(
resourceName: currentMenu.menu_name_kor,
summary: `메뉴 "${currentMenu.menu_name_kor}" 삭제 (하위 ${childMenuIds.length}개 포함, 총 ${allMenuIdsToDelete.length}건)`,
changes: { before: { menuNameKor: currentMenu.menu_name_kor } },
ipAddress: (req as any).ip,
ipAddress: getClientIp(req),
requestPath: req.originalUrl,
});
@@ -1772,7 +1772,7 @@ export async function deleteMenusBatch(
resourceType: "MENU",
summary: `메뉴 일괄 삭제: ${deletedCount}개 삭제, ${failedCount}개 실패`,
changes: { before: { deletedMenus, failedMenuIds } },
ipAddress: (req as any).ip,
ipAddress: getClientIp(req),
requestPath: req.originalUrl,
});
}
@@ -1883,7 +1883,7 @@ export async function toggleMenuStatus(
resourceName: currentMenu.menu_name_kor,
summary: `메뉴 "${currentMenu.menu_name_kor}" 상태 변경: ${currentStatus}${newStatus}`,
changes: { before: { status: currentStatus }, after: { status: newStatus }, fields: ["status"] },
ipAddress: (req as any).ip,
ipAddress: getClientIp(req),
requestPath: req.originalUrl,
});
@@ -2526,7 +2526,7 @@ export const changeUserStatus = async (
resourceName: currentUser.user_name,
summary: `사용자 "${currentUser.user_name}" 상태 변경: ${currentUser.status}${status}`,
changes: { before: { status: currentUser.status }, after: { status }, fields: ["status"] },
ipAddress: (req as any).ip,
ipAddress: getClientIp(req),
requestPath: req.originalUrl,
});
@@ -2677,7 +2677,7 @@ export const saveUser = async (req: AuthenticatedRequest, res: Response) => {
resourceName: userData.userName,
summary: isExistingUser ? `사용자 "${userData.userName}" 정보 수정` : `사용자 "${userData.userName}" 등록`,
changes: { after: { userId: userData.userId, userName: userData.userName, deptName: userData.deptName, status: userData.status } },
ipAddress: (req as any).ip,
ipAddress: getClientIp(req),
requestPath: req.originalUrl,
});
@@ -2881,7 +2881,7 @@ export const createCompany = async (
resourceName: createdCompany.company_name,
summary: `회사 "${createdCompany.company_name}" (${createdCompany.company_code}) 등록`,
changes: { after: { company_code: createdCompany.company_code, company_name: createdCompany.company_name } },
ipAddress: (req as any).ip,
ipAddress: getClientIp(req),
requestPath: req.originalUrl,
});
@@ -3127,7 +3127,7 @@ export const updateCompany = async (
before: { company_name: beforeCompany?.company_name, status: beforeCompany?.status },
after: { company_name: updatedCompany.company_name, status: updatedCompany.status },
},
ipAddress: (req as any).ip,
ipAddress: getClientIp(req),
requestPath: req.originalUrl,
});
@@ -3202,7 +3202,7 @@ export const deleteCompany = async (
resourceName: deletedCompany.company_name,
summary: `회사 "${deletedCompany.company_name}" (${deletedCompany.company_code}) 삭제`,
changes: { before: { company_code: deletedCompany.company_code, company_name: deletedCompany.company_name } },
ipAddress: (req as any).ip,
ipAddress: getClientIp(req),
requestPath: req.originalUrl,
});
@@ -3382,7 +3382,7 @@ export const updateProfile = async (
resourceName: updatedUser?.user_name || "",
summary: `프로필 수정 (${updateFields.length}개 항목)`,
changes: { after: { userName, email, tel, cellPhone, locale } },
ipAddress: (req as any).ip,
ipAddress: getClientIp(req),
requestPath: req.originalUrl,
});
@@ -3509,7 +3509,7 @@ export const resetUserPassword = async (
resourceName: currentUser.user_name,
summary: `사용자 "${currentUser.user_name}" 비밀번호 초기화`,
changes: { fields: ["user_password"] },
ipAddress: (req as any).ip,
ipAddress: getClientIp(req),
requestPath: req.originalUrl,
});
@@ -3723,7 +3723,7 @@ export async function copyMenu(
resourceId: menuObjid,
summary: `메뉴(${menuObjid}) → 회사 "${targetCompanyCode}"로 복사`,
changes: { after: { targetCompanyCode, menuObjid } },
ipAddress: (req as any).ip,
ipAddress: getClientIp(req),
requestPath: req.originalUrl,
});
@@ -4051,7 +4051,7 @@ export const saveUserWithDept = async (
resourceName: userInfo.user_name,
summary: `사용자 "${userInfo.user_name}" ${isExistingUser ? "수정" : "등록"} (부서: ${mainDept?.dept_name || "없음"})`,
changes: { after: { userName: userInfo.user_name, email: userInfo.email, deptName: mainDept?.dept_name, status: userInfo.status } },
ipAddress: (req as any).ip,
ipAddress: getClientIp(req),
requestPath: req.originalUrl,
});