Compare commits

...

61 커밋

작성자 SHA1 메시지 날짜
77f881a7c1 Merge pull request 'release: 2026-03-27.3 (7건 커밋)' (#121) from develop into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 9m13s
2026-03-27 08:14:56 +09:00
ce55cdd115 docs: 릴리즈 노트 정리 (2026-03-27) 2026-03-27 08:12:44 +09:00
83cd865363 Merge pull request 'feat(batch): 비정상 궤적 포함 저장 플래그 추가 — 강화학습 데이터 수집용' (#120) from feature/include-abnormal-tracks-flag-v2 into develop 2026-03-27 08:07:32 +09:00
44cd532d52 docs: 릴리즈 노트 업데이트 2026-03-27 08:06:53 +09:00
8f784de358 feat(batch): 비정상 궤적 포함 저장 플래그 추가 — 강화학습 데이터 수집용
GPS 스푸핑 등 비정상 운항 패턴의 강화학습 분류기 고도화를 위해,
비정상 궤적을 정상 테이블(5min/hourly/daily)과 캐시(L1/L2)에도
포함 저장하는 설정 플래그 추가.

- vessel.batch.track.include-abnormal-in-tracks 플래그 (기본 false)
- 5min: isAbnormal 시에도 filteredTracks에 포함 (플래그 true)
- Hourly/Daily: correctedTrack null 시에도 originalTrack 포함 (플래그 true)
- 비정상 검출 + t_abnormal_tracks 기록은 플래그와 무관하게 항상 유지
- prod 환경 true 설정 (강화학습 데이터 수집)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 08:06:29 +09:00
6a597958e1 Merge pull request 'fix(metrics): REST API 경로 client_id 수집 누락 수정' (#119) from fix/client-id-rest-api into develop 2026-03-27 08:06:20 +09:00
74aace919b docs: 릴리즈 노트 업데이트 2026-03-27 08:05:47 +09:00
df957be2fe fix(metrics): REST API 경로 client_id 수집 누락 수정
- JWT 쿠키 파싱을 WebSocketStompConfig.extractClientIdFromRequest() static 메서드로 추출
- GisControllerV2 → GisServiceV2 → enqueueRestMetric에 clientId 전달 추가
- WebSocket 경로는 이미 정상 (htlee@gcsc.co.kr 수집 확인)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 08:01:43 +09:00
573f4ff70d Merge pull request 'release: 2026-03-27.2 (4건 커밋)' (#118) from develop into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 9m14s
2026-03-27 07:17:51 +09:00
99a7f607f7 Merge pull request 'release: 2026-03-27 (5건 커밋)' (#116) from develop into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 9m4s
2026-03-27 06:40:38 +09:00
22710068d8 Merge pull request 'release: 2026-03-19 (9건 커밋)' (#114) from develop into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 9m8s
2026-03-19 07:48:19 +09:00
444430d272 Merge pull request 'release: 2026-03-18 (4건 커밋)' (#112) from develop into main
Some checks failed
Build & Deploy / build-and-deploy (push) Failing after 28m38s
2026-03-18 17:09:13 +09:00
796bd09f29 Merge pull request 'release: 2026-03-17.3 (2건 커밋)' (#110) from develop into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 9m44s
2026-03-17 10:02:39 +09:00
75d3919410 Merge pull request 'release: 2026-03-17.2 (2건 커밋)' (#108) from develop into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 9m32s
2026-03-17 09:29:58 +09:00
e571a571df Merge pull request 'release: 2026-03-17 (2건 커밋)' (#106) from develop into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 9m38s
2026-03-17 08:41:57 +09:00
fa03c7d80d Merge pull request 'release: 2026-03-13 (4건 커밋)' (#104) from develop into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 8m46s
2026-03-13 10:20:40 +09:00
9bd2135337 Merge pull request 'release: 2026-03-10.2 (4건 커밋)' (#102) from develop into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 8m30s
2026-03-10 11:20:19 +09:00
7539441d95 Merge pull request 'release: 2026-03-10 (4건 커밋)' (#100) from develop into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 8m33s
2026-03-10 09:21:05 +09:00
fb1076ac11 Merge pull request 'release: 2026-03-09.2 (4건 커밋)' (#98) from develop into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 8m24s
2026-03-09 11:27:08 +09:00
9d6e5ca408 Merge pull request 'release: 2026-03-09 (119건 커밋)' (#96) from develop into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 8m12s
2026-03-09 06:51:51 +09:00
882c07a7c6 Merge pull request 'release: 2026-03-08 (115건 커밋)' (#94) from develop into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 8m12s
2026-03-08 09:33:03 +09:00
2434b3ddb2 Merge pull request 'release: 2026-03-02.3 (109건 커밋)' (#92) from develop into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 3m42s
2026-03-02 16:52:33 +09:00
7a21d5b8b0 Merge pull request 'release: 2026-03-02.2 (105건 커밋)' (#90) from develop into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 2m29s
2026-03-02 15:40:24 +09:00
bbd14fab8c Merge pull request 'release: 2026-03-02 (98건 커밋)' (#87) from develop into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 2m22s
2026-03-02 00:21:39 +09:00
77613af4be Merge pull request 'perf: API 응답 크기 최적화 + Swagger 최신화' (#84) from develop into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 2m16s
2026-03-01 22:55:52 +09:00
57226ef2a9 Merge pull request 'feat: DataPipeline 일별 차트 시각화 개선 — Stacked Bar + Duration Bar' (#82) from develop into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 2m49s
2026-02-21 12:29:12 +09:00
8c1cfdd6b5 Merge pull request 'fix: ST_AsText WKT 공백 불일치로 인한 daily merge 전량 필터 수정' (#80) from develop into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 4m12s
2026-02-21 01:17:02 +09:00
51780b80bb Merge pull request 'fix: L2 워밍업 범위 확장 — Daily Job 전 기동 시 어제 데이터 포함' (#78) from develop into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 3m8s
2026-02-21 00:43:44 +09:00
e16aa2d645 Merge pull request 'chore: L2 HourlyTrackCache maxSize 3.5M→7M 상향' (#76) from develop into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 4m33s
2026-02-21 00:36:48 +09:00
893a54ec8e Merge pull request 'chore: L2 HourlyTrackCache maxSize 3.5M→5M 상향' (#74) from develop into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 3m25s
2026-02-21 00:28:28 +09:00
a0963a1332 Merge pull request 'fix: html2canvas oklch/oklab 색상 파싱 에러 수정' (#72) from develop into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 3m8s
2026-02-20 20:50:42 +09:00
3f55f80d2b Merge pull request 'feat: UI 레이아웃 수정 + 구역분석/STS 보고서 모달 + 이미지 저장' (#70) from develop into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 5m10s
2026-02-20 18:46:55 +09:00
d3520a6fd8 Merge pull request 'feat: 다중구역이동 항적 분석 + STS 접촉 분석 프론트엔드 이관' (#68) from develop into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 3m47s
2026-02-20 17:08:13 +09:00
a7b9e76d51 Merge pull request 'feat: 항적/리플레이 선종 아이콘 + Raw Data 패널' (#66) from develop into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 2m41s
2026-02-20 16:00:18 +09:00
9ae56f5517 Merge pull request 'fix: 항적 조회 500 에러 + 리플레이 쿼리 무반응 수정' (#64) from develop into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 3m35s
2026-02-20 15:37:39 +09:00
137a22a411 Merge pull request 'feat: Ship-GIS 기능 이관 — 최근위치/선박항적/뷰포트 리플레이' (#62) from develop into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 4m0s
2026-02-20 15:22:11 +09:00
14e61e6bd0 Merge pull request 'perf: Daily Job 인메모리 캐시 기반 최적화 — N+1 SQL 제거' (#60) from develop into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 2m52s
2026-02-20 11:39:54 +09:00
9a1d4b7b2e Merge pull request 'feat: recent-positions IMO + 선박사진 enrichment' (#57) from develop into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 2m46s
2026-02-20 02:18:23 +09:00
0caea9c766 Merge pull request 'fix: UTC 타임존 변환 + Daily 캐시 부분 fallback 추가' (#53) from develop into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 3m20s
2026-02-20 00:47:45 +09:00
e9aa0302cd Merge pull request 'feat: 중국허가선박 최신 위치 조회 API' (#51) from develop into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 2m34s
2026-02-19 23:04:28 +09:00
9f98682347 Merge pull request 'fix: V2 캐시 조회 시 누락 MMSI DB fallback 추가' (#49) from develop into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 2m48s
2026-02-19 22:53:19 +09:00
e6cb152d29 Merge pull request 'feat: ChnPrmShip 전용 DB 이력 + API enrichment + ShipImage V2' (#47) from develop into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 2m35s
2026-02-19 22:38:17 +09:00
85c8b5b28e Merge pull request 'docs: Swagger UI 현행화' (#45) from develop into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 2m34s
2026-02-19 21:30:31 +09:00
b581233240 Merge pull request 'fix: 캐시 maxSize 설정 경로 수정' (#43) from develop into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 2m36s
2026-02-19 21:00:42 +09:00
a237648fe7 Merge pull request 'fix: L1/L2 캐시 maxSize 상향 + AisTarget hitRate 타입 수정' (#41) from develop into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 3m10s
2026-02-19 20:47:46 +09:00
5cf6e32d71 Merge pull request 'perf: API 응답 최적화 + 점진적 렌더링 + 해구 choropleth 지도' (#39) from develop into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 2m35s
2026-02-19 20:26:23 +09:00
c3d0b15f97 Merge pull request 'feat: Phase 4 — 비정상 항적 + 시스템 메트릭 (7/7 완성)' (#37) from develop into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 2m40s
2026-02-19 19:20:31 +09:00
6f17006811 Merge pull request 'feat: Phase 3 — API Explorer 지도 스캐폴딩' (#35) from develop into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 2m35s
2026-02-19 19:14:40 +09:00
f49f1ac4e4 Merge pull request 'perf: L1/L2 캐시 maxSize 상향 (실측 기반)' (#33) from develop into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 2m45s
2026-02-19 19:10:05 +09:00
eabeee1bb7 Merge pull request 'fix: 해구 통계 ROUND 함수 타입 캐스팅 오류 수정' (#31) from develop into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 2m31s
2026-02-19 19:01:28 +09:00
ec20dc8e76 Merge pull request 'fix: 해구 조회 바운딩 박스 간소화' (#29) from develop into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 2m36s
2026-02-19 18:54:44 +09:00
e2a692a5e2 Merge pull request 'fix: 해구 통계 디버그 로깅' (#27) from develop into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 2m31s
2026-02-19 18:50:25 +09:00
86f0c457e3 Merge pull request 'fix: toLocalDateTime 변환 강화' (#23) from develop into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 2m29s
2026-02-19 18:39:54 +09:00
1c963b3d75 Merge pull request 'fix: Timestamp 캐스팅 오류 수정' (#21) from develop into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 2m31s
2026-02-19 18:36:19 +09:00
065f14ede4 Merge pull request 'fix: MonitoringController 레거시 타일 쿼리 전환 + 해구 통계 수정' (#19) from develop into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 2m45s
2026-02-19 18:30:55 +09:00
e70def6611 Merge pull request 'chore: AIS API 인증 정보 추가 (prod)' (#17) from develop into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 2m32s
2026-02-19 18:08:56 +09:00
318d2aefbb Merge pull request 'Release: Phase 2 — DataPipeline + AreaStats' (#15) from develop into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 2m31s
2026-02-19 17:56:58 +09:00
478aa44e59 Merge pull request 'Release: Dashboard API 연동 오류 수정 + Phase 1 안정화' (#13) from develop into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 2m31s
2026-02-19 17:35:31 +09:00
997dad8117 Merge pull request 'feat: React 19 SPA Dashboard Phase 1 + 안전 배포 시스템' (#11) from feature/dashboard-phase-1 into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 2m30s
Reviewed-on: #11
2026-02-19 17:09:18 +09:00
941fb3cf4a Merge pull request 'release: Gitea Actions CI/CD 파이프라인 + systemd 서비스 구성' (#9) from develop into main
Some checks failed
Build & Deploy / build-and-deploy (push) Failing after 3m6s
Reviewed-on: #9
2026-02-19 14:32:05 +09:00
b9ace1681c Merge pull request 'release: SNP API 전환 + 인메모리 캐시 최적화 + 다계층 캐시 조회 통합' (#7) from develop into main
Reviewed-on: #7
2026-02-19 14:26:30 +09:00
10개의 변경된 파일85개의 추가작업 그리고 47개의 파일을 삭제

파일 보기

@ -4,6 +4,14 @@
## [Unreleased]
## [2026-03-27.3]
### 추가
- 비정상 궤적 포함 저장 플래그 (`include-abnormal-in-tracks`) — 강화학습 데이터 수집용
### 수정
- REST API 경로 client_id 수집 누락 수정 — JWT 쿠키 파싱 공용 메서드 추출
## [2026-03-27.2]
### 수정

파일 보기

@ -62,6 +62,9 @@ public class DailyAggregationStepConfig {
@Value("${vessel.batch.chunk-size:5000}")
private int chunkSize;
@Value("${vessel.batch.track.include-abnormal-in-tracks:false}")
private boolean includeAbnormalInTracks;
@Bean
public Step mergeDailyTracksStep() {
log.info("Building mergeDailyTracksStep with cache-based in-memory merge");
@ -110,7 +113,9 @@ public class DailyAggregationStepConfig {
return new CompositeTrackWriter(
vesselTrackBulkWriter,
abnormalTrackWriter,
"daily"
"daily",
null,
includeAbnormalInTracks
);
}

파일 보기

@ -69,6 +69,9 @@ public class HourlyAggregationStepConfig {
@Value("${vessel.batch.chunk-size:5000}")
private int chunkSize;
@Value("${vessel.batch.track.include-abnormal-in-tracks:false}")
private boolean includeAbnormalInTracks;
//
// Step 1: 5분 시간 병합 (인메모리 캐시 기반)
//
@ -122,7 +125,8 @@ public class HourlyAggregationStepConfig {
vesselTrackBulkWriter,
abnormalTrackWriter,
"hourly",
hourlyTrackCache
hourlyTrackCache,
includeAbnormalInTracks
);
}

파일 보기

@ -96,6 +96,9 @@ public class VesselTrackStepConfig {
@Value("${vessel.batch.chunk-size:1000}")
private int chunkSize;
@Value("${vessel.batch.track.include-abnormal-in-tracks:false}")
private boolean includeAbnormalInTracks;
@PostConstruct
public void init() {
// 5분 Job의 이름을 명시적으로 설정
@ -203,18 +206,21 @@ public class VesselTrackStepConfig {
log.warn("비정상 궤적 감지 [{}]: vessel={}, avg_speed={}, distance={}",
abnormalReason, track.getVesselKey(), track.getAvgSpeed(), track.getDistanceNm());
saveAbnormalTrack(track, abnormalReason);
if (includeAbnormalInTracks) {
filteredTracks.add(track); // 플래그 true 정상 테이블+캐시에도 포함
}
} else {
filteredTracks.add(track);
}
// 정상 궤적의 종료 위치 저장 (캐시 업데이트용)
if (track.getEndPosition() != null) {
currentBucketEndPositions.put(track.getMmsi(), VesselBucketPositionDto.builder()
.mmsi(track.getMmsi())
.endLon(track.getEndPosition().getLon())
.endLat(track.getEndPosition().getLat())
.endTime(track.getEndPosition().getTime())
.build());
}
// 궤적의 종료 위치 저장 (캐시 업데이트용) 비정상 포함 시에도 위치 추적
if (filteredTracks.contains(track) && track.getEndPosition() != null) {
currentBucketEndPositions.put(track.getMmsi(), VesselBucketPositionDto.builder()
.mmsi(track.getMmsi())
.endLon(track.getEndPosition().getLon())
.endLat(track.getEndPosition().getLat())
.endTime(track.getEndPosition().getTime())
.build());
}
}

파일 보기

@ -25,21 +25,24 @@ public class CompositeTrackWriter implements ItemWriter<AbnormalDetectionResult>
private final AbnormalTrackWriter abnormalTrackWriter;
private final String targetTable;
private final HourlyTrackCache hourlyTrackCache; // nullable (daily writer는 미사용)
private final boolean includeAbnormalInTracks;
public CompositeTrackWriter(VesselTrackBulkWriter vesselTrackBulkWriter,
AbnormalTrackWriter abnormalTrackWriter,
String targetTable,
HourlyTrackCache hourlyTrackCache) {
HourlyTrackCache hourlyTrackCache,
boolean includeAbnormalInTracks) {
this.vesselTrackBulkWriter = vesselTrackBulkWriter;
this.abnormalTrackWriter = abnormalTrackWriter;
this.targetTable = targetTable;
this.hourlyTrackCache = hourlyTrackCache;
this.includeAbnormalInTracks = includeAbnormalInTracks;
}
public CompositeTrackWriter(VesselTrackBulkWriter vesselTrackBulkWriter,
AbnormalTrackWriter abnormalTrackWriter,
String targetTable) {
this(vesselTrackBulkWriter, abnormalTrackWriter, targetTable, null);
this(vesselTrackBulkWriter, abnormalTrackWriter, targetTable, null, false);
}
@BeforeStep
@ -66,9 +69,11 @@ public class CompositeTrackWriter implements ItemWriter<AbnormalDetectionResult>
abnormalResults.add(result);
// 정정된 궤적이 있으면 정상 궤적으로 저장
// null이면 전체 궤적이 비정상이므로 제외
// null이면 전체 궤적이 비정상이므로 제외 (플래그 true면 원본 포함)
if (result.getCorrectedTrack() != null) {
normalTracks.add(result.getCorrectedTrack());
} else if (includeAbnormalInTracks) {
normalTracks.add(result.getOriginalTrack());
} else {
log.debug("비정상 궤적 전체 제외: vessel={}",
result.getOriginalTrack().getVesselKey());

파일 보기

@ -191,7 +191,11 @@ public class GisControllerV2 {
)
@RequestBody VesselTracksRequest request,
HttpServletRequest httpRequest) {
return gisServiceV2.getVesselTracksV2(request, getClientIp(httpRequest));
return gisServiceV2.getVesselTracksV2(request, getClientIp(httpRequest), getClientId(httpRequest));
}
private String getClientId(HttpServletRequest request) {
return gc.mda.signal_batch.global.config.WebSocketStompConfig.extractClientIdFromRequest(request);
}
private String getClientIp(HttpServletRequest request) {

파일 보기

@ -285,7 +285,7 @@ public class GisServiceV2 {
/**
* 선박별 항적 조회 V2 (캐시 + Semaphore + 간소화 + ChnPrmShip enrichment)
*/
public List<CompactVesselTrack> getVesselTracksV2(VesselTracksRequest request, String clientIp) {
public List<CompactVesselTrack> getVesselTracksV2(VesselTracksRequest request, String clientIp, String clientId) {
String queryId = "rest-vessels-" + UUID.randomUUID().toString().substring(0, 8);
long startMs = System.currentTimeMillis();
boolean slotAcquired = false;
@ -329,7 +329,7 @@ public class GisServiceV2 {
result.size(), request.getVessels().size(),
dailyTrackCacheManager.isEnabled(), request.isIncludeChnPrmShip());
enqueueRestMetric(queryId, request, result, startMs, clientIp);
enqueueRestMetric(queryId, request, result, startMs, clientIp, clientId);
return result;
@ -347,7 +347,7 @@ public class GisServiceV2 {
}
private void enqueueRestMetric(String queryId, VesselTracksRequest request,
List<CompactVesselTrack> result, long startMs, String clientIp) {
List<CompactVesselTrack> result, long startMs, String clientIp, String clientId) {
try {
int totalPoints = result.stream().mapToInt(CompactVesselTrack::getPointCount).sum();
long responseBytes = (long) result.size() * 200 + (long) totalPoints * 40;
@ -367,6 +367,7 @@ public class GisServiceV2 {
.elapsedMs(System.currentTimeMillis() - startMs)
.status("COMPLETED")
.clientIp(clientIp)
.clientId(clientId)
.build());
} catch (Exception e) {
log.debug("Failed to enqueue REST metric: {}", e.getMessage());

파일 보기

@ -235,42 +235,44 @@ public class WebSocketStompConfig implements WebSocketMessageBrokerConfigurer {
return "unknown";
}
/**
* GC_SESSION 쿠키에서 JWT payload의 email 클레임 추출.
* JWT 검증은 nginx auth_request에서 이미 완료 여기서는 payload 디코딩만 수행.
*/
private String extractEmailFromJwtCookie(HttpServletRequest request) {
Cookie[] cookies = request.getCookies();
if (cookies == null) return null;
return extractClientIdFromRequest(request);
}
}
String token = null;
for (Cookie cookie : cookies) {
if ("GC_SESSION".equals(cookie.getName())) {
token = cookie.getValue();
break;
}
/**
* GC_SESSION 쿠키에서 JWT payload의 email 클레임 추출 (REST/WebSocket 공용).
* JWT 검증은 nginx auth_request에서 이미 완료 여기서는 payload 디코딩만 수행.
*/
public static String extractClientIdFromRequest(HttpServletRequest request) {
Cookie[] cookies = request.getCookies();
if (cookies == null) return null;
String token = null;
for (Cookie cookie : cookies) {
if ("GC_SESSION".equals(cookie.getName())) {
token = cookie.getValue();
break;
}
if (token == null || token.isEmpty()) return null;
}
if (token == null || token.isEmpty()) return null;
try {
// JWT: header.payload.signature payload만 Base64URL 디코딩
String[] parts = token.split("\\.");
if (parts.length < 2) return null;
try {
String[] parts = token.split("\\.");
if (parts.length < 2) return null;
String payload = new String(Base64.getUrlDecoder().decode(parts[1]));
// 간단한 JSON 파싱 (Jackson 의존 없이): "email":"value" 추출
int emailIdx = payload.indexOf("\"email\"");
if (emailIdx < 0) return null;
String payload = new String(Base64.getUrlDecoder().decode(parts[1]));
int emailIdx = payload.indexOf("\"email\"");
if (emailIdx < 0) return null;
int colonIdx = payload.indexOf(':', emailIdx);
int quoteStart = payload.indexOf('"', colonIdx + 1);
int quoteEnd = payload.indexOf('"', quoteStart + 1);
if (quoteStart < 0 || quoteEnd < 0) return null;
int colonIdx = payload.indexOf(':', emailIdx);
int quoteStart = payload.indexOf('"', colonIdx + 1);
int quoteEnd = payload.indexOf('"', quoteStart + 1);
if (quoteStart < 0 || quoteEnd < 0) return null;
return payload.substring(quoteStart + 1, quoteEnd);
} catch (Exception e) {
return null;
}
return payload.substring(quoteStart + 1, quoteEnd);
} catch (Exception e) {
return null;
}
}
}

파일 보기

@ -173,6 +173,7 @@ vessel: # spring 하위가 아닌 최상위 레벨
# 궤적 비정상 검출 설정
track:
include-abnormal-in-tracks: true # 비정상 궤적도 정상 테이블+캐시에 포함 (강화학습 데이터 수집용)
abnormal-detection:
large-gap-threshold-hours: 4 # 이 시간 이상 gap은 연결 안함
extreme-speed-threshold: 1000 # 이 속도 이상은 무조건 비정상 (knots)

파일 보기

@ -159,6 +159,8 @@ vessel:
page-size: ${BATCH_PAGE_SIZE:10000}
partition-size: ${BATCH_PARTITION_SIZE:24}
skip-limit: 100
track:
include-abnormal-in-tracks: false # true: 비정상 궤적도 정상 테이블+캐시에 포함 (강화학습 데이터 수집용)
retry-limit: 3
# Reader 설정
use-cursor-reader: true # Cursor Reader 사용 여부