# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## 프로젝트 개요 S&P Maritime API에서 선박/항만/사건 데이터를 수집하여 PostgreSQL에 저장하는 배치 시스템. React 기반 관리 UI 포함. ## 빌드 & 실행 ```bash # Java 버전 설정 sdk use java 17.0.18-amzn # 프론트엔드 빌드 (src/main/resources/static/으로 출력) cd frontend && npm install && npm run build && cd .. # 백엔드 빌드 (프론트 빌드 후 실행) mvn clean package -DskipTests -Dskip.npm -Dskip.installnodenpm # 로컬 실행 mvn spring-boot:run # 테스트 mvn test # 프론트엔드 개발 서버 (localhost:5173, API는 8041로 프록시) cd frontend && npm run dev ``` ## 서버 설정 - 포트: 8041, Context Path: `/snp-collector` - Swagger UI: `http://localhost:8041/snp-collector/swagger-ui/index.html` - 프론트엔드 vite base: `/snp-collector/` (context-path와 일치해야 함) - 프론트엔드 빌드 출력: `frontend/` → `src/main/resources/static/` (emptyOutDir: true) ## 배치 Job 아키텍처 ### 베이스 클래스 계층 (`common/batch/`) ``` BaseJobConfig # 단일 Step chunk-oriented Job └── BaseMultiStepJobConfig # 다중 Step Job (createJobFlow() 오버라이드) └── BasePartitionedJobConfig # 파티셔닝 병렬 처리 Job ``` - **BaseApiReader**: WebClient 기반 Maritime API 호출. GET/POST 지원. BatchApiLog 자동 기록. - **BaseProcessor**: DTO→Entity 변환. `processItem()` 구현. - **BaseWriter**: `writeItems()` 구현. BaseJdbcRepository의 saveAll() 사용 (기존 ID 조회 → insert/update 분리 → PreparedStatement 배치). - **BaseEntity**: 공통 감사 필드 (createdAt, updatedAt, jobExecutionId). ### 새 Job 추가 패턴 각 Job은 `jobs/batch/{도메인}/` 하위에 config, dto, entity, reader, processor, writer, repository 구성: 1. `*JobConfig` extends BaseJobConfig (또는 BaseMultiStepJobConfig/BasePartitionedJobConfig) 2. `*Reader` extends BaseApiReader — `fetchDataFromApi()` 또는 `fetchNextBatch()` 구현 3. `*Processor` extends BaseProcessor — `processItem()` 구현 4. `*Writer` extends BaseWriter — `writeItems()` 구현 5. `*Repository` extends BaseJdbcRepository — SQL insert/update 구현 ### Job 실행 흐름 1. **스케줄**: Quartz JDBC Store → `QuartzBatchJob` → `QuartzJobService` → Spring Batch Job 실행 2. **수동 실행**: `BatchController.POST /api/batch/jobs/{jobName}/execute` 3. **재수집**: 실패 레코드 자동 재시도 (`AutoRetryJobExecutionListener`, 최대 3회) 4. **스케줄 초기화**: `SchedulerInitializer`가 앱 시작 시 DB의 `JobScheduleEntity`를 Quartz에 등록 ## 주요 API 경로 (/api/batch) | 메서드 | 경로 | 설명 | |--------|------|------| | POST | /jobs/{jobName}/execute | 배치 작업 실행 | | GET | /jobs | 작업 목록 | | GET | /jobs/{jobName}/executions | 실행 이력 | | GET | /executions/{id}/detail | 실행 상세 (Step 포함) | | POST | /executions/{id}/stop | 실행 중지 | | GET/POST | /schedules | 스케줄 관리 (CRUD) | | GET | /dashboard | 대시보드 | | GET | /timeline | 타임라인 | ## 프론트엔드 - React 19 + TypeScript + Vite + Tailwind CSS - 라우팅: React Router (basename `/snp-collector`) - 페이지: Dashboard, Jobs, Executions, ExecutionDetail, Recollects, RecollectDetail, Schedules, Timeline - API 클라이언트: `frontend/src/api/batchApi.ts` - 전역 상태: ToastContext, ThemeContext ## Lint/Format - 백엔드: 별도 lint 도구 미설정 (checkstyle, spotless 없음). IDE 기본 포매터 사용. - 프론트엔드: `cd frontend && npm run lint` (ESLint) ## 배포 - Gitea Actions (`.gitea/workflows/deploy.yml`) - Maven Docker 이미지 (maven:3.9-eclipse-temurin-17) - 빌드 산출물: `/deploy/snp-collector/app.jar`