diff --git a/backend/src/main/java/gc/mda/kcg/auth/entity/LoginHistory.java b/backend/src/main/java/gc/mda/kcg/auth/entity/LoginHistory.java index e994de7..2c22bc0 100644 --- a/backend/src/main/java/gc/mda/kcg/auth/entity/LoginHistory.java +++ b/backend/src/main/java/gc/mda/kcg/auth/entity/LoginHistory.java @@ -17,7 +17,7 @@ import lombok.NoArgsConstructor; import java.time.LocalDateTime; @Entity -@Table(name = "login_history", schema = "kcg") +@Table(name = "login_history") @Getter @Builder @NoArgsConstructor diff --git a/backend/src/main/java/gc/mda/kcg/auth/entity/User.java b/backend/src/main/java/gc/mda/kcg/auth/entity/User.java index d939d15..438886e 100644 --- a/backend/src/main/java/gc/mda/kcg/auth/entity/User.java +++ b/backend/src/main/java/gc/mda/kcg/auth/entity/User.java @@ -15,7 +15,7 @@ import lombok.Setter; import java.time.LocalDateTime; @Entity -@Table(name = "users", schema = "kcg") +@Table(name = "users") @Getter @Setter @Builder diff --git a/backend/src/main/java/gc/mda/kcg/config/WebConfig.java b/backend/src/main/java/gc/mda/kcg/config/WebConfig.java index b9afae0..d968d87 100644 --- a/backend/src/main/java/gc/mda/kcg/config/WebConfig.java +++ b/backend/src/main/java/gc/mda/kcg/config/WebConfig.java @@ -14,7 +14,7 @@ import java.util.List; @Configuration public class WebConfig { - @Value("${app.cors.allowed-origins:http://localhost:5173}") + @Value("${app.cors.allowed-origins:http://localhost:5174,http://localhost:5173}") private List allowedOrigins; @Bean diff --git a/backend/src/main/java/gc/mda/kcg/domain/aircraft/AircraftPosition.java b/backend/src/main/java/gc/mda/kcg/domain/aircraft/AircraftPosition.java index 42f5639..192151a 100644 --- a/backend/src/main/java/gc/mda/kcg/domain/aircraft/AircraftPosition.java +++ b/backend/src/main/java/gc/mda/kcg/domain/aircraft/AircraftPosition.java @@ -7,7 +7,7 @@ import org.locationtech.jts.geom.Point; import java.time.Instant; @Entity -@Table(name = "aircraft_positions", schema = "kcg") +@Table(name = "aircraft_positions") @Getter @Setter @NoArgsConstructor diff --git a/backend/src/main/java/gc/mda/kcg/domain/analysis/VesselAnalysisResult.java b/backend/src/main/java/gc/mda/kcg/domain/analysis/VesselAnalysisResult.java index 4a4e926..46f71f2 100644 --- a/backend/src/main/java/gc/mda/kcg/domain/analysis/VesselAnalysisResult.java +++ b/backend/src/main/java/gc/mda/kcg/domain/analysis/VesselAnalysisResult.java @@ -9,7 +9,7 @@ import java.time.Instant; import java.util.Map; @Entity -@Table(name = "vessel_analysis_results", schema = "kcg") +@Table(name = "vessel_analysis_results") @Getter @Setter @NoArgsConstructor diff --git a/backend/src/main/java/gc/mda/kcg/domain/event/Event.java b/backend/src/main/java/gc/mda/kcg/domain/event/Event.java index 385d22e..21ebd3f 100644 --- a/backend/src/main/java/gc/mda/kcg/domain/event/Event.java +++ b/backend/src/main/java/gc/mda/kcg/domain/event/Event.java @@ -9,7 +9,7 @@ import java.time.Instant; import java.util.Map; @Entity -@Table(name = "events", schema = "kcg") +@Table(name = "events") @Getter @Setter @NoArgsConstructor diff --git a/backend/src/main/java/gc/mda/kcg/domain/osint/OsintFeed.java b/backend/src/main/java/gc/mda/kcg/domain/osint/OsintFeed.java index 10bd1c7..495d888 100644 --- a/backend/src/main/java/gc/mda/kcg/domain/osint/OsintFeed.java +++ b/backend/src/main/java/gc/mda/kcg/domain/osint/OsintFeed.java @@ -9,7 +9,6 @@ import java.time.Instant; @Entity @Table( name = "osint_feeds", - schema = "kcg", uniqueConstraints = @UniqueConstraint(columnNames = {"source", "source_url"}) ) @Getter diff --git a/backend/src/main/java/gc/mda/kcg/domain/satellite/SatelliteTle.java b/backend/src/main/java/gc/mda/kcg/domain/satellite/SatelliteTle.java index 105f912..534e1b8 100644 --- a/backend/src/main/java/gc/mda/kcg/domain/satellite/SatelliteTle.java +++ b/backend/src/main/java/gc/mda/kcg/domain/satellite/SatelliteTle.java @@ -6,7 +6,7 @@ import lombok.*; import java.time.Instant; @Entity -@Table(name = "satellite_tle", schema = "kcg") +@Table(name = "satellite_tle") @Getter @Setter @NoArgsConstructor diff --git a/backend/src/main/java/gc/mda/kcg/domain/sensor/PressureReading.java b/backend/src/main/java/gc/mda/kcg/domain/sensor/PressureReading.java index f405295..0d4c19b 100644 --- a/backend/src/main/java/gc/mda/kcg/domain/sensor/PressureReading.java +++ b/backend/src/main/java/gc/mda/kcg/domain/sensor/PressureReading.java @@ -8,7 +8,6 @@ import java.time.Instant; @Entity @Table( name = "pressure_readings", - schema = "kcg", uniqueConstraints = @UniqueConstraint(columnNames = {"station", "reading_time"}) ) @Getter diff --git a/backend/src/main/java/gc/mda/kcg/domain/sensor/SeismicEvent.java b/backend/src/main/java/gc/mda/kcg/domain/sensor/SeismicEvent.java index f877e3e..7d05688 100644 --- a/backend/src/main/java/gc/mda/kcg/domain/sensor/SeismicEvent.java +++ b/backend/src/main/java/gc/mda/kcg/domain/sensor/SeismicEvent.java @@ -6,7 +6,7 @@ import lombok.*; import java.time.Instant; @Entity -@Table(name = "seismic_events", schema = "kcg") +@Table(name = "seismic_events") @Getter @Setter @NoArgsConstructor diff --git a/backend/src/main/resources/application-local.yml.example b/backend/src/main/resources/application-local.yml.example index 70490de..23e3d7b 100644 --- a/backend/src/main/resources/application-local.yml.example +++ b/backend/src/main/resources/application-local.yml.example @@ -1,16 +1,19 @@ spring: datasource: - url: jdbc:postgresql://localhost:5432/kcgdb?currentSchema=kcg - username: kcg_user - password: kcg_pass + url: ${DB_URL:jdbc:postgresql://localhost:5432/kcgdb?currentSchema=kcg,public} + username: ${DB_USERNAME:kcg_user} + password: ${DB_PASSWORD:kcg_pass} app: jwt: - secret: local-dev-secret-key-32chars-minimum!! - expiration-ms: 86400000 + secret: ${JWT_SECRET:local-dev-secret-key-32chars-minimum!!} + expiration-ms: ${JWT_EXPIRATION_MS:86400000} google: - client-id: YOUR_GOOGLE_CLIENT_ID + client-id: ${GOOGLE_CLIENT_ID:YOUR_GOOGLE_CLIENT_ID} auth: - allowed-domain: gcsc.co.kr + allowed-domain: ${AUTH_ALLOWED_DOMAIN:gcsc.co.kr} collector: - open-sky-client-id: YOUR_OPENSKY_CLIENT_ID - open-sky-client-secret: YOUR_OPENSKY_CLIENT_SECRET + open-sky-client-id: ${OPENSKY_CLIENT_ID:YOUR_OPENSKY_CLIENT_ID} + open-sky-client-secret: ${OPENSKY_CLIENT_SECRET:YOUR_OPENSKY_CLIENT_SECRET} + prediction-base-url: ${PREDICTION_BASE_URL:http://localhost:8001} + cors: + allowed-origins: ${APP_CORS_ALLOWED_ORIGINS:http://localhost:5174,http://localhost:5173} diff --git a/backend/src/main/resources/application-prod.yml b/backend/src/main/resources/application-prod.yml index 89792f5..ca754d0 100644 --- a/backend/src/main/resources/application-prod.yml +++ b/backend/src/main/resources/application-prod.yml @@ -16,4 +16,4 @@ app: open-sky-client-secret: ${OPENSKY_CLIENT_SECRET:} prediction-base-url: ${PREDICTION_BASE_URL:http://192.168.1.18:8001} cors: - allowed-origins: http://localhost:5173,https://kcg.gc-si.dev + allowed-origins: ${APP_CORS_ALLOWED_ORIGINS:http://localhost:5174,http://localhost:5173,https://kcg.gc-si.dev} diff --git a/backend/src/main/resources/application.yml b/backend/src/main/resources/application.yml index 8ab9a87..da13d6d 100644 --- a/backend/src/main/resources/application.yml +++ b/backend/src/main/resources/application.yml @@ -6,6 +6,6 @@ spring: ddl-auto: none properties: hibernate: - default_schema: kcg + default_schema: ${DB_SCHEMA:kcg} server: - port: 8080 + port: ${SERVER_PORT:8080} diff --git a/frontend/tsconfig.app.json b/frontend/tsconfig.app.json index a9b5a59..5996e39 100644 --- a/frontend/tsconfig.app.json +++ b/frontend/tsconfig.app.json @@ -10,6 +10,7 @@ /* Bundler mode */ "moduleResolution": "bundler", + "resolveJsonModule": true, "allowImportingTsExtensions": true, "verbatimModuleSyntax": true, "moduleDetection": "force", diff --git a/prediction/cache/vessel_store.py b/prediction/cache/vessel_store.py index a4089aa..7ba95da 100644 --- a/prediction/cache/vessel_store.py +++ b/prediction/cache/vessel_store.py @@ -7,6 +7,7 @@ import numpy as np _KST = ZoneInfo('Asia/Seoul') import pandas as pd +from time_bucket import compute_initial_window_start, compute_safe_bucket logger = logging.getLogger(__name__) @@ -192,8 +193,6 @@ class VesselStore: """Remove track points older than N hours and evict empty MMSI entries.""" import datetime as _dt - from time_bucket import compute_initial_window_start, compute_safe_bucket - safe_bucket = compute_safe_bucket() cutoff_bucket = compute_initial_window_start(hours, safe_bucket) now = datetime.now(timezone.utc) @@ -210,6 +209,7 @@ class VesselStore: mask = bucket_col >= pd.Timestamp(cutoff_bucket) else: ts_col = df['timestamp'] + # Handle tz-aware and tz-naive timestamps uniformly if hasattr(ts_col.dtype, 'tz') and ts_col.dtype.tz is not None: mask = ts_col >= pd.Timestamp(cutoff_aware) else: diff --git a/prediction/db/snpdb.py b/prediction/db/snpdb.py index 2048c58..8b46df5 100644 --- a/prediction/db/snpdb.py +++ b/prediction/db/snpdb.py @@ -62,7 +62,6 @@ def fetch_all_tracks(hours: int = 24) -> pd.DataFrame: LineStringM 지오메트리에서 개별 포인트를 추출하며, 한국 해역(122-132E, 31-39N) 내 최근 N시간 데이터를 반환한다. - safe_bucket(현재 - 12분)까지만 조회하여 미완성 버킷을 제외한다. """ safe_bucket = compute_safe_bucket() window_start = compute_initial_window_start(hours, safe_bucket) @@ -106,8 +105,8 @@ def fetch_all_tracks(hours: int = 24) -> pd.DataFrame: def fetch_incremental(last_bucket: datetime) -> pd.DataFrame: """last_bucket 이후의 신규 궤적 포인트를 조회한다. - safe_bucket(현재 - 12분)까지만 조회하여 미완성 버킷을 제외하고, - from_bucket(last_bucket - 15분)부터 재수집하여 지연 INSERT를 보상한다. + 스케줄러 증분 업데이트에 사용되며, time_bucket > last_bucket 조건으로 + 이미 처리한 버킷을 건너뛴다. """ safe_bucket = compute_safe_bucket() from_bucket = compute_incremental_window_start(last_bucket) diff --git a/prediction/scheduler.py b/prediction/scheduler.py index 8bae5c7..46a7dea 100644 --- a/prediction/scheduler.py +++ b/prediction/scheduler.py @@ -121,6 +121,7 @@ def run_analysis_cycle(): # 4.7 어구 연관성 분석 (멀티모델 패턴 추적) try: from algorithms.gear_correlation import run_gear_correlation + from algorithms.gear_parent_inference import run_gear_parent_inference corr_result = run_gear_correlation( vessel_store=vessel_store, @@ -132,12 +133,6 @@ def run_analysis_cycle(): corr_result['updated'], corr_result['raw_inserted'], corr_result['models'], ) - except Exception as e: - logger.warning('gear correlation failed: %s', e) - - # 4.8 어구 모선 추론 (episode continuity + 다층 점수 모델) - try: - from algorithms.gear_parent_inference import run_gear_parent_inference inference_result = run_gear_parent_inference( vessel_store=vessel_store, @@ -154,7 +149,7 @@ def run_analysis_cycle(): inference_result['skipped'], ) except Exception as e: - logger.warning('gear parent inference failed: %s', e) + logger.warning('gear correlation failed: %s', e) # 5. 선박별 추가 알고리즘 → AnalysisResult 생성 results = []