Files
sam-docs/front/[API-2025-12-04] client-api-analysis.md
hskwon 08a8259313 docs: 5130 레거시 분석 문서 및 기존 문서 초기 커밋
- 5130 레거시 시스템 분석 (00_OVERVIEW ~ 08_SAM_COMPARISON)
- MES 프로젝트 문서
- API/프론트엔드 스펙 문서
- 가이드 및 레퍼런스 문서
2025-12-04 18:47:19 +09:00

9.0 KiB

거래처 관리 API 분석

작성일: 2025-12-04 목적: sam-api 백엔드 Client API와 프론트엔드 거래처 관리 페이지 간 연동 분석


1. 현재 상태 요약

프론트엔드 (sam-react-prod)

  • 파일: src/app/[locale]/(protected)/sales/client-management-sales-admin/page.tsx
  • 상태: API 미연동 - 로컬 샘플 데이터(SAMPLE_CUSTOMERS)로만 동작
  • 모든 CRUD가 클라이언트 사이드에서만 수행됨

백엔드 (sam-api)

  • 컨트롤러: app/Http/Controllers/Api/V1/ClientController.php
  • 서비스: app/Services/ClientService.php
  • 모델: app/Models/Orders/Client.php
  • 상태: API 구현 완료 - 모든 CRUD 기능 제공

2. 백엔드 API 명세

2.1 Client (거래처) API

Method Endpoint 설명 인증
GET /api/v1/clients 목록 조회 (페이지네이션, 검색) Required
GET /api/v1/clients/{id} 단건 조회 Required
POST /api/v1/clients 생성 Required
PUT /api/v1/clients/{id} 수정 Required
DELETE /api/v1/clients/{id} 삭제 Required
PATCH /api/v1/clients/{id}/toggle 활성/비활성 토글 Required

2.2 Client Group (거래처 그룹) API

Method Endpoint 설명 인증
GET /api/v1/client-groups 그룹 목록 Required
GET /api/v1/client-groups/{id} 그룹 단건 Required
POST /api/v1/client-groups 그룹 생성 Required
PUT /api/v1/client-groups/{id} 그룹 수정 Required
DELETE /api/v1/client-groups/{id} 그룹 삭제 Required
PATCH /api/v1/client-groups/{id}/toggle 그룹 활성/비활성 Required

2.3 목록 조회 파라미터 (GET /api/v1/clients)

파라미터 타입 설명 기본값
page integer 페이지 번호 1
size integer 페이지당 개수 20
q string 검색어 (이름, 코드, 담당자) -
only_active boolean 활성 거래처만 조회 -

3. 데이터 모델 비교

3.1 필드 매핑 분석

프론트엔드 필드 백엔드 필드 상태 비고
id id 동일
code client_code 매핑 필요 필드명 변경
name name 동일
representative contact_person 매핑 필요 필드명 변경
phone phone 동일
email email 동일
address address 동일
registeredDate created_at 매핑 필요 필드명 변경
status is_active 매핑 필요 "활성"/"비활성" ↔ "Y"/"N"
businessNo - 백엔드 없음 추가 필요
businessType - 백엔드 없음 추가 필요
businessItem - 백엔드 없음 추가 필요
- tenant_id 백엔드 전용 자동 처리
- client_group_id ⚠️ 프론트 없음 그룹 기능 미구현

3.2 백엔드 모델 필드 (Client.php)

protected $fillable = [
    'tenant_id',
    'client_group_id',
    'client_code',        // 거래처 코드
    'name',               // 거래처명
    'contact_person',     // 담당자
    'phone',              // 전화번호
    'email',              // 이메일
    'address',            // 주소
    'is_active',          // 활성 상태 (Y/N)
];

4. 백엔드 수정 요청 사항

4.1 Client 모델 필드 추가 요청

## 백엔드 API 수정 요청

### 파일 위치
`app/Models/Orders/Client.php` - Client 모델

### 현재 문제
프론트엔드에서 사용하는 사업자 정보 필드가 백엔드에 없음

### 수정 요청
다음 필드를 Client 모델에 추가:

| 필드명 | 타입 | 설명 | nullable |
|--------|------|------|----------|
| `business_no` | string(20) | 사업자등록번호 | nullable |
| `business_type` | string(50) | 업태 | nullable |
| `business_item` | string(100) | 업종 | nullable |

### 마이그레이션 예시
```sql
ALTER TABLE clients ADD COLUMN business_no VARCHAR(20) NULL;
ALTER TABLE clients ADD COLUMN business_type VARCHAR(50) NULL;
ALTER TABLE clients ADD COLUMN business_item VARCHAR(100) NULL;

---

## 5. 프론트엔드 API 연동 구현 계획

### 5.1 필요한 작업

| # | 작업 | 우선순위 | 상태 |
|---|------|---------|------|
| 1 | Next.js API Proxy 생성 (`/api/proxy/clients/[...path]`) | 🔴 HIGH | ⬜ 미완료 |
| 2 | 커스텀 훅 생성 (`useClientList`) | 🔴 HIGH | ⬜ 미완료 |
| 3 | 타입 정의 업데이트 (`CustomerAccount` → API 응답 매핑) | 🟡 MEDIUM | ⬜ 미완료 |
| 4 | CRUD 함수를 API 호출로 변경 | 🔴 HIGH | ⬜ 미완료 |
| 5 | 거래처 그룹 기능 추가 (선택) | 🟢 LOW | ⬜ 미완료 |

### 5.2 API Proxy 구현 패턴

```typescript
// /src/app/api/proxy/clients/route.ts
import { NextRequest, NextResponse } from 'next/server';

const BACKEND_URL = process.env.NEXT_PUBLIC_API_URL;

export async function GET(request: NextRequest) {
  const token = request.cookies.get('access_token')?.value;
  const searchParams = request.nextUrl.searchParams;

  const response = await fetch(
    `${BACKEND_URL}/api/v1/clients?${searchParams.toString()}`,
    {
      headers: {
        'Authorization': `Bearer ${token}`,
        'X-API-KEY': process.env.NEXT_PUBLIC_API_KEY || '',
      },
    }
  );

  return NextResponse.json(await response.json());
}

5.3 useClientList 훅 구현 패턴

// /src/hooks/useClientList.ts
export function useClientList() {
  const [clients, setClients] = useState<Client[]>([]);
  const [pagination, setPagination] = useState<PaginationInfo | null>(null);
  const [isLoading, setIsLoading] = useState(false);

  const fetchClients = async (params: FetchParams) => {
    setIsLoading(true);
    const searchParams = new URLSearchParams({
      page: String(params.page || 1),
      size: String(params.size || 20),
      ...(params.q && { q: params.q }),
      ...(params.onlyActive !== undefined && { only_active: String(params.onlyActive) }),
    });

    const response = await fetch(`/api/proxy/clients?${searchParams}`);
    const data = await response.json();

    setClients(data.data.data);
    setPagination({
      currentPage: data.data.current_page,
      lastPage: data.data.last_page,
      total: data.data.total,
    });
    setIsLoading(false);
  };

  return { clients, pagination, isLoading, fetchClients };
}

6. 데이터 변환 유틸리티

6.1 API 응답 → 프론트엔드 타입 변환

// API 응답 타입
interface ClientApiResponse {
  id: number;
  client_code: string;
  name: string;
  contact_person: string | null;
  phone: string | null;
  email: string | null;
  address: string | null;
  is_active: 'Y' | 'N';
  created_at: string;
  updated_at: string;
}

// 프론트엔드 타입으로 변환
function transformClient(api: ClientApiResponse): CustomerAccount {
  return {
    id: String(api.id),
    code: api.client_code,
    name: api.name,
    representative: api.contact_person || '',
    phone: api.phone || '',
    email: api.email || '',
    address: api.address || '',
    businessNo: '',      // TODO: 백엔드 필드 추가 후 매핑
    businessType: '',    // TODO: 백엔드 필드 추가 후 매핑
    businessItem: '',    // TODO: 백엔드 필드 추가 후 매핑
    registeredDate: api.created_at.split(' ')[0],
    status: api.is_active === 'Y' ? '활성' : '비활성',
  };
}

6.2 프론트엔드 → API 요청 변환

function transformToApiRequest(form: FormData): ClientCreateRequest {
  return {
    client_code: form.code,
    name: form.name,
    contact_person: form.representative || null,
    phone: form.phone || null,
    email: form.email || null,
    address: form.address || null,
    is_active: 'Y',
  };
}

7. 결론 및 권장 사항

7.1 즉시 진행 가능 (백엔드 변경 없이)

  1. API Proxy 생성
  2. useClientList 훅 구현
  3. 기본 CRUD 연동 (현재 백엔드 필드만 사용)

7.2 백엔드 변경 필요

  1. ⚠️ business_no, business_type, business_item 필드 추가
  2. ⚠️ ClientService, ClientStoreRequest, ClientUpdateRequest 업데이트
  3. ⚠️ Swagger 문서 업데이트

7.3 선택적 개선

  1. 거래처 그룹 기능 프론트엔드 구현
  2. 거래처 상세 페이지 구현
  3. 엑셀 내보내기/가져오기 기능

참고 파일

백엔드 (sam-api)

  • app/Http/Controllers/Api/V1/ClientController.php
  • app/Http/Controllers/Api/V1/ClientGroupController.php
  • app/Services/ClientService.php
  • app/Services/ClientGroupService.php
  • app/Models/Orders/Client.php
  • app/Models/Orders/ClientGroup.php
  • app/Swagger/v1/ClientApi.php
  • routes/api.php (Line 316-333)

프론트엔드 (sam-react-prod)

  • src/app/[locale]/(protected)/sales/client-management-sales-admin/page.tsx