docs/prediction-analysis.md §7 P1 권고의 "UI 미노출 탐지" 해소 중 두 번째.
prediction algorithms/transshipment.py 5단계 필터 파이프라인 결과를 전체 목록·
집계·상세 수준으로 조회하는 READ 전용 대시보드.
### 배경
기존 features/vessel/TransferDetection.tsx 는 선박 상세 수준(특정 MMSI 의 환적
이력)이고, 환적 의심 선박 전체 목록을 보려면 ChinaFishing 의 탭 중 하나를 거쳐야
했다. /api/analysis/transship 엔드포인트는 이미 존재하나 전용 페이지가 없었음.
### 변경
- frontend/src/features/detection/TransshipmentDetection.tsx 신설 (405 라인)
- PageContainer + PageHeader(ArrowLeftRight) + KPI 5장
(Total / Transship tier CRITICAL/HIGH/MEDIUM / Risk CRITICAL)
- DataTable 8컬럼 (analyzedAt / mmsi / pairMmsi / duration / tier / risk / zone)
- features.transship_tier 읽어 Badge 로 심각도 표시
- 필터: hours(1/6/12/24/48) / riskLevel / mmsi 검색
- 상세 패널: 분석 피처 JSON 원본 + 좌표 + transship_score
- 기존 analysisApi.getTransshipSuspects 재사용 — backend 변경 없음
- index.ts + componentRegistry.ts 등록
- detection.json (ko/en) transshipment.* 네임스페이스 추가 (각 44키)
- common.json (ko/en) nav.transshipment 추가
- V033__menu_transshipment_detection.sql
- auth_perm_tree(detection:transshipment, nav_sort=910)
- ADMIN 5 ops + OPERATOR/ANALYST/FIELD/VIEWER READ
### 권한 주의
/api/analysis/transship 의 @RequirePermission 은 현재 detection:dark-vessel.
이 메뉴 READ 만으로는 API 호출 불가. 현행 운영자 역할(OPERATOR/ANALYST/FIELD)
은 dark-vessel READ 도 보유하므로 실용 동작.
향후 VesselAnalysisController.listTransshipSuspects 의 @RequirePermission 을
detection:transshipment 로 교체하는 권한 일관화는 별도 MR (후속).
### 검증
- npx tsc --noEmit 통과
- pre-commit tsc + ESLint 통과 예정
- Flyway V033 자동 적용 (백엔드 재배포 필요)
|
||
|---|---|---|
| .. | ||
| .mvn/wrapper | ||
| src | ||
| .sdkmanrc | ||
| mvnw | ||
| mvnw.cmd | ||
| pom.xml | ||
| README.md | ||
Backend (Spring Boot)
운영 배포 중 — rocky-211 :18080 (kcg-ai-backend systemd).
구성
- Runtime: Spring Boot 3.5.7 + Java 21
- DB: PostgreSQL (kcgaidb) + Flyway V001~V030 (51 테이블)
- Auth: Spring Security + JWT 쿠키 + BCrypt
- Cache: Caffeine (권한 트리 10분 TTL)
- Permission: 트리 기반 RBAC (47 리소스 × 5 operation)
- HTTP client:
RestClient+ 명시적@Bean주입 (predictionRestClient,signalBatchRestClient)
책임
- 자체 인증/권한/감사 로그 + 관리자 API
- 운영자 의사결정 (모선 확정·제외·학습, 어구 정체성 충돌 분류)
- prediction 분석 결과 조회 (
/api/analysis/*) + 이벤트 허브 (/api/events,/api/alerts) - prediction 실시간 상태 프록시 (
/api/prediction/*)
빌드 · 배포
# 로컬 실행
./mvnw spring-boot:run
# 프로덕션 빌드
./mvnw clean package -DskipTests
# → target/kcg-ai-backend-*.jar
# 운영 배포 (수동)
scp target/kcg-ai-backend-*.jar rocky-211:/opt/kcg-ai-backend/
ssh rocky-211 "sudo systemctl restart kcg-ai-backend"
필수 컴파일 설정 (PR #79 hotfix)
Spring 6.1 의 parameter-level @Qualifier 주입이 동작하려면 두 가지가 필수:
pom.xml—maven-compiler-plugin의default-compile과default-testCompile양쪽 execution 에<parameters>true</parameters>설정. 파라미터 이름을 바이트코드에 보존해야@Qualifierresolve 가 가능.src/main/java/lombok.config—lombok.copyableAnnotations += org.springframework.beans.factory.annotation.Qualifier설정. Lombok@RequiredArgsConstructor가 필드의@Qualifier를 생성자 파라미터에 복사해야 Spring 이 인식.
둘 중 하나라도 누락되면 PredictionProxyController 같은 다중 RestClient bean 주입 컨트롤러가 기동 시점에
NoUniqueBeanDefinitionException 으로 크래시 루프에 빠진다. 로컬에서 ./mvnw spring-boot:run 실패는
운영 restart 시 동일하게 재현되므로 MR 범위 밖이어도 우선 해결.
주요 패키지 구조
src/main/java/gc/mda/kcg/
├── config/ # RestClientConfig, SecurityConfig, OpenApi, CorsConfig, CaffeineConfig 등
├── auth/ # LoginController, JWT, 비밀번호 정책
├── permission/ # 트리 RBAC, @RequirePermission AOP, 캐시
├── audit/ # @Auditable AOP, AuditLogService, AccessLogFilter
├── domain/
│ ├── analysis/ # VesselAnalysisController, GearCollisionController (V030), PredictionProxyController 등
│ ├── fleet/ # ParentInferenceWorkflowController, FleetService
│ ├── event/ # EventController, AlertController
│ ├── enforcement/ # EnforcementController, EnforcementPlanController
│ ├── master/ # MasterDataController (CodeMaster, GearTypeMaster, VesselPermit 등)
│ ├── admin/ # AdminLogController, AdminStatsController, UserManagementController
│ └── stats/ # StatsController (KPI 집계)
└── Application.java
모든 컨트롤러는 controller → service → repository 계층을 준수하며, 쓰기 액션은
@RequirePermission + @Auditable 로 권한·감사 일관 적용.
Flyway 마이그레이션
- 경로: src/main/resources/db/migration/V001__*.sql ~ V030__gear_identity_collision.sql
- 최신: V030 (2026-04-17) —
gear_identity_collisions테이블 +detection:gear-collision권한 트리 - Flyway 자동 적용: Spring Boot 기동 시점
디렉토리 밖 의존성
- prediction → kcgaidb: prediction 이 직접 write. backend 는 HTTP 호출 없이 DB 조회로만 연동
- signal-batch:
http://192.168.1.18:18090/signal-batch(정적정보 보강,signalBatchRestClient주입) - prediction (FastAPI):
http://redis-211:18092(실시간 상태/채팅 프록시 전용)
운영 체크리스트
- 빌드 성공 → local
./mvnw spring-boot:run기동 확인 → curl/api/auth/me200 확인 - scp 배포 →
systemctl restart kcg-ai-backend→journalctl -u kcg-ai-backend -n 100 - 응답 확인:
curl -k https://kcg-ai-monitoring.gc-si.dev/api/analysis/vessels?hours=1 - Flyway 에러 시:
backend.application로그에서Migration ... failed확인