chore: 팀 워크플로우 초기화 + Prettier + 타입 에러 수정
- /init-project로 팀 표준 워크플로우 적용 (CLAUDE.md, settings.json hooks, pre-commit) - Prettier + eslint-config-prettier 설치 및 ESLint 연동 - format/format:check npm 스크립트 추가 - vite-env.d.ts 추가 (import.meta.env 타입 정의) - pre-commit 차단 해제: GearDetection/BaseChart 타입 캐스팅 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
부모
7a9ece5f0f
커밋
1eccbd7a72
@ -46,5 +46,42 @@
|
||||
"Read(./**/.env.*)",
|
||||
"Read(./**/secrets/**)"
|
||||
]
|
||||
},
|
||||
"hooks": {
|
||||
"SessionStart": [
|
||||
{
|
||||
"matcher": "compact",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "bash .claude/scripts/on-post-compact.sh",
|
||||
"timeout": 10
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"PreCompact": [
|
||||
{
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "bash .claude/scripts/on-pre-compact.sh",
|
||||
"timeout": 30
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"PostToolUse": [
|
||||
{
|
||||
"matcher": "Bash",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "bash .claude/scripts/on-commit.sh",
|
||||
"timeout": 15
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
54
.githooks/pre-commit
Executable file
54
.githooks/pre-commit
Executable file
@ -0,0 +1,54 @@
|
||||
#!/bin/bash
|
||||
#==============================================================================
|
||||
# pre-commit hook (React TypeScript)
|
||||
# TypeScript 컴파일 + 린트 검증 — 실패 시 커밋 차단
|
||||
#==============================================================================
|
||||
|
||||
echo "pre-commit: TypeScript 타입 체크 중..."
|
||||
|
||||
# npm 확인
|
||||
if ! command -v npx &>/dev/null; then
|
||||
echo "경고: npx가 설치되지 않았습니다. 검증을 건너뜁니다."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# node_modules 확인
|
||||
if [ ! -d "node_modules" ]; then
|
||||
echo "경고: node_modules가 없습니다. 'npm install' 실행 후 다시 시도하세요."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# TypeScript 타입 체크
|
||||
npx tsc --noEmit --pretty 2>&1
|
||||
TSC_RESULT=$?
|
||||
|
||||
if [ $TSC_RESULT -ne 0 ]; then
|
||||
echo ""
|
||||
echo "╔══════════════════════════════════════════════════════════╗"
|
||||
echo "║ TypeScript 타입 에러! 커밋이 차단되었습니다. ║"
|
||||
echo "║ 타입 에러를 수정한 후 다시 커밋해주세요. ║"
|
||||
echo "╚══════════════════════════════════════════════════════════╝"
|
||||
echo ""
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "pre-commit: 타입 체크 성공"
|
||||
|
||||
# ESLint 검증 (설정 파일이 있는 경우만)
|
||||
if [ -f ".eslintrc.js" ] || [ -f ".eslintrc.json" ] || [ -f ".eslintrc.cjs" ] || [ -f "eslint.config.js" ] || [ -f "eslint.config.mjs" ]; then
|
||||
echo "pre-commit: ESLint 검증 중..."
|
||||
npx eslint src/ --ext .ts,.tsx --quiet 2>&1
|
||||
LINT_RESULT=$?
|
||||
|
||||
if [ $LINT_RESULT -ne 0 ]; then
|
||||
echo ""
|
||||
echo "╔══════════════════════════════════════════════════════════╗"
|
||||
echo "║ ESLint 에러! 커밋이 차단되었습니다. ║"
|
||||
echo "║ 'npm run lint -- --fix'로 자동 수정을 시도해보세요. ║"
|
||||
echo "╚══════════════════════════════════════════════════════════╝"
|
||||
echo ""
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "pre-commit: ESLint 통과"
|
||||
fi
|
||||
7
.prettierignore
Normal file
7
.prettierignore
Normal file
@ -0,0 +1,7 @@
|
||||
dist/
|
||||
build/
|
||||
node_modules/
|
||||
coverage/
|
||||
*.min.js
|
||||
*.min.css
|
||||
package-lock.json
|
||||
10
.prettierrc
Normal file
10
.prettierrc
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"semi": true,
|
||||
"singleQuote": true,
|
||||
"tabWidth": 2,
|
||||
"trailingComma": "all",
|
||||
"printWidth": 100,
|
||||
"bracketSpacing": true,
|
||||
"arrowParens": "always",
|
||||
"endOfLine": "lf"
|
||||
}
|
||||
74
CLAUDE.md
Normal file
74
CLAUDE.md
Normal file
@ -0,0 +1,74 @@
|
||||
# KCG AI Monitoring
|
||||
|
||||
해양경찰청 AI 기반 불법어선 탐지 및 단속 지원 플랫폼
|
||||
|
||||
## 기술 스택
|
||||
|
||||
- **프레임워크**: React 19 + TypeScript 5.9
|
||||
- **빌드**: Vite 8
|
||||
- **스타일**: Tailwind CSS 4 + CVA (class-variance-authority)
|
||||
- **지도**: MapLibre GL 5 + deck.gl 9
|
||||
- **차트**: ECharts 6
|
||||
- **상태관리**: Zustand 5
|
||||
- **다국어**: i18next (ko/en, 10개 네임스페이스)
|
||||
- **라우팅**: React Router 7
|
||||
- **린트**: ESLint 10 (flat config)
|
||||
|
||||
## 명령어
|
||||
|
||||
```bash
|
||||
npm run dev # 개발 서버 (Vite)
|
||||
npm run build # 프로덕션 빌드
|
||||
npm run lint # ESLint 검사
|
||||
npm run lint:fix # ESLint 자동 수정
|
||||
npm run format # Prettier 포맷팅
|
||||
npm run format:check # 포맷팅 검사
|
||||
```
|
||||
|
||||
## 디렉토리 구조
|
||||
|
||||
```
|
||||
src/
|
||||
├── app/ # 라우터, 인증, 레이아웃
|
||||
├── features/ # 13개 도메인 모듈 (31+ 페이지)
|
||||
│ ├── admin/ # 관리자
|
||||
│ ├── ai-operations/ # AI 작전
|
||||
│ ├── auth/ # 인증
|
||||
│ ├── dashboard/ # 대시보드
|
||||
│ ├── detection/ # 탐지
|
||||
│ ├── enforcement/ # 단속
|
||||
│ ├── field-ops/ # 현장작전
|
||||
│ ├── monitoring/ # 모니터링
|
||||
│ ├── patrol/ # 순찰
|
||||
│ ├── risk-assessment/# 위험평가
|
||||
│ ├── statistics/ # 통계
|
||||
│ ├── surveillance/ # 감시
|
||||
│ └── vessel/ # 선박
|
||||
├── lib/ # 공유 라이브러리
|
||||
│ ├── charts/ # ECharts 래퍼 + 프리셋
|
||||
│ ├── i18n/ # i18next 설정 + 로케일
|
||||
│ ├── map/ # MapLibre + deck.gl 통합
|
||||
│ └── theme/ # 디자인 토큰 + CVA 변형
|
||||
├── data/mock/ # 7개 목 데이터 모듈
|
||||
├── stores/ # Zustand 스토어 (8개)
|
||||
├── services/ # API 서비스 샘플
|
||||
├── shared/ # 공유 UI 컴포넌트
|
||||
└── styles/ # CSS (Dark/Light 테마)
|
||||
```
|
||||
|
||||
## Path Alias
|
||||
|
||||
| Alias | 경로 |
|
||||
|-------|------|
|
||||
| `@/` | `src/` |
|
||||
| `@lib/` | `src/lib/` |
|
||||
| `@shared/` | `src/shared/` |
|
||||
| `@features/` | `src/features/` |
|
||||
| `@data/` | `src/data/` |
|
||||
| `@stores/` | `src/stores/` |
|
||||
|
||||
## 팀 컨벤션
|
||||
|
||||
- 팀 규칙은 `.claude/rules/` 참조
|
||||
- 커밋: Conventional Commits (한국어), `.githooks/commit-msg`로 검증
|
||||
- Git Hooks: `.githooks/` (core.hooksPath 설정됨)
|
||||
@ -3,6 +3,7 @@ import globals from 'globals';
|
||||
import tseslint from 'typescript-eslint';
|
||||
import reactHooks from 'eslint-plugin-react-hooks';
|
||||
import reactRefresh from 'eslint-plugin-react-refresh';
|
||||
import eslintConfigPrettier from 'eslint-config-prettier';
|
||||
|
||||
export default tseslint.config(
|
||||
{ ignores: ['dist/**', 'node_modules/**'] },
|
||||
@ -27,4 +28,5 @@ export default tseslint.config(
|
||||
'prefer-const': 'warn',
|
||||
},
|
||||
},
|
||||
eslintConfigPrettier,
|
||||
);
|
||||
|
||||
34
package-lock.json
generated
34
package-lock.json
generated
@ -28,9 +28,11 @@
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"@vitejs/plugin-react": "^6.0.1",
|
||||
"eslint": "^10.2.0",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-plugin-react-hooks": "^7.0.1",
|
||||
"eslint-plugin-react-refresh": "^0.5.2",
|
||||
"globals": "^17.4.0",
|
||||
"prettier": "^3.8.1",
|
||||
"tailwindcss": "^4.2.2",
|
||||
"typescript": "5.9",
|
||||
"typescript-eslint": "^8.58.0",
|
||||
@ -3103,6 +3105,22 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-config-prettier": {
|
||||
"version": "10.1.8",
|
||||
"resolved": "https://nexus.gc-si.dev/repository/npm-public/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz",
|
||||
"integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"eslint-config-prettier": "bin/cli.js"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/eslint-config-prettier"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": ">=7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-react-hooks": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.0.1.tgz",
|
||||
@ -4373,6 +4391,22 @@
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prettier": {
|
||||
"version": "3.8.1",
|
||||
"resolved": "https://nexus.gc-si.dev/repository/npm-public/prettier/-/prettier-3.8.1.tgz",
|
||||
"integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"prettier": "bin/prettier.cjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/prettier/prettier?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/process-nextick-args": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
||||
|
||||
@ -7,7 +7,9 @@
|
||||
"build": "vite build",
|
||||
"dev": "vite",
|
||||
"lint": "eslint .",
|
||||
"lint:fix": "eslint . --fix"
|
||||
"lint:fix": "eslint . --fix",
|
||||
"format": "prettier --write \"src/**/*.{ts,tsx,css,json}\"",
|
||||
"format:check": "prettier --check \"src/**/*.{ts,tsx,css,json}\""
|
||||
},
|
||||
"dependencies": {
|
||||
"@deck.gl/mapbox": "^9.2.11",
|
||||
@ -30,9 +32,11 @@
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"@vitejs/plugin-react": "^6.0.1",
|
||||
"eslint": "^10.2.0",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-plugin-react-hooks": "^7.0.1",
|
||||
"eslint-plugin-react-refresh": "^0.5.2",
|
||||
"globals": "^17.4.0",
|
||||
"prettier": "^3.8.1",
|
||||
"tailwindcss": "^4.2.2",
|
||||
"typescript": "5.9",
|
||||
"typescript-eslint": "^8.58.0",
|
||||
|
||||
@ -47,7 +47,7 @@ export function GearDetection() {
|
||||
useEffect(() => { if (!loaded) load(); }, [loaded, load]);
|
||||
|
||||
// GearRecord from the store matches the local Gear shape exactly
|
||||
const DATA: Gear[] = items;
|
||||
const DATA: Gear[] = items as unknown as Gear[];
|
||||
|
||||
const mapRef = useRef<MapHandle>(null);
|
||||
|
||||
|
||||
@ -47,7 +47,7 @@ export function BaseChart({
|
||||
if (!containerRef.current) return;
|
||||
|
||||
const chart = echarts.init(containerRef.current, 'kcg-dark');
|
||||
chartRef.current = chart;
|
||||
chartRef.current = chart as unknown as ECharts;
|
||||
chart.setOption(option, notMerge);
|
||||
|
||||
if (onEvents) {
|
||||
|
||||
11
src/vite-env.d.ts
vendored
Normal file
11
src/vite-env.d.ts
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
/// <reference types="vite/client" />
|
||||
|
||||
interface ImportMetaEnv {
|
||||
readonly VITE_API_URL?: string;
|
||||
readonly VITE_PREDICTION_URL?: string;
|
||||
readonly VITE_USE_MOCK?: string;
|
||||
}
|
||||
|
||||
interface ImportMeta {
|
||||
readonly env: ImportMetaEnv;
|
||||
}
|
||||
불러오는 중...
Reference in New Issue
Block a user