Files
sam-docs/plans/mng-item-field-management-plan.md
hskwon 1c4a1ebe09 Merge remote-tracking branch 'origin/main'
# Conflicts:
#	plans/items-table-unification-plan.md
#	plans/mng-item-field-management-plan.md
2025-12-16 09:27:37 +09:00

26 KiB

MNG 품목기준 필드 관리 개발 계획

테넌트별 품목기준관리(ItemMaster) 시스템 필드 시딩 및 커스텀 필드 관리 기능

작성일: 2025-12-09 상태: 계획 중 관련 문서:

  • docs/specs/item-master-field-integration.md
  • docs/specs/item-master-field-key-validation.md
  • docs/specs/ITEM-MASTER-INDEX.md

1. 개요

1.1 목적

  • 테넌트별 품목기준 시스템 필드(고정 컬럼) 일괄 등록/삭제
  • 신규 테넌트 생성 시 초기 필드 데이터 자동 시딩
  • 기존 테넌트에 필드 데이터 수동 시딩
  • 커스텀 필드 추가/삭제 관리
  • 향후 회계, 생산 등 다양한 도메인 확장 지원

1.2 핵심 개념

┌─────────────────────────────────────────────────────────────────┐
│                    품목기준 필드 구분                            │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ┌─────────────────────────────────────┐                       │
│  │  시스템 필드 (System Fields)         │                       │
│  │  ─────────────────────────────────  │                       │
│  │  - products 테이블 고정 컬럼         │                       │
│  │    (code, name, unit, is_active...) │                       │
│  │  - materials 테이블 고정 컬럼        │                       │
│  │    (material_code, name, spec...)   │                       │
│  │  - storage_type = 'column'          │                       │
│  │  - 시딩으로 일괄 등록               │                       │
│  └─────────────────────────────────────┘                       │
│                                                                 │
│  ┌─────────────────────────────────────┐                       │
│  │  커스텀 필드 (Custom Fields)         │                       │
│  │  ─────────────────────────────────  │                       │
│  │  - 테넌트별 추가 필드                │                       │
│  │  - attributes JSON에 저장            │                       │
│  │  - storage_type = 'json'            │                       │
│  │  - MNG에서 수동 추가/삭제            │                       │
│  └─────────────────────────────────────┘                       │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

1.3 대상 테이블 (source_table)

source_table 설명 item_type
products 제품 테이블 FG (완제품), PT (부품)
materials 자재 테이블 SM (부자재), RM (원자재), CS (소모품)
product_components BOM 테이블 -
material_inspections 자재 검수 -
material_receipts 자재 입고 -

2. 기능 설계

2.1 메인 화면: 품목기준 필드 관리

URL: GET /item-master/fields

┌─────────────────────────────────────────────────────────────────┐
│ 품목기준 필드 관리                                               │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  테넌트: [현재 테넌트명]                                         │
│                                                                 │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │ 시스템 필드 시딩                                         │   │
│  │ ───────────────────────────────────────────────────────│   │
│  │                                                         │   │
│  │  소스 테이블별 상태:                                     │   │
│  │  ┌────────────────┬──────────┬─────────┬────────────┐  │   │
│  │  │ 테이블          │ 필드 수  │ 상태    │ 액션       │  │   │
│  │  ├────────────────┼──────────┼─────────┼────────────┤  │   │
│  │  │ products       │ 12/12    │ ●완료   │ [초기화]   │  │   │
│  │  │ materials      │ 0/8      │ ○미등록 │ [시딩]     │  │   │
│  │  │ product_comp.. │ 5/5      │ ●완료   │ [초기화]   │  │   │
│  │  │ material_ins.. │ 0/8      │ ○미등록 │ [시딩]     │  │   │
│  │  │ material_rec.. │ 0/10     │ ○미등록 │ [시딩]     │  │   │
│  │  └────────────────┴──────────┴─────────┴────────────┘  │   │
│  │                                                         │   │
│  │  [전체 시딩]  [전체 초기화]                              │   │
│  │                                                         │   │
│  └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │ 커스텀 필드 관리                                   [+ 추가] │   │
│  │ ───────────────────────────────────────────────────────│   │
│  │                                                         │   │
│  │  필터: [소스 테이블 ▼] [필드 타입 ▼]                     │   │
│  │                                                         │   │
│  │  ┌───┬─────────┬───────────┬────────┬────────┬───────┐│   │
│  │  │ □ │ 필드키  │ 필드명    │ 타입   │ 소스   │ 액션  ││   │
│  │  ├───┼─────────┼───────────┼────────┼────────┼───────┤│   │
│  │  │ □ │ weight  │ 무게      │ number │products│ [삭제]││   │
│  │  │ □ │ grade   │ 등급      │dropdown│materials│[삭제]││   │
│  │  │ □ │ color   │ 색상      │ textbox│products│ [삭제]││   │
│  │  └───┴─────────┴───────────┴────────┴────────┴───────┘│   │
│  │                                                         │   │
│  │  [선택 삭제]                                             │   │
│  │                                                         │   │
│  └─────────────────────────────────────────────────────────┘   │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

2.2 시스템 필드 시딩

기능: 특정 source_table의 시스템 필드를 item_fields에 일괄 등록

시딩 데이터 예시 (products):

[
    ['field_key' => 'code', 'field_name' => '품목코드', 'field_type' => 'textbox', 'is_required' => true],
    ['field_key' => 'name', 'field_name' => '품목명', 'field_type' => 'textbox', 'is_required' => true],
    ['field_key' => 'unit', 'field_name' => '단위', 'field_type' => 'dropdown', 'is_required' => true],
    ['field_key' => 'product_type', 'field_name' => '제품유형', 'field_type' => 'dropdown'],
    ['field_key' => 'is_sellable', 'field_name' => '판매가능', 'field_type' => 'checkbox'],
    ['field_key' => 'is_purchasable', 'field_name' => '구매가능', 'field_type' => 'checkbox'],
    ['field_key' => 'is_producible', 'field_name' => '생산가능', 'field_type' => 'checkbox'],
    ['field_key' => 'is_active', 'field_name' => '활성화', 'field_type' => 'checkbox'],
    // ...
]

저장 시 설정:

[
    'tenant_id' => $currentTenantId,
    'source_table' => 'products',
    'source_column' => 'code',  // field_key와 동일
    'storage_type' => 'column', // DB 컬럼 직접 저장
    'is_system' => true,        // 시스템 필드 표시 (선택적)
]

2.3 시스템 필드 초기화

기능: 특정 source_table의 시스템 필드를 삭제하고 다시 시딩

주의사항:

  • 커스텀 필드는 유지 (storage_type = 'json'인 필드)
  • 확인 다이얼로그 필수
  • 삭제 전 관련 entity_relationships도 정리 필요

2.4 커스텀 필드 추가

URL: POST /item-master/fields/custom

추가 모달:

┌─────────────────────────────────────────────┐
│ 커스텀 필드 추가                      [닫기] │
├─────────────────────────────────────────────┤
│                                             │
│  소스 테이블: [products ▼]                  │
│                                             │
│  필드 키: [_______________]                 │
│  * 영문, 숫자, 언더스코어만 허용             │
│  * 시스템 예약어 사용 불가                   │
│                                             │
│  필드명: [_______________]                  │
│                                             │
│  필드 타입: [textbox ▼]                     │
│  - textbox, number, dropdown,               │
│    checkbox, date, textarea                 │
│                                             │
│  필수 여부: [ ] 필수                        │
│                                             │
│  기본값: [_______________] (선택)           │
│                                             │
│  옵션 (dropdown 선택 시):                   │
│  ┌─────────────────────────────────────┐   │
│  │ 라벨      │ 값       │            │   │
│  │ [옵션1  ] │ [val1  ] │ [+ 추가]   │   │
│  └─────────────────────────────────────┘   │
│                                             │
│  [취소]                        [저장]       │
│                                             │
└─────────────────────────────────────────────┘

저장 시 설정:

[
    'tenant_id' => $currentTenantId,
    'source_table' => 'products',
    'source_column' => null,                    // 커스텀 필드는 null
    'storage_type' => 'json',                   // JSON 저장
    'json_path' => 'attributes.custom_weight',  // 저장 경로
    'is_system' => false,
]

2.5 커스텀 필드 삭제

기능: 선택한 커스텀 필드 삭제

주의사항:

  • 시스템 필드(storage_type = 'column')는 삭제 불가
  • 이미 데이터가 있는 경우 경고
  • entity_relationships 정리 필요

3. 데이터 구조

3.1 item_fields 테이블 (기존 + 확장)

item_fields
├── id
├── tenant_id
├── field_key             -- 고유 키 (code, name, custom_weight)
├── field_name            -- 표시명 (품목코드, 품목명, 커스텀 무게)
├── field_type            -- 필드 타입 (textbox, dropdown...)
├── is_required           -- 필수 여부
├── order_no              -- 정렬 순서
├── default_value         -- 기본값
├── options               -- 드롭다운 옵션 JSON
├── properties            -- 속성 JSON
├── validation_rules      -- 검증 규칙 JSON
├── source_table          -- 소스 테이블 (products, materials)
├── source_column         -- 소스 컬럼 (시스템 필드만)
├── storage_type          -- 저장 방식 (column, json)
├── json_path             -- JSON 저장 경로 (커스텀 필드만)
├── is_active
├── created_at / updated_at / deleted_at

3.2 시스템 필드 정의 (SystemFields 상수)

// app/Constants/SystemFields.php 활용
// 이미 구현된 상수 클래스에서 시딩 데이터 추출

class SystemFields
{
    public const PRODUCTS = [
        'code', 'name', 'unit', 'product_type', 'category_id',
        'is_sellable', 'is_purchasable', 'is_producible', 'is_active',
        'certification_number', 'certification_date', 'certification_expiry',
        // ...
    ];

    public const MATERIALS = [
        'material_code', 'name', 'item_name', 'specification',
        'unit', 'category_id', 'is_inspection', 'search_tag',
        // ...
    ];
}

4. 파일 구조

mng/
├── app/
│   ├── Http/
│   │   └── Controllers/
│   │       └── ItemFieldController.php           # 신규
│   ├── Models/
│   │   └── ItemField.php                         # 신규 (MNG 전용)
│   ├── Services/
│   │   └── ItemFieldSeedingService.php           # 신규: 시딩 로직
│   └── Constants/
│       └── SystemFieldDefinitions.php            # 신규: 시딩 데이터 정의
├── resources/
│   └── views/
│       └── item-fields/
│           ├── index.blade.php                   # 메인 화면
│           ├── _seeding-section.blade.php        # 시딩 섹션 (partial)
│           ├── _custom-fields-section.blade.php  # 커스텀 필드 섹션
│           └── _create-modal.blade.php           # 추가 모달
└── routes/
    └── web.php                                   # 라우트 추가

5. 구현 단계

Phase 1: 기반 구조 (0.5일)

작업 파일 설명
ItemField 모델 app/Models/ItemField.php API DB 참조 모델
상수 클래스 app/Constants/SystemFieldDefinitions.php 테이블별 시딩 데이터
라우트 등록 routes/web.php CRUD 라우트
메뉴 추가 사이드바 품목기준 > 필드 관리

Phase 2: 시딩 기능 (1일)

작업 파일 설명
시딩 서비스 ItemFieldSeedingService.php 시딩/초기화 로직
메인 화면 index.blade.php 시딩 상태 표시
시딩 API ItemFieldController.php 시딩/초기화 엔드포인트
확인 다이얼로그 JS 초기화 확인

Phase 3: 커스텀 필드 관리 (1일)

작업 파일 설명
커스텀 필드 목록 index.blade.php 목록 표시
추가 모달 _create-modal.blade.php 필드 추가 UI
필드 키 검증 ItemFieldController.php 예약어/중복 체크
삭제 기능 ItemFieldController.php 삭제 처리

Phase 4: 테스트/마무리 (0.5일)

작업 설명
시딩 테스트 전체/개별 시딩
초기화 테스트 초기화 후 재시딩
커스텀 필드 테스트 추가/삭제
예약어 검증 테스트 시스템 필드명 입력 시도

6. API 엔드포인트

메서드 URL 설명
GET /item-master/fields 필드 관리 메인 화면
GET /item-master/fields/status 테이블별 시딩 상태 조회 (AJAX)
POST /item-master/fields/seed 시스템 필드 시딩
POST /item-master/fields/reset 시스템 필드 초기화
GET /item-master/fields/custom 커스텀 필드 목록 (AJAX)
POST /item-master/fields/custom 커스텀 필드 추가
DELETE /item-master/fields/custom/{id} 커스텀 필드 삭제

7. 체크리스트

Phase 1: 기반 구조

  • ItemField 모델 생성 (API DB 참조)
  • SystemFieldDefinitions 상수 클래스 생성
  • 라우트 등록
  • 사이드바 메뉴 추가

Phase 2: 시딩 기능

  • ItemFieldSeedingService 생성
  • 테이블별 시딩 상태 조회
  • 단일 테이블 시딩
  • 전체 테이블 시딩
  • 시스템 필드 초기화
  • 확인 다이얼로그

Phase 3: 커스텀 필드

  • 커스텀 필드 목록 조회
  • 커스텀 필드 추가 모달
  • field_key 예약어 검증 연동
  • 커스텀 필드 삭제
  • 일괄 삭제

Phase 4: 마무리

  • 시딩 테스트
  • 초기화 테스트
  • 커스텀 필드 테스트
  • 에러 처리

8. SystemFieldDefinitions 상수 클래스

<?php
// mng/app/Constants/SystemFieldDefinitions.php

namespace App\Constants;

class SystemFieldDefinitions
{
    /**
     * products 테이블 시스템 필드 정의
     */
    public const PRODUCTS = [
        ['field_key' => 'code', 'field_name' => '품목코드', 'field_type' => 'textbox', 'is_required' => true, 'order_no' => 1],
        ['field_key' => 'name', 'field_name' => '품목명', 'field_type' => 'textbox', 'is_required' => true, 'order_no' => 2],
        ['field_key' => 'unit', 'field_name' => '단위', 'field_type' => 'dropdown', 'is_required' => true, 'order_no' => 3],
        ['field_key' => 'product_type', 'field_name' => '제품유형', 'field_type' => 'dropdown', 'order_no' => 4, 'options' => [
            ['label' => '완제품', 'value' => 'FG'],
            ['label' => '부품', 'value' => 'PT'],
        ]],
        ['field_key' => 'category_id', 'field_name' => '카테고리', 'field_type' => 'dropdown', 'order_no' => 5],
        ['field_key' => 'is_sellable', 'field_name' => '판매가능', 'field_type' => 'checkbox', 'order_no' => 6, 'default_value' => 'true'],
        ['field_key' => 'is_purchasable', 'field_name' => '구매가능', 'field_type' => 'checkbox', 'order_no' => 7],
        ['field_key' => 'is_producible', 'field_name' => '생산가능', 'field_type' => 'checkbox', 'order_no' => 8, 'default_value' => 'true'],
        ['field_key' => 'is_active', 'field_name' => '활성화', 'field_type' => 'checkbox', 'order_no' => 9, 'default_value' => 'true'],
        ['field_key' => 'certification_number', 'field_name' => '인증번호', 'field_type' => 'textbox', 'order_no' => 10],
        ['field_key' => 'certification_date', 'field_name' => '인증일자', 'field_type' => 'date', 'order_no' => 11],
        ['field_key' => 'certification_expiry', 'field_name' => '인증만료일', 'field_type' => 'date', 'order_no' => 12],
    ];

    /**
     * materials 테이블 시스템 필드 정의
     */
    public const MATERIALS = [
        ['field_key' => 'material_code', 'field_name' => '자재코드', 'field_type' => 'textbox', 'is_required' => true, 'order_no' => 1],
        ['field_key' => 'name', 'field_name' => '자재명', 'field_type' => 'textbox', 'is_required' => true, 'order_no' => 2],
        ['field_key' => 'item_name', 'field_name' => '품목명', 'field_type' => 'textbox', 'order_no' => 3],
        ['field_key' => 'specification', 'field_name' => '규격', 'field_type' => 'textbox', 'order_no' => 4],
        ['field_key' => 'unit', 'field_name' => '단위', 'field_type' => 'dropdown', 'is_required' => true, 'order_no' => 5],
        ['field_key' => 'category_id', 'field_name' => '카테고리', 'field_type' => 'dropdown', 'order_no' => 6],
        ['field_key' => 'is_inspection', 'field_name' => '검수필요', 'field_type' => 'checkbox', 'order_no' => 7],
        ['field_key' => 'search_tag', 'field_name' => '검색태그', 'field_type' => 'textarea', 'order_no' => 8],
    ];

    /**
     * product_components 테이블 (BOM) 시스템 필드 정의
     */
    public const PRODUCT_COMPONENTS = [
        ['field_key' => 'ref_type', 'field_name' => '참조유형', 'field_type' => 'dropdown', 'order_no' => 1, 'options' => [
            ['label' => '제품', 'value' => 'product'],
            ['label' => '자재', 'value' => 'material'],
        ]],
        ['field_key' => 'ref_id', 'field_name' => '참조품목', 'field_type' => 'dropdown', 'order_no' => 2],
        ['field_key' => 'quantity', 'field_name' => '수량', 'field_type' => 'number', 'is_required' => true, 'order_no' => 3],
        ['field_key' => 'formula', 'field_name' => '계산공식', 'field_type' => 'textbox', 'order_no' => 4],
        ['field_key' => 'note', 'field_name' => '비고', 'field_type' => 'textarea', 'order_no' => 5],
    ];

    /**
     * material_inspections 테이블 시스템 필드 정의
     */
    public const MATERIAL_INSPECTIONS = [
        ['field_key' => 'inspection_date', 'field_name' => '검수일', 'field_type' => 'date', 'is_required' => true, 'order_no' => 1],
        ['field_key' => 'inspector_id', 'field_name' => '검수자', 'field_type' => 'dropdown', 'order_no' => 2],
        ['field_key' => 'status', 'field_name' => '검수상태', 'field_type' => 'dropdown', 'order_no' => 3, 'options' => [
            ['label' => '대기', 'value' => 'pending'],
            ['label' => '진행중', 'value' => 'in_progress'],
            ['label' => '완료', 'value' => 'completed'],
            ['label' => '불합격', 'value' => 'rejected'],
        ]],
        ['field_key' => 'lot_no', 'field_name' => 'LOT번호', 'field_type' => 'textbox', 'order_no' => 4],
        ['field_key' => 'quantity', 'field_name' => '검수수량', 'field_type' => 'number', 'order_no' => 5],
        ['field_key' => 'passed_quantity', 'field_name' => '합격수량', 'field_type' => 'number', 'order_no' => 6],
        ['field_key' => 'rejected_quantity', 'field_name' => '불합격수량', 'field_type' => 'number', 'order_no' => 7],
        ['field_key' => 'note', 'field_name' => '비고', 'field_type' => 'textarea', 'order_no' => 8],
    ];

    /**
     * material_receipts 테이블 시스템 필드 정의
     */
    public const MATERIAL_RECEIPTS = [
        ['field_key' => 'receipt_date', 'field_name' => '입고일', 'field_type' => 'date', 'is_required' => true, 'order_no' => 1],
        ['field_key' => 'lot_no', 'field_name' => 'LOT번호', 'field_type' => 'textbox', 'order_no' => 2],
        ['field_key' => 'quantity', 'field_name' => '입고수량', 'field_type' => 'number', 'is_required' => true, 'order_no' => 3],
        ['field_key' => 'unit_price', 'field_name' => '단가', 'field_type' => 'number', 'order_no' => 4],
        ['field_key' => 'total_price', 'field_name' => '금액', 'field_type' => 'number', 'order_no' => 5],
        ['field_key' => 'supplier_id', 'field_name' => '공급업체', 'field_type' => 'dropdown', 'order_no' => 6],
        ['field_key' => 'warehouse_id', 'field_name' => '입고창고', 'field_type' => 'dropdown', 'order_no' => 7],
        ['field_key' => 'po_number', 'field_name' => '발주번호', 'field_type' => 'textbox', 'order_no' => 8],
        ['field_key' => 'invoice_number', 'field_name' => '송장번호', 'field_type' => 'textbox', 'order_no' => 9],
        ['field_key' => 'note', 'field_name' => '비고', 'field_type' => 'textarea', 'order_no' => 10],
    ];

    /**
     * 소스 테이블 목록
     */
    public const SOURCE_TABLES = [
        'products' => '제품',
        'materials' => '자재',
        'product_components' => 'BOM',
        'material_inspections' => '자재검수',
        'material_receipts' => '자재입고',
    ];

    /**
     * 소스 테이블별 필드 정의 가져오기
     */
    public static function getFieldsFor(string $sourceTable): array
    {
        return match ($sourceTable) {
            'products' => self::PRODUCTS,
            'materials' => self::MATERIALS,
            'product_components' => self::PRODUCT_COMPONENTS,
            'material_inspections' => self::MATERIAL_INSPECTIONS,
            'material_receipts' => self::MATERIAL_RECEIPTS,
            default => [],
        };
    }

    /**
     * 전체 테이블 필드 수 조회
     */
    public static function getTotalFieldCount(string $sourceTable): int
    {
        return count(self::getFieldsFor($sourceTable));
    }
}

9. 향후 확장

9.1 신규 도메인 추가 시

  1. SystemFieldDefinitions에 상수 추가
  2. SOURCE_TABLES에 테이블 추가
  3. MNG에서 해당 테이블 시딩

9.2 예정 도메인

  • 회계 (journals, accounts)
  • 생산 (work_orders, production_records)
  • 재고 (inventories, stock_movements)
  • 품질 (quality_controls)

변경 이력

날짜 내용
2025-12-09 문서 목적 수정: 권한 관리 → 품목기준 필드 시딩/관리
2025-12-09 초안 작성