Files
sam-docs/front/[API-2025-12-04] client-api-analysis.md
hskwon 914667738b docs: clients is_active Boolean 변경 반영
- client-policy.md: TINYINT(1), true/false 상태값 반영, Hard Delete 명시
- client-api-analysis.md: 스키마/타입 Boolean 업데이트, Soft Delete → Hard Delete 수정
2025-12-08 20:26:01 +09:00

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.php
  • api/app/Http/Controllers/Api/V1/ClientGroupController.php
  • api/app/Services/ClientService.php
  • api/app/Services/ClientGroupService.php

모델

  • api/app/Models/Orders/Client.php
  • api/app/Models/Orders/ClientGroup.php

요청 클래스

  • api/app/Http/Requests/Client/ClientStoreRequest.php
  • api/app/Http/Requests/Client/ClientUpdateRequest.php

마이그레이션

  • api/database/migrations/2025_12_04_145912_add_business_fields_to_clients_table.php
  • api/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단계)

  1. 로그인 → 토큰 추출
  2. 거래처 목록 조회
  3. 거래처 생성
  4. 거래처 단건 조회
  5. 거래처 수정
  6. 수정 확인 조회
  7. 비활성화 토글
  8. 활성화 토글
  9. 거래처 검색
  10. 거래처 삭제
  11. 삭제 확인 (404 예상)

Client Group API Flow (10단계)

  1. 로그인 → 토큰 추출
  2. 그룹 목록 조회
  3. 그룹 생성 (group_code, group_name, price_rate 필수)
  4. 그룹 단건 조회
  5. 그룹 수정
  6. 수정 확인 조회
  7. 비활성화 토글
  8. 활성화 토글
  9. 그룹 삭제
  10. 삭제 확인 (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