# Screen 149 필드 타입 검증 가이드

## 배경
- **화면 149**: 품목정보 (item_info 테이블) 폼
- **division 컬럼**: DB에서 `input_type = 'text'`로 변경했으나 화면에는 여전히 SELECT 드롭다운으로 표시
- **unit 컬럼**: `input_type = 'category'` → SELECT 드롭다운으로 표시되어야 함

## DB 현황 (vexplor-dev 조회 결과)

| column_name | company_code | input_type |
|-------------|--------------|------------|
| division | * | category |
| division | COMPANY_7 | **text** |
| division | COMPANY_8, 9, 10, 18, 19, 20, 21 | category |
| unit | * | text |
| unit | COMPANY_18, 19, 20, 21, 7, 8, 9 | **category** |

**주의:** `wace` 사용자는 `company_code = '*'` (최고 관리자)입니다.
- division: company * → **category** (text 아님)
- unit: company * → **text** (category 아님)

**회사별로 다릅니다.** 예: COMPANY_7의 division은 text, unit은 category.

---

## 수동 검증 절차

### 1. 로그인
- URL: `http://localhost:9771/login`
- User ID: `wace`
- Password: `wace0909!!`
- 회사: "탑씰" (해당 회사 코드 확인 필요)

### 2. 화면 149 접속
- URL: `http://localhost:9771/screens/149`
- 페이지 로드 대기

### 3. 필드 확인

#### 구분 (division)
- **예상 (DB 기준):**
  - company *: SELECT (category)
  - COMPANY_7: TEXT INPUT (text)
- **실제:** TEXT INPUT 또는 SELECT 중 어느 쪽인지 확인

#### 단위 (unit)
- **예상 (DB 기준):**
  - company *: TEXT INPUT (text)
  - COMPANY_18~21, 7~9: SELECT (category)
- **실제:** TEXT INPUT 또는 SELECT 중 어느 쪽인지 확인

### 4. 스크린샷
- 구분, 단위 필드가 함께 보이도록 캡처

---

## 코드 흐름 (input_type → 렌더링)

### 1. 컬럼 메타 로드
```
DynamicComponentRenderer
  → loadColumnMeta(screenTableName)
  → GET /api/table-management/tables/item_info/columns?size=1000
  → columnMetaCache[tableName][columnName] = { inputType, ... }
```

### 2. 렌더 타입 결정 (357~369행)
```javascript
const dbInputType = columnMetaCache[screenTableName]?.[baseCol]?.inputType;
const ft = dbInputType || componentConfig?.fieldType;

if (["text", "number", ...].includes(ft)) return "v2-input";   // 텍스트 입력
if (["select", "category", "entity"].includes(ft)) return "v2-select";  // 드롭다운
```

### 3. mergeColumnMeta (81~130행)
- DB `input_type`이 화면 저장값보다 우선
- `needsSync`이면 DB 값으로 덮어씀

---

## 캐시 관련

### 1. 프론트엔드 (DynamicComponentRenderer)
- `columnMetaCache`: TTL 5초
- `table-columns-refresh` 이벤트 시 즉시 무효화 및 재로드

### 2. 백엔드 (tableManagementService)
- 컬럼 목록: 5분 TTL
- `updateColumnInputType` 호출 시 해당 테이블 캐시 삭제

### 3. 캐시 무효화가 필요한 경우
- 데이터 타입 관리에서 변경 후 화면이 갱신되지 않을 때
- **대응:** 페이지 새로고침 또는 `?_t=timestamp`로 API 재요청

---

## 가능한 원인

### 1. 회사 코드 불일치
- 로그인한 사용자 회사와 DB의 `company_code`가 다를 수 있음
- `wace`는 `company_code = '*'` → division은 category, unit은 text

### 2. 화면 레이아웃에 저장된 값
- `componentConfig.fieldType`이 있으면 DB보다 우선될 수 있음
- 코드상으로는 `dbInputType`이 우선이므로, DB가 제대로 로드되면 덮어씀

### 3. 캐시
- 백엔드 5분, 프론트 5초
- 데이터 타입 변경 후 곧바로 화면을 열면 이전 캐시가 사용될 수 있음

### 4. API 응답 구조
- `columnMetaCache`에 넣을 때 `col.column_name || col.columnName` 사용
- `mergeColumnMeta`는 `meta.input_type || meta.inputType` 사용
- 백엔드는 `inputType`(camelCase) 반환 → `columnMetaCache`에 `inputType` 유지

---

## 디버깅용 Console 스크립트

화면 149 로드 후 브라우저 Console에서 실행:

```javascript
// 1. columnMetaCache 조회 (DynamicComponentRenderer 내부)
// React DevTools로 DynamicComponentRenderer 선택 후
// 또는 전역에 노출해 둔 경우:
const meta = window.__COLUMN_META_CACHE__?.item_info;
if (meta) {
  console.log("division:", meta.division?.inputType || meta.division?.input_type);
  console.log("unit:", meta.unit?.inputType || meta.unit?.input_type);
}

// 2. API 직접 호출
fetch("/api/table-management/tables/item_info/columns?size=1000", {
  credentials: "include"
})
  .then(r => r.json())
  .then(d => {
    const cols = d.data?.columns || d.columns || [];
    const div = cols.find(c => (c.columnName || c.column_name) === "division");
    const unit = cols.find(c => (c.columnName || c.column_name) === "unit");
    console.log("API division:", div?.inputType || div?.input_type);
    console.log("API unit:", unit?.inputType || unit?.input_type);
  });
```

---

## 권장 사항

1. **회사 코드 확인**
   - 로그인한 사용자의 `company_code` 확인
   - `division`/`unit`을 text/category로 바꾼 회사가 맞는지 확인

2. **캐시 우회**
   - 데이터 타입 변경 후 페이지 새로고침
   - 또는 5초 이상 대기 후 다시 접속

3. **데이터 타입 관리에서 변경 시**
   - 저장 후 `table-columns-refresh` 이벤트 발생 여부 확인
   - 화면 디자이너의 V2FieldConfigPanel에서 변경 시에는 이벤트가 발생함

4. **테이블 관리 UI에서 변경 시**
   - `table-columns-refresh` 이벤트가 발생하는지 확인
   - 없으면 해당 화면에서 수동으로 `window.dispatchEvent(new CustomEvent("table-columns-refresh"))` 호출 후 재검증
