Files
sam-docs/front/[API-2025-12-06] item-crud-backend-requests.md
hskwon e152de469a docs: Client API Flow Tester JSON 추가 및 문서 업데이트
- Client API CRUD 플로우 테스트 JSON 추가 (11단계)
- Client Group API CRUD 플로우 테스트 JSON 추가 (10단계)
- client_groups 테이블 스키마 정정 (group_code, group_name, price_rate 필드)
- API 응답 구조 및 필드 타입 주의사항 문서화
- Flow Tester 섹션 추가 (사용법 및 주의사항)
2025-12-08 20:19:32 +09:00

16 KiB

품목 등록/수정 백엔드 API 수정 요청

프론트엔드 품목관리 기능 개발 중 발견된 백엔드 수정 필요 사항 정리


🔴 [핵심] field_key 통일 필요 - 근본적 구조 개선

상태: 🔴 구조 개선 필요

발견일: 2025-12-06

요약

항목 내용
근본 원인 품목기준관리 / 품목관리 API 요청서 분리로 키값 불일치
해결 방향 품목기준관리 field_key = Single Source of Truth
백엔드 요청 동적 필드 → attributes JSON 저장, field_key 통일
프론트 작업 백엔드 완료 후 하드코딩 매핑 제거

현재 문제

품목기준관리 field_key    프론트엔드 변환      백엔드 API 응답
─────────────────────    ─────────────────    ─────────────────
Part_type            →   part_type        →   part_type (불일치!)
Installation_type_1  →   installation_type →  저장 안됨
side_dimensions_horizontal → side_spec_width → 저장 안됨

두 개의 요청서가 따로 놀면서 백엔드에서 각각 다르게 구현 → 키 불일치 발생

이상적인 구조

품목기준관리 (field_key 정의)
         │
         ▼
    ┌────────────┐
    │ field_key  │ ← Single Source of Truth
    └────────────┘
         │
    ┌────┴────┬────────┬────────┐
    ▼         ▼        ▼        ▼
  등록       수정      상세     리스트

  (전부 동일한 field_key로 저장/조회/렌더링)

기대 효과

  1. 단위 필드 혼란 해결: field_key가 "unit"이면 그게 단위 (명확!)
  2. 필드 타입 자동 인식: 품목기준관리 field_type 보고 자동 렌더링
  3. 누락 데이터 분석 용이: field_key 하나만 확인하면 끝
  4. 디버깅 속도 향상: API 응답 = 폼 데이터 (변환 없음)

수정 요청

  1. 품목기준관리 field_key를 기준으로 API 요청/응답 키 통일
  2. 동적 필드는 attributes JSON에 field_key 그대로 저장
  3. 조회 시에도 field_key 그대로 응답

영향 범위

  • 품목관리 전체 (등록/수정/상세/리스트)
  • 모든 품목 유형 (FG, PT, SM, RM, CS)

우선순위

🔴 최우선 - 이 구조 개선 후 아래 개별 이슈들 대부분 자동 해결


1. 소모품(CS) 등록 시 규격(specification) 저장 안됨

상태: 🔴 수정 필요

발견일: 2025-12-06

파일 위치

/app/Http/Requests/Item/ItemStoreRequest.php - rules() 메서드 (Line 14-42)

현재 문제

  • specification 필드가 validation rules에 없음
  • Laravel FormRequest는 rules에 정의되지 않은 필드를 $request->validated() 결과에서 제외
  • 프론트엔드에서 specification: "테스트" 값을 보내도 백엔드에서 무시됨
  • DB에 규격 값이 null로 저장됨

프론트엔드 확인 사항

  • DynamicItemForm에서 97_specificationspecspecification으로 정상 변환됨
  • API 요청 payload에 specification 필드 포함 확인됨
  • 백엔드 ItemsService.createMaterial()에서 $data['specification'] 참조하나 값이 없음

수정 요청

// /app/Http/Requests/Item/ItemStoreRequest.php

public function rules(): array
{
    return [
        // 필수 필드
        'code' => 'required|string|max:50',
        'name' => 'required|string|max:255',
        'product_type' => 'required|string|in:FG,PT,SM,RM,CS',
        'unit' => 'required|string|max:20',

        // 선택 필드
        'category_id' => 'nullable|integer|exists:categories,id',
        'description' => 'nullable|string',
        'specification' => 'nullable|string|max:255',  // ✅ 추가 필요

        // ... 나머지 기존 필드들 ...
    ];
}

영향 범위

  • 소모품(CS) 등록
  • 원자재(RM) 등록 (해당 시)
  • 부자재(SM) 등록 (해당 시)

2. Material(SM, RM, CS) 수정 시 material_code 중복 에러

상태: 🔴 수정 필요

발견일: 2025-12-06

현재 문제

  • Material 수정 시 material_code 중복 체크 에러 발생
  • 케이스 1: 값을 변경하지 않아도 자기 자신과 중복 체크됨
  • 케이스 2: 소프트 삭제된 품목의 코드와도 중복 체크됨
  • 에러 메시지: Duplicate entry '알루미늄-옵션2-2' for key 'materials.materials_material_code_unique'

원인

  1. UPDATE 시 자기 자신의 ID를 제외하지 않음
  2. 소프트 삭제(deleted_at)된 레코드도 unique 체크에 포함됨

수정 요청

// Material 수정 Request 파일 (MaterialUpdateRequest.php 또는 해당 파일)
use Illuminate\Validation\Rule;

public function rules(): array
{
    return [
        // ... 기존 필드들 ...

        // ✅ 수정 시 자기 자신 제외 + 소프트삭제 제외하고 unique 체크
        'material_code' => [
            'required',
            'string',
            'max:255',
            Rule::unique('materials', 'material_code')
                ->whereNull('deleted_at')      // 소프트삭제된 건 제외
                ->ignore($this->route('id')),  // 자기 자신 제외
        ],

        // ... 나머지 필드들 ...
    ];
}

영향 범위

  • 원자재(RM) 수정
  • 부자재(SM) 수정
  • 소모품(CS) 수정

비고

  • 현재 수정 자체가 불가능하여 수정 후 데이터 검증이 어려움
  • 이 이슈 해결 후 수정 기능 재검증 필요

3. Material(SM, RM) 수정 시 규격(specification) 로딩 안됨

상태: 🔴 확인 필요

발견일: 2025-12-06

현재 문제

  • SM(부자재), RM(원자재) 수정 페이지 진입 시 규격 값이 표시 안됨
  • 1회 수정 후 다시 수정 페이지 진입 시 규격 값 없음
  • CS(소모품)과 동일한 문제로 추정

원인 추정

  • 백엔드에서 options 배열이 제대로 저장되지 않거나 반환되지 않음
  • SM/RM은 standard_* 필드 조합으로 specification을 생성하고, 이 값을 options 배열에도 저장
  • 수정 페이지에서는 options 배열을 읽어서 폼에 표시
  • options가 null이면 규격 필드들이 빈 값으로 표시됨

확인 요청

// Material 조회 API 응답에서 options 필드 확인 필요
// GET /api/v1/items/{id}?item_type=MATERIAL

// 응답 예시 (정상)
{
    "id": 396,
    "name": "썬더볼트",
    "specification": "부자재2-2",
    "options": [
        {"label": "standard_1", "value": "부자재2"},
        {"label": "standard_2", "value": "2"}
    ]  // ✅ options 배열이 있어야 함
}

// 응답 예시 (문제)
{
    "id": 396,
    "name": "썬더볼트",
    "specification": "부자재2-2",
    "options": null  // ❌ options가 null이면 규격 로딩 불가
}

수정 요청

  1. Material 저장 시 options 배열 정상 저장 확인
  2. Material 조회 시 options 필드 반환 확인
  3. options가 JSON 컬럼이라면 정상적인 JSON 형식으로 저장되는지 확인

영향 범위

  • 원자재(RM) 수정
  • 부자재(SM) 수정

4. Material(SM, RM, CS) 비고(remarks) 저장 안됨

상태: 🔴 수정 필요

발견일: 2025-12-06

현재 문제

  • 소모품(CS), 원자재(RM), 부자재(SM) 등록/수정 시 비고(remarks)가 저장되지 않음
  • 프론트에서 noteremarks로 정상 변환하여 전송
  • 백엔드 Service에서 $data['remarks'] 참조하지만 값이 없음

원인 분석

  • 프론트엔드: noteremarks 변환 (materialTransform.ts:115)
  • 백엔드 Service: 'remarks' => $data['remarks'] ?? null (ItemsService.php:301)
  • 백엔드 Model: remarks 컬럼 존재 (Material.php:31)
  • 백엔드 Request: remarks validation rule 없음 누락

수정 요청

// /app/Http/Requests/Item/ItemStoreRequest.php
// /app/Http/Requests/Item/ItemUpdateRequest.php

public function rules(): array
{
    return [
        // 기존 필드들...
        'description' => 'nullable|string',

        // ✅ 추가 필요
        'remarks' => 'nullable|string',  // 비고 필드

        // ... 나머지 필드들 ...
    ];
}

영향 범위

  • 소모품(CS) 등록/수정
  • 원자재(RM) 등록/수정
  • 부자재(SM) 등록/수정

비고

  • 1번 이슈(specification)와 동일한 원인: Request validation 누락
  • 함께 처리하면 효율적

5. 품목기준관리 옵션 필드 식별자 필요 (장기 개선)

상태: 🟡 개선 권장

발견일: 2025-12-06

현재 문제

  • 품목기준관리에서 옵션 필드의 field_key를 자유롭게 입력 가능
  • 프론트엔드는 standard_*, option_* 패턴으로 옵션 필드를 식별
  • 패턴에 맞지 않는 field_key (예: st_2)는 규격(specification) 조합에서 누락됨
  • 결과: 부자재(SM)의 규격값이 저장되지 않음

임시 해결 (프론트엔드)

  • 품목기준관리에서 field_key를 standard_* 패턴으로 통일
  • 예: st_2standard_2

근본 해결 요청 (백엔드)

// 품목기준관리 API 응답에 옵션 필드 여부 표시

// 현재 응답
{
    "field_key": "st_2",
    "field_type": "select",
    "field_name": "규격옵션"
}

// 개선 요청
{
    "field_key": "st_2",
    "field_type": "select",
    "field_name": "규격옵션",
    "is_spec_option": true  // ✅ 규격 조합용 옵션 필드인지 표시
}

기대 효과

  • 프론트엔드가 field_key 패턴에 의존하지 않음
  • is_spec_option: true인 필드만 규격 조합에 사용
  • 새로운 field_key 패턴이 추가되어도 프론트 수정 불필요

영향 범위

  • 원자재(RM) 등록/수정
  • 부자재(SM) 등록/수정
  • 향후 추가되는 Material 유형

6. 조립부품(PT-ASSEMBLY) 필드 저장 안됨 - fillable 누락

상태: 🔴 수정 필요

발견일: 2025-12-06

현재 문제

  • 조립부품 등록 후 상세보기/수정 페이지에서 데이터가 제대로 표시되지 않음
  • 프론트엔드는 데이터를 정상 전송하고 있음
  • 백엔드에서 조립부품 필드들이 저장되지 않음

원인 분석

프론트엔드 전송 데이터 (정상)

// DynamicItemForm/index.tsx - handleFormSubmit()
const submitData = {
    ...convertedData,           // 폼 데이터 (installation_type, assembly_type 등 포함)
    product_type: 'PT',
    part_type: 'ASSEMBLY',      // ✅ 명시적 추가
    bending_diagram: base64,    // ✅ 캔버스 이미지
    bom: [...],                 // ✅ BOM 데이터
};

백엔드 저장 로직 (문제)

// ItemsService.php - createProduct()
private function createProduct(array $data, int $tenantId, int $userId): Product
{
    $payload = $data;
    // ... 기본 필드만 설정
    return Product::create($payload);  // Mass Assignment
}

Product 모델 fillable (누락 필드 있음)

// Product.php
protected $fillable = [
    'tenant_id', 'code', 'name', 'unit', 'category_id',
    'product_type',
    'attributes', 'description',        // ✅ attributes JSON 있음
    'part_type',                         // ✅ 있음
    'bending_diagram', 'bending_details', // ✅ 있음
    // ❌ installation_type 없음
    // ❌ assembly_type 없음
    // ❌ side_spec_width 없음
    // ❌ side_spec_height 없음
    // ❌ length 없음
];

필드별 저장 상태

필드 프론트 전송 fillable 저장 여부
part_type 컬럼 저장됨
bending_diagram 컬럼 ⚠️ 파일 업로드 별도 처리
installation_type 없음 저장 안됨
assembly_type 없음 저장 안됨
side_spec_width 없음 저장 안됨
side_spec_height 없음 저장 안됨
length 없음 저장 안됨
bom ⚠️ 별도 처리 확인 필요

수정 요청

방법 1: attributes JSON에 저장 (권장)

// ItemsService.php - createProduct() 수정

private function createProduct(array $data, int $tenantId, int $userId): Product
{
    // 조립부품 전용 필드들을 attributes JSON으로 묶기
    $assemblyFields = ['installation_type', 'assembly_type', 'side_spec_width', 'side_spec_height', 'length'];
    $attributes = $data['attributes'] ?? [];

    foreach ($assemblyFields as $field) {
        if (isset($data[$field])) {
            $attributes[$field] = $data[$field];
            unset($data[$field]);  // payload에서 제거
        }
    }

    $payload = $data;
    $payload['tenant_id'] = $tenantId;
    $payload['created_by'] = $userId;
    $payload['attributes'] = !empty($attributes) ? $attributes : null;
    // ... 나머지 동일

    return Product::create($payload);
}

방법 2: 컬럼 추가 + fillable 등록

// Product.php - fillable에 추가
protected $fillable = [
    // 기존 필드들...
    'installation_type',    // ✅ 추가
    'assembly_type',        // ✅ 추가
    'side_spec_width',      // ✅ 추가
    'side_spec_height',     // ✅ 추가
    'length',               // ✅ 추가 (또는 assembly_length)
];

// + migration으로 컬럼 추가 필요

프론트엔드 대응 (완료)

  • 프론트에서 data.xxx 또는 data.attributes.xxx 둘 다에서 값을 찾도록 수정 완료
  • 상세보기: items/[id]/page.tsx - mapApiResponseToItemMaster 함수
  • 수정페이지: items/[id]/edit/page.tsx - mapApiResponseToFormData 함수

영향 범위

  • 조립부품(PT-ASSEMBLY) 등록/조회/수정
  • 설치유형, 마감, 측면규격, 길이 모든 필드

우선순위

🔴 높음 - 조립부품 등록 기능이 완전히 동작하지 않음


7. 파일 업로드 API 500 에러 - ApiResponse 클래스 네임스페이스 불일치

상태: 🔴 수정 필요

발견일: 2025-12-06

현재 문제

  • 품목 파일 업로드 (전개도, 시방서, 인정서) 시 500 에러 발생
  • 절곡부품, 조립부품 모두 동일한 에러
  • 파일이 업로드되지 않음

에러 로그

[2025-12-06 17:28:22] DEV.ERROR: Class "App\Http\Responses\ApiResponse" not found
{"exception":"[object] (Error(code: 0): Class \"App\\Http\\Responses\\ApiResponse\" not found
at /home/webservice/api/app/Http/Controllers/Api/V1/ItemsFileController.php:31)

원인 분석

네임스페이스 불일치

위치 네임스페이스
ItemsFileController.php (Line 7) use App\Http\Responses\ApiResponse
실제 파일 위치 App\Helpers\ApiResponse

파일 위치

/app/Http/Controllers/Api/V1/ItemsFileController.php (Line 7)

현재 코드

<?php

namespace App\Http\Controllers\Api\V1;

use App\Http\Controllers\Controller;
use App\Http\Requests\ItemsFileUploadRequest;
use App\Http\Responses\ApiResponse;  // ❌ 잘못된 경로
// ...

수정 요청

<?php

namespace App\Http\Controllers\Api\V1;

use App\Http\Controllers\Controller;
use App\Http\Requests\ItemsFileUploadRequest;
use App\Helpers\ApiResponse;  // ✅ 올바른 경로
// ...

영향 범위

  • 절곡부품(PT-BENDING) 전개도 업로드
  • 조립부품(PT-ASSEMBLY) 전개도 업로드
  • 제품(FG) 시방서 업로드
  • 제품(FG) 인정서 업로드

우선순위

🔴 긴급 - 모든 파일 업로드 기능이 동작하지 않음 (한 줄 수정으로 해결 가능)


수정 완료 내역

수정 완료된 항목은 아래로 이동

(아직 없음)


참고 사항

관련 파일 (프론트엔드)

  • src/app/[locale]/(protected)/items/create/page.tsx - 품목 등록 페이지
  • src/app/[locale]/(protected)/items/[id]/edit/page.tsx - 품목 수정 페이지
  • src/components/items/DynamicItemForm/index.tsx - 동적 폼 컴포넌트

관련 파일 (백엔드)

  • /app/Http/Controllers/Api/V1/ItemsController.php - 품목 API 컨트롤러
  • /app/Services/ItemsService.php - 품목 서비스 레이어
  • /app/Http/Requests/Item/ItemStoreRequest.php - 등록 요청 검증
  • /app/Http/Requests/Item/ItemUpdateRequest.php - 수정 요청 검증
  • /app/Models/Materials/Material.php - Material 모델