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.
2026-03-04 13:49:08 +09:00
|
|
|
import { Response } from "express";
|
|
|
|
|
import { AuthenticatedRequest } from "../middleware/authMiddleware";
|
2026-03-12 10:41:57 +09:00
|
|
|
import { auditLogService, getClientIp, AuditAction, AuditResourceType } from "../services/auditLogService";
|
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.
2026-03-04 13:49:08 +09:00
|
|
|
import { query } from "../database/db";
|
|
|
|
|
import logger from "../utils/logger";
|
|
|
|
|
|
|
|
|
|
export const getAuditLogs = async (
|
|
|
|
|
req: AuthenticatedRequest,
|
|
|
|
|
res: Response
|
|
|
|
|
): Promise<void> => {
|
|
|
|
|
try {
|
|
|
|
|
const userCompanyCode = req.user?.companyCode;
|
2026-03-17 11:31:54 +09:00
|
|
|
const isSuperAdmin = req.user?.userType === "SUPER_ADMIN";
|
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.
2026-03-04 13:49:08 +09:00
|
|
|
|
|
|
|
|
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<void> => {
|
|
|
|
|
try {
|
|
|
|
|
const userCompanyCode = req.user?.companyCode;
|
2026-03-17 11:31:54 +09:00
|
|
|
const isSuperAdmin = req.user?.userType === "SUPER_ADMIN";
|
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.
2026-03-04 13:49:08 +09:00
|
|
|
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<void> => {
|
|
|
|
|
try {
|
|
|
|
|
const userCompanyCode = req.user?.companyCode;
|
2026-03-17 11:31:54 +09:00
|
|
|
const isSuperAdmin = req.user?.userType === "SUPER_ADMIN";
|
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.
2026-03-04 13:49:08 +09:00
|
|
|
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: "사용자 목록 조회 중 오류가 발생했습니다.",
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
};
|
2026-03-12 10:41:57 +09:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 프론트엔드에서 직접 감사 로그 기록 (그룹 복제 등 프론트 오케스트레이션 작업용)
|
|
|
|
|
*/
|
|
|
|
|
export const createAuditLog = async (
|
|
|
|
|
req: AuthenticatedRequest,
|
|
|
|
|
res: Response
|
|
|
|
|
): Promise<void> => {
|
|
|
|
|
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: "감사 로그 기록 실패" });
|
|
|
|
|
}
|
|
|
|
|
};
|