feat: Integrate audit logging for various operations

- Added audit logging functionality across multiple controllers, including menu, user, department, flow, screen, and table management.
- Implemented logging for create, update, and delete actions, capturing relevant details such as company code, user information, and changes made.
- Enhanced the category tree service with a new endpoint to check if category values are in use, improving data integrity checks.
- Updated routes to include new functionalities and ensure proper logging for batch operations and individual record changes.
- This integration improves traceability and accountability for data modifications within the application.
This commit is contained in:
kjs
2026-03-04 13:49:08 +09:00
parent f04d224b09
commit b4d5367e2b
26 changed files with 2620 additions and 140 deletions

View File

@@ -12,7 +12,8 @@ import {
ColumnListResponse,
ColumnSettingsResponse,
} from "../types/tableManagement";
import { query } from "../database/db"; // 🆕 query 함수 import
import { query } from "../database/db";
import { auditLogService } from "../services/auditLogService";
/**
* 테이블 목록 조회
@@ -962,6 +963,21 @@ export async function addTableData(
logger.info(`테이블 데이터 추가 완료: ${tableName}, id: ${result.insertedId}`);
auditLogService.log({
companyCode: req.user?.companyCode || "",
userId: req.user?.userId || "",
userName: req.user?.userName || "",
action: "CREATE",
resourceType: "DATA",
resourceId: result.insertedId || "",
resourceName: tableName,
tableName,
summary: `${tableName} 데이터 추가`,
changes: { after: data },
ipAddress: (req as any).ip,
requestPath: req.originalUrl,
});
const response: ApiResponse<{ id: string | null }> = {
success: true,
message: "테이블 데이터를 성공적으로 추가했습니다.",
@@ -1080,6 +1096,16 @@ export async function editTableData(
return;
}
// 변경된 필드만 추출
const changedBefore: Record<string, any> = {};
const changedAfter: Record<string, any> = {};
for (const key of Object.keys(updatedData)) {
if (String(originalData[key] ?? "") !== String(updatedData[key] ?? "")) {
changedBefore[key] = originalData[key];
changedAfter[key] = updatedData[key];
}
}
// 데이터 수정
await tableManagementService.editTableData(
tableName,
@@ -1089,6 +1115,23 @@ export async function editTableData(
logger.info(`테이블 데이터 수정 완료: ${tableName}`);
if (Object.keys(changedAfter).length > 0) {
auditLogService.log({
companyCode: req.user?.companyCode || "",
userId: req.user?.userId || "",
userName: req.user?.userName || "",
action: "UPDATE",
resourceType: "DATA",
resourceId: originalData.id?.toString() || "",
resourceName: tableName,
tableName,
summary: `${tableName} 데이터 수정`,
changes: { before: changedBefore, after: changedAfter },
ipAddress: (req as any).ip,
requestPath: req.originalUrl,
});
}
const response: ApiResponse<null> = {
success: true,
message: "테이블 데이터를 성공적으로 수정했습니다.",
@@ -1406,6 +1449,22 @@ export async function deleteTableData(
`테이블 데이터 삭제 완료: ${tableName}, ${deletedCount}건 삭제`
);
const deleteItems = Array.isArray(data) ? data : [data];
auditLogService.log({
companyCode: req.user?.companyCode || "",
userId: req.user?.userId || "",
userName: req.user?.userName || "",
action: "DELETE",
resourceType: "DATA",
resourceId: deleteItems[0]?.id?.toString() || "",
resourceName: tableName,
tableName,
summary: `${tableName} 데이터 삭제 (${deletedCount}건)`,
changes: { before: { deletedCount, items: deleteItems.length } },
ipAddress: (req as any).ip,
requestPath: req.originalUrl,
});
const response: ApiResponse<{ deletedCount: number }> = {
success: true,
message: `테이블 데이터를 성공적으로 삭제했습니다. (${deletedCount}건)`,
@@ -2285,6 +2344,21 @@ export async function multiTableSave(
subTableResultsCount: subTableResults.length,
});
auditLogService.log({
companyCode: req.user?.companyCode || "",
userId: req.user?.userId || "",
userName: req.user?.userName || "",
action: isUpdate ? "UPDATE" : "CREATE",
resourceType: "DATA",
resourceId: savedPkValue?.toString() || "",
resourceName: mainTableName,
tableName: mainTableName,
summary: `${mainTableName} 데이터 ${isUpdate ? "수정" : "생성"}${subTableResults.length > 0 ? ` (서브 테이블 ${subTableResults.length}건)` : ""}`,
changes: { after: mainData },
ipAddress: (req as any).ip,
requestPath: req.originalUrl,
});
res.json({
success: true,
message: "다중 테이블 저장이 완료되었습니다.",