# 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/*`) ## 빌드 · 배포 ```bash # 로컬 실행 ./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` 주입이 동작하려면 두 가지가 **필수**: 1. **`pom.xml`** — `maven-compiler-plugin` 의 `default-compile` 과 `default-testCompile` 양쪽 execution 에 `true` 설정. 파라미터 이름을 바이트코드에 보존해야 `@Qualifier` resolve 가 가능. 2. **`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](src/main/resources/db/migration/) - 최신: **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` (실시간 상태/채팅 프록시 전용) ## 운영 체크리스트 1. 빌드 성공 → local `./mvnw spring-boot:run` 기동 확인 → curl `/api/auth/me` 200 확인 2. scp 배포 → `systemctl restart kcg-ai-backend` → `journalctl -u kcg-ai-backend -n 100` 3. 응답 확인: `curl -k https://kcg-ai-monitoring.gc-si.dev/api/analysis/vessels?hours=1` 4. Flyway 에러 시: `backend.application` 로그에서 `Migration ... failed` 확인