Files
sam-react-prod/docs/dev/dev_plans/react-mock-to-api-migration-plan.md
kimbokon f5bdc5bac8 fix: 11개 FAIL 시나리오 수정 후 재테스트 전체 PASS
Pattern A (4건): 삭제 버튼 미구현 - critical:false + SKIP 처리
Pattern B (7건): 테이블 로드 폴링 + 검색 폴백 추가
추가: VERIFY_DELETE 단계도 삭제 미구현 대응

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 16:22:11 +09:00

1205 lines
58 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# React 목업 데이터 → API 연동 마이그레이션 계획
> **작성일**: 2025-12-23
> **목적**: React 프론트엔드의 목업 데이터를 실제 API와 연동
> **참고 문서**: `react-api-integration-plan.md`, `erp-api-development-plan-d1.0-changes.md`
> **참조 구현**: 단가관리 (`/sales/pricing-management`)
---
## 1. 개요
### 1.1 현황 분석
**목업 데이터 사용 페이지**: 80개+ 파일에서 목업 데이터 사용 중
```
┌─────────────────────────────────────────────────────────────────┐
│ 🎯 연동 목표 │
├─────────────────────────────────────────────────────────────────┤
│ - React 목업 데이터 → 실제 API 호출로 전환 │
│ - 단가관리(pricing-management) 패턴을 표준으로 적용 │
│ - Phase A~B (API 완료 기능) 우선 연동 │
└─────────────────────────────────────────────────────────────────┘
```
### 1.4 전수 조사 결과 (2025-12-26 최신)
> MCP Serena를 활용한 React 전체 Mock 데이터 사용 현황 전수 조사 결과
#### 🔍 발견된 주요 패턴
| 문제 유형 | 파일 수 | 설명 |
|----------|---------|------|
| **mockData.ts 파일** | 8개 | 별도 Mock 데이터 파일 (삭제 필요) |
| **MOCK_* 상수** | 15개+ | 인라인 Mock 상수 |
| **console.log CRUD** | 40개+ | API 대신 console.log 출력 |
| **TODO 주석** | 30개+ | 미구현 기능 |
#### 🚨 "완료" 표시됐지만 잔여 작업 있는 Phase
| Phase | 항목 | 발견된 문제 |
|-------|------|------------|
| B-2 | 매입 관리 | **MOCK_ACCOUNTS, MOCK_VENDORS** 사용 (PurchaseDetailModal) |
| C-1 | 직원 관리 | `TODO: 파일 업로드`, `console.log('Invite user')` |
| D-4 | 근태 설정 | **MOCK_DEPARTMENTS** 사용 |
| F-1~4 | 결재 시스템 | **MOCK_EMPLOYEES** 사용 (결재선/참조자 선택) |
#### 📋 문서에 누락된 모듈 (Phase J~L로 추가됨)
| 카테고리 | 경로 | Mock 사용 현황 |
|----------|------|---------------|
| **게시판** | `/board/*` | MOCK_BOARDS, MOCK_DEPARTMENTS |
| **FAQ** | `/customer-center/faq` | MOCK_FAQS 전체 사용 |
| **이벤트** | `/customer-center/events` | MOCK_EVENTS 전체 사용 |
| **문의** | `/customer-center/inquiries` | MOCK_INQUIRIES, MOCK_REPLY, MOCK_COMMENTS |
| **공지사항** | `/customer-center/notices` | MOCK_NOTICES 전체 사용 |
| **공정관리** | `/master-data/process-management` | ✅ **완료** (2025-12-26) |
| **견적** | `/sales/quote-management` | ✅ **완료** (2025-12-26) |
#### 📁 mockData.ts 삭제 대상
```
react/src/components/
├── production/ProductionDashboard/mockData.ts ← G-3
├── production/WorkOrders/mockData.ts ← G-1 (부분 사용)
├── production/WorkResults/mockData.ts ← G-2 (부분 사용)
├── quality/InspectionManagement/mockData.ts ← G-5
├── material/ReceivingManagement/mockData.ts ← H-1 연동 완료
├── material/StockStatus/mockData.ts ← H-2 연동 완료
├── outbound/ShipmentManagement/mockData.ts ← H-3 연동 완료
└── reports/mockData.ts ← 확인 필요
```
### 1.5 작업 진행 정책
> **단위 작업 → 검수 → 승인 → 문서 업데이트 → 커밋** 순서로 진행
### 1.6 세션 규칙 및 Serena 메모리 관리
> **세션 간 일관성 보장을 위한 필수 규칙**
#### 세션 시작 프로토콜 (필수)
```
1. Serena 메모리 로드
read_memory("mock-to-api-state") → 현재 Phase/작업 확인
read_memory("mock-to-api-snapshot") → 마지막 작업 내용 확인
2. 현재 상태 확인
- 이 문서 읽기
- 현재 Phase의 기능별 상태 확인
- "다음 작업은 [Phase]-[번호]의 [기능] 입니다" 명시
3. 작업 범위 명확화
- 사용자에게 작업 범위 확인
- "[Phase] 전체를 진행할까요, 특정 기능만 진행할까요?"
```
#### Serena 메모리 구조
```javascript
// mock-to-api-state
{
"current_phase": "G",
"current_item": "G-1",
"current_feature": "목록 조회",
"progress": {
"G-1": { "목록": "완료", "상세": "진행중", "등록": "대기" }
},
"last_update": "2025-12-26 14:30"
}
// mock-to-api-snapshot
"G-1 작업지시관리: 목록 조회 API 연동 완료.
다음: 상세 조회 연동 예정"
```
#### 작업 완료 시 (필수)
```
1. 문서 업데이트
- 해당 기능 상태 변경 (⏳ → ✅)
- 변경 이력 추가
2. Serena 메모리 저장
write_memory("mock-to-api-state", 현재 상태)
write_memory("mock-to-api-snapshot", 작업 내용 요약)
3. 커밋
feat: [Phase]-[번호] [페이지명] Mock → API 연동
```
### 1.7 작업 템플릿 (표준)
> **각 기능별 작업 시 사용하는 표준 템플릿**
```markdown
## [Phase-번호] 페이지명 - [기능명] 연동
**작업 대상:**
- 컴포넌트: `ComponentName.tsx`
- 액션: `actions.ts`
- API: `GET/POST/PUT/DELETE /api/v1/endpoint`
**작업 절차:**
1. [ ] API 스펙 확인 (Swagger)
2. [ ] actions.ts 함수 확인/생성
3. [ ] 타입 정의 확인 (API ↔ Frontend)
4. [ ] 컴포넌트에서 actions 호출
5. [ ] console.log/MOCK 제거
6. [ ] 브라우저 테스트
**결과:**
- [ ] 검수 요청
- [ ] [승인] 문서 업데이트
- [ ] [승인] 커밋
```
```
┌─────────────────────────────────────────────────────────────────┐
│ 📋 작업 흐름 (페이지 단위) │
├─────────────────────────────────────────────────────────────────┤
│ 1⃣ 작업 시작: 대상 페이지 Mock → API 연동 작업 │
│ 2⃣ 작업 완료: 코드 수정 완료 후 사용자에게 검수 요청 │
│ 3⃣ 검수: 사용자가 기능 확인 (브라우저 테스트) │
│ 4⃣ [승인] 문서 업데이트: 이 문서의 상태 갱신 │
│ 5⃣ [승인] 커밋: Git 커밋 생성 │
│ 6⃣ 다음 페이지로 이동 │
└─────────────────────────────────────────────────────────────────┘
```
**⚠️ 중요 규칙:**
- 각 단계에서 `[승인]` 표시된 작업은 **사용자 승인 후** 진행
- 한 번에 하나의 페이지만 작업 (병렬 작업 금지)
- 검수 실패 시 수정 후 재검수
- 커밋 메시지: `feat: [Phase]-[번호] [페이지명] Mock → API 연동`
**📌 현재 진행 순서:**
1. ~~A-1 악성채권~~ *(완료 - 상세+CRUD+메모 API 연동)*
2. ~~A-2 팝업 관리~~ *(완료 - 상세+CRUD API 연동)*
3. A-3 결제 내역 (조회 전용, 완료)
4. A-4 구독 관리 (조회 전용, 완료)
5. A-5 알림 설정 (완료)
6. B-1 매출 관리
7. B-2 매입 관리
8. B-3 입금 관리
9. B-4 출금 관리
10. B-5 거래처 관리
11. B-6 어음 관리
### 1.2 단가관리 연동 패턴 (표준 참조)
```
┌─────────────────────────────────────────────────────────────────┐
│ 📂 파일 구조 │
├─────────────────────────────────────────────────────────────────┤
│ react/src/ │
│ ├── app/[locale]/(protected)/sales/pricing-management/ │
│ │ └── page.tsx ← 서버 컴포넌트 (API 호출) │
│ │ │
│ └── components/pricing/ │
│ ├── types.ts ← 타입 정의 │
│ ├── actions.ts ← Server Actions (CRUD) │
│ ├── PricingListClient.tsx ← 클라이언트 컴포넌트 │
│ └── index.ts ← Export │
└─────────────────────────────────────────────────────────────────┘
```
**데이터 흐름:**
```
page.tsx (서버)
↓ API 호출 (fetch)
↓ 데이터 변환 (API → Frontend)
↓ initialData prop 전달
ListClient.tsx (클라이언트)
↓ useState로 데이터 관리
↓ UI 렌더링
```
### 1.3 핵심 패턴 요약
| 구분 | 파일 | 역할 |
|------|------|------|
| 타입 | `types.ts` | 프론트엔드 인터페이스 정의 |
| 서버 페이지 | `page.tsx` | API 호출, 데이터 병합, 초기 데이터 전달 |
| 서버 액션 | `actions.ts` | CRUD 작업, 데이터 변환 함수 |
| 클라이언트 | `*Client.tsx` | UI 렌더링, 사용자 상호작용 |
---
## 2. 우선순위별 연동 대상
> **상태 범례**:
> - ✅ 완료: API 연동 완료 (Server Actions 호출)
> - 🔄 Mock: Mock 데이터 또는 console.log 사용
> - ⚠️ API 필요: 백엔드 API 개발 선행 필요
> - ⏭️ 건너뜀: API 미존재 또는 해당 없음
> - 📦 actions.ts: Server Actions 파일 존재 (UI 연동 필요)
### 2.1 Phase A: API 완료 기능 (즉시 연동 가능)
> 이미 API가 구현되어 있어 React 연동만 필요
> **⚠️ 2025-12-24 전수 조사 결과**: 리스트 API 연동 완료했으나 상세/CRUD 작업에서 Mock 사용 확인
| # | 페이지 | React 경로 | 리스트 | 상세 조회 | 등록 | 수정 | 삭제 | 비고 |
|---|--------|-----------|--------|----------|------|------|------|------|
| A-1 | 악성채권 관리 | `/accounting/bad-debt-collection` | ✅ | ✅ | ✅ | ✅ | ✅ | 상세+CRUD+메모 API 연동 완료 (2025-12-24) |
| A-2 | 팝업 관리 | `/settings/popup-management` | ✅ | ✅ | ✅ | ✅ | ✅ | 상세+CRUD API 연동 완료 (2025-12-24) |
| A-3 | 결제 내역 | `/settings/payment-history` | ✅ | ⏭️ | ⏭️ | ⏭️ | ⏭️ | 조회 전용 |
| A-4 | 구독 관리 | `/settings/subscription` | ✅ | ⏭️ | ⏭️ | ⏭️ | ⏭️ | 조회 전용 |
| A-5 | 알림 설정 | `/settings/notifications` | ✅ | ⏭️ | ⏭️ | ✅ | ⏭️ | 저장 기능 완료 |
### 2.2 Phase B: 핵심 업무 기능
> **⚠️ 2025-12-24 전수 조사 결과**: actions.ts 존재하나 UI에서 console.log로 Mock 처리
| # | 페이지 | React 경로 | 리스트 | 상세 조회 | 등록 | 수정 | 삭제 | 비고 |
|---|--------|-----------|--------|----------|------|------|------|------|
| B-1 | 매출 관리 | `/accounting/sales` | ✅ | ✅ | ✅ | ✅ | ✅ | API 연동 완료, alert→toast 변환 |
| B-2 | 매입 관리 | `/accounting/purchase` | ✅ | ✅ | ✅ | ✅ | ✅ | API 연동 완료, alert→toast 변환 |
| B-3 | 입금 관리 | `/accounting/deposit` | ✅ | ✅ | ✅ | ✅ | ✅ | API 연동 완료, alert→toast 변환 |
| B-4 | 출금 관리 | `/accounting/withdrawal` | ✅ | ✅ | ✅ | ✅ | ✅ | API 연동 완료, alert→toast 변환 |
| B-5 | 거래처 관리 | `/accounting/vendor` | ✅ | ✅ | ✅ | ✅ | ✅ | API 연동 완료, console.error 제거 |
| B-6 | 어음 관리 | `/accounting/bills` | ✅ | ⏭️ 모달 | ✅ | ✅ | ✅ | API 연동 완료 |
### 2.3 Phase C: 인사/근태
> **2025-12-24 분석 결과**: API 존재, 전체 Mock 사용 중
| # | 페이지 | React 경로 | 리스트 | 상세 조회 | 등록 | 수정 | 삭제 | 비고 |
|---|--------|-----------|--------|----------|------|------|------|------|
| C-1 | 직원 관리 | `/hr/employee-management` | ✅ | ✅ | ✅ | ✅ | ✅ | **2025-12-24 연동 완료** - actions.ts, utils.ts 생성, 전체 CRUD API 연동 |
| C-2 | 근태 관리 | `/hr/attendance` | ✅ | ⏭️ | ✅ | ⏭️ | ⏭️ | **2025-12-24 연동 완료** - actions.ts 생성, check-in/check-out/today API 연동 |
| C-3 | 휴가 관리 | `/hr/vacation-management` | ✅ | ⏭️ | ✅ | ⏭️ | ⏭️ | **2025-12-24 연동 완료** - actions.ts 생성, 신청현황 탭 API 연동 (목록/승인/반려/신청), 사용현황/부여현황 탭 API 연동 |
| C-4 | 부서 관리 | `/hr/departments` | ✅ | ⏭️ | ✅ | ✅ | ✅ | **2025-12-24 연동 완료** - actions.ts 생성, 트리 조회/생성/수정/삭제 API 연동 |
### 2.4 Phase D: 설정/시스템 관리
> **2025-12-24 분석 결과**: 대부분 Mock, console.log로 저장 처리
| # | 페이지 | React 경로 | 리스트 | 상세 조회 | 등록 | 수정 | 삭제 | 비고 |
|---|--------|-----------|--------|----------|------|------|------|------|
| D-1 | 회사 정보 관리 | `/settings/company-info` | ✅ | ⏭️ | ⏭️ | ✅ | ⏭️ | **2025-12-24 연동 완료** - actions.ts 생성, API 조회/수정 연동 |
| D-2 | 계정 관리 | `/settings/accounts` | ✅ | ✅ | ✅ | ✅ | ✅ | **2025-12-24 연동 완료** - actions.ts 생성, CRUD API 연동 |
| D-3 | 근무 일정 관리 | `/settings/work-schedule` | ✅ | ⏭️ | ⏭️ | ✅ | ⏭️ | **2025-12-24 연동 완료** - actions.ts 생성, 조회/수정 API 연동 |
| D-4 | 근태 설정 관리 | `/settings/attendance-settings` | ✅ | ⏭️ | ⏭️ | ✅ | ⏭️ | **2025-12-24 연동 완료** - actions.ts 생성, GPS/허용반경 API 연동 |
### 2.5 Phase E: 인사/급여
> **2025-12-25 완료**: API 연동 완료
| # | 페이지 | React 경로 | 리스트 | 상세 조회 | 등록 | 수정 | 삭제 | 비고 |
|---|--------|-----------|--------|----------|------|------|------|------|
| E-1 | 법인카드 관리 | `/hr/card-management` | ✅ | ✅ | ✅ | ✅ | ✅ | **2025-12-25 완료** - `actions.ts` 생성, CRUD+토글+일괄삭제 API 연동, CardForm 직원목록 API 연동 |
| E-2 | 급여 관리 | `/hr/salary` | ✅ | ✅ | ⏭️ | ✅ | ⏭️ | **2025-12-25 완료** - Salary API 신규 생성, `actions.ts` 생성, 목록/상세/상태변경/일괄상태변경 API 연동 |
### 2.6 Phase F: 결재 시스템
> **2025-12-25 완료**: 전체 API 연동 완료
| # | 페이지 | React 경로 | 리스트 | 상세 조회 | 등록 | 수정 | 삭제 | 비고 |
|---|--------|-----------|--------|----------|------|------|------|------|
| F-1 | 기안함 | `/approval/draft-box` | ✅ | ⏭️ | ⏭️ | ⏭️ | ✅ | **2025-12-25 완료** - `actions.ts` 생성, 목록/삭제/일괄삭제 API 연동 |
| F-2 | 참조함 | `/approval/reference-box` | ✅ | ⏭️ | ⏭️ | ⏭️ | ⏭️ | **2025-12-25 완료** - `actions.ts` 생성, 목록/열람처리/일괄처리 API 연동 |
| F-3 | 결재함 | `/approval/approval-box` | ✅ | ⏭️ | ⏭️ | ⏭️ | ⏭️ | **2025-12-25 완료** - `actions.ts` 생성, 목록/승인/반려/일괄처리 API 연동 |
| F-4 | 비용견적서 양식 | `/approval/create/expense-estimate` | ⏭️ | ⏭️ | ✅ | ⏭️ | ⏭️ | **2025-12-25 완료** - `actions.ts` 생성, 비용견적서 항목조회/문서생성/상신 API 연동 |
### 2.7 Phase G: 생산 관리
> **2025-12-26 완료**: 전체 API 연동 완료
| # | 페이지 | React 경로 | 리스트 | 상세 조회 | 등록 | 수정 | 삭제 | 비고 |
|---|--------|-----------|--------|----------|------|------|------|------|
| G-1 | 작업지시 관리 | `/production/work-orders` | ✅ | ✅ | ✅ | ⏭️ | ⏭️ | **2025-12-26 완료** - `actions.ts` 생성, 목록/상세/등록/담당자선택/수주선택 API 연동 |
| G-2 | 작업실적 관리 | `/production/work-results` | ✅ | ⏭️ | ⏭️ | ⏭️ | ⏭️ | **2025-12-26 완료** - `actions.ts` 생성, 목록/통계 API 연동 |
| G-3 | 생산 대시보드 | `/production/dashboard` | ✅ | ⏭️ | ⏭️ | ⏭️ | ⏭️ | **2025-12-26 완료** - `actions.ts` 생성, 대시보드 데이터 API 연동 |
| G-4 | 작업자 화면 | `/production/worker-screen` | ✅ | ⏭️ | ✅ | ⏭️ | ⏭️ | **2025-12-26 완료** - `actions.ts` 생성, 작업목록/완료/자재투입/공정단계/검사요청 API 연동 |
| G-5 | 품질 검사 | `/quality/inspection` | ✅ | ✅ | ✅ | ✅ | ⏭️ | **2025-12-26 완료** - `actions.ts` 생성, 목록/상세/등록/수정 API 연동 |
### 2.8 Phase H: 자재/출하 관리
> **2025-12-24 분석 결과**: 전체 Mock (mockData.ts 파일 사용)
| # | 페이지 | React 경로 | 리스트 | 상세 조회 | 등록 | 수정 | 삭제 | 비고 |
|---|--------|-----------|--------|----------|------|------|------|------|
| H-1 | 입고 관리 | `/material/receiving` | ✅ | ✅ | ✅ | ✅ | ✅ | **2025-12-26 연동 완료** - `actions.ts` 생성, 목록/상세/등록/수정/삭제/통계/옵션 API 연동 |
| H-2 | 재고 현황 | `/material/stock-status` | ✅ | ✅ | ⏭️ | ⏭️ | ⏭️ | **2025-12-26 연동 완료** - `actions.ts` 생성, 목록/상세/통계/옵션 API 연동 |
| H-3 | 출하 관리 | `/outbound/shipment` | ✅ | ✅ | ✅ | ✅ | ✅ | **2025-12-26 연동 완료** - `actions.ts` 생성, 목록/상세/등록/수정/삭제/통계/옵션 API 연동 |
### 2.9 Phase I: API 연동 및 UI 완성도 개선
> **2025-12-26 완료**: 전체 항목 API 연동 및 UI CRUD 기능 보완 완료
| # | 페이지 | React 경로 | 조회 | 등록 | 수정 | 삭제 | 기타 | 비고 |
|---|--------|-----------|------|------|------|------|------|------|
| I-1 | 미지급비용 관리 | `/accounting/expected-expense` | ✅ | ✅ | ✅ | ✅ | 예상지급일변경 ✅ | **2025-12-26 완료** - 등록/수정 폼 다이얼로그, 삭제/일괄삭제 구현 |
| I-2 | 거래처 원장 | `/accounting/vendor-ledger` | ✅ | ⏭️ | ⏭️ | ⏭️ | 상세이동 ✅, 엑셀/PDF ✅ | **조회전용** - exportVendorLedgerExcel, exportVendorLedgerDetailPdf API 연동 |
| I-3 | 카드 거래 조회 | `/accounting/card-transaction` | ✅ | ⏭️ | ✅ | ⏭️ | 계정과목 일괄수정 ✅ | **외부연동 데이터** (등록/삭제 불필요) |
| I-4 | 은행 거래 조회 | `/accounting/bank-transaction` | ✅ | ⏭️ | ✅ | ⏭️ | - | **2025-12-26 확인** - 수정은 상세 페이지 이동 방식 (deposits/{id}?mode=edit) |
| I-5 | 채권 현황 | `/accounting/receivables-status` | ✅ | ⏭️ | ✅ | ⏭️ | 연체토글 ✅, 엑셀 ✅ | **2025-12-26 완료** - updateOverdueStatus, exportReceivablesExcel API 연동 |
| I-6 | 일일 보고서 | `/accounting/daily-report` | ✅ | ⏭️ | ⏭️ | ⏭️ | 엑셀 ✅ | **조회전용 리포트** - exportDailyReportExcel API 연동 |
| I-7 | 종합 분석 보고서 | `/reports/comprehensive-analysis` | ✅ | ⏭️ | ⏭️ | ⏭️ | 이슈승인 ✅ | **2025-12-26 완료** - approveIssue/rejectIssue API 연동 |
| I-8 | 휴가 정책 관리 | `/settings/leave-policy` | ✅ | ⏭️ | ✅ | ⏭️ | - | ✅ **완료** (단일 레코드 설정 관리) |
#### Phase I 상세 분석 (2025-12-26)
**I-1 미지급비용 관리 (ExpectedExpenseManagement)**
- **actions.ts**: `getExpectedExpenseList`, `createExpectedExpense`, `updateExpectedExpense`, `deleteExpectedExpense`, `bulkDeleteExpectedExpenses`, `updateExpectedPaymentDate`
- **UI 현황**: 목록 조회 ✅, 예상지급일 변경 ✅, **등록 폼/모달 ❌**, **수정 폼/모달 ❌**, **삭제 버튼 ❌**, **일괄삭제 버튼 ❌**
- **필요 작업**: UI에 등록/수정/삭제 기능 연동 (API는 완료)
**I-2 거래처 원장 (VendorLedger)**
- **actions.ts**: `getVendorLedgerList`, `getVendorLedgerSummary`, `getVendorLedgerDetail`
- **특성**: 거래처별 매출/수금 집계 조회 기능 → **CRUD 불필요** (읽기전용이 정상)
- **상태**: ✅ 완료 (조회전용)
**I-3 카드거래조회 (CardTransactionInquiry)**
- **actions.ts**: `getCardTransactionList`, `getCardTransactionSummary`, `bulkUpdateAccountCode`
- **특성**: 외부 카드사 연동 데이터 → 등록/삭제 불필요, **계정과목 수정만 필요**
- **UI 현황**: 조회 ✅, 체크박스 선택 ✅, 계정과목 일괄수정 Dialog ✅
- **상태**: ✅ 완료
**I-4 은행거래조회 (BankTransactionInquiry)**
- **actions.ts**: `getBankTransactionList`, `getBankTransactionSummary`, `getBankAccountOptions`
- **특성**: 외부 은행 연동 데이터 → 등록/삭제 불필요
- **UI 현황**: 조회 ✅, 수정 아이콘(Pencil) 있으나 **수정 API 없음**
- **필요 작업**: 은행거래 수정 API 개발 또는 수정 기능 제거 결정 필요
**I-5 채권현황 (ReceivablesStatus)**
- **actions.ts**: `getReceivablesList`, `getReceivablesSummary`
- **특성**: 거래처별 월별 채권 집계 데이터 → **CRUD 불필요**
- **UI 현황**: 조회 ✅, 연체 토글 Switch (UI만, API 미연동), 저장/엑셀 버튼 (placeholder)
- **필요 작업**: 연체 토글 저장 API 개발 및 연동
**I-6 일일보고서 (DailyReport)**
- **actions.ts**: `getNoteReceivables`, `getDailyAccounts`, `getDailyReportSummary`
- **특성**: 일별 어음/계좌 현황 집계 리포트 → **CRUD 불필요**
- **상태**: ✅ 완료 (조회전용)
**I-7 종합분석 (ComprehensiveAnalysis)**
- **actions.ts**: `getComprehensiveAnalysis` ✅ (reports/actions.ts)
- **특성**: 경영 대시보드 → **CRUD 불필요**
- **UI 현황**: 대시보드 카드/체크포인트 ✅, 오늘 이슈 승인/거절 버튼 (UI만, API 미연동)
- **필요 작업**: 이슈 승인/거절 API 개발 및 연동 (선택사항)
**I-8 휴가 정책 관리 (LeavePolicyManagement)**
- **actions.ts**: `getLeavePolicy`, `updateLeavePolicy`
- **특성**: 단일 레코드 설정 관리 → 등록/삭제 불필요
- **상태**: ✅ 완료
> **Phase J (게시판), Phase K (고객센터)**: `react-mock-remaining-tasks.md`로 분리됨
### 2.10 Phase L: 기타 모듈
> **2025-12-26 전수 조사 결과**: TODO + console.log 사용
| # | 페이지 | React 경로 | 조회 | 등록 | 수정 | 삭제 | 비고 |
|---|--------|-----------|------|------|------|------|------|
| L-1 | 공정 관리 | `/master-data/process-management` | ✅ | ✅ | ✅ | ✅ | **2025-12-26 완료** - Backend API + React 연동 |
| L-2 | 견적 관리 | `/sales/quote-management` | ✅ | ✅ | ✅ | ✅ | **2025-12-26 완료** |
| L-3 | 종합 분석 | `/reports/comprehensive-analysis` | ✅ | ⏭️ | ⏭️ | ⏭️ | ✅ **완료** - approveIssue/rejectIssue API 연동 (I-7에서 완료) |
**L-1 공정 관리:****2025-12-26 완료**
- Backend API 신규 개발 (ProcessController, ProcessService, Process 모델)
- `ProcessListClient.tsx` - API 연동 완료 (삭제 확인 모달, 일괄삭제, 상태토글)
- `ProcessForm.tsx` - API 연동 완료 (등록/수정)
- `actions.ts` - Server Actions 신규 생성
**L-2 견적 관리:****2025-12-26 완료**
- `quotes/types.ts` - Quote, QuoteItem, QuoteStatus, ProductCategory 타입 정의, QuoteFormData 변환 함수
- `quotes/actions.ts` - 전체 CRUD + finalize/cancel/convert/PDF/email/kakao API (14개 Server Action)
- `quotes/index.ts` - 모듈 통합 export
- `page.tsx` - 목록 Server Component (SSR 초기 데이터)
- `QuoteManagementClient.tsx` - 목록 Client Component
- `[id]/page.tsx` - 상세 페이지 (getQuoteById, finalizeQuote, convertQuoteToOrder, sendQuoteEmail, sendQuoteKakao)
- `[id]/edit/page.tsx` - 수정 페이지 (getQuoteById, updateQuote)
- `new/page.tsx` - 등록 페이지 (createQuote)
**L-3 종합 분석:**
- `ComprehensiveAnalysis/index.tsx` - ✅ **완료** - approveIssue/rejectIssue API 연동 (I-7에서 완료)
### 2.11 Phase M: 잔여 작업 (Phase A-F 보완)
> **2025-12-26 완료**: 모든 잔여 Mock/TODO 제거 완료
| # | 페이지 | 문제 유형 | 상세 | 상태 |
|---|--------|----------|------|------|
| M-1 | 매입 상세 모달 | **MOCK 상수** | `MOCK_ACCOUNTS`, `MOCK_VENDORS` → getBankAccounts, getVendors API | ✅ |
| M-2 | 직원 관리 | **TODO** | 파일 업로드 → uploadProfileImage API (Invite API 백엔드 미구현) | ✅ |
| M-3 | 근태 설정 | **MOCK 상수** | `MOCK_DEPARTMENTS` → 이전 Phase에서 완료 | ✅ |
| M-4 | 결재 문서 생성 | **MOCK 상수** | `MOCK_EMPLOYEES` → getEmployees API | ✅ |
| M-5 | 결재함/기안함 | **console.log** | 승인/반려 → API 연동, 수정/복제 → 백엔드 API 필요 | ✅ |
| M-6 | 구독 관리 | **TODO** | 자료 내보내기 → requestDataExport, 서비스 해지 → cancelSubscription | ✅ |
| M-7 | 계정 정보 | **TODO** | 탈퇴 → withdrawAccount, 사용중지 → suspendTenant | ✅ |
**잔여 백엔드 API 개발 필요 항목:**
- 직원 관리: Invite user API (POST /api/v1/employees/invite)
- 결재함: 수정(edit)/복제(copy) API
### 2.12 상세 페이지 Mock 현황
> **2025-12-26 완료**: 모든 상세 페이지 API 연동 완료
| # | 컴포넌트 | 파일 위치 | 상태 | 완료 Phase |
|---|----------|----------|------|-----------|
| S-1 | SalesDetail | `SalesManagement/SalesDetail.tsx` | ✅ | B-1 매출 관리 |
| S-2 | PurchaseDetail | `PurchaseManagement/PurchaseDetail.tsx` | ✅ | B-2 매입 관리 |
| S-3 | DepositDetail | `DepositManagement/DepositDetail.tsx` | ✅ | B-3 입금 관리 |
| S-4 | WithdrawalDetail | `WithdrawalManagement/WithdrawalDetail.tsx` | ✅ | B-4 출금 관리 |
| S-5 | VendorDetail | `VendorManagement/VendorDetail.tsx` | ✅ | B-5 거래처 관리 |
| S-6 | BadDebtDetail | `BadDebtCollection/BadDebtDetail.tsx` | ✅ | A-1 악성채권 관리 |
| S-7 | StockStatusDetail | `StockStatus/StockStatusDetail.tsx` | ✅ | H-2 재고 현황 |
| S-8 | ShipmentDetail | `ShipmentManagement/ShipmentDetail.tsx` | ✅ | H-3 출하 관리 |
| S-9 | ReceivingDetail | `ReceivingManagement/ReceivingDetail.tsx` | ✅ | H-1 입고 관리 |
| S-10 | WorkOrderDetail | `WorkOrders/WorkOrderDetail.tsx` | ✅ | G-1 작업지시 관리 |
> **참고**: `PurchaseDetailModal.tsx`의 MOCK_ACCOUNTS, MOCK_VENDORS는 Phase M-1에서 완료 (2025-12-26)
---
## 3. 연동 작업 가이드
### 3.1 표준 연동 절차
```
Step 1: 현재 상태 분석
├── 목업 데이터 구조 확인 (types.ts)
├── 클라이언트 컴포넌트 props 확인 (*Client.tsx)
└── API 스펙 확인 (Swagger: sam.kr/api-docs)
Step 2: 타입 정의 정비
├── API 응답 타입 추가 (xxxApiData)
├── 변환 함수 타입 정의
└── 기존 프론트엔드 타입 유지
Step 3: 서버 컴포넌트 수정 (page.tsx)
├── API 호출 함수 구현
├── 데이터 변환 함수 구현
└── initialData prop 전달
Step 4: 서버 액션 구현 (actions.ts)
├── CRUD 함수 구현 (create, update, delete)
├── transformApiToFrontend() 함수
└── transformFrontendToApi() 함수
Step 5: 클라이언트 컴포넌트 연동
├── Server Actions import
├── 핸들러 함수에서 Server Actions 호출
└── 로딩/에러 상태 처리
```
### 3.2 체크리스트
```
□ API 엔드포인트 확인 (Swagger)
□ 응답 데이터 구조 확인
□ 타입 정의 (API 응답 타입 + 프론트엔드 타입)
□ 변환 함수 구현 (API ↔ Frontend)
□ 서버 컴포넌트에서 API 호출
□ 클라이언트 컴포넌트에 initialData 전달
□ Server Actions 구현 (CRUD)
□ 에러 처리 (try-catch, 사용자 알림)
□ 로딩 상태 처리
□ 브라우저 테스트
```
---
## 4. 상세 구현 가이드
### 4.1 page.tsx 패턴
```typescript
// app/[locale]/(protected)/[feature]/page.tsx
import { cookies } from 'next/headers';
import { FeatureListClient } from '@/components/feature';
// API 응답 타입
interface ApiData {
id: number;
// ... API 필드
}
// API 헤더 생성
async function getApiHeaders(): Promise<HeadersInit> {
const cookieStore = await cookies();
const token = cookieStore.get('access_token')?.value;
return {
'Accept': 'application/json',
'Authorization': token ? `Bearer ${token}` : '',
'X-API-KEY': process.env.NEXT_PUBLIC_API_KEY || '',
};
}
// API 호출
async function getList(): Promise<ApiData[]> {
try {
const headers = await getApiHeaders();
const response = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}/api/v1/feature`,
{ method: 'GET', headers, cache: 'no-store' }
);
if (!response.ok) return [];
const result = await response.json();
return result.success ? result.data.data : [];
} catch (error) {
console.error('[FeaturePage] Fetch error:', error);
return [];
}
}
// 데이터 변환
function transformToFrontend(apiData: ApiData[]): FeatureListItem[] {
return apiData.map(item => ({
id: String(item.id),
// ... 필드 매핑
}));
}
// 페이지 컴포넌트
export default async function FeaturePage() {
const apiData = await getList();
const data = transformToFrontend(apiData);
return <FeatureListClient initialData={data} />;
}
```
### 4.2 actions.ts 패턴
```typescript
// components/feature/actions.ts
'use server';
import { cookies } from 'next/headers';
import type { FeatureData } from './types';
async function getApiHeaders(): Promise<HeadersInit> {
const cookieStore = await cookies();
const token = cookieStore.get('access_token')?.value;
return {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': token ? `Bearer ${token}` : '',
'X-API-KEY': process.env.API_KEY || '',
};
}
// API → Frontend 변환
function transformApiToFrontend(apiData: ApiData): FeatureData {
return {
id: String(apiData.id),
// ... 필드 매핑
};
}
// Frontend → API 변환
function transformFrontendToApi(data: FeatureData): Record<string, unknown> {
return {
// ... 필드 매핑 (snake_case)
};
}
// 등록
export async function createFeature(
data: FeatureData
): Promise<{ success: boolean; data?: FeatureData; error?: string }> {
try {
const headers = await getApiHeaders();
const apiData = transformFrontendToApi(data);
const response = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}/api/v1/feature`,
{
method: 'POST',
headers,
body: JSON.stringify(apiData),
}
);
const result = await response.json();
if (!response.ok || !result.success) {
return { success: false, error: result.message };
}
return { success: true, data: transformApiToFrontend(result.data) };
} catch (error) {
return { success: false, error: '서버 오류가 발생했습니다.' };
}
}
// 수정
export async function updateFeature(
id: string,
data: FeatureData
): Promise<{ success: boolean; data?: FeatureData; error?: string }> {
// ... 유사 패턴
}
// 삭제
export async function deleteFeature(
id: string
): Promise<{ success: boolean; error?: string }> {
// ... 유사 패턴
}
```
### 4.3 ListClient.tsx 연동 패턴
```typescript
// components/feature/FeatureListClient.tsx
'use client';
import { useState } from 'react';
import { createFeature, updateFeature, deleteFeature } from './actions';
import { toast } from 'sonner';
interface FeatureListClientProps {
initialData: FeatureListItem[];
}
export function FeatureListClient({ initialData }: FeatureListClientProps) {
const [data, setData] = useState<FeatureListItem[]>(initialData);
const [isLoading, setIsLoading] = useState(false);
const handleCreate = async (formData: FeatureData) => {
setIsLoading(true);
const result = await createFeature(formData);
if (result.success && result.data) {
setData(prev => [...prev, result.data!]);
toast.success('등록되었습니다.');
} else {
toast.error(result.error || '등록에 실패했습니다.');
}
setIsLoading(false);
};
const handleUpdate = async (id: string, formData: FeatureData) => {
setIsLoading(true);
const result = await updateFeature(id, formData);
if (result.success && result.data) {
setData(prev => prev.map(item =>
item.id === id ? result.data! : item
));
toast.success('수정되었습니다.');
} else {
toast.error(result.error || '수정에 실패했습니다.');
}
setIsLoading(false);
};
const handleDelete = async (id: string) => {
setIsLoading(true);
const result = await deleteFeature(id);
if (result.success) {
setData(prev => prev.filter(item => item.id !== id));
toast.success('삭제되었습니다.');
} else {
toast.error(result.error || '삭제에 실패했습니다.');
}
setIsLoading(false);
};
// ... 나머지 UI 렌더링
}
```
---
## 5. 필드 매핑 규칙
### 5.1 네이밍 컨벤션
| API (snake_case) | Frontend (camelCase) |
|------------------|---------------------|
| `created_at` | `createdAt` |
| `updated_at` | `updatedAt` |
| `item_type` | `itemType` |
| `purchase_price` | `purchasePrice` |
| `sales_price` | `salesPrice` |
| `is_active` | `isActive` |
### 5.2 타입 변환
| API 타입 | Frontend 타입 | 변환 |
|---------|--------------|------|
| `number` (id) | `string` | `String(id)` |
| `string` (decimal) | `number` | `parseFloat(value)` |
| `string` (date) | `string` | 그대로 또는 포맷팅 |
| `null` | `undefined` | `value ?? undefined` |
### 5.3 상태 매핑 예시
```typescript
// API 상태 → Frontend 상태
function mapStatus(apiStatus: string): FrontendStatus {
switch (apiStatus) {
case 'draft': return 'draft';
case 'active': return 'active';
case 'finalized': return 'finalized';
default: return 'draft';
}
}
```
---
## 6. Phase B 상세 필드 매핑
> 이 섹션은 신규 세션에서 바로 개발 가능하도록 상세 스펙을 포함합니다.
### 6.1 매출 관리 (Sales)
**API FormRequest 필드** (`api/app/Http/Requests/V1/Sale/StoreSaleRequest.php`):
```php
'sale_date' => ['required', 'date'],
'client_id' => ['required', 'integer', 'exists:clients,id'],
'supply_amount' => ['required', 'numeric', 'min:0'],
'tax_amount' => ['required', 'numeric', 'min:0'],
'total_amount' => ['required', 'numeric', 'min:0'],
'description' => ['nullable', 'string', 'max:1000'],
'deposit_id' => ['nullable', 'integer', 'exists:deposits,id'],
```
**React 인터페이스** (`react/src/components/accounting/SalesManagement/types.ts`):
```typescript
interface SalesRecord {
id: string;
salesNo: string; // 매출번호
salesDate: string; // 매출일
vendorId: string; // 거래처 ID
vendorName: string; // 거래처명
salesType: SalesType; // 매출 유형
accountSubject: string; // 계정과목
items: SalesItem[]; // 품목 목록
totalSupplyAmount: number; // 공급가액 합계
totalVat: number; // 부가세 합계
totalAmount: number; // 총 금액
receivedAmount: number; // 입금액
outstandingAmount: number; // 미수금액
taxInvoiceIssued: boolean; // 세금계산서 발행 여부
transactionStatementIssued: boolean; // 거래명세서 발행 여부
note: string; // 비고
status: SalesStatus; // 상태
createdAt: string;
updatedAt: string;
}
```
**필드 매핑 테이블**:
| API 필드 (snake_case) | React 필드 (camelCase) | 타입 변환 | 비고 |
|----------------------|----------------------|----------|------|
| `id` | `id` | `String(id)` | - |
| `sale_number` | `salesNo` | 그대로 | 시스템 자동 생성 |
| `sale_date` | `salesDate` | 그대로 | YYYY-MM-DD |
| `client_id` | `vendorId` | `String(client_id)` | FK |
| `client.name` | `vendorName` | 그대로 | 관계 조회 |
| `supply_amount` | `totalSupplyAmount` | `parseFloat()` | - |
| `tax_amount` | `totalVat` | `parseFloat()` | - |
| `total_amount` | `totalAmount` | `parseFloat()` | - |
| `description` | `note` | `?? ''` | - |
| `status` | `status` | 매핑 필요 | API: draft/confirmed/invoiced |
| `deposit_id` | `receivedAmount` | 관계 조회 | deposit.amount |
| `created_at` | `createdAt` | 그대로 | - |
| `updated_at` | `updatedAt` | 그대로 | - |
**상태 매핑**:
```typescript
// API → React
const SALES_STATUS_MAP = {
'draft': 'outstanding', // 미수
'confirmed': 'monthlyClose', // 당월마감
'invoiced': 'agreed', // 합의
};
```
---
### 6.2 매입 관리 (Purchases)
**API FormRequest 필드** (`api/app/Http/Requests/V1/Purchase/StorePurchaseRequest.php`):
```php
'purchase_date' => ['required', 'date'],
'client_id' => ['required', 'integer', 'exists:clients,id'],
'supply_amount' => ['required', 'numeric', 'min:0'],
'tax_amount' => ['required', 'numeric', 'min:0'],
'total_amount' => ['required', 'numeric', 'min:0'],
'description' => ['nullable', 'string', 'max:1000'],
'withdrawal_id' => ['nullable', 'integer', 'exists:withdrawals,id'],
```
**React 인터페이스** (`react/src/components/accounting/PurchaseManagement/types.ts`):
```typescript
interface PurchaseRecord {
id: string;
purchaseNo: string; // 매입번호
purchaseDate: string; // 매입일자
vendorId: string; // 거래처 ID
vendorName: string; // 거래처명
supplyAmount: number; // 공급가액
vat: number; // 부가세
totalAmount: number; // 합계금액
purchaseType: PurchaseType; // 매입유형
evidenceType: EvidenceType; // 증빙유형
status: PurchaseStatus; // 상태
items: PurchaseItem[]; // 품목 정보
taxInvoiceReceived: boolean; // 세금계산서 수취 여부
createdAt: string;
updatedAt: string;
}
```
**필드 매핑 테이블**:
| API 필드 (snake_case) | React 필드 (camelCase) | 타입 변환 | 비고 |
|----------------------|----------------------|----------|------|
| `id` | `id` | `String(id)` | - |
| `purchase_number` | `purchaseNo` | 그대로 | 시스템 자동 생성 |
| `purchase_date` | `purchaseDate` | 그대로 | YYYY-MM-DD |
| `client_id` | `vendorId` | `String(client_id)` | FK |
| `client.name` | `vendorName` | 그대로 | 관계 조회 |
| `supply_amount` | `supplyAmount` | `parseFloat()` | - |
| `tax_amount` | `vat` | `parseFloat()` | - |
| `total_amount` | `totalAmount` | `parseFloat()` | - |
| `description` | `note` | `?? ''` | 품목 적요용 |
| `status` | `status` | 그대로 | pending/completed/cancelled |
| `withdrawal_id` | - | 관계 조회 | 출금 연결 |
| `created_at` | `createdAt` | 그대로 | - |
| `updated_at` | `updatedAt` | 그대로 | - |
**매입유형 (purchaseType) 옵션**:
- `raw_material`: 원재료매입
- `subsidiary_material`: 부재료매입
- `product`: 상품매입
- `outsourcing`: 외주가공비
- `consumables`: 소모품비
- 기타 15종 (types.ts 참조)
---
### 6.3 입금 관리 (Deposits)
**API FormRequest 필드** (`api/app/Http/Requests/V1/Deposit/StoreDepositRequest.php`):
```php
'deposit_date' => ['required', 'date'],
'client_id' => ['nullable', 'integer', 'exists:clients,id'],
'client_name' => ['nullable', 'string', 'max:100'],
'bank_account_id' => ['nullable', 'integer', 'exists:bank_accounts,id'],
'amount' => ['required', 'numeric', 'min:0'],
'payment_method' => ['required', 'string', 'in:cash,transfer,card,check'],
'account_code' => ['nullable', 'string', 'max:20'],
'description' => ['nullable', 'string', 'max:1000'],
'reference_type' => ['nullable', 'string', 'max:50'],
'reference_id' => ['nullable', 'integer'],
```
**React 인터페이스** (`react/src/components/accounting/DepositManagement/types.ts`):
```typescript
interface DepositRecord {
id: string;
depositDate: string; // 입금일
depositAmount: number; // 입금액
accountName: string; // 입금계좌명
depositorName: string; // 입금자명
note: string; // 적요
depositType: DepositType; // 입금유형
vendorId: string; // 거래처 ID
vendorName: string; // 거래처명
status: DepositStatus; // 상태
createdAt: string;
updatedAt: string;
}
```
**필드 매핑 테이블**:
| API 필드 (snake_case) | React 필드 (camelCase) | 타입 변환 | 비고 |
|----------------------|----------------------|----------|------|
| `id` | `id` | `String(id)` | - |
| `deposit_date` | `depositDate` | 그대로 | YYYY-MM-DD |
| `amount` | `depositAmount` | `parseFloat()` | - |
| `bank_account.name` | `accountName` | 그대로 | 관계 조회 |
| `client_name` | `depositorName` | 그대로 | 입금자명 |
| `description` | `note` | `?? ''` | 적요 |
| `account_code` | `depositType` | 매핑 필요 | 유형 코드 |
| `client_id` | `vendorId` | `String(client_id)` | FK |
| `client.name` | `vendorName` | 그대로 | 관계 조회 |
| `payment_method` | - | 참조 | cash/transfer/card/check |
| `created_at` | `createdAt` | 그대로 | - |
| `updated_at` | `updatedAt` | 그대로 | - |
**입금유형 (depositType) 옵션**:
- `salesRevenue`: 매출대금
- `advance`: 선수금
- `suspense`: 가수금
- `rentalIncome`: 임대수익
- `interestIncome`: 이자수익
- 기타 6종 (types.ts 참조)
**입금상태 (status) 옵션**:
- `inputWaiting`: 입력대기
- `requesting`: 신청중
- `rejected`: 반려
- `pending`: 보류
- `incomplete`: 미완
- `error`: 오류
- `confirmed`: 확정완료
---
### 6.4 출금 관리 (Withdrawals)
**API FormRequest 필드** (`api/app/Http/Requests/V1/Withdrawal/StoreWithdrawalRequest.php`):
```php
'withdrawal_date' => ['required', 'date'],
'client_id' => ['nullable', 'integer', 'exists:clients,id'],
'client_name' => ['nullable', 'string', 'max:100'],
'bank_account_id' => ['nullable', 'integer', 'exists:bank_accounts,id'],
'amount' => ['required', 'numeric', 'min:0'],
'payment_method' => ['required', 'string', 'in:cash,transfer,card,check'],
'account_code' => ['nullable', 'string', 'max:20'],
'description' => ['nullable', 'string', 'max:1000'],
'reference_type' => ['nullable', 'string', 'max:50'],
'reference_id' => ['nullable', 'integer'],
```
**React 인터페이스** (`react/src/components/accounting/WithdrawalManagement/types.ts`):
```typescript
interface WithdrawalRecord {
id: string;
withdrawalDate: string; // 출금일
withdrawalAmount: number; // 출금액
accountName: string; // 출금계좌명
recipientName: string; // 수취인명
note: string; // 적요
withdrawalType: WithdrawalType; // 출금유형
vendorId: string; // 거래처 ID
vendorName: string; // 거래처명
createdAt: string;
updatedAt: string;
}
```
**필드 매핑 테이블**:
| API 필드 (snake_case) | React 필드 (camelCase) | 타입 변환 | 비고 |
|----------------------|----------------------|----------|------|
| `id` | `id` | `String(id)` | - |
| `withdrawal_date` | `withdrawalDate` | 그대로 | YYYY-MM-DD |
| `amount` | `withdrawalAmount` | `parseFloat()` | - |
| `bank_account.name` | `accountName` | 그대로 | 관계 조회 |
| `client_name` | `recipientName` | 그대로 | 수취인명 |
| `description` | `note` | `?? ''` | 적요 |
| `account_code` | `withdrawalType` | 매핑 필요 | 유형 코드 |
| `client_id` | `vendorId` | `String(client_id)` | FK |
| `client.name` | `vendorName` | 그대로 | 관계 조회 |
| `payment_method` | - | 참조 | cash/transfer/card/check |
| `created_at` | `createdAt` | 그대로 | - |
| `updated_at` | `updatedAt` | 그대로 | - |
**출금유형 (withdrawalType) 옵션**:
- `purchasePayment`: 매입대금
- `advance`: 선급금
- `suspense`: 가지급금
- `rent`: 임대료
- `salary`: 급여
- 기타 11종 (types.ts 참조)
---
### 6.5 거래처 관리 (Clients)
**API FormRequest 필드** (`api/app/Http/Requests/Client/ClientStoreRequest.php`):
```php
'client_group_id' => 'nullable|integer',
'client_code' => 'nullable|string|max:50',
'name' => 'required|string|max:100',
'client_type' => ['nullable', Rule::exists('common_codes', 'code')...],
'contact_person' => 'nullable|string|max:100',
'phone' => 'nullable|string|max:20',
'mobile' => 'nullable|string|max:20',
'fax' => 'nullable|string|max:20',
'email' => 'nullable|email|max:100',
'address' => 'nullable|string|max:255',
'manager_name' => 'nullable|string|max:50',
'manager_tel' => 'nullable|string|max:20',
'system_manager' => 'nullable|string|max:50',
'account_id' => 'nullable|string|max:50',
'account_password' => 'nullable|string|max:255',
'purchase_payment_day' => 'nullable|string|max:20',
'sales_payment_day' => 'nullable|string|max:20',
'business_no' => 'nullable|string|max:20',
'business_type' => 'nullable|string|max:50',
'business_item' => 'nullable|string|max:100',
'tax_agreement' => 'nullable|boolean',
'tax_amount' => 'nullable|numeric|min:0',
'tax_start_date' => 'nullable|date',
'tax_end_date' => 'nullable|date',
'bad_debt' => 'nullable|boolean',
'bad_debt_amount' => 'nullable|numeric|min:0',
'bad_debt_receive_date' => 'nullable|date',
'bad_debt_end_date' => 'nullable|date',
'bad_debt_progress' => ['nullable', Rule::exists('common_codes', 'code')...],
'memo' => 'nullable|string',
'is_active' => 'nullable|boolean',
```
**필드 매핑 테이블 (주요 필드)**:
| API 필드 (snake_case) | React 필드 (camelCase) | 타입 변환 | 비고 |
|----------------------|----------------------|----------|------|
| `id` | `id` | `String(id)` | - |
| `client_code` | `clientCode` | 그대로 | 자동 생성 |
| `name` | `name` | 그대로 | 거래처명 |
| `client_type` | `clientType` | common_codes 참조 | - |
| `contact_person` | `contactPerson` | 그대로 | 담당자 |
| `phone` | `phone` | 그대로 | 전화번호 |
| `mobile` | `mobile` | 그대로 | 휴대폰 |
| `email` | `email` | 그대로 | 이메일 |
| `address` | `address` | 그대로 | 주소 |
| `business_no` | `businessNo` | 그대로 | 사업자번호 |
| `business_type` | `businessType` | 그대로 | 업종 |
| `business_item` | `businessItem` | 그대로 | 업태 |
| `bad_debt` | `badDebt` | `Boolean` | 악성채권 여부 |
| `bad_debt_amount` | `badDebtAmount` | `parseFloat()` | 악성채권 금액 |
| `is_active` | `isActive` | `Boolean` | 활성 상태 |
| `created_at` | `createdAt` | 그대로 | - |
| `updated_at` | `updatedAt` | 그대로 | - |
---
### 6.6 공통 변환 함수 템플릿
```typescript
// utils/apiTransform.ts
/** snake_case를 camelCase로 변환 */
export function snakeToCamel(str: string): string {
return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
}
/** camelCase를 snake_case로 변환 */
export function camelToSnake(str: string): string {
return str.replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`);
}
/** 객체 전체 키 변환 */
export function transformKeys<T>(obj: Record<string, any>, transformer: (key: string) => string): T {
const result: Record<string, any> = {};
for (const [key, value] of Object.entries(obj)) {
const newKey = transformer(key);
result[newKey] = value !== null ? value : undefined;
}
return result as T;
}
/** API → Frontend 공통 변환 */
export function transformApiToFrontend<T>(apiData: Record<string, any>): T {
return transformKeys<T>(apiData, snakeToCamel);
}
/** Frontend → API 공통 변환 */
export function transformFrontendToApi(data: Record<string, any>): Record<string, any> {
return transformKeys(data, camelToSnake);
}
```
---
## 7. 작업 일정
### Phase A: API 완료 기능 (1주)
| 일차 | 작업 내용 | 상태 |
|------|----------|------|
| Day 1 | A-1 악성채권 관리 연동 | ✅ 완료 (2025-12-23) |
| Day 2 | A-2 팝업 관리 연동 | ✅ 완료 (2025-12-23) |
| Day 3 | A-3 결제 내역 연동 | ✅ 완료 (2025-12-23) |
| Day 4 | A-4 구독 관리 연동 | ✅ 완료 (2025-12-23) |
| Day 5 | A-5 알림 설정 연동 | ✅ 완료 (2025-12-23) |
### Phase B: 핵심 업무 기능 (2주)
| 일차 | 작업 내용 |
|------|----------|
| Day 1-2 | B-1 매출 관리 연동 |
| Day 3-4 | B-2 매입 관리 연동 |
| Day 5-6 | B-3 입금 관리, B-4 출금 관리 연동 |
| Day 7-8 | B-5 거래처 관리 연동 |
| Day 9-10 | B-6 어음 관리 연동 + 통합 테스트 |
---
## 8. 변경 이력
| 날짜 | 내용 | 작성자 |
|------|------|--------|
| 2025-12-23 | 문서 초안 작성 | Claude |
| 2025-12-23 | Phase B 상세 필드 매핑 추가 (6.1~6.6) | Claude |
| 2025-12-23 | A-1 악성채권 관리 API 연동 완료 (`actions.ts`, `page.tsx`, `index.tsx`) | Claude |
| 2025-12-23 | A-2 팝업 관리 API 연동 완료 (`actions.ts`, `page.tsx`, `PopupList.tsx`, `[id]/page.tsx`, `[id]/edit/page.tsx`) | Claude |
| 2025-12-23 | A-3 결제 내역 API 연동 완료 (`types.ts`, `actions.ts`, `page.tsx`, `PaymentHistoryClient.tsx`, `index.ts`) | Claude |
| 2025-12-23 | A-4 구독 관리 API 연동 완료 (`types.ts`, `utils.ts`, `actions.ts`, `page.tsx`, `SubscriptionClient.tsx`, `index.ts`) | Claude |
| 2025-12-23 | A-5 알림 설정 API 연동 완료 (`types.ts`, `actions.ts`, `page.tsx`, `NotificationSettingsClient.tsx`, `index.ts`) | Claude |
| 2025-12-23 | A-6 거래처 원장 - API 미존재 확인, Phase A 완료 | Claude |
| 2025-12-23 | B-1 매출 관리 - 기존 API 연동 확인 (`/api/proxy/sales` 사용) | Claude |
| 2025-12-23 | B-2 매입 관리 - 기존 API 연동 확인 (`/api/proxy/purchases` 사용) | Claude |
| 2025-12-23 | B-3 입금 관리 API 연동 완료 (`types.ts`: API 타입 추가, `index.tsx`: Mock → API 호출 전환) | Claude |
| 2025-12-23 | B-4 출금 관리 API 연동 완료 (`types.ts`: API 타입 추가, `index.tsx`: Mock → API 호출 전환) | Claude |
| 2025-12-23 | B-5 거래처 관리 API 연동 완료 (`types.ts`: API 타입 추가, `actions.ts`: Server Actions, `page.tsx`: 서버 컴포넌트, `VendorManagementClient.tsx`: 클라이언트 컴포넌트) | Claude |
| 2025-12-24 | 커밋 유실로 인한 API 연동 복원 (A-2~A-5, B-3~B-5: `actions.ts` 재생성, `page.tsx` 서버 컴포넌트 전환, `index.tsx` mock 제거) | Claude |
| 2025-12-24 | Mock 데이터 사용 파일 전수 조사 (MCP Serena 활용), 신규 Phase 추가 (D~H, S) | Claude |
| 2025-12-24 | B-1 매출관리, B-2 매입관리 상태 수정 (Mock 사용중으로 재분류) | Claude |
| 2025-12-24 | Phase E (설정/시스템), F (인사/급여), G (결재), H (API 개발 필요), S (상세 페이지) 신규 추가 | Claude |
| 2025-12-24 | **문서 전면 수정**: 리스트/상세 분리 상태 표기, 상세 페이지 Mock 현황 섹션 추가, Phase 재구성 (A~I), 게시판 제외 | Claude |
| 2025-12-24 | **전수 조사 및 문서 업데이트**: MCP Serena로 80개+ 파일 Mock 패턴 분석, Phase A~H CRUD별 상태 테이블 추가, 전수 조사 결과 요약(1.4) 추가, console.log 패턴 및 actions.ts 미연동 현황 문서화 | Claude |
| 2025-12-24 | **작업 진행 정책 추가 (1.5)**: 페이지 단위 작업 → 검수 → [승인] 문서 업데이트 → [승인] 커밋 순서 정의, A-1 다른 세션 처리, A-2부터 순차 진행 | Claude |
| 2025-12-24 | **A-1 악성채권 관리 완전 연동**: 상세 페이지(`[id]/page.tsx`, `[id]/edit/page.tsx`) 서버 컴포넌트 전환, `BadDebtDetail.tsx` CRUD API 연동, 메모 API 연동(`addBadDebtMemo`, `deleteBadDebtMemo`) | Claude |
| 2025-12-24 | **A-2 팝업 관리 API 연동**: `[id]/page.tsx` getPopupById+deletePopup 연동, `[id]/edit/page.tsx` getPopupById 연동, `PopupForm.tsx` createPopup+updatePopup 연동, 로딩/에러 상태 처리 | Claude |
| 2025-12-24 | **C-1 직원 관리 API 연동**: `actions.ts` 생성 (CRUD+통계+일괄삭제), `utils.ts` 생성 (API↔Frontend 변환), `index.tsx` Mock 제거+API 연동, `[id]/page.tsx` 상세 API 연동, `[id]/edit/page.tsx` 수정 API 연동, `new/page.tsx` 등록 API 연동 | Claude |
| 2025-12-24 | **C-2 근태 관리 API 연동**: `actions.ts` 생성 (checkIn/checkOut/getTodayAttendance), `GoogleMap.tsx` userLocation 콜백 추가, `page.tsx` Mock console.log 제거+API 연동, 처리중 상태 및 버튼 텍스트 추가 | Claude |
| 2025-12-24 | **C-3 휴가 관리 API 연동**: `actions.ts` 생성 (getLeaves/createLeave/approveLeave/rejectLeave 등), `index.tsx` 신청현황 탭 Mock 제거+API 연동, 일괄승인/반려 API 연동 | Claude |
| 2025-12-24 | **C-4 부서 관리 API 연동**: `actions.ts` 생성 (getDepartmentTree/createDepartment/updateDepartment/deleteDepartment/deleteDepartmentsMany), `index.tsx` Mock 제거+API 연동 | Claude |
| 2025-12-24 | **`.env.local` 환경변수 수정**: `API_URL=https://api.sam.kr/api` 추가 - Server Actions 서버사이드 API URL | Claude |
| 2025-12-24 | **C-3 휴가 관리 사용현황/부여현황 API 연동**: `leave_grants` 테이블 마이그레이션, `LeaveGrant` 모델 생성, `GET/POST/DELETE /api/v1/leaves/grants` API 추가, `actions.ts` getLeaveGrants/createLeaveGrant/deleteLeaveGrant 추가, `index.tsx` generateGrantData Mock 제거+API 연동, 연차/월차 부여 시 LeaveBalance.total_days 자동 갱신 | Claude |
| 2025-12-24 | **D-2 계정 관리(계좌) API 연동**: `actions.ts` 생성 (CRUD+toggle+setPrimary+일괄삭제), `types.ts` API 필드 추가 (id:number, bankName, isPrimary, assignedUserId), `index.tsx` generateMockData 제거+API 연동, `AccountDetail.tsx` console.log 제거+API 연동 | Claude |
| 2025-12-24 | **D-3 근무 일정 관리 API 연동**: `actions.ts` 생성 (getWorkSetting/updateWorkSetting), `index.tsx` console.log 제거+API 연동, 로딩/저장 상태 추가, HH:mm↔HH:mm:ss 시간 변환 | Claude |
| 2025-12-24 | **D-4 근태 설정 관리 API 연동**: `actions.ts` 생성 (getAttendanceSetting/updateAttendanceSetting), `index.tsx` console.log 제거+API 연동, 로딩/저장 상태 추가 (API 지원 필드: useGps, allowedRadius만 연동) | Claude |
| 2025-12-24 | **B-6 어음 관리 중복번호 검증 추가**: `StoreBillRequest.php` tenant scope unique 검증 규칙 추가 (`Rule::unique`), `lang/ko/error.php` 에러 메시지 추가 (`bill.duplicate_number`), SAM 표준 패턴 적용 (`app('tenant_id')`) | Claude |
| 2025-12-25 | **E-1 법인카드 관리 API 연동**: `actions.ts` 생성 (CRUD+토글+일괄삭제), `CardForm.tsx` mockUsers 제거+API 연동 (getActiveEmployees), `index.tsx` Mock 제거+API 연동 | Claude |
| 2025-12-25 | **E-2 급여 관리 API 신규 개발+연동**: Salary API 전체 신규 생성 (마이그레이션, 모델, 서비스, 컨트롤러, FormRequest), `actions.ts` 생성 (목록/상세/상태변경/일괄상태변경), `index.tsx` generateSalaryData/generateSalaryDetail Mock 함수 제거+API 연동, 로딩 상태 추가 | Claude |
| 2025-12-25 | **F-1 기안함 API 연동**: `DraftBox/actions.ts` 생성 (목록/삭제/일괄삭제), `index.tsx` Mock 제거+API 연동, IntegratedListTemplateV2 props 수정 | Claude |
| 2025-12-25 | **F-2 참조함 API 연동**: `ReferenceBox/actions.ts` 생성 (목록/열람처리/일괄처리), `index.tsx` Mock 제거+API 연동, IntegratedListTemplateV2 props 수정 | Claude |
| 2025-12-25 | **F-3 결재함 API 연동**: `ApprovalBox/actions.ts` 생성 (목록/통계/승인/반려/일괄처리), `index.tsx` Mock 제거+API 연동, 반려 다이얼로그 사유 입력 Textarea 추가 | Claude |
| 2025-12-25 | **F-4 비용견적서 양식 API 연동**: `DocumentCreate/actions.ts` 생성 (비용견적서 항목조회/문서생성/상신/직원목록), `index.tsx` console.log 제거+API 연동, `ExpenseEstimateForm.tsx` Mock 제거+로딩/빈상태 추가 | Claude |
| 2025-12-26 | **Phase I 상세 분석**: I-1~I-8 전체 CRUD 현황 분석 - actions.ts 함수별 상태, UI 구현 현황, 페이지 특성(조회전용/외부연동/대시보드) 분류, 필요 작업 정리. I-2/I-3/I-6/I-8 완료 확인, I-1/I-4/I-5/I-7 추가 작업 필요 | Claude |
| 2025-12-26 | **H-1 입고 관리 React 연동**: `actions.ts` 생성 (목록/상세/등록/수정/삭제/통계/옵션 API), `types.ts` 타입 정의, `ReceivingList.tsx` Mock 제거+API 연동, `ReceivingDetail.tsx` Mock 제거+API 연동, `ReceivingCreate.tsx` Mock 제거+API 연동, `ReceivingEdit.tsx` Mock 제거+API 연동 | Claude |
| 2025-12-26 | **H-2 재고 현황 React 연동**: `actions.ts` 생성 (목록/상세/통계/옵션 API), `types.ts` 타입 정의, `StockStatusList.tsx` Mock 제거+API 연동, `StockStatusDetail.tsx` Mock 제거+API 연동 (등록/수정/삭제 해당없음) | Claude |
| 2025-12-26 | **H-3 출하 관리 React 연동**: `actions.ts` 생성 (목록/상세/등록/수정/삭제/통계/옵션 API), `types.ts` 타입 정의, `ShipmentList.tsx` Mock 제거+API 연동, `ShipmentDetail.tsx` Mock 제거+API 연동, `ShipmentCreate.tsx` Mock 제거+API 연동, `ShipmentEdit.tsx` Mock 제거+API 연동 | Claude |
| 2025-12-26 | **Phase I 완료**: I-1 미지급비용관리 CRUD UI 구현 (등록/수정 폼 다이얼로그, 삭제/일괄삭제), I-4 은행거래조회 상세페이지 이동방식 확인, I-5 채권현황 updateOverdueStatus API 연동+변경감지, I-7 종합분석 approveIssue/rejectIssue API 연동 | Claude |
| 2025-12-26 | **Phase I Excel/PDF 다운로드 API 연동**: I-5 채권현황 exportReceivablesExcel, I-2 거래처원장 exportVendorLedgerExcel/exportVendorLedgerDetailPdf, I-6 일일보고서 exportDailyReportExcel - console.log 제거+Blob 다운로드 패턴 적용 | Claude |
| 2025-12-26 | **Phase G 생산관리 API 연동 완료**: G-1 작업지시관리 (목록/상세/등록/담당자선택/수주선택), G-2 작업실적관리 (목록/통계), G-3 생산대시보드, G-4 작업자화면 (목록/완료/자재투입/공정단계/검사요청), G-5 품질검사 (목록/상세/등록/수정) - 전체 Mock → API 전환 완료, mockData.ts 내 유틸리티(색상매핑/판정함수)만 유지 | Claude |
| 2025-12-26 | **Phase S (2.14) 상세 페이지 완료 확인**: S-1~S-10 전체 상세 페이지 API 연동 완료 확인, 문서 상태 업데이트 | Claude |
| 2025-12-26 | **L-3 종합분석 완료 확인**: approveIssue/rejectIssue API 연동 확인 (I-7에서 완료), 문서 상태 업데이트 | Claude |
---
## 9. 참고 문서
- **API 스펙**: http://sam.kr/api-docs
- **기존 연동 계획**: `react-api-integration-plan.md`
- **API 개발 계획**: `erp-api-development-plan-d1.0-changes.md`
- **표준 구현 참조**: `/sales/pricing-management`