# Item Master field_key 검증 정책 ## 개요 field_key 저장 및 검증 정책을 변경하여 시스템 필드(고정 컬럼)와의 충돌을 방지합니다. ## 변경 사항 ### 1. field_key 저장 정책 변경 **변경 전:** ``` field_key = {id}_{입력값} 예: 98_code, 99_name ``` **변경 후:** ``` field_key = {입력값} 예: code, name (단, 시스템 예약어는 사용 불가) ``` ### 2. 시스템 필드 예약어 검증 추가 #### 검증 흐름 ``` field_key 입력 ↓ source_table 확인 (products / materials) ↓ 해당 테이블 예약어 체크 ↓ 기존 필드 중복 체크 ↓ 저장 ``` #### source_table 기반 예약어 매핑 | source_table | 대상 테이블 | 예약어 목록 | |--------------|-------------|-------------| | `products` | products | code, name, unit, product_type, ... | | `materials` | materials | name, material_code, material_type, ... | | `null` | 전체 | products + materials 예약어 모두 체크 (안전 모드) | ## 구현 상세 ### 파일 구조 ``` app/ ├── Constants/ │ └── SystemFields.php # 신규: 예약어 상수 클래스 └── Services/ └── ItemMaster/ └── ItemFieldService.php # 수정: 예약어 검증 추가 ``` ### SystemFields 상수 클래스 ```php // app/Constants/SystemFields.php class SystemFields { // 소스 테이블 상수 public const SOURCE_TABLE_PRODUCTS = 'products'; public const SOURCE_TABLE_MATERIALS = 'materials'; // 그룹 ID 상수 public const GROUP_ITEM_MASTER = 1; // products 테이블 고정 컬럼 public const PRODUCTS = [ 'code', 'name', 'unit', 'category_id', 'product_type', 'description', 'is_sellable', 'is_purchasable', 'is_producible', 'is_variable_size', 'is_active', 'safety_stock', 'lead_time', 'product_category', 'part_type', 'bending_diagram', 'bending_details', 'specification_file', 'specification_file_name', 'certification_file', 'certification_file_name', 'certification_number', 'certification_start_date', 'certification_end_date', 'attributes', 'attributes_archive', ]; // materials 테이블 고정 컬럼 public const MATERIALS = [ 'name', 'item_name', 'specification', 'material_code', 'material_type', 'unit', 'category_id', 'is_inspection', 'is_active', 'search_tag', 'remarks', 'attributes', 'options', ]; // 공통 시스템 컬럼 public const COMMON = [ 'id', 'tenant_id', 'created_by', 'updated_by', 'deleted_by', 'created_at', 'updated_at', 'deleted_at', ]; // source_table 기반 예약어 조회 public static function getReservedKeys(string $sourceTable): array; // 예약어 여부 확인 public static function isReserved(string $fieldKey, string $sourceTable): bool; // 그룹 내 전체 예약어 조회 (안전 모드) public static function getAllReservedKeysForGroup(int $groupId): array; // 그룹 내 예약어 여부 확인 public static function isReservedInGroup(string $fieldKey, int $groupId): bool; } ``` ### ItemFieldService 검증 메서드 ```php private function validateFieldKeyUnique( string $fieldKey, int $tenantId, ?string $sourceTable = null, int $groupId = 1, ?int $excludeId = null ): void { // 1. 시스템 필드(예약어) 체크 if ($sourceTable) { if (SystemFields::isReserved($fieldKey, $sourceTable)) { throw ValidationException::withMessages([ 'field_key' => [__('error.field_key_reserved', ['field_key' => $fieldKey])], ]); } } else { // 안전 모드: 그룹 내 모든 테이블 예약어 체크 if (SystemFields::isReservedInGroup($fieldKey, $groupId)) { throw ValidationException::withMessages([ 'field_key' => [__('error.field_key_reserved', ['field_key' => $fieldKey])], ]); } } // 2. 기존 필드 중복 체크 // ... } ``` ### 호출 예시 ```php // 독립 필드 생성 시 $this->validateFieldKeyUnique( $data['field_key'], $tenantId, $data['source_table'] ?? null, // 'products' 또는 'materials' $data['group_id'] ?? 1 ); // 필드 수정 시 $this->validateFieldKeyUnique( $data['field_key'], $tenantId, $data['source_table'] ?? null, $field->group_id ?? 1, $id // excludeId ); ``` ## 에러 메시지 | 상황 | 메시지 키 | 메시지 | |------|----------|--------| | 시스템 예약어 충돌 | `error.field_key_reserved` | `"code"은(는) 시스템 예약어로 사용할 수 없습니다.` | | 기존 필드 중복 | `validation.unique` | `field_key은(는) 이미 사용 중입니다.` | ```php // lang/ko/error.php 'field_key_reserved' => '":field_key"은(는) 시스템 예약어로 사용할 수 없습니다.', // lang/ko/validation.php (Laravel 기본) 'unique' => ':attribute은(는) 이미 사용 중입니다.', ``` ## clone 메서드 field_key 복제 정책 ``` 원본 field_key: custom_field 복제본: custom_field_copy 중복 시: custom_field_copy2, custom_field_copy3, ... ``` ## 관련 파일 | 파일 | 변경 유형 | 설명 | |------|----------|------| | `app/Constants/SystemFields.php` | 신규 | 예약어 상수 클래스 | | `app/Services/ItemMaster/ItemFieldService.php` | 수정 | 검증 로직 추가 | | `lang/ko/error.php` | 수정 | 에러 메시지 추가 | ## 참고 - ItemPage 테이블의 `source_table` 컬럼: 실제 저장 테이블명 (products, materials) - ItemPage 테이블의 `item_type` 컬럼: FG, PT, SM, RM, CS (품목 유형 코드) - `group_id`: 카테고리 격리용 (1 = 품목관리)