kcg-ai-monitoring/CLAUDE.md
htlee 479a4bfc56 docs: 디자인 시스템 SSOT 개발 지침 + 릴리즈 노트 갱신
CLAUDE.md '디자인 시스템' 섹션 신규:
- 쇼케이스(/design-system.html)를 단일 진실 공급원으로 명시
- 공통 컴포넌트 목록 (Button/Input/Select/PageContainer/PageHeader/Badge 등)
- 카탈로그 API 사용 패턴 (getAlertLevelIntent/Label 등)
- CSS 작성 6대 규칙 (인라인 색상 금지, 하드코딩 Tailwind 색상 금지,
  className override 정책, 시맨틱 토큰 우선, !important 절대 금지,
  vendor prefix 수동 대응)
- 페이지 작성 표준 템플릿
- 접근성 (WCAG 2.1 Level A) 필수 사항
- 변경 사이클 (쇼케이스 → 카탈로그 → 컴포넌트 → 자동 반영)
- 금지 패턴 체크리스트

RELEASE-NOTES.md [Unreleased]에 디자인 시스템 SSOT 작업 항목 추가:
- 쇼케이스 페이지 + 신규 공통 컴포넌트 + 중앙 레지스트리
- 35+ feature 페이지 마이그레이션
- Badge intent 팔레트 테마 분리
- 접근성 전수 처리 (Select TypeScript 강제 등)
2026-04-08 13:29:28 +09:00

11 KiB
Raw Blame 히스토리

KCG AI Monitoring (모노레포)

해양경찰청 AI 기반 불법어선 탐지 및 단속 지원 플랫폼

모노레포 구조

kcg-ai-monitoring/
├── frontend/        # React 19 + TypeScript + Vite (UI)
├── backend/         # Spring Boot 3.x + Java 21 (인증/권한/감사 + 분석 API)
├── prediction/      # Python 3.9 + FastAPI (AIS 분석 엔진, 5분 주기)
├── database/        # PostgreSQL 마이그레이션 (Flyway V001~V016, 48 테이블)
│   └── migration/
├── deploy/          # 배포 가이드 + 서버 설정 문서
├── docs/            # 프로젝트 문서 (SFR, 아키텍처)
├── .gitea/          # Gitea Actions CI/CD (프론트 자동배포)
├── .claude/         # Claude Code 워크플로우
├── .githooks/       # Git hooks
└── Makefile         # 통합 dev/build 명령

시스템 구성

[Frontend Vite :5173] ──→ [Backend Spring :8080] ──→ [PostgreSQL kcgaidb]
                                                           ↑ write
                          [Prediction FastAPI :8001] ──────┘ (5분 주기 분석 결과 저장)
                                ↑ read                       ↑ read
                          [SNPDB PostgreSQL] (AIS 원본)     [Iran Backend] (레거시 프록시, 선택)
  • 자체 백엔드: 인증/권한/감사로그/관리자 + 운영자 의사결정 (확정/제외/학습)
  • iran 백엔드 프록시: 분석 결과 read-only 참조 (vessel_analysis, group_polygons, correlations)
  • 신규 DB (kcgaidb): 자체 생산 데이터만 저장, prediction 분석 테이블은 미복사

명령어

make install          # 전체 의존성 설치
make dev              # 프론트 + 백엔드 동시 실행
make dev-all          # 프론트 + 백엔드 + prediction 동시 실행
make dev-frontend     # 프론트만
make dev-backend      # 백엔드만
make dev-prediction   # prediction 분석 엔진만 (FastAPI :8001)
make build            # 전체 빌드
make lint             # 프론트 lint
make format           # 프론트 prettier

기술 스택

Frontend (frontend/)

  • React 19, TypeScript 5.9, Vite 8
  • Tailwind CSS 4 + CVA
  • MapLibre GL 5 + deck.gl 9 (지도)
  • ECharts 6 (차트)
  • Zustand 5 (상태관리)
  • i18next (ko/en)
  • React Router 7
  • ESLint 10 + Prettier

Prediction (prediction/) — 분석 엔진

  • Python 3.11+, FastAPI, APScheduler
  • 14개 알고리즘 (어구 추론, 다크베셀, 스푸핑, 환적, 위험도 등)
  • 7단계 분류 파이프라인 (전처리→행동→리샘플→특징→분류→클러스터→계절)
  • AIS 원본: SNPDB (5분 증분), 결과: kcgaidb (직접 write)
  • prediction과 backend는 DB만 공유 (HTTP 호출 X)

Backend (backend/)

  • Spring Boot 3.x + Java 21
  • Spring Security + JWT
  • PostgreSQL + Flyway
  • Caffeine (권한 캐싱)
  • 트리 기반 RBAC (wing 패턴)

Database (kcgaidb)

  • PostgreSQL
  • 사용자: kcg-app
  • 스키마: kcg

배포 환경

서비스 서버 (SSH) 포트 관리
프론트엔드 rocky-211 nginx 443 Gitea Actions 자동배포
백엔드 rocky-211 18080 systemctl restart kcg-ai-backend
prediction redis-211 18092 systemctl restart kcg-ai-prediction

권한 체계

좌측 탭(메뉴) = 권한 그룹, 내부 패널/액션 = 자식 자원, CRUD 단위 개별 제어. 상세는 .claude/plans/vast-tinkering-knuth.md 참조.

팀 컨벤션

  • 팀 규칙: .claude/rules/
  • 커밋: Conventional Commits (한국어), .githooks/commit-msg 검증
  • pre-commit: frontend/ 디렉토리 기준 TypeScript + ESLint 검증

디자인 시스템 (필수 준수)

프론트엔드 UI는 /design-system.html 쇼케이스를 단일 진실 공급원(SSOT) 으로 한다. 모든 페이지/컴포넌트는 쇼케이스에 정의된 컴포넌트와 토큰만 사용한다.

쇼케이스 진입

  • URL: https://kcg-ai-monitoring.gc-si.dev/design-system.html (메인 SPA와 별개)
  • 소스: frontend/design-system.html + frontend/src/designSystemMain.tsx + frontend/src/design-system/
  • 추적 ID 체계: TRK-<카테고리>-<슬러그> (예: TRK-BADGE-critical-sm)
    • 호버 시 툴팁, "ID 복사 모드"에서 클릭 시 클립보드 복사
    • URL 해시 딥링크: #trk=TRK-BUTTON-primary-md
  • 단축키 A: 다크/라이트 테마 토글

공통 컴포넌트 (반드시 사용)

컴포넌트 위치 용도
Badge @shared/components/ui/badge 8 intent × 4 size, className으로 색상 override 금지
Button @shared/components/ui/button 5 variant × 3 size (primary/secondary/ghost/outline/destructive)
Input / Select / Textarea / Checkbox / Radio @shared/components/ui/ 폼 요소 (Select는 aria-label 타입 강제)
TabBar / TabButton @shared/components/ui/tabs underline / pill / segmented 3 variant
Card / CardHeader / CardTitle / CardContent @shared/components/ui/card 4 variant
PageContainer @shared/components/layout 페이지 루트 (size sm/md/lg + fullBleed)
PageHeader @shared/components/layout 페이지 헤더 (icon + title + description + demo + actions)
Section @shared/components/layout Card + CardHeader + CardTitle + CardContent 단축

카탈로그 기반 라벨/색상

분류 데이터는 frontend/src/shared/constants/의 19+ 카탈로그를 참조한다. 중앙 레지스트리는 catalogRegistry.ts이며, 쇼케이스가 자동 열거한다.

import { Badge } from '@shared/components/ui/badge';
import { getAlertLevelIntent, getAlertLevelLabel } from '@shared/constants/alertLevels';

<Badge intent={getAlertLevelIntent(event.level)} size="sm">
  {getAlertLevelLabel(event.level, t, lang)}
</Badge>

ad-hoc 한글/영문 상태 문자열은 getStatusIntent() (statusIntent.ts) 사용. 숫자 위험도는 getRiskIntent(0~100) 사용.

CSS 작성 규칙

  1. 인라인 색상 금지style={{ backgroundColor: '#ef4444' }} 같은 정적 색상은 작성 금지
    • 예외: 동적 데이터 기반 (backgroundColor: meta.hex, progress width ${value}%)
  2. 하드코딩 Tailwind 색상 금지bg-red-500/20 text-red-400 같은 직접 작성 금지
    • 반드시 Badge intent 또는 카탈로그 API 호출
  3. className override 정책
    • 레이아웃/위치 보정: <Badge intent="info" className="w-full justify-center">
    • 색상/글자 크기 override: <Badge intent="info" className="bg-red-500 text-xs">
  4. 시맨틱 토큰 우선theme.css @layer utilities의 토큰 사용
    • text-heading / text-label / text-hint / text-on-vivid / text-on-bright
    • bg-surface-raised / bg-surface-overlay / bg-card / bg-background
  5. !important 절대 금지cn() + tailwind-merge로 충돌 해결
  6. -webkit- 벤더 prefix — 수동 작성 CSS는 backdrop-filter 등 prefix 직접 추가 (Tailwind는 자동)

페이지 작성 표준 템플릿

import { PageContainer, PageHeader, Section } from '@shared/components/layout';
import { Button } from '@shared/components/ui/button';
import { Badge } from '@shared/components/ui/badge';
import { getAlertLevelIntent, getAlertLevelLabel } from '@shared/constants/alertLevels';
import { Shield, Plus } from 'lucide-react';
import { useTranslation } from 'react-i18next';

export function MyPage() {
  const { t, i18n } = useTranslation('common');
  const lang = i18n.language as 'ko' | 'en';

  return (
    <PageContainer>
      <PageHeader
        icon={Shield}
        iconColor="text-blue-400"
        title="페이지 제목"
        description="페이지 설명"
        actions={
          <Button variant="primary" icon={<Plus className="w-4 h-4" />}>
            추가
          </Button>
        }
      />
      <Section title="데이터 목록">
        <Badge intent={getAlertLevelIntent('HIGH')} size="sm">
          {getAlertLevelLabel('HIGH', t, lang)}
        </Badge>
      </Section>
    </PageContainer>
  );
}

접근성 (a11y) 필수

  • <button>: type="button" 명시 + 아이콘 전용은 aria-label 필수
  • <input> / <textarea> / <select>: aria-label 또는 <label htmlFor> 필수
  • Select 컴포넌트: TypeScript union type으로 aria-label/aria-labelledby/title 중 하나 컴파일 타임 강제
  • 위반 시 WCAG 2.1 Level A 위반 + axe DevTools 경고

변경 사이클

  1. 디자인 변경이 필요하면 → 쇼케이스에서 먼저 미세조정 → 시각 검증
  2. 카탈로그 라벨/색상 변경 → shared/constants/* 또는 variantMeta.ts만 수정
  3. 컴포넌트 변형 추가 → lib/theme/variants.ts CVA에만 추가
  4. 실 페이지는 컴포넌트만 사용, 변경 시 자동 반영

금지 패턴 체크리스트

  • <Badge className="bg-red-500/20 text-red-400"><Badge intent="critical">
  • <button className="bg-blue-600 ..."><Button variant="primary">
  • <input className="bg-surface ..."><Input>
  • <div className="p-5 space-y-4"> 페이지 루트 → <PageContainer>
  • -m-4 negative margin 해킹 → <PageContainer fullBleed>
  • style={{ color: '#ef4444' }} 정적 색상 → 시맨틱 토큰 또는 카탈로그
  • !importantcn() 활용
  • 페이지 내 const STATUS_COLORS = {...} 로컬 재정의 → shared/constants 카탈로그

System Flow 뷰어 (개발 단계용)

  • URL: https://kcg-ai-monitoring.gc-si.dev/system-flow.html (메인 SPA와 별개)
  • 소스: frontend/system-flow.html + frontend/src/systemFlowMain.tsx + frontend/src/flow/
  • 매니페스트: frontend/src/flow/manifest/ (10개 카테고리 JSON + meta.json + edges.json)
  • 노드 ID 명명: <category>.<snake_case> (예: output.event_generator, ui.parent_review)
  • 딥링크: /system-flow.html#node=<node_id> — 산출문서에서 노드 직접 참조
  • 가이드: docs/system-flow-guide.md 참조

/version 스킬 사후 처리 (필수)

/version 스킬을 실행하여 새 SemVer 버전이 결정되면, Claude는 이어서 다음 작업을 자동으로 수행한다 (/version 스킬 자체는 팀 공통 파일이라 직접 수정하지 않음):

  1. manifest 동기화: /version이 결정한 새 버전을 frontend/src/flow/manifest/meta.json에 반영
    • version: 새 SemVer (예: "1.2.0")
    • updatedAt: 현재 ISO datetime (new Date().toISOString())
    • releaseDate: 오늘 날짜 (YYYY-MM-DD)
  2. 같은 커밋에 포함: frontend/src/flow/manifest/meta.json/version 스킬이 만든 커밋에 amend하거나, docs: VERSION-HISTORY 갱신 + system-flow manifest 동기화로 통합 커밋
  3. 서버 archive는 CI/CD가 자동 처리: 별도 작업 불필요. main 머지 후 Gitea Actions가 빌드 + dist 배포 + /deploy/kcg-ai-monitoring-archive/system-flow/v{version}_{date}/에 스냅샷 영구 보존

노드 ID 안정성

  • 노드 ID는 절대 변경 금지 (산출문서가 참조하므로 깨짐)
  • 노드 제거 시 status: 'deprecated'로 마킹 (1~2 릴리즈 유지 후 삭제)
  • 새 노드 추가 시 status: 'implemented' 또는 'planned'