# 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 { 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 { 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 ; } ``` ### 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 { 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 { 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(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(obj: Record, transformer: (key: string) => string): T { const result: Record = {}; 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(apiData: Record): T { return transformKeys(apiData, snakeToCamel); } /** Frontend → API 공통 변환 */ export function transformFrontendToApi(data: Record): Record { 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`