fix(audit-log): URL 단/복수 + DB 컬럼명 + 응답 키 case 일괄 정정

- frontend `/audit-log` → 백엔드 `/audit-logs` (단/복수 mismatch)
- mapper auditLog.xml: `CREATED_DATE` → `CREATED_AT` (PostgreSQL 실제 컬럼명)
- AuditLogStats interface camelCase → snake_case (백엔드 응답 키 일치)

그렘린 카오스 테스트 + fetch hook 으로 발견. Application error / 500 / 404 모두 해결.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-02 16:11:26 +09:00
parent db06c95724
commit 53f2638b82
4 changed files with 23 additions and 23 deletions
@@ -25,17 +25,17 @@
AND SAL.TABLE_NAME = #{table_name}
</if>
<if test="date_from != null and date_from != ''">
AND SAL.CREATED_DATE >= #{date_from}::TIMESTAMPTZ
AND SAL.CREATED_AT >= #{date_from}::TIMESTAMPTZ
</if>
<if test="date_to != null and date_to != ''">
AND SAL.CREATED_DATE &lt;= #{date_to}::TIMESTAMPTZ
AND SAL.CREATED_AT &lt;= #{date_to}::TIMESTAMPTZ
</if>
<if test="search != null and search != ''">
AND (SAL.SUMMARY ILIKE CONCAT('%', #{search}, '%')
OR SAL.RESOURCE_NAME ILIKE CONCAT('%', #{search}, '%')
OR SAL.USER_NAME ILIKE CONCAT('%', #{search}, '%'))
</if>
ORDER BY SAL.CREATED_DATE DESC
ORDER BY SAL.CREATED_AT DESC
LIMIT #{limit} OFFSET #{offset}
</select>
@@ -60,10 +60,10 @@
AND SAL.TABLE_NAME = #{table_name}
</if>
<if test="date_from != null and date_from != ''">
AND SAL.CREATED_DATE >= #{date_from}::TIMESTAMPTZ
AND SAL.CREATED_AT >= #{date_from}::TIMESTAMPTZ
</if>
<if test="date_to != null and date_to != ''">
AND SAL.CREATED_DATE &lt;= #{date_to}::TIMESTAMPTZ
AND SAL.CREATED_AT &lt;= #{date_to}::TIMESTAMPTZ
</if>
<if test="search != null and search != ''">
AND (SAL.SUMMARY ILIKE CONCAT('%', #{search}, '%')
@@ -74,13 +74,13 @@
<!-- 일별 감사 로그 건수 -->
<select id="selectDailyCounts" parameterType="map" resultType="map">
SELECT DATE(CREATED_DATE) AS DATE, COUNT(*)::INT AS COUNT
SELECT DATE(CREATED_AT) AS DATE, COUNT(*)::INT AS COUNT
FROM SYSTEM_AUDIT_LOG
WHERE CREATED_DATE >= NOW() - INTERVAL '1 day' * #{days}
WHERE CREATED_AT >= NOW() - INTERVAL '1 day' * #{days}
<if test="company_code != null and company_code != ''">
AND (COMPANY_CODE = #{company_code} OR COMPANY_CODE = '*')
</if>
GROUP BY DATE(CREATED_DATE)
GROUP BY DATE(CREATED_AT)
ORDER BY DATE DESC
</select>
@@ -88,7 +88,7 @@
<select id="selectResourceTypeCounts" parameterType="map" resultType="map">
SELECT RESOURCE_TYPE, COUNT(*)::INT AS COUNT
FROM SYSTEM_AUDIT_LOG
WHERE CREATED_DATE >= NOW() - INTERVAL '1 day' * #{days}
WHERE CREATED_AT >= NOW() - INTERVAL '1 day' * #{days}
<if test="company_code != null and company_code != ''">
AND (COMPANY_CODE = #{company_code} OR COMPANY_CODE = '*')
</if>
@@ -100,7 +100,7 @@
<select id="selectActionCounts" parameterType="map" resultType="map">
SELECT ACTION, COUNT(*)::INT AS COUNT
FROM SYSTEM_AUDIT_LOG
WHERE CREATED_DATE >= NOW() - INTERVAL '1 day' * #{days}
WHERE CREATED_AT >= NOW() - INTERVAL '1 day' * #{days}
<if test="company_code != null and company_code != ''">
AND (COMPANY_CODE = #{company_code} OR COMPANY_CODE = '*')
</if>
@@ -112,7 +112,7 @@
<select id="selectTopUsers" parameterType="map" resultType="map">
SELECT USER_ID, COALESCE(MAX(USER_NAME), USER_ID) AS USER_NAME, COUNT(*)::INT AS COUNT
FROM SYSTEM_AUDIT_LOG
WHERE CREATED_DATE >= NOW() - INTERVAL '1 day' * #{days}
WHERE CREATED_AT >= NOW() - INTERVAL '1 day' * #{days}
<if test="company_code != null and company_code != ''">
AND (COMPANY_CODE = #{company_code} OR COMPANY_CODE = '*')
</if>
+4 -4
View File
@@ -422,20 +422,20 @@ export default function AuditLogPage() {
<CardContent className="p-4">
<p className="text-muted-foreground text-xs"> 30 </p>
<p className="text-2xl font-bold">
{stats.dailyCounts.reduce((s, d) => s + d.count, 0).toLocaleString()}
{stats.daily_counts.reduce((s, d) => s + d.count, 0).toLocaleString()}
</p>
</CardContent>
</Card>
<Card>
<CardContent className="p-4">
<p className="text-muted-foreground text-xs"> </p>
<p className="text-2xl font-bold">{stats.resourceTypeCounts.length}</p>
<p className="text-2xl font-bold">{stats.resource_type_counts.length}</p>
</CardContent>
</Card>
<Card>
<CardContent className="p-4">
<p className="text-muted-foreground text-xs"> </p>
<p className="text-2xl font-bold">{stats.topUsers.length}</p>
<p className="text-2xl font-bold">{stats.top_users.length}</p>
</CardContent>
</Card>
<Card>
@@ -443,7 +443,7 @@ export default function AuditLogPage() {
<p className="text-muted-foreground text-xs"> </p>
<p className="text-2xl font-bold">
{(
stats.dailyCounts.find(
stats.daily_counts.find(
(d) =>
new Date(d.date).toDateString() ===
new Date().toDateString()
@@ -1169,7 +1169,7 @@ export default function CopyScreenModal({
// 그룹 복제 요약 감사 로그 1건 기록
try {
await apiClient.post("/audit-log", {
await apiClient.post("/audit-logs", {
action: "COPY",
resource_type: "SCREEN",
resource_id: String(sourceGroup.id),
+7 -7
View File
@@ -32,10 +32,10 @@ export interface AuditLogFilters {
}
export interface AuditLogStats {
dailyCounts: Array<{ date: string; count: number }>;
resourceTypeCounts: Array<{ resource_type: string; count: number }>;
actionCounts: Array<{ action: string; count: number }>;
topUsers: Array<{ user_id: string; user_name: string; count: number }>;
daily_counts: Array<{ date: string; count: number }>;
resource_type_counts: Array<{ resource_type: string; count: number }>;
action_counts: Array<{ action: string; count: number }>;
top_users: Array<{ user_id: string; user_name: string; count: number }>;
}
export async function getAuditLogs(
@@ -59,7 +59,7 @@ export async function getAuditLogs(
if (filters.page) params.append("page", String(filters.page));
if (filters.limit) params.append("limit", String(filters.limit));
const response = await apiClient.get(`/audit-log?${params.toString()}`);
const response = await apiClient.get(`/audit-logs?${params.toString()}`);
return response.data;
}
@@ -71,7 +71,7 @@ export async function getAuditLogStats(
if (companyCode) params.append("companyCode", companyCode);
if (days) params.append("days", String(days));
const response = await apiClient.get(`/audit-log/stats?${params.toString()}`);
const response = await apiClient.get(`/audit-logs/stats?${params.toString()}`);
return response.data;
}
@@ -87,6 +87,6 @@ export async function getAuditLogUsers(
const params = new URLSearchParams();
if (companyCode) params.append("companyCode", companyCode);
const response = await apiClient.get(`/audit-log/users?${params.toString()}`);
const response = await apiClient.get(`/audit-logs/users?${params.toString()}`);
return response.data;
}