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:
11
backend-node/src/routes/auditLogRoutes.ts
Normal file
11
backend-node/src/routes/auditLogRoutes.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { Router } from "express";
|
||||
import { authenticateToken } from "../middleware/authMiddleware";
|
||||
import { getAuditLogs, getAuditLogStats, getAuditLogUsers } from "../controllers/auditLogController";
|
||||
|
||||
const router = Router();
|
||||
|
||||
router.get("/", authenticateToken, getAuditLogs);
|
||||
router.get("/stats", authenticateToken, getAuditLogStats);
|
||||
router.get("/users", authenticateToken, getAuditLogUsers);
|
||||
|
||||
export default router;
|
||||
@@ -3,6 +3,7 @@ import { dataService } from "../services/dataService";
|
||||
import { masterDetailExcelService } from "../services/masterDetailExcelService";
|
||||
import { authenticateToken } from "../middleware/authMiddleware";
|
||||
import { AuthenticatedRequest } from "../types/auth";
|
||||
import { auditLogService } from "../services/auditLogService";
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
@@ -736,17 +737,39 @@ router.post(
|
||||
return res.status(400).json(result);
|
||||
}
|
||||
|
||||
const inserted = result.data?.inserted || 0;
|
||||
const updated = result.data?.updated || 0;
|
||||
const deleted = result.data?.deleted || 0;
|
||||
|
||||
console.log(`✅ 그룹화된 데이터 UPSERT 성공: ${tableName}`, {
|
||||
inserted: result.data?.inserted || 0,
|
||||
updated: result.data?.updated || 0,
|
||||
deleted: result.data?.deleted || 0,
|
||||
inserted, updated, deleted,
|
||||
});
|
||||
|
||||
const parts: string[] = [];
|
||||
if (inserted > 0) parts.push(`${inserted}건 생성`);
|
||||
if (updated > 0) parts.push(`${updated}건 수정`);
|
||||
if (deleted > 0) parts.push(`${deleted}건 삭제`);
|
||||
|
||||
if (parts.length > 0) {
|
||||
auditLogService.log({
|
||||
companyCode: req.user?.companyCode || "",
|
||||
userId: req.user?.userId || "",
|
||||
userName: req.user?.userName || "",
|
||||
action: inserted > 0 && updated === 0 && deleted === 0 ? "BATCH_CREATE" : "UPDATE",
|
||||
resourceType: "DATA",
|
||||
tableName,
|
||||
summary: `${tableName} 테이블 배치 처리: ${parts.join(", ")}`,
|
||||
changes: { after: { inserted, updated, deleted } },
|
||||
ipAddress: (req as any).ip,
|
||||
requestPath: req.originalUrl,
|
||||
});
|
||||
}
|
||||
|
||||
return res.json({
|
||||
success: true,
|
||||
message: "데이터가 저장되었습니다.",
|
||||
inserted: result.data?.inserted || 0,
|
||||
updated: result.data?.updated || 0,
|
||||
inserted,
|
||||
updated,
|
||||
deleted: result.data?.deleted || 0,
|
||||
savedIds: result.data?.savedIds || [],
|
||||
});
|
||||
@@ -824,6 +847,19 @@ router.post(
|
||||
|
||||
console.log(`✅ 레코드 생성 성공: ${tableName}`);
|
||||
|
||||
auditLogService.log({
|
||||
companyCode: req.user?.companyCode || "",
|
||||
userId: req.user?.userId || "",
|
||||
userName: req.user?.userName || "",
|
||||
action: "CREATE",
|
||||
resourceType: "DATA",
|
||||
resourceId: result.data?.id ? String(result.data.id) : undefined,
|
||||
tableName,
|
||||
summary: `${tableName} 테이블에 데이터 1건 생성`,
|
||||
ipAddress: (req as any).ip,
|
||||
requestPath: req.originalUrl,
|
||||
});
|
||||
|
||||
return res.status(201).json({
|
||||
success: true,
|
||||
data: result.data,
|
||||
@@ -880,6 +916,20 @@ router.put(
|
||||
|
||||
console.log(`✅ 레코드 수정 성공: ${tableName}/${id}`);
|
||||
|
||||
auditLogService.log({
|
||||
companyCode: req.user?.companyCode || "",
|
||||
userId: req.user?.userId || "",
|
||||
userName: req.user?.userName || "",
|
||||
action: "UPDATE",
|
||||
resourceType: "DATA",
|
||||
resourceId: String(id),
|
||||
tableName,
|
||||
summary: `${tableName} 테이블 데이터 수정 (ID:${id})`,
|
||||
changes: { after: data, fields: Object.keys(data || {}) },
|
||||
ipAddress: (req as any).ip,
|
||||
requestPath: req.originalUrl,
|
||||
});
|
||||
|
||||
return res.json({
|
||||
success: true,
|
||||
data: result.data,
|
||||
@@ -940,6 +990,20 @@ router.post(
|
||||
}
|
||||
|
||||
console.log(`✅ 레코드 삭제 성공: ${tableName}`);
|
||||
|
||||
auditLogService.log({
|
||||
companyCode: req.user?.companyCode || "",
|
||||
userId: req.user?.userId || "",
|
||||
userName: req.user?.userName || "",
|
||||
action: "DELETE",
|
||||
resourceType: "DATA",
|
||||
tableName,
|
||||
summary: `${tableName} 테이블 데이터 삭제 (복합키)`,
|
||||
changes: { before: compositeKey },
|
||||
ipAddress: (req as any).ip,
|
||||
requestPath: req.originalUrl,
|
||||
});
|
||||
|
||||
return res.json(result);
|
||||
} catch (error: any) {
|
||||
console.error(`레코드 삭제 오류 (${req.params.tableName}):`, error);
|
||||
@@ -1032,6 +1096,19 @@ router.delete(
|
||||
|
||||
console.log(`✅ 레코드 삭제 성공: ${tableName}/${id}`);
|
||||
|
||||
auditLogService.log({
|
||||
companyCode: req.user?.companyCode || "",
|
||||
userId: req.user?.userId || "",
|
||||
userName: req.user?.userName || "",
|
||||
action: "DELETE",
|
||||
resourceType: "DATA",
|
||||
resourceId: String(id),
|
||||
tableName,
|
||||
summary: `${tableName} 테이블 데이터 삭제 (ID:${id})`,
|
||||
ipAddress: (req as any).ip,
|
||||
requestPath: req.originalUrl,
|
||||
});
|
||||
|
||||
return res.json({
|
||||
success: true,
|
||||
message: "레코드가 삭제되었습니다.",
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
createScreen,
|
||||
updateScreen,
|
||||
updateScreenInfo,
|
||||
updateScreenTableName,
|
||||
deleteScreen,
|
||||
bulkDeleteScreens,
|
||||
checkScreenDependencies,
|
||||
@@ -65,6 +66,7 @@ router.get("/screens/:id/menu", getScreenMenu); // 화면에 할당된 메뉴
|
||||
router.post("/screens", createScreen);
|
||||
router.put("/screens/:id", updateScreen);
|
||||
router.put("/screens/:id/info", updateScreenInfo); // 화면 정보만 수정
|
||||
router.patch("/screens/:screenId/table-name", updateScreenTableName); // 화면 테이블명 변경
|
||||
router.get("/screens/:id/dependencies", checkScreenDependencies); // 의존성 체크
|
||||
router.delete("/screens/:id", deleteScreen); // 휴지통으로 이동
|
||||
router.delete("/screens/bulk/delete", bulkDeleteScreens); // 활성 화면 일괄 삭제 (휴지통으로 이동)
|
||||
|
||||
Reference in New Issue
Block a user