커밋 그래프

11 커밋

작성자 SHA1 메시지 날짜
c1cc36b134 refactor(design-system): 하드코딩 색상 라이트/다크 대응 + raw button/input 공통 컴포넌트 치환
30개 파일 전 영역에 동일한 패턴으로 SSOT 준수:

**StatBox 재설계 (2파일)**:
- RealGearGroups, RealVesselAnalysis 의 `color: string` prop 제거
- `intent: BadgeIntent` prop + `INTENT_TEXT_CLASS` 매핑 도입

**raw `<button>` → Button 컴포넌트 (다수)**:
- `bg-blue-600 hover:bg-blue-500 text-on-vivid ...` → `<Button variant="primary">`
- `bg-orange-600 ...` / `bg-green-600 ...` → `<Button variant="primary">`
- `bg-red-600 ...` → `<Button variant="destructive">`
- 아이콘 전용 → `<Button variant="ghost" aria-label=".." icon={...} />`
- detection/enforcement/admin/parent-inference/statistics/ai-operations/auth 전영역

**raw `<input>` → Input 컴포넌트**:
- parent-inference (ParentReview, ParentExclusion, LabelSession)
- admin (PermissionsPanel, UserRoleAssignDialog)
- ai-operations (AIAssistant)
- auth (LoginPage)

**raw `<select>` → Select 컴포넌트**:
- detection (RealGearGroups, RealVesselAnalysis, ChinaFishing)

**커스텀 탭 → TabBar/TabButton (segmented/underline)**:
- ChinaFishing: 모드 탭 + 선박 탭 + 통계 탭

**raw `<input type="checkbox">` → Checkbox**:
- GearDetection FilterCheckGroup

**하드코딩 Tailwind 색상 라이트/다크 쌍 변환 (전영역)**:
- `text-red-400` → `text-red-600 dark:text-red-400`
- `text-green-400` → `text-green-600 dark:text-green-400`
- blue/cyan/orange/yellow/purple/amber 동일 패턴
- `text-*-500` 아이콘도 `text-*-600 dark:text-*-500` 로 라이트 모드 대응
- 상태 dot (bg-red-500 animate-pulse 등)은 의도적 시각 구분이므로 유지

**에러 메시지 한글 → t('error.errorPrefix') 통일**:
- detection/parent-inference/admin 에서 `에러: {error}` 패턴 → `t('error.errorPrefix', { msg: error })`

**결과**: tsc 0 errors / eslint 0 errors (84 warnings 기존)
2026-04-16 17:09:14 +09:00
8af693a2df refactor(i18n): alert/confirm/aria-label 하드코딩 한글 제거
공통 번역 리소스 확장:
- common.json 에 aria / error / dialog / success / message 네임스페이스 추가
- ko/en 양쪽 동일 구조 유지 (aria 36 키 + error 7 키 + dialog 4 키 + message 5 키)

alert/confirm 11건 → t() 치환:
- parent-inference: ParentReview / LabelSession / ParentExclusion
- admin: PermissionsPanel / UserRoleAssignDialog / AccessControl

aria-label 한글 40+건 → t() 치환:
- parent-inference (group_key/sub_cluster/정답 parent MMSI/스코프 필터 등)
- admin (역할 코드/이름, 알림 제목/내용, 시작일/종료일, 코드 검색, 대분류 필터, 수신 현황 기준일)
- detection (그룹 유형/해역 필터, 관심영역, 필터 설정/초기화, 멤버 수, 미니맵/재생 닫기)
- enforcement (확인/선박 상세/단속 등록/오탐 처리)
- vessel/statistics/ai-operations (조회 시작/종료 시각, 업로드 패널 닫기, 전송, 예시 URL 복사)
- 공통 컴포넌트 (SearchInput, NotificationBanner)

MainLayout 언어 토글:
- title 삼항분기 → t('message.switchToEnglish'/'switchToKorean')
- aria-label="페이지 내 검색" → t('aria.searchInPage')
- 토글 버튼 자체에 aria-label={t('aria.languageToggle')} 추가
2026-04-16 16:32:37 +09:00
45371315ba feat: prediction 알고리즘 재설계 + 프론트 CRUD 권한 가드 보완 (#29) 2026-04-13 11:08:11 +09:00
e401c07dd3 feat(frontend): 워크플로우 연결 Step 5 — 자동갱신 + 모선추론 연결 + i18n
자동 갱신 (30초, 깜박임 없음):
- eventStore: silentRefresh() 메서드 추가 (loading 상태 미변경, 데이터만 교체)
- EventList: 30초 인터벌로 silentRefresh + loadStats 호출
- DarkVesselDetection: 30초 인터벌로 getDarkVessels silent 갱신

모선추론 자동 연결:
- ParentReview CONFIRM → createLabelSession 자동 호출 (학습 데이터 수집 시작)
- ParentReview REJECT → excludeForGroup 자동 호출 (잘못된 후보 재추론 방지)
- 자동 연결 실패 시 리뷰 자체는 유지 (catch 무시)

i18n (ko/en):
- darkTier: CRITICAL/HIGH/WATCH/NONE 라벨
- transshipTier: CRITICAL/HIGH/WATCH 라벨
- adminSubGroup: AI 플랫폼/시스템 운영/사용자 관리/감사·보안

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 11:43:18 +09:00
6887a2b4fc feat(frontend): 워크플로우 연결 Step 4 — Enforcement 연계 + admin 서브그룹
EnforcementHistory:
- eventId 역추적 컬럼 추가 (#{eventId} 클릭 → EventList 이동)
- Record 인터페이스에 eventId 필드 추가

EnforcementPlan:
- 미배정 CRITICAL 이벤트 패널 신설 (NEW 상태 CRITICAL 이벤트 표시)
- getEvents(level=CRITICAL, status=NEW) 연동

MainLayout:
- admin 메뉴 4개 서브그룹 분리 (AI 플랫폼/시스템 운영/사용자 관리/감사·보안)
- NavDivider 타입 도입으로 그룹 내 소제목 라벨 렌더링
- 기존 RBAC 필터링 + collapsed 모드 호환 유지

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 11:32:03 +09:00
0679c04bfe feat(frontend): 워크플로우 연결 Step 2 — EventList 워크플로우 + MMSI 링크
- EventList 인라인 액션 버튼 4종 추가 (확인/선박상세/단속등록/오탐)
  - 확인(ACK): NEW 상태 이벤트만 활성, ackEvent API 연동
  - 선박 상세: /vessel/{mmsi} 네비게이션
  - 단속 등록: createEnforcementRecord API → 이벤트 RESOLVED 자동 전환
  - 오탐 처리: updateEventStatus(FALSE_POSITIVE) 연동
- MMSI → VesselDetail 링크 3개 화면 적용
  - EventList: MMSI 컬럼 클릭 → /vessel/{mmsi}
  - DarkVesselDetection: MMSI 컬럼 클릭 → /vessel/{mmsi}
  - EnforcementHistory: 대상 선박 컬럼 클릭 → /vessel/{mmsi}
- PredictionEvent 타입에 features 필드 추가 (dark_tier, transship_score 등)
- analysisApi.ts 서비스 신규 생성 (직접 조회 API 5개 연동)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 10:50:31 +09:00
2483174081 refactor(frontend): Badge className 위반 37건 전수 제거
- 4개 catalog(eventStatuses/enforcementResults/enforcementActions/patrolStatuses)에
  intent 필드 추가 + getXxxIntent() 헬퍼 신규
- statusIntent.ts 공통 유틸: 한글/영문 상태 문자열 → BadgeIntent 매핑
  + getRiskIntent(0-100) 점수 기반 매핑
- 모든 Badge className="..." 패턴을 intent prop으로 치환:
  - admin (AuditLogs/AccessControl/SystemConfig/NoticeManagement/DataHub)
  - ai-operations (AIModelManagement/MLOpsPage)
  - enforcement (EventList/EnforcementHistory)
  - field-ops (AIAlert)
  - detection (GearIdentification)
  - patrol (PatrolRoute/FleetOptimization)
  - parent-inference (ParentExclusion)
  - statistics (ExternalService/ReportManagement)
  - surveillance (MapControl)
  - risk-assessment (EnforcementPlan)
  - monitoring (SystemStatusPanel — ServiceCard statusColor → statusIntent 리팩토)
  - dashboard (Dashboard PatrolStatusBadge)

이제 Badge의 테마별 팔레트(라이트 파스텔 + 다크 translucent)가 자동 적용되며,
쇼케이스에서 palette 조정 시 모든 Badge 사용처에 일관되게 반영됨.
2026-04-08 12:28:23 +09:00
2976796652 refactor(frontend): enforcement/field-ops/patrol PageContainer/PageHeader 적용
- EnforcementHistory/EventList/EnforcementPlan: primary Button 액션
- EventList: Select 공통 컴포넌트로 등급 필터 치환
- AIAlert/ShipAgent/MobileService: PageContainer + PageHeader(demo)
- PatrolRoute/FleetOptimization: primary Button 액션 2개씩

Phase B-3 완료. 총 10개 파일.
2026-04-08 11:57:01 +09:00
a07c745cbc feat(frontend): 40+ 페이지 Badge/시맨틱 토큰 마이그레이션
- 모든 feature 페이지의 Badge className 패턴을 intent/size prop으로 변환
- 컬러풀 액션 버튼 (bg-*-500/600/700 + text-heading) -> text-on-vivid
- 검색/필터 버튼 배경 bg-blue-400 + text-on-bright (밝은 배경 위 검정)
- ROLE_COLORS 4곳 중복 제거 (MainLayout/UserRoleAssignDialog/
  PermissionsPanel/AccessControl) -> getRoleBadgeStyle 공통 호출
- PermissionsPanel 역할 생성/수정에 ColorPicker 통합
- MainLayout: PagePagination + scroll page state 제거 (데이터 페이지네이션 혼동)
- Dashboard RiskBar 단위 버그 수정 (0~100 정수 처리)
- ReportManagement, TransferDetection p-5 space-y-4 padding 복구
- EnforcementHistory 그리드 minmax 적용으로 컬럼 잘림 해소
- timeline 시간 formatDateTime 적용 (ISO T 구분자 처리)
- 각 feature 페이지가 공통 카탈로그 API (getXxxIntent/Label/Classes) 사용
2026-04-08 10:53:58 +09:00
4e6ac8645a feat: S5 프론트 실데이터 전환 — EventList/Statistics/EnforcementHistory/Dashboard KPI
이벤트 목록 (EventList):
- eventStore를 GET /api/events 호출로 전환
- 서버 필터링 (level/status/category), 페이지네이션
- 상태 배지 (NEW/ACK/IN_PROGRESS/RESOLVED/FALSE_POSITIVE)
- getEventStats() 기반 KPI 카드

단속 이력 (EnforcementHistory):
- 신규 services/enforcement.ts (GET/POST /enforcement/records, /plans)
- enforcementStore를 API 기반으로 전환
- KPI 카드 (총단속/처벌/AI일치/오탐) 클라이언트 계산

통계 (Statistics):
- kpi.ts를 GET /api/stats/kpi, /stats/monthly 실제 호출로 전환
- toMonthlyTrend/toViolationTypes 변환 헬퍼 추가
- BarChart/AreaChart 기존 구조 유지

대시보드 KPI:
- kpiStore를 API 기반으로 전환 (getKpiMetrics + getMonthlyStats)
- Dashboard KPI_UI_MAP에 kpiKey 기반 매핑 추가

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 12:14:53 +09:00
e6319a571c refactor: 모노레포 구조로 전환 (frontend/ + backend/ + database/)
Phase 1: 모노레포 디렉토리 구조 구축

- 기존 React 프로젝트를 frontend/ 디렉토리로 이동 (git mv)
- backend/ 디렉토리 생성 (Phase 2에서 Spring Boot 초기화)
- database/migration/ 디렉토리 생성 (Phase 2에서 Flyway 마이그레이션)
- 루트 .gitignore에 frontend/, backend/ 경로 반영
- 루트 CLAUDE.md를 모노레포 가이드로 갱신
- Makefile 추가 (dev/build/lint 통합 명령)
- frontend/vite.config.ts에 /api → :8080 백엔드 proxy 설정
- .githooks/pre-commit을 모노레포 구조에 맞게 갱신
  (frontend/ 변경 시 frontend/ 내부에서 검증)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 08:47:24 +09:00