- client-policy.md: TINYINT(1), true/false 상태값 반영, Hard Delete 명시 - client-api-analysis.md: 스키마/타입 Boolean 업데이트, Soft Delete → Hard Delete 수정
16 KiB
16 KiB
거래처 관리 API 분석 및 구현 현황
작성일: 2025-12-04 최종 업데이트: 2025-12-08 상태: ✅ 백엔드 + 프론트엔드 구현 완료
1. 구현 현황 요약
✅ 백엔드 API 구조 (구현 완료)
Client (거래처) API
| Method | Endpoint | 설명 | 상태 |
|---|---|---|---|
GET |
/api/v1/clients |
목록 조회 (페이지네이션, 검색) | ✅ 완료 |
GET |
/api/v1/clients/{id} |
단건 조회 | ✅ 완료 |
POST |
/api/v1/clients |
생성 | ✅ 완료 |
PUT |
/api/v1/clients/{id} |
수정 | ✅ 완료 |
DELETE |
/api/v1/clients/{id} |
삭제 | ✅ 완료 |
PATCH |
/api/v1/clients/{id}/toggle |
활성/비활성 토글 | ✅ 완료 |
Client Group (거래처 그룹) API
| Method | Endpoint | 설명 | 상태 |
|---|---|---|---|
GET |
/api/v1/client-groups |
그룹 목록 | ✅ 완료 |
GET |
/api/v1/client-groups/{id} |
그룹 단건 | ✅ 완료 |
POST |
/api/v1/client-groups |
그룹 생성 | ✅ 완료 |
PUT |
/api/v1/client-groups/{id} |
그룹 수정 | ✅ 완료 |
DELETE |
/api/v1/client-groups/{id} |
그룹 삭제 | ✅ 완료 |
PATCH |
/api/v1/client-groups/{id}/toggle |
그룹 활성/비활성 | ✅ 완료 |
✅ 프론트엔드 구현 현황 (구현 완료)
| 작업 | 상태 | 파일 |
|---|---|---|
| API Proxy | ✅ 완료 | /api/proxy/[...path]/route.ts (catch-all) |
useClientList 훅 |
✅ 완료 | src/hooks/useClientList.ts |
| 타입 정의 (확장 필드 포함) | ✅ 완료 | src/hooks/useClientList.ts |
| 거래처 등록 페이지 | ✅ 완료 | .../client-management-sales-admin/new/page.tsx |
| 거래처 상세 페이지 | ✅ 완료 | .../client-management-sales-admin/[id]/page.tsx |
| 거래처 수정 페이지 | ✅ 완료 | .../client-management-sales-admin/[id]/edit/page.tsx |
| 목록 페이지 개선 | ✅ 완료 | 모달 삭제, 페이지 네비게이션 적용 |
2. 테이블 스키마 (구현 완료)
2.1 clients 테이블 ✅
CREATE TABLE clients (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
tenant_id BIGINT NOT NULL,
client_group_id BIGINT NULL,
-- 기본 정보
client_code VARCHAR(50) NOT NULL,
name VARCHAR(255) NOT NULL,
client_type ENUM('매입','매출','매입매출') DEFAULT '매입',
-- 사업자 정보
business_no VARCHAR(20) NULL, -- 사업자등록번호
business_type VARCHAR(50) NULL, -- 업태
business_item VARCHAR(100) NULL, -- 업종
-- 연락처 정보
contact_person VARCHAR(100) NULL, -- 대표 담당자
phone VARCHAR(20) NULL,
mobile VARCHAR(20) NULL,
fax VARCHAR(20) NULL,
email VARCHAR(255) NULL,
address TEXT NULL,
-- 담당자 정보
manager_name VARCHAR(50) NULL, -- 담당자명
manager_tel VARCHAR(20) NULL, -- 담당자 전화
system_manager VARCHAR(50) NULL, -- 시스템 관리자
-- 발주처 설정
account_id VARCHAR(50) NULL, -- 계정 ID
account_password VARCHAR(255) NULL, -- 비밀번호 (암호화, hidden)
purchase_payment_day VARCHAR(20) NULL, -- 매입 결제일
sales_payment_day VARCHAR(20) NULL, -- 매출 결제일
-- 약정 세금
tax_agreement BOOLEAN DEFAULT FALSE,
tax_amount DECIMAL(15,2) NULL,
tax_start_date DATE NULL,
tax_end_date DATE NULL,
-- 악성채권 정보
bad_debt BOOLEAN DEFAULT FALSE,
bad_debt_amount DECIMAL(15,2) NULL,
bad_debt_receive_date DATE NULL,
bad_debt_end_date DATE NULL,
bad_debt_progress ENUM('협의중','소송중','회수완료','대손처리') NULL,
-- 기타
memo TEXT NULL,
is_active TINYINT(1) DEFAULT 1, -- 1=활성, 0=비활성
-- 감사 컬럼
created_at TIMESTAMP,
updated_at TIMESTAMP
);
2.2 client_groups 테이블 ✅
CREATE TABLE client_groups (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
tenant_id BIGINT NOT NULL,
group_code VARCHAR(30) NOT NULL, -- 그룹 코드 (필수)
group_name VARCHAR(100) NOT NULL, -- 그룹명 (필수)
price_rate DECIMAL(6,4) NOT NULL, -- 단가율 (필수, 0~99.9999)
is_active BOOLEAN DEFAULT TRUE,
created_by BIGINT NULL,
updated_by BIGINT NULL,
deleted_by BIGINT NULL,
created_at TIMESTAMP,
updated_at TIMESTAMP,
deleted_at TIMESTAMP NULL -- Soft Delete
);
⚠️ 주의: client_groups API 필드명
group_code(필수) - 그룹 코드group_name(필수) - 그룹명 (name이 아님!)price_rate(필수) - 단가율is_active(선택) - boolean
3. API 엔드포인트 상세 (구현 완료)
3.1 목록 조회 GET /api/v1/clients ✅
Query Parameters:
| 파라미터 | 타입 | 설명 | 기본값 |
|---|---|---|---|
page |
int | 페이지 번호 | 1 |
size |
int | 페이지당 개수 | 20 |
q |
string | 검색어 (이름, 코드, 담당자) | - |
only_active |
boolean | 활성 거래처만 조회 | - |
Response:
{
"success": true,
"message": "message.fetched",
"data": {
"current_page": 1,
"data": [
{
"id": 1,
"client_code": "CLI-001",
"name": "ABC상사",
"client_type": "매입매출",
"business_no": "123-45-67890",
"business_type": "제조업",
"business_item": "기계부품",
"contact_person": "홍길동",
"phone": "02-1234-5678",
"mobile": "010-1234-5678",
"fax": "02-1234-5679",
"email": "hong@abc.com",
"address": "서울시 강남구...",
"manager_name": "김철수",
"manager_tel": "02-1234-5680",
"purchase_payment_day": "말일",
"sales_payment_day": "말일",
"tax_agreement": false,
"bad_debt": false,
"memo": null,
"is_active": true,
"client_group": { "id": 1, "name": "VIP" }
}
],
"total": 1
}
}
3.2 단건 조회 GET /api/v1/clients/{id} ✅
단건 조회 시 모든 필드 포함 (목록과 동일 구조)
3.3 거래처 등록 POST /api/v1/clients ✅
Request Body:
{
"client_code": "CLI-002",
"name": "XYZ무역",
"client_type": "매입",
"client_group_id": 1,
"business_no": "234-56-78901",
"business_type": "도소매업",
"business_item": "전자부품",
"contact_person": "이영희",
"phone": "02-2345-6789",
"mobile": "010-2345-6789",
"fax": "02-2345-6790",
"email": "lee@xyz.com",
"address": "서울시 서초구...",
"manager_name": "박민수",
"manager_tel": "02-2345-6791",
"system_manager": "관리자A",
"account_id": "xyz_user",
"account_password": "secret123",
"purchase_payment_day": "15일",
"sales_payment_day": "말일",
"tax_agreement": true,
"tax_amount": 1000000,
"tax_start_date": "2025-01-01",
"tax_end_date": "2025-12-31",
"bad_debt": false,
"memo": "신규 거래처"
}
3.4 거래처 수정 PUT /api/v1/clients/{id} ✅
등록과 동일한 필드 구조 (부분 수정 가능)
주의: account_password는 입력한 경우에만 업데이트됨
3.5 거래처 삭제 DELETE /api/v1/clients/{id} ✅
Hard Delete 적용 (연관 주문이 없는 경우만 삭제 가능)
3.6 활성/비활성 토글 PATCH /api/v1/clients/{id}/toggle ✅
Response:
{
"success": true,
"message": "message.updated",
"data": {
"id": 1,
"is_active": false
}
}
4. 필드 구조 (7개 섹션)
섹션 1: 기본 정보
| 필드명 | 타입 | 필수 | 설명 |
|---|---|---|---|
client_code |
string | ✅ | 거래처 코드 |
name |
string | ✅ | 거래처명 |
client_type |
enum | ❌ | 매입/매출/매입매출 (기본: 매입) |
client_group_id |
int | ❌ | 거래처 그룹 ID |
섹션 2: 사업자 정보
| 필드명 | 타입 | 필수 | 설명 |
|---|---|---|---|
business_no |
string | ❌ | 사업자등록번호 |
business_type |
string | ❌ | 업태 |
business_item |
string | ❌ | 업종 |
섹션 3: 연락처 정보
| 필드명 | 타입 | 필수 | 설명 |
|---|---|---|---|
contact_person |
string | ❌ | 대표 담당자 |
phone |
string | ❌ | 전화번호 |
mobile |
string | ❌ | 휴대폰 |
fax |
string | ❌ | 팩스 |
email |
string | ❌ | 이메일 |
address |
text | ❌ | 주소 |
섹션 4: 담당자 정보
| 필드명 | 타입 | 필수 | 설명 |
|---|---|---|---|
manager_name |
string | ❌ | 담당자명 |
manager_tel |
string | ❌ | 담당자 전화 |
system_manager |
string | ❌ | 시스템 관리자 |
섹션 5: 발주처 설정
| 필드명 | 타입 | 필수 | 설명 |
|---|---|---|---|
account_id |
string | ❌ | 계정 ID |
account_password |
string | ❌ | 비밀번호 (hidden) |
purchase_payment_day |
string | ❌ | 매입 결제일 |
sales_payment_day |
string | ❌ | 매출 결제일 |
섹션 6: 약정 세금
| 필드명 | 타입 | 필수 | 설명 |
|---|---|---|---|
tax_agreement |
boolean | ❌ | 세금 약정 여부 |
tax_amount |
decimal | ❌ | 약정 금액 |
tax_start_date |
date | ❌ | 약정 시작일 |
tax_end_date |
date | ❌ | 약정 종료일 |
섹션 7: 악성채권 정보
| 필드명 | 타입 | 필수 | 설명 |
|---|---|---|---|
bad_debt |
boolean | ❌ | 악성채권 여부 |
bad_debt_amount |
decimal | ❌ | 악성채권 금액 |
bad_debt_receive_date |
date | ❌ | 채권 발생일 |
bad_debt_end_date |
date | ❌ | 채권 만료일 |
bad_debt_progress |
enum | ❌ | 진행 상태 |
섹션 8: 기타
| 필드명 | 타입 | 필수 | 설명 |
|---|---|---|---|
memo |
text | ❌ | 메모 |
is_active |
boolean | ❌ | 활성 상태 (기본: true) |
5. 프론트엔드 타입 정의
5.1 API 응답 타입
export type ClientType = "매입" | "매출" | "매입매출";
export type BadDebtProgress = "협의중" | "소송중" | "회수완료" | "대손처리" | "";
export interface ClientApiResponse {
id: number;
tenant_id: number;
client_group_id: number | null;
client_code: string;
name: string;
client_type?: ClientType;
business_no: string | null;
business_type: string | null;
business_item: string | null;
contact_person: string | null;
phone: string | null;
mobile?: string | null;
fax?: string | null;
email: string | null;
address: string | null;
manager_name?: string | null;
manager_tel?: string | null;
system_manager?: string | null;
account_id?: string | null;
purchase_payment_day?: string | null;
sales_payment_day?: string | null;
tax_agreement?: boolean;
tax_amount?: number | null;
tax_start_date?: string | null;
tax_end_date?: string | null;
bad_debt?: boolean;
bad_debt_amount?: number | null;
bad_debt_receive_date?: string | null;
bad_debt_end_date?: string | null;
bad_debt_progress?: BadDebtProgress;
memo?: string | null;
is_active: boolean;
created_at: string;
updated_at: string;
}
5.2 프론트엔드 변환 타입
export interface Client {
id: string;
code: string;
name: string;
businessNo: string;
representative: string;
phone: string;
address: string;
email: string;
businessType: string;
businessItem: string;
registeredDate: string;
status: "활성" | "비활성";
groupId: string | null;
clientType: ClientType;
mobile: string;
fax: string;
managerName: string;
managerTel: string;
systemManager: string;
accountId: string;
purchasePaymentDay: string;
salesPaymentDay: string;
taxAgreement: boolean;
taxAmount: string;
taxStartDate: string;
taxEndDate: string;
badDebt: boolean;
badDebtAmount: string;
badDebtReceiveDate: string;
badDebtEndDate: string;
badDebtProgress: BadDebtProgress;
memo: string;
}
6. 백엔드 참고 파일
컨트롤러/서비스
api/app/Http/Controllers/Api/V1/ClientController.phpapi/app/Http/Controllers/Api/V1/ClientGroupController.phpapi/app/Services/ClientService.phpapi/app/Services/ClientGroupService.php
모델
api/app/Models/Orders/Client.phpapi/app/Models/Orders/ClientGroup.php
요청 클래스
api/app/Http/Requests/Client/ClientStoreRequest.phpapi/app/Http/Requests/Client/ClientUpdateRequest.php
마이그레이션
api/database/migrations/2025_12_04_145912_add_business_fields_to_clients_table.phpapi/database/migrations/2025_12_04_205603_add_extended_fields_to_clients_table.php
Swagger
api/app/Swagger/v1/ClientApi.php
라우트
api/routes/api.php(Line 316-333)
7. 프론트엔드 참고 파일
훅
react/src/hooks/useClientList.ts- CRUD 훅 (530줄)react/src/hooks/useClientGroupList.ts- 그룹 CRUD 훅
컴포넌트
react/src/components/clients/ClientRegistration.tsx- 등록/수정 폼 (sam-design 기반)react/src/components/clients/ClientDetail.tsx- 상세 보기
페이지
react/src/app/[locale]/(protected)/sales/client-management-sales-admin/page.tsx- 목록react/src/app/[locale]/(protected)/sales/client-management-sales-admin/new/page.tsx- 등록react/src/app/[locale]/(protected)/sales/client-management-sales-admin/[id]/page.tsx- 상세react/src/app/[locale]/(protected)/sales/client-management-sales-admin/[id]/edit/page.tsx- 수정
8. 추가 개선 사항 (선택)
| 항목 | 우선순위 | 상태 |
|---|---|---|
| 거래처 그룹 관리 UI | 🟢 LOW | ⬜ 미구현 |
| 엑셀 내보내기/가져오기 | 🟢 LOW | ⬜ 미구현 |
| 거래처 검색 고급 필터 | 🟢 LOW | ⬜ 미구현 |
9. API Flow Tester 테스트 파일
9.1 Flow Tester 설명
API Flow Tester를 사용하여 Client 및 Client Group API의 전체 CRUD 플로우를 자동으로 테스트할 수 있습니다.
9.2 테스트 파일 위치
| 파일 | 설명 |
|---|---|
docs/front/flow-tests/client-api-flow.json |
거래처 API CRUD 플로우 테스트 (11단계) |
docs/front/flow-tests/client-group-api-flow.json |
거래처 그룹 API CRUD 플로우 테스트 (10단계) |
9.3 테스트 플로우 요약
Client API Flow (11단계)
- 로그인 → 토큰 추출
- 거래처 목록 조회
- 거래처 생성
- 거래처 단건 조회
- 거래처 수정
- 수정 확인 조회
- 비활성화 토글
- 활성화 토글
- 거래처 검색
- 거래처 삭제
- 삭제 확인 (404 예상)
Client Group API Flow (10단계)
- 로그인 → 토큰 추출
- 그룹 목록 조회
- 그룹 생성 (
group_code,group_name,price_rate필수) - 그룹 단건 조회
- 그룹 수정
- 수정 확인 조회
- 비활성화 토글
- 활성화 토글
- 그룹 삭제
- 삭제 확인 (404 예상)
9.4 Flow Tester 사용 시 주의사항
환경변수 설정 필요:
FLOW_TESTER_USER_ID=테스트계정ID
FLOW_TESTER_USER_PWD=테스트계정비밀번호
API 응답 구조 차이점:
/login응답:{ "access_token": "...", "token_type": "..." }(루트 레벨)- 기타 API 응답:
{ "success": true, "data": {...} }(data 래핑)
필드 타입 주의:
is_active: boolean (true/false), 문자열"Y"/"N"아님price_rate: numeric (0~99.9999)
최종 업데이트: 2025-12-08