From b70ef399b5e7f9e9c324c174b852bf21715c83e5 Mon Sep 17 00:00:00 2001 From: htlee Date: Tue, 7 Apr 2026 12:05:04 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20prediction=5Fstats=5Fmonthly.stat=5Fmont?= =?UTF-8?q?h=20CHAR(7)=20=E2=86=92=20DATE=20=ED=83=80=EC=9E=85=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 날짜 기반 정렬/범위쿼리/집계함수 활용을 위해 VARCHAR(7)→DATE로 변환. 매월 1일(2026-04-01)로 저장. 엔티티/Repository/Controller 파라미터 동시 수정. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../kcg/domain/stats/PredictionStatsMonthly.java | 5 +++-- .../stats/PredictionStatsMonthlyRepository.java | 5 +++-- .../gc/mda/kcg/domain/stats/StatsController.java | 4 ++-- .../db/migration/V012__prediction_events_stats.sql | 2 +- .../db/migration/V013__enforcement_operations.sql | 14 +++++++------- 5 files changed, 16 insertions(+), 14 deletions(-) diff --git a/backend/src/main/java/gc/mda/kcg/domain/stats/PredictionStatsMonthly.java b/backend/src/main/java/gc/mda/kcg/domain/stats/PredictionStatsMonthly.java index 9a406ff..81eda4e 100644 --- a/backend/src/main/java/gc/mda/kcg/domain/stats/PredictionStatsMonthly.java +++ b/backend/src/main/java/gc/mda/kcg/domain/stats/PredictionStatsMonthly.java @@ -6,6 +6,7 @@ import org.hibernate.annotations.JdbcTypeCode; import org.hibernate.type.SqlTypes; import java.math.BigDecimal; +import java.time.LocalDate; import java.time.OffsetDateTime; import java.util.Map; @@ -15,8 +16,8 @@ import java.util.Map; public class PredictionStatsMonthly { @Id - @Column(name = "stat_month", length = 7, columnDefinition = "char(7)") - private String statMonth; + @Column(name = "stat_month") + private LocalDate statMonth; @Column(name = "total_detections") private Integer totalDetections; diff --git a/backend/src/main/java/gc/mda/kcg/domain/stats/PredictionStatsMonthlyRepository.java b/backend/src/main/java/gc/mda/kcg/domain/stats/PredictionStatsMonthlyRepository.java index 5763620..3c8994e 100644 --- a/backend/src/main/java/gc/mda/kcg/domain/stats/PredictionStatsMonthlyRepository.java +++ b/backend/src/main/java/gc/mda/kcg/domain/stats/PredictionStatsMonthlyRepository.java @@ -2,8 +2,9 @@ package gc.mda.kcg.domain.stats; import org.springframework.data.jpa.repository.JpaRepository; +import java.time.LocalDate; import java.util.List; -public interface PredictionStatsMonthlyRepository extends JpaRepository { - List findByStatMonthBetweenOrderByStatMonthAsc(String from, String to); +public interface PredictionStatsMonthlyRepository extends JpaRepository { + List findByStatMonthBetweenOrderByStatMonthAsc(LocalDate from, LocalDate to); } diff --git a/backend/src/main/java/gc/mda/kcg/domain/stats/StatsController.java b/backend/src/main/java/gc/mda/kcg/domain/stats/StatsController.java index 2d565ce..a2ed5f0 100644 --- a/backend/src/main/java/gc/mda/kcg/domain/stats/StatsController.java +++ b/backend/src/main/java/gc/mda/kcg/domain/stats/StatsController.java @@ -38,8 +38,8 @@ public class StatsController { @GetMapping("/monthly") @RequirePermission(resource = "statistics", operation = "READ") public List getMonthly( - @RequestParam String from, - @RequestParam String to + @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate from, + @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate to ) { return monthlyRepository.findByStatMonthBetweenOrderByStatMonthAsc(from, to); } diff --git a/backend/src/main/resources/db/migration/V012__prediction_events_stats.sql b/backend/src/main/resources/db/migration/V012__prediction_events_stats.sql index 0e8ee95..853e8dd 100644 --- a/backend/src/main/resources/db/migration/V012__prediction_events_stats.sql +++ b/backend/src/main/resources/db/migration/V012__prediction_events_stats.sql @@ -181,7 +181,7 @@ CREATE TABLE kcg.prediction_stats_daily ( -- 사전 집계 통계 — 월별 -- ============================================================ CREATE TABLE kcg.prediction_stats_monthly ( - stat_month VARCHAR(7) PRIMARY KEY, -- 'YYYY-MM' + stat_month DATE PRIMARY KEY, -- 매월 1일 (2026-04-01) total_detections INT DEFAULT 0, total_enforcements INT DEFAULT 0, by_category JSONB, diff --git a/backend/src/main/resources/db/migration/V013__enforcement_operations.sql b/backend/src/main/resources/db/migration/V013__enforcement_operations.sql index 4a4a8ba..a6705d5 100644 --- a/backend/src/main/resources/db/migration/V013__enforcement_operations.sql +++ b/backend/src/main/resources/db/migration/V013__enforcement_operations.sql @@ -263,10 +263,10 @@ INSERT INTO kcg.enforcement_plans (plan_uid, title, zone_code, area_name, -- ============================================================ INSERT INTO kcg.prediction_stats_monthly (stat_month, total_detections, total_enforcements, by_violation_type, event_count, critical_event_count, false_positive_count, ai_accuracy_pct) VALUES -('2025-10', 128, 42, '{"EEZ_VIOLATION":45,"DARK_VESSEL":32,"MMSI_TAMPERING":23,"ILLEGAL_TRANSSHIP":15,"ILLEGAL_GEAR":13}', 85, 12, 16, 81.0), -('2025-11', 145, 38, '{"EEZ_VIOLATION":51,"DARK_VESSEL":36,"MMSI_TAMPERING":26,"ILLEGAL_TRANSSHIP":17,"ILLEGAL_GEAR":15}', 97, 15, 14, 84.0), -('2025-12', 167, 55, '{"EEZ_VIOLATION":59,"DARK_VESSEL":42,"MMSI_TAMPERING":30,"ILLEGAL_TRANSSHIP":20,"ILLEGAL_GEAR":16}', 112, 18, 12, 86.0), -('2026-01', 189, 61, '{"EEZ_VIOLATION":66,"DARK_VESSEL":47,"MMSI_TAMPERING":34,"ILLEGAL_TRANSSHIP":23,"ILLEGAL_GEAR":19}', 126, 22, 10, 88.0), -('2026-02', 156, 48, '{"EEZ_VIOLATION":55,"DARK_VESSEL":39,"MMSI_TAMPERING":28,"ILLEGAL_TRANSSHIP":19,"ILLEGAL_GEAR":15}', 104, 17, 9, 89.0), -('2026-03', 172, 52, '{"EEZ_VIOLATION":60,"DARK_VESSEL":43,"MMSI_TAMPERING":31,"ILLEGAL_TRANSSHIP":21,"ILLEGAL_GEAR":17}', 115, 19, 8, 90.0), -('2026-04', 67, 15, '{"EEZ_VIOLATION":24,"DARK_VESSEL":17,"MMSI_TAMPERING":12,"ILLEGAL_TRANSSHIP":8,"ILLEGAL_GEAR":6}', 45, 8, 2, 93.0); +('2025-10-01', 128, 42, '{"EEZ_VIOLATION":45,"DARK_VESSEL":32,"MMSI_TAMPERING":23,"ILLEGAL_TRANSSHIP":15,"ILLEGAL_GEAR":13}', 85, 12, 16, 81.0), +('2025-11-01', 145, 38, '{"EEZ_VIOLATION":51,"DARK_VESSEL":36,"MMSI_TAMPERING":26,"ILLEGAL_TRANSSHIP":17,"ILLEGAL_GEAR":15}', 97, 15, 14, 84.0), +('2025-12-01', 167, 55, '{"EEZ_VIOLATION":59,"DARK_VESSEL":42,"MMSI_TAMPERING":30,"ILLEGAL_TRANSSHIP":20,"ILLEGAL_GEAR":16}', 112, 18, 12, 86.0), +('2026-01-01', 189, 61, '{"EEZ_VIOLATION":66,"DARK_VESSEL":47,"MMSI_TAMPERING":34,"ILLEGAL_TRANSSHIP":23,"ILLEGAL_GEAR":19}', 126, 22, 10, 88.0), +('2026-02-01', 156, 48, '{"EEZ_VIOLATION":55,"DARK_VESSEL":39,"MMSI_TAMPERING":28,"ILLEGAL_TRANSSHIP":19,"ILLEGAL_GEAR":15}', 104, 17, 9, 89.0), +('2026-03-01', 172, 52, '{"EEZ_VIOLATION":60,"DARK_VESSEL":43,"MMSI_TAMPERING":31,"ILLEGAL_TRANSSHIP":21,"ILLEGAL_GEAR":17}', 115, 19, 8, 90.0), +('2026-04-01', 67, 15, '{"EEZ_VIOLATION":24,"DARK_VESSEL":17,"MMSI_TAMPERING":12,"ILLEGAL_TRANSSHIP":8,"ILLEGAL_GEAR":6}', 45, 8, 2, 93.0);