# SAM ERP 프론트엔드 종합 검수 보고서

> 작성일: 2026-02-19
> 분석 범위: src/ 전체 (1,438개 TS/TSX 파일, ~314K줄)
> 분석 방법: 5개 에이전트 병렬 분석 (코드품질, 번들/성능, 에러/UX, 아키텍처, 모바일/보안)

---

## 종합 스코어카드

| 영역 | 점수 | 등급 | 핵심 이슈 |
|------|------|------|-----------|
| **코드 품질** | 7.5/10 | 🟢 양호 | TS 규율 우수, any 133건/TODO 121건 잔존 |
| **번들/성능** | 8.5/10 | 🟢 우수 | 동적 로드 적용, tree-shaking 양호 |
| **에러/UX 일관성** | 5.5/10 | 🟡 보통 | 에러바운더리 우수, 로딩UI/접근성 미흡 |
| **아키텍처** | 6.5/10 | 🟡 보통 | 순환의존 없음, 상태관리 중복 |
| **모바일 대응** | 6/10 | 🟡 보통 | 57% 반응형, 터치영역 미달 |
| **보안** | 7/10 | 🟢 양호 | 인증 강함, CSP unsafe 허용 |

**전체: 6.8/10** — 기능적으로 안정적이나, UX 일관성과 아키텍처 정리에 개선 여지

---

## 우선순위별 개선 항목

### P0: 보안 이슈 (즉시 조치)

| # | 항목 | 심각도 | 현황 | 조치 |
|---|------|--------|------|------|
| S-1 | CSP `unsafe-inline`/`unsafe-eval` | 🔴 높음 | middleware.ts에서 허용 중 | nonce 기반으로 전환 |
| S-2 | `new Function()` 코드 주입 | 🔴 높음 | ComputedField.tsx에서 사용 | 사용자 입력 검증 추가 또는 safe-eval 대체 |
| S-3 | sanitizeHTML 함수 강도 | 🟡 중간 | 5개 파일에서 사용 중 | DOMPurify 사용 여부 확인 |

### P1: 아키텍처 정리 (1~2주)

| # | 항목 | 현황 | 개선안 |
|---|------|------|--------|
| A-1 | **상태관리 중복** | ItemMasterContext + itemStore + useItemMasterStore 3중 | Zustand 하나로 통합 |
| A-2 | **테마 중복** | ThemeContext + themeStore 병존 | Zustand로 완전 마이그레이션 |
| A-3 | **utils 폴더 중복** | `src/utils/` (2개) + `src/lib/utils/` (11개) 병존 | `src/utils/` → `src/lib/utils/`로 통합 |
| A-4 | **상수 산재** | constants/ 1개 파일만, 나머지 각 컴포넌트 내부 하드코딩 | 도메인별 `constants/` 정리 |

### P2: 코드 품질 (2~3주)

| # | 항목 | 건수 | 현황 | 조치 |
|---|------|------|------|------|
| Q-1 | `as any` 타입 캐스트 | 64건 | 주로 form errors 처리 | 제네릭 타입 정의 |
| Q-2 | `: any` 타입 선언 | 48건 | API 응답/props 타입 | 인터페이스 정의 |
| Q-3 | TODO/FIXME 누적 | 121건 (68파일) | useItemMasterStore 15건 등 | 이슈화 → 점진적 해소 |
| Q-4 | God 컴포넌트 | 5개 | ItemMasterContext 2,200줄, MainDashboard 1,400줄 | 단계적 분리 |
| Q-5 | 거대 훅 | 1개 | useCEODashboard 37.9KB | stats/charts/timeline 분리 |
| Q-6 | `alert()`/`confirm()` 잔존 | 32건 | 15개 alert + 17개 confirm | ConfirmDialog/toast로 교체 |

### P3: UX 일관성 (3~4주)

| # | 항목 | 현황 | 목표 |
|---|------|------|------|
| U-1 | **로딩 UI** | 40+ 페이지에서 `"로딩 중..."` 텍스트만 사용, Skeleton 2개만 | Skeleton 기반 로딩으로 통일 |
| U-2 | **접근성 (a11y)** | aria-label 3건, role 9건 | 주요 폼/테이블에 ARIA 추가 |
| U-3 | **i18n 사용률** | 인프라 완성(ko/en/ja), 실제 사용 ~5% | 점진적 적용 확대 |
| U-4 | **Zod 검증** | 2개 폼만 적용 | 신규 폼 필수, 기존은 유지 |
| U-5 | **EmptyState 활용** | 컴포넌트 존재하나 하드코딩 "데이터 없음" 다수 | EmptyState 컴포넌트 통일 |

### P4: 모바일/성능 (선택)

| # | 항목 | 현황 | 조치 |
|---|------|------|------|
| M-1 | **반응형 커버리지** | 57% 페이지 적용 | HR/대시보드 등 미적용 페이지 보강 |
| M-2 | **터치 영역** | Checkbox 20x20px (권장 44x44px) | 모바일 터치 타겟 확대 |
| M-3 | **html2canvas + dom-to-image** 중복 | 2개 라이브러리 공존 | 하나로 통합 (~50-80KB 절감) |
| M-4 | **Tiptap 동적 로딩** | 보드/팝업에서만 사용하나 번들 포함 | next/dynamic 적용 (~80-100KB 절감) |
| M-5 | **도메인별 actions.ts 표준화** | accounting만 page-level actions, 나머지는 컴포넌트 내부 | accounting 패턴으로 통일 |

---

## 잘 되어있는 점 (유지 사항)

### 코드 품질
- ✅ **TypeScript 규율**: @ts-ignore 0건, @ts-nocheck 1건(레거시)
- ✅ **console.log 관리**: 23건만 (16건은 logger 유틸리티)
- ✅ **에러 바운더리**: 글로벌 + Protected 레벨 4개, Slack 연동
- ✅ **Toast 시스템**: sonner 기반 1,277개 인스턴스 일관 사용

### 번들/성능
- ✅ **XLSX 동적 로드**: 버튼 클릭 시에만 ~400KB 로드
- ✅ **대시보드 코드 스플리팅**: ~850KB 초기 번들에서 제외
- ✅ **tree-shaking**: `import *` 0건, lodash/moment 미사용
- ✅ **Zustand 정규화**: 체계적 상태 + Immer + selector hooks
- ✅ **Tailwind v4**: 최신 버전, 효율적 트리셰이킹

### 아키텍처
- ✅ **순환 의존성 없음**: pages→components→ui 단방향
- ✅ **API 계층**: buildApiUrl 43개 actions.ts 전면 적용
- ✅ **executePaginatedAction**: 14개 파일 표준화

### 보안
- ✅ **Bot 차단**: 25개 패턴 필터링
- ✅ **다층 인증**: Bearer Token + Authorization 헤더 + Sanctum + API Key
- ✅ **Open Redirect 방지**: 내부 경로 검증
- ✅ **환경변수 분리**: NEXT_PUBLIC_ 적절히 사용
- ✅ **민감 정보 노출 없음**: console.log에 토큰/비밀번호 출력 0건

---

## 주요 파일 참조

### God 컴포넌트 (분리 대상)
- `src/contexts/ItemMasterContext.tsx` (2,200줄)
- `src/components/business/MainDashboard.tsx` (1,400줄)
- `src/hooks/useCEODashboard.ts` (37.9KB)

### any 타입 집중 지역
- `src/components/items/ItemForm/forms/parts/` (22건)
- `src/components/items/ItemMasterDataManagement/` (18건)
- `src/components/quotes/LocationDetailPanel.tsx` (10건)

### 보안 확인 대상
- `src/middleware.ts` (CSP 설정)
- `src/components/**/ComputedField.tsx` (new Function)
- sanitizeHTML 사용 파일 5개 (게시판, 팝업, 고객센터)

### 상태관리 중복
- `src/contexts/ItemMasterContext.tsx` vs `src/stores/itemStore.ts` vs `src/stores/item-master/useItemMasterStore.ts`
- `src/contexts/ThemeContext.tsx` vs `src/stores/themeStore.ts`

---

## 기존 로드맵과의 관계

| 기존 항목 | 상태 | 이번 분석 결과 |
|-----------|------|---------------|
| D-1 God 컴포넌트 분리 | ⏳ 대기 | → P2-Q4로 재확인, 여전히 필요 |
| D-2 `as` 타입 캐스트 | 보류 | → P2-Q1/Q2로 133건 확인 (기존 ~200건에서 감소) |
| D-6 TODO 102건 | ⏳ 대기 | → P2-Q3으로 121건 확인 (소폭 증가) |
| A-2 DataTable 최적화 | ⏳ 대기 | → 에이전트 분석 결과 re-render 위험 낮음 (우선순위 하향) |

### 신규 발견 항목 (기존 로드맵에 없었던 것)
- **S-1~S-3**: 보안 이슈 (CSP, code injection, sanitization)
- **A-1~A-2**: 상태관리 3중 중복
- **U-1~U-5**: UX 일관성 전반 (로딩/접근성/i18n/빈상태)
- **M-3~M-4**: 라이브러리 중복/동적 로딩 기회

---

## 실행 로드맵 요약

```
Week 1-2: P0 보안 + P1 아키텍처 정리
  ├── CSP nonce 전환
  ├── ComputedField 보안 패치
  ├── 상태관리 중복 정리 (Context → Zustand)
  └── utils 폴더 통합

Week 3-4: P2 코드 품질
  ├── any 타입 정리 (form errors 제네릭)
  ├── alert/confirm → ConfirmDialog 교체
  └── TODO/FIXME 이슈 정리

Week 5-6: P3 UX 일관성 (선택)
  ├── Skeleton 로딩 UI 통일
  ├── EmptyState 활용 확대
  └── 접근성 기본 적용

이후: P4 모바일/성능 (필요 시)
```