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:
@@ -1,6 +1,7 @@
|
||||
import { Response } from "express";
|
||||
import { screenManagementService } from "../services/screenManagementService";
|
||||
import { AuthenticatedRequest } from "../types/auth";
|
||||
import { auditLogService } from "../services/auditLogService";
|
||||
|
||||
// 화면 목록 조회
|
||||
export const getScreens = async (req: AuthenticatedRequest, res: Response) => {
|
||||
@@ -108,6 +109,21 @@ export const createScreen = async (
|
||||
screenData,
|
||||
companyCode
|
||||
);
|
||||
|
||||
auditLogService.log({
|
||||
companyCode,
|
||||
userId: (req.user as any)?.userId || "",
|
||||
userName: (req.user as any)?.userName || "",
|
||||
action: "CREATE",
|
||||
resourceType: "SCREEN",
|
||||
resourceId: String(newScreen?.id || ""),
|
||||
resourceName: newScreen?.screenName || screenData.screenName,
|
||||
summary: `화면 "${newScreen?.screenName || screenData.screenName}" 생성`,
|
||||
changes: { after: { screenName: newScreen?.screenName, tableName: newScreen?.tableName } },
|
||||
ipAddress: (req as any).ip,
|
||||
requestPath: req.originalUrl,
|
||||
});
|
||||
|
||||
res.status(201).json({ success: true, data: newScreen });
|
||||
} catch (error) {
|
||||
console.error("화면 생성 실패:", error);
|
||||
@@ -125,12 +141,31 @@ export const updateScreen = async (
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const { companyCode } = req.user as any;
|
||||
const beforeScreen = await screenManagementService.getScreenById(parseInt(id));
|
||||
const updateData = { ...req.body, companyCode };
|
||||
const updatedScreen = await screenManagementService.updateScreen(
|
||||
parseInt(id),
|
||||
updateData,
|
||||
companyCode
|
||||
);
|
||||
|
||||
auditLogService.log({
|
||||
companyCode,
|
||||
userId: (req.user as any)?.userId || "",
|
||||
userName: (req.user as any)?.userName || "",
|
||||
action: "UPDATE",
|
||||
resourceType: "SCREEN",
|
||||
resourceId: id,
|
||||
resourceName: updatedScreen?.screenName || updateData.screenName,
|
||||
summary: `화면 "${updatedScreen?.screenName || updateData.screenName}" 수정`,
|
||||
changes: {
|
||||
before: { screenName: beforeScreen?.screenName, tableName: beforeScreen?.tableName, isActive: beforeScreen?.isActive },
|
||||
after: { screenName: updateData.screenName, tableName: updateData.tableName, isActive: updateData.isActive },
|
||||
},
|
||||
ipAddress: (req as any).ip,
|
||||
requestPath: req.originalUrl,
|
||||
});
|
||||
|
||||
res.json({ success: true, data: updatedScreen });
|
||||
} catch (error) {
|
||||
console.error("화면 수정 실패:", error);
|
||||
@@ -140,6 +175,33 @@ export const updateScreen = async (
|
||||
}
|
||||
};
|
||||
|
||||
// 화면 테이블명 변경
|
||||
export const updateScreenTableName = async (
|
||||
req: AuthenticatedRequest,
|
||||
res: Response
|
||||
) => {
|
||||
try {
|
||||
const { screenId } = req.params;
|
||||
const { companyCode } = req.user as any;
|
||||
const { tableName } = req.body;
|
||||
|
||||
if (!tableName) {
|
||||
return res.status(400).json({ success: false, message: "테이블명이 필요합니다." });
|
||||
}
|
||||
|
||||
await screenManagementService.updateScreenTableName(
|
||||
parseInt(screenId),
|
||||
tableName,
|
||||
companyCode
|
||||
);
|
||||
|
||||
res.json({ success: true, message: "테이블명이 변경되었습니다." });
|
||||
} catch (error) {
|
||||
console.error("테이블명 변경 실패:", error);
|
||||
res.status(500).json({ success: false, message: "테이블명 변경에 실패했습니다." });
|
||||
}
|
||||
};
|
||||
|
||||
// 화면 정보 수정 (메타데이터만)
|
||||
export const updateScreenInfo = async (
|
||||
req: AuthenticatedRequest,
|
||||
@@ -170,6 +232,8 @@ export const updateScreenInfo = async (
|
||||
restApiJsonPath,
|
||||
});
|
||||
|
||||
const beforeScreen = await screenManagementService.getScreenById(parseInt(id));
|
||||
|
||||
await screenManagementService.updateScreenInfo(
|
||||
parseInt(id),
|
||||
{
|
||||
@@ -186,6 +250,24 @@ export const updateScreenInfo = async (
|
||||
},
|
||||
companyCode
|
||||
);
|
||||
|
||||
auditLogService.log({
|
||||
companyCode,
|
||||
userId: (req.user as any)?.userId || "",
|
||||
userName: (req.user as any)?.userName || "",
|
||||
action: "UPDATE",
|
||||
resourceType: "SCREEN",
|
||||
resourceId: id,
|
||||
resourceName: screenName,
|
||||
summary: `화면 "${screenName}" 정보 수정`,
|
||||
changes: {
|
||||
before: { screenName: beforeScreen?.screenName, tableName: beforeScreen?.tableName, description: beforeScreen?.description, isActive: beforeScreen?.isActive },
|
||||
after: { screenName, tableName, description, isActive },
|
||||
},
|
||||
ipAddress: (req as any).ip,
|
||||
requestPath: req.originalUrl,
|
||||
});
|
||||
|
||||
res.json({ success: true, message: "화면 정보가 수정되었습니다." });
|
||||
} catch (error) {
|
||||
console.error("화면 정보 수정 실패:", error);
|
||||
@@ -227,6 +309,9 @@ export const deleteScreen = async (
|
||||
const { companyCode, userId } = req.user as any;
|
||||
const { deleteReason, force } = req.body;
|
||||
|
||||
const screenInfo = await screenManagementService.getScreenById(parseInt(id));
|
||||
const screenName = screenInfo?.screenName || "";
|
||||
|
||||
await screenManagementService.deleteScreen(
|
||||
parseInt(id),
|
||||
companyCode,
|
||||
@@ -234,6 +319,21 @@ export const deleteScreen = async (
|
||||
deleteReason,
|
||||
force || false
|
||||
);
|
||||
|
||||
auditLogService.log({
|
||||
companyCode,
|
||||
userId: userId || "",
|
||||
userName: (req.user as any)?.userName || "",
|
||||
action: "DELETE",
|
||||
resourceType: "SCREEN",
|
||||
resourceId: id,
|
||||
resourceName: screenName,
|
||||
summary: `화면(ID:${id}, ${screenName}) 삭제 (사유: ${deleteReason || "없음"})`,
|
||||
changes: { before: { deleteReason, force } },
|
||||
ipAddress: (req as any).ip,
|
||||
requestPath: req.originalUrl,
|
||||
});
|
||||
|
||||
res.json({ success: true, message: "화면이 휴지통으로 이동되었습니다." });
|
||||
} catch (error: any) {
|
||||
console.error("화면 삭제 실패:", error);
|
||||
@@ -513,6 +613,20 @@ export const copyScreenWithModals = async (
|
||||
modalScreens: modalScreens || [],
|
||||
});
|
||||
|
||||
auditLogService.log({
|
||||
companyCode: targetCompanyCode || companyCode,
|
||||
userId: userId || "",
|
||||
userName: (req.user as any)?.userName || "",
|
||||
action: "COPY",
|
||||
resourceType: "SCREEN",
|
||||
resourceId: id,
|
||||
resourceName: mainScreen?.screenName,
|
||||
summary: `화면 일괄 복사 (메인 1개 + 모달 ${result.modalScreens.length}개, 원본 ID:${id})`,
|
||||
changes: { after: { sourceScreenId: id, targetCompanyCode, mainScreenName: mainScreen?.screenName } },
|
||||
ipAddress: (req as any).ip,
|
||||
requestPath: req.originalUrl,
|
||||
});
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: result,
|
||||
@@ -548,6 +662,20 @@ export const copyScreen = async (
|
||||
}
|
||||
);
|
||||
|
||||
auditLogService.log({
|
||||
companyCode,
|
||||
userId: userId || "",
|
||||
userName: (req.user as any)?.userName || "",
|
||||
action: "COPY",
|
||||
resourceType: "SCREEN",
|
||||
resourceId: String(copiedScreen?.id || ""),
|
||||
resourceName: screenName,
|
||||
summary: `화면 "${screenName}" 복사 (원본 ID:${id})`,
|
||||
changes: { after: { sourceScreenId: id, screenName, screenCode } },
|
||||
ipAddress: (req as any).ip,
|
||||
requestPath: req.originalUrl,
|
||||
});
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: copiedScreen,
|
||||
@@ -647,6 +775,21 @@ export const saveLayout = async (req: AuthenticatedRequest, res: Response) => {
|
||||
layoutData,
|
||||
companyCode
|
||||
);
|
||||
|
||||
const screenInfo = await screenManagementService.getScreenById(parseInt(screenId));
|
||||
auditLogService.log({
|
||||
companyCode,
|
||||
userId: (req.user as any)?.userId || "",
|
||||
userName: (req.user as any)?.userName || "",
|
||||
action: "UPDATE",
|
||||
resourceType: "SCREEN_LAYOUT",
|
||||
resourceId: screenId,
|
||||
resourceName: screenInfo?.screenName || "",
|
||||
summary: `화면(ID:${screenId}, ${screenInfo?.screenName || ""}) 레이아웃 저장`,
|
||||
ipAddress: (req as any).ip,
|
||||
requestPath: req.originalUrl,
|
||||
});
|
||||
|
||||
res.json({ success: true, data: savedLayout });
|
||||
} catch (error) {
|
||||
console.error("레이아웃 저장 실패:", error);
|
||||
@@ -723,6 +866,21 @@ export const saveLayoutV2 = async (req: AuthenticatedRequest, res: Response) =>
|
||||
layoutData,
|
||||
companyCode
|
||||
);
|
||||
|
||||
const screenInfo = await screenManagementService.getScreenById(parseInt(screenId));
|
||||
auditLogService.log({
|
||||
companyCode,
|
||||
userId: (req.user as any)?.userId || "",
|
||||
userName: (req.user as any)?.userName || "",
|
||||
action: "UPDATE",
|
||||
resourceType: "SCREEN_LAYOUT",
|
||||
resourceId: screenId,
|
||||
resourceName: screenInfo?.screenName || "",
|
||||
summary: `화면(ID:${screenId}, ${screenInfo?.screenName || ""}) V2 레이아웃 저장`,
|
||||
ipAddress: (req as any).ip,
|
||||
requestPath: req.originalUrl,
|
||||
});
|
||||
|
||||
res.json({ success: true, message: "V2 레이아웃이 저장되었습니다." });
|
||||
} catch (error) {
|
||||
console.error("V2 레이아웃 저장 실패:", error);
|
||||
@@ -895,6 +1053,21 @@ export const saveLayoutPop = async (req: AuthenticatedRequest, res: Response) =>
|
||||
companyCode,
|
||||
userId
|
||||
);
|
||||
|
||||
const screenInfo = await screenManagementService.getScreenById(parseInt(screenId));
|
||||
auditLogService.log({
|
||||
companyCode,
|
||||
userId: userId || "",
|
||||
userName: (req.user as any)?.userName || "",
|
||||
action: "UPDATE",
|
||||
resourceType: "SCREEN_LAYOUT",
|
||||
resourceId: screenId,
|
||||
resourceName: screenInfo?.screenName || "",
|
||||
summary: `화면(ID:${screenId}, ${screenInfo?.screenName || ""}) POP 레이아웃 저장`,
|
||||
ipAddress: (req as any).ip,
|
||||
requestPath: req.originalUrl,
|
||||
});
|
||||
|
||||
res.json({ success: true, message: "POP 레이아웃이 저장되었습니다." });
|
||||
} catch (error) {
|
||||
console.error("POP 레이아웃 저장 실패:", error);
|
||||
|
||||
Reference in New Issue
Block a user