Files
sam-react-prod/claudedocs/item-master/[API-REQUEST-2026-02-12] dynamic-field-type-backend-spec.md
유병철 020d74f36c feat(WEB): DynamicItemForm 필드 타입 확장 및 컴포넌트 레지스트리 추가
- DynamicFieldRenderer에 신규 필드 타입 추가 (Currency, File, MultiSelect, Radio, Reference, Toggle, UnitValue, Computed)
- DynamicTableSection 및 TableCellRenderer 추가
- 필드 프리셋 및 설정 구조 분리
- 컴포넌트 레지스트리 개발 도구 페이지 추가
- UniversalListPage 개선
- 근태관리 코드 정리
- 즐겨찾기 기능 및 동적 필드 타입 백엔드 스펙 문서 추가

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 11:17:57 +09:00

12 KiB

동적 필드 타입 확장 — 백엔드 API 스펙

작성일: 2026-02-12 프론트 구현 완료: [IMPL-2026-02-11] dynamic-field-components.md 설계 근거: [DESIGN-2026-02-11] dynamic-field-type-extension.md


요약

프론트엔드에서 14종 필드 타입 + table 섹션 타입 + 조건부 표시 연산자 9종을 렌더링할 준비가 완료되었습니다.

백엔드에서 해당 field_typeproperties JSON을 DB에 저장하고 API로 반환하면, 프론트에서 추가 작업 없이 자동 렌더링됩니다.


1. field_type 확장

현재 (6종)

textbox | number | dropdown | checkbox | date | textarea

추가 필요 (8종)

reference | multi-select | file | currency | unit-value | radio | toggle | computed

전체 (14종)

-- item_fields.field_type 컬럼의 허용값
ENUM('textbox', 'number', 'dropdown', 'checkbox', 'date', 'textarea',
     'reference', 'multi-select', 'file',
     'currency', 'unit-value', 'radio',
     'toggle', 'computed')

영향 범위

  • item_fields 테이블의 field_type 컬럼
  • item_master_fields 테이블의 field_type 컬럼 (deprecated지만 아직 사용 중이면)
  • 필드 생성/수정 API의 validation rule

2. 각 field_type별 properties JSON 스펙

모든 설정은 기존 item_fields.properties JSON 컬럼에 저장합니다.

2-1. reference (다른 테이블 검색/선택)

{
  "source": "vendors",        // 필수. 프리셋: vendors|items|customers|employees|warehouses|processes|equipment|sites|vehicles
  "displayField": "name",     // 선택. 기본 "name"
  "valueField": "id",         // 선택. 기본 "id"
  "searchFields": ["name"],   // 선택. 검색 대상 필드
  "searchApiUrl": "/api/...", // source="custom"일 때만 필수
  "columns": [                // 선택. 검색 모달 표시 컬럼
    { "key": "code", "label": "코드", "width": "100px" },
    { "key": "name", "label": "이름" }
  ],
  "displayFormat": "{code} - {name}",  // 선택. 선택 후 표시 포맷
  "returnFields": ["id", "code", "name"] // 선택. 프론트에 반환할 필드
}

저장값: string (선택한 항목의 valueField 값, 기본 id)

프론트 동작: source 프리셋이 있으면 /api/proxy/{source}?search={query} 호출. 없으면 searchApiUrl 사용.


2-2. multi-select (복수 선택 태그)

{
  "maxSelections": 5,       // 선택. 최대 선택 수 (기본: 무제한)
  "allowCustom": false,     // 선택. 직접 입력 허용 (기본: false)
  "layout": "chips"         // 선택. "chips" | "list" (기본: "chips")
}

options: 기존 dropdown과 동일 [{label, value}]item_fields.options 컬럼 사용

저장값: string[] JSON (예: ["CUT","BEND","WELD"])


2-3. file (파일/이미지 첨부)

{
  "accept": ".pdf,.doc,.jpg,.png",  // 선택. 허용 확장자 (기본: "*")
  "maxSize": 10485760,              // 선택. 최대 파일 크기 bytes (기본: 10MB)
  "maxFiles": 3,                    // 선택. 최대 파일 수 (기본: 1)
  "preview": true,                  // 선택. 이미지 미리보기 (기본: true)
  "category": "drawing"             // 선택. 파일 카테고리 태그
}

저장값: 파일 업로드 후 반환된 URL 또는 file ID

필요 API: POST /v1/files/upload (multipart) — 이미 있으면 그대로 사용


2-4. currency (통화 금액)

{
  "currency": "KRW",       // 선택. 기본 "KRW". 지원: KRW|USD|EUR|JPY|CNY|GBP
  "precision": 0,          // 선택. 소수점 자리 (기본: 0)
  "showSymbol": true,      // 선택. 통화 기호 표시 (기본: true)
  "allowNegative": false   // 선택. 음수 허용 (기본: false)
}

저장값: number (포맷 없는 원시 숫자)


2-5. unit-value (값 + 단위 조합)

{
  "units": [                // 필수. 단위 목록
    { "label": "mm", "value": "mm" },
    { "label": "cm", "value": "cm" },
    { "label": "m", "value": "m" }
  ],
  "defaultUnit": "mm",     // 선택. 기본 단위
  "precision": 2            // 선택. 소수점 자리
}

저장값: {"value": 100, "unit": "mm"} JSON


2-6. radio (라디오 버튼 그룹)

{
  "layout": "horizontal"   // 선택. "horizontal" | "vertical" (기본: "vertical")
}

options: 기존 dropdown과 동일 [{label, value}]item_fields.options 컬럼 사용

저장값: string (선택한 value)


2-7. toggle (On/Off 스위치)

{
  "onLabel": "사용",        // 선택. 기본 "ON"
  "offLabel": "미사용",     // 선택. 기본 "OFF"
  "onValue": "Y",          // 선택. 기본 "true"
  "offValue": "N"           // 선택. 기본 "false"
}

저장값: string (onValue 또는 offValue)


2-8. computed (계산 필드, 읽기전용)

{
  "formula": "unit_price * quantity",  // 필수. 수식 (field_key 참조)
  "dependsOn": ["unit_price", "quantity"], // 필수. 의존 필드 field_key 목록
  "format": "currency",               // 선택. "currency" | "number" | "percent"
  "precision": 0                       // 선택. 소수점 자리
}

저장값: number (프론트에서 자동 계산, 백엔드 저장 시에도 계산 검증 권장)

지원 연산: +, -, *, /, (, ) — field_key를 변수로 사용


3. section type 확장

현재

item_sections.type: ENUM('fields', 'bom')

추가 필요

item_sections.type: ENUM('fields', 'bom', 'table')

table 섹션의 properties JSON

item_sections.properties 컬럼 (신규 또는 기존 description 등과 함께):

{
  "tableConfig": {
    "columns": [
      {
        "key": "process_name",      // 컬럼 키
        "label": "공정명",          // 컬럼 헤더
        "fieldType": "reference",   // 셀 입력 타입 (ItemFieldType)
        "width": "150px",          // 선택
        "isRequired": true,        // 선택
        "isReadonly": false,       // 선택
        "options": [...],          // dropdown/radio/multi-select용
        "properties": {            // 해당 필드 타입의 properties
          "source": "processes"
        }
      },
      {
        "key": "cycle_time",
        "label": "사이클타임(초)",
        "fieldType": "number",
        "width": "100px"
      }
    ],
    "minRows": 1,               // 선택. 최소 행 수
    "maxRows": 30,              // 선택. 최대 행 수
    "summaryRow": [             // 선택. 합계행
      { "columnKey": "cycle_time", "type": "sum" },
      { "columnKey": "setup_time", "type": "avg" }
    ]
  }
}

summaryRow type: "sum" | "avg" | "count" | "label"

table 섹션 데이터 저장/조회 API

GET  /v1/items/{itemId}/section-data/{sectionId}
PUT  /v1/items/{itemId}/section-data/{sectionId}

요청/응답 body:

{
  "rows": [
    { "process_name": "절단", "cycle_time": 30, "setup_time": 10 },
    { "process_name": "절곡", "cycle_time": 45, "setup_time": 15 }
  ]
}

이미 유사한 API가 있으면 그대로 사용. 없으면 신규 생성 필요.


4. display_condition 연산자 확장

현재

// item_fields.display_condition
{
  "fieldConditions": [
    {
      "fieldKey": "item_type",
      "expectedValue": "FG",          // 정확히 일치 (equals만)
      "targetFieldIds": ["10", "11"]
    }
  ]
}

확장 (operator 필드 추가)

{
  "fieldConditions": [
    {
      "fieldKey": "item_type",
      "operator": "in",                // 신규: 연산자
      "expectedValue": "FG,PT",        // in/not_in은 콤마 구분
      "targetFieldIds": ["10", "11"]
    },
    {
      "fieldKey": "quantity",
      "operator": "greater_than",
      "expectedValue": "100",
      "targetSectionIds": ["5"]
    }
  ]
}

지원 연산자 목록

operator 설명 expectedValue 형식 예시
equals 정확히 일치 (기본값) 단일값 "FG"
not_equals 불일치 단일값 "RM"
in 목록 중 하나 일치 콤마 구분 "FG,PT,SM"
not_in 목록 중 어느 것에도 불일치 콤마 구분 "RM,CS"
greater_than 초과 (숫자) 숫자 문자열 "100"
less_than 미만 (숫자) 숫자 문자열 "0"
gte 이상 (숫자) 숫자 문자열 "50"
lte 이하 (숫자) 숫자 문자열 "1000"
contains 부분 문자열 포함 문자열 "강판"

하위호환: operator가 없으면 프론트에서 equals로 처리. 기존 데이터 마이그레이션 불필요.


5. 기존 API 변경 없음 (확인)

다음 API들은 이미 field_typeproperties를 통과시키므로 변경 불필요:

API 용도 비고
GET /v1/item-master/pages/{id}/structure 페이지 구조 조회 field_type, properties 이미 반환
POST /v1/item-master/fields 필드 생성 field_type, properties 이미 수신
PUT /v1/item-master/fields/{id} 필드 수정 동일
GET /v1/item-master/init 초기화 조회 field_type 이미 반환

변경이 필요한 부분:

  1. field_type validation rule에 8종 추가
  2. item_sections.type'table' 추가
  3. (선택) table 섹션 데이터 저장/조회 API 신규

6. 작업 우선순위 제안

즉시 (프론트와 바로 연동 가능)

# 작업 난이도 설명
1 field_type 허용값 8종 추가 낮음 DB ENUM 또는 validation 수정만
2 display_condition operator 저장 허용 낮음 JSON이므로 스키마 변경 없음

다음 단계

# 작업 난이도 설명
3 section type 'table' 추가 중간 DB + API validation
4 table 섹션 데이터 API 중간 신규 엔드포인트 (CRUD)
5 reference 소스별 검색 API 높음 각 소스(vendors, items 등)의 검색 API 표준화

나중 (필요 시)

# 작업 난이도 설명
6 파일 업로드 API 높음 POST /v1/files/upload (이미 있으면 불필요)
7 computed 필드 서버사이드 검증 중간 저장 시 수식 재계산하여 값 검증

7. 테스트 방법

백엔드 작업 완료 후 확인 순서:

  1. 페이지 빌더 (/dev/page-builder)에서 신규 field_type으로 필드 추가
  2. 품목 등록 페이지에서 해당 필드가 올바르게 렌더링되는지 확인
  3. 저장/조회 사이클 테스트 (값이 properties 형식에 맞게 저장/복원되는지)

부록: 프론트 파일 매핑

field_type 프론트 컴포넌트 파일
textbox TextField DynamicItemForm/fields/TextField.tsx
number NumberField DynamicItemForm/fields/NumberField.tsx
dropdown DropdownField DynamicItemForm/fields/DropdownField.tsx
checkbox CheckboxField DynamicItemForm/fields/CheckboxField.tsx
date DateField DynamicItemForm/fields/DateField.tsx
textarea TextareaField DynamicItemForm/fields/TextareaField.tsx
reference ReferenceField DynamicItemForm/fields/ReferenceField.tsx
multi-select MultiSelectField DynamicItemForm/fields/MultiSelectField.tsx
file FileField DynamicItemForm/fields/FileField.tsx
currency CurrencyField DynamicItemForm/fields/CurrencyField.tsx
unit-value UnitValueField DynamicItemForm/fields/UnitValueField.tsx
radio RadioField DynamicItemForm/fields/RadioField.tsx
toggle ToggleField DynamicItemForm/fields/ToggleField.tsx
computed ComputedField DynamicItemForm/fields/ComputedField.tsx
section type 프론트 컴포넌트 파일
fields (기존 필드 렌더링) DynamicItemForm/index.tsx
bom DynamicBOMSection DynamicItemForm/sections/DynamicBOMSection.tsx
table DynamicTableSection DynamicItemForm/sections/DynamicTableSection.tsx