Skip to content

Commit b4cca96

Browse files
committed
fix(ingest): apply sync timestamp for forest fire warning events
1 parent de48a91 commit b4cca96

2 files changed

Lines changed: 32 additions & 9 deletions

File tree

src/modules/ingest/app/sources/forest-fire-warning.source.test.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,17 @@ describe('ForestFireWarningSource', () => {
2121
frfr_wrnng_step_cd: '주의',
2222
frfr_wrnng_rgstn_dtm: '2026-01-28 10:54:36',
2323
frfr_wrnng_issu_dtm: '2026-01-27 17:00',
24+
sync_dt: '2026-01-28 10:54:36',
2425
lgdng_ctprv_cd: '52',
2526
lgdng_nm: '전북특별자치도',
2627
lgdng_sgng_cd: '000',
2728
},
2829
{
2930
frfr_wrnng_id: '200',
3031
frfr_wrnng_step_cd: '주의',
31-
frfr_wrnng_rgstn_dtm: '2026-01-26 00:00:00',
32+
frfr_wrnng_rgstn_dtm: '2026-01-24 00:00:00',
3233
frfr_wrnng_issu_dtm: '2026-01-25 17:00',
34+
sync_dt: '2026-01-24 00:00:00',
3335
lgdng_ctprv_cd: '51',
3436
lgdng_nm: '강원특별자치도',
3537
lgdng_sgng_cd: '000',
@@ -65,6 +67,7 @@ describe('ForestFireWarningSource', () => {
6567
frfr_wrnng_step_cd: '주의',
6668
frfr_wrnng_rgstn_dtm: '2026-01-28 10:54:36',
6769
frfr_wrnng_issu_dtm: '2026-01-27 17:00',
70+
sync_dt: '2026-01-28 10:27:02',
6871
lgdng_ctprv_cd: '52',
6972
lgdng_nm: '전북특별자치도',
7073
loest_ara_nm: '전북특별자치도',
@@ -75,6 +78,7 @@ describe('ForestFireWarningSource', () => {
7578
frfr_wrnng_step_cd: '주의',
7679
frfr_wrnng_rgstn_dtm: '2026-01-28 10:54:36',
7780
frfr_wrnng_issu_dtm: '2026-01-27 17:00',
81+
sync_dt: '2026-01-28 10:27:02',
7882
lgdng_ctprv_cd: '52',
7983
lgdng_nm: '전북특별자치도 전주시',
8084
loest_ara_nm: '전주시',
@@ -85,6 +89,7 @@ describe('ForestFireWarningSource', () => {
8589
frfr_wrnng_step_cd: '주의',
8690
frfr_wrnng_rgstn_dtm: '2026-01-28 10:54:36',
8791
frfr_wrnng_issu_dtm: '2026-01-27 17:00',
92+
sync_dt: '2026-01-28 10:27:02',
8893
lgdng_ctprv_cd: '51',
8994
lgdng_nm: '강원특별자치도 양구군',
9095
loest_ara_nm: '양구군',
@@ -115,7 +120,7 @@ describe('ForestFireWarningSource', () => {
115120
expect(result.events).toHaveLength(1);
116121
expect(result.events[0].title).toBe('전북특별자치도 산불경보 주의 단계 발령');
117122
expect(result.events[0].level).toBe(EventLevels.Minor);
118-
expect(result.events[0].occurredAt).toBe('2026-01-28T01:54:36.000Z');
123+
expect(result.events[0].occurredAt).toBe('2026-01-28T01:27:02.000Z');
119124
expect(result.events[0].body).toBe('발령 시각: 2026-01-27 17:00\n대상 지역: 전북특별자치도, 전주시');
120125
const payload = result.events[0].payload as { items?: unknown[] } | null;
121126
expect(payload?.items).toHaveLength(2);
@@ -129,6 +134,7 @@ describe('ForestFireWarningSource', () => {
129134
frfr_wrnng_step_cd: '경계',
130135
frfr_wrnng_rgstn_dtm: '2026-01-28 10:00:00',
131136
frfr_wrnng_issu_dtm: '2026-01-28 09:00',
137+
sync_dt: '2026-01-28 10:00:00',
132138
lgdng_ctprv_cd: '52',
133139
lgdng_nm: '전북특별자치도',
134140
loest_ara_nm: '전북특별자치도',
@@ -139,6 +145,7 @@ describe('ForestFireWarningSource', () => {
139145
frfr_wrnng_step_cd: '경계',
140146
frfr_wrnng_rgstn_dtm: '2026-01-28 10:00:00',
141147
frfr_wrnng_issu_dtm: '2026-01-28 09:30',
148+
sync_dt: '2026-01-28 10:00:00',
142149
lgdng_ctprv_cd: '52',
143150
lgdng_nm: '전북특별자치도 전주시',
144151
loest_ara_nm: '전주시',
@@ -149,6 +156,7 @@ describe('ForestFireWarningSource', () => {
149156
frfr_wrnng_step_cd: '경계',
150157
frfr_wrnng_rgstn_dtm: '2026-01-28 11:00:00',
151158
frfr_wrnng_issu_dtm: '2026-01-28 09:00',
159+
sync_dt: '2026-01-28 11:00:00',
152160
lgdng_ctprv_cd: '52',
153161
lgdng_nm: '전북특별자치도 익산시',
154162
loest_ara_nm: '익산시',
@@ -197,6 +205,7 @@ describe('ForestFireWarningSource', () => {
197205
frfr_wrnng_step_cd: '주의',
198206
frfr_wrnng_rgstn_dtm: '2026-01-28 12:00:00',
199207
frfr_wrnng_issu_dtm: '2026-01-28 11:00',
208+
sync_dt: '2026-01-28 12:00:00',
200209
lgdng_ctprv_cd: '26',
201210
lgdng_nm: '부산광역시',
202211
lgdng_sgng_cd: '000',
@@ -206,6 +215,7 @@ describe('ForestFireWarningSource', () => {
206215
frfr_wrnng_step_cd: '주의',
207216
frfr_wrnng_rgstn_dtm: '2026-01-28 12:00:00',
208217
frfr_wrnng_issu_dtm: '2026-01-28 11:00',
218+
sync_dt: '2026-01-28 12:00:00',
209219
lgdng_ctprv_cd: '26',
210220
lgdng_nm: '부산광역시 사하구',
211221
lgdng_sgng_cd: '290',
@@ -215,6 +225,7 @@ describe('ForestFireWarningSource', () => {
215225
frfr_wrnng_step_cd: '주의',
216226
frfr_wrnng_rgstn_dtm: '2026-01-28 12:00:00',
217227
frfr_wrnng_issu_dtm: '2026-01-28 11:00',
228+
sync_dt: '2026-01-28 12:00:00',
218229
lgdng_ctprv_cd: '26',
219230
lgdng_nm: '부산광역시 해운대구',
220231
lgdng_sgng_cd: '300',
@@ -252,6 +263,7 @@ describe('ForestFireWarningSource', () => {
252263
frfr_wrnng_step_cd: '관심',
253264
frfr_wrnng_rgstn_dtm: '2026-01-28 09:00:00',
254265
frfr_wrnng_issu_dtm: '2026-01-28 08:30',
266+
sync_dt: '2026-01-28 09:00:00',
255267
lgdng_cd: '전국',
256268
},
257269
],

src/modules/ingest/app/sources/forest-fire-warning.source.ts

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ const schemaFireWarningItem = z
1919
frfr_wrnng_step_cd: z.string().nullish(),
2020
frfr_wrnng_rgstn_dtm: z.string().nullish(),
2121
frfr_wrnng_issu_dtm: z.string().nullish(),
22+
sync_dt: z.string().nullish(),
2223
frfr_wrnng_issu_rsn: z.string().nullish(),
2324
lgdng_cd: z.string().nullish(),
2425
lgdng_ctprv_cd: z.string().nullish(),
@@ -47,6 +48,7 @@ type FireWarningGroup = {
4748
stepLabel: string;
4849
items: FireWarningItem[];
4950
occurredAt: string;
51+
syncedAt: string;
5052
issuedAt: string;
5153
regionNames: string[];
5254
};
@@ -93,8 +95,9 @@ export class ForestFireWarningSource implements Source {
9395
}
9496

9597
const occurredAt = parseKstDateTime(normalizeText(item.frfr_wrnng_rgstn_dtm));
98+
const syncedAt = parseKstDateTime(normalizeText(item.sync_dt));
9699
const issuedAt = normalizeText(item.frfr_wrnng_issu_dtm);
97-
if (!occurredAt || !issuedAt) {
100+
if (!occurredAt || !syncedAt || !issuedAt) {
98101
continue;
99102
}
100103

@@ -128,7 +131,7 @@ export class ForestFireWarningSource implements Source {
128131
}
129132

130133
const groupKey = buildGroupKey(ctprvCode, stepLabel, occurredAt, issuedAt);
131-
const group = groups.get(groupKey) ?? createGroup(ctprvCode, stepLabel, occurredAt, issuedAt);
134+
const group = groups.get(groupKey) ?? createGroup(ctprvCode, stepLabel, occurredAt, syncedAt, issuedAt);
132135
group.items.push(item);
133136

134137
const regionName = resolveRegionName(item);
@@ -165,12 +168,19 @@ function parseResponseJson(rawText: string): unknown {
165168
}
166169
}
167170

168-
function createGroup(ctprvCode: string, stepLabel: string, occurredAt: string, issuedAt: string): FireWarningGroup {
171+
function createGroup(
172+
ctprvCode: string,
173+
stepLabel: string,
174+
occurredAt: string,
175+
syncedAt: string,
176+
issuedAt: string,
177+
): FireWarningGroup {
169178
return {
170179
ctprvCode,
171180
stepLabel,
172181
items: [],
173182
occurredAt,
183+
syncedAt,
174184
issuedAt,
175185
regionNames: [],
176186
};
@@ -184,7 +194,7 @@ function buildEvent(group: FireWarningGroup): SourceEvent {
184194
kind: EventKinds.Wildfire,
185195
title: buildTitle(regionText, group.stepLabel),
186196
body: buildBody(group.issuedAt, group.regionNames, ctprvName),
187-
occurredAt: group.occurredAt,
197+
occurredAt: group.syncedAt, // API에 경보 반영이 늦어서 동기화 시간(거의 현재 시간)을 사용
188198
regionText,
189199
level: mapWarningLevel(group.stepLabel),
190200
payload: { items: group.items },
@@ -200,17 +210,18 @@ function buildNationalEvents(items: FireWarningItem[]): SourceEvent[] {
200210
continue;
201211
}
202212

203-
const issuedAt = normalizeText(item.frfr_wrnng_issu_dtm);
204213
const occurredAt = parseKstDateTime(normalizeText(item.frfr_wrnng_rgstn_dtm));
205-
if (!issuedAt) {
214+
const syncedAt = parseKstDateTime(normalizeText(item.sync_dt));
215+
const issuedAt = normalizeText(item.frfr_wrnng_issu_dtm);
216+
if (!occurredAt || !syncedAt || !issuedAt) {
206217
continue;
207218
}
208219

209220
events.push({
210221
kind: EventKinds.Wildfire,
211222
title: buildTitle(NATIONAL_REGION_LABEL, stepLabel),
212223
body: buildBody(issuedAt, [], null),
213-
occurredAt,
224+
occurredAt: syncedAt, // API에 경보 반영이 늦어서 동기화 시간(거의 현재 시간)을 사용
214225
regionText: NATIONAL_REGION_LABEL,
215226
level: mapWarningLevel(stepLabel),
216227
payload: { items: [item] },

0 commit comments

Comments
 (0)