- 입력 필드/포장등록/담기 버튼 독립 ON/OFF 분리 - NumberInputModal을 4단계 상태 머신으로 재작성 (수량 -> 포장 수 -> 개당 수량 -> summary) - 포장 단위 커스텀 지원 (기본 6종 + 디자이너 추가) - 본문 필드에 계산식 통합 (3-드롭다운 수식 빌더) - 입력 필드: limitColumn(동적 상한), saveTable/saveColumn(저장 대상) - 저장 대상 테이블 선택을 TableCombobox로 교체 (검색 가능) - 다중 정렬 지원 + 하위 호환 (sorts.map 에러 수정) - GroupedColumnSelect 항상 테이블명 헤더 표시 - 반응형 표시 우선순위 (required/shrink/hidden) 설정 - PackageEntry/CartItem 타입 확장, CardPackageConfig 신규 Co-authored-by: Cursor <cursoragent@cursor.com>
13 KiB
현재 구현 계획: pop-card-list 입력 필드/계산 필드 구조 개편
작성일: 2026-02-24 상태: 계획 완료, 코딩 대기 목적: 입력 필드 설정 단순화 + 본문 필드에 계산식 통합 + 기존 계산 필드 섹션 제거
1. 변경 개요
배경
- 기존: "입력 필드", "계산 필드", "담기 버튼" 3개가 별도 섹션으로 분리
- 문제: 계산 필드가 본문 필드와 동일한 위치에 표시되어야 하는데 별도 영역에 있음
- 문제: 입력 필드의 min/max 고정값은 비실용적 (실제로는 DB 컬럼 기준 제한이 필요)
- 문제: step, columnName, sourceColumns, resultColumn 등 죽은 코드 존재
목표
- 본문 필드에 계산식 지원 추가 - 필드별로 "DB 컬럼" 또는 "계산식" 선택
- 입력 필드 설정 단순화 - 고정 min/max 제거, 제한 기준 컬럼 방식으로 변경
- 기존 "계산 필드" 섹션 제거 - 본문 필드에 통합되므로 불필요
- 죽은 코드 정리
2. 수정 대상 파일 (3개)
파일 A: frontend/lib/registry/pop-components/types.ts
변경 A-1: CardFieldBinding 타입 확장
현재 코드 (라인 367~372):
export interface CardFieldBinding {
id: string;
columnName: string;
label: string;
textColor?: string;
}
변경 코드:
export interface CardFieldBinding {
id: string;
label: string;
textColor?: string;
valueType: "column" | "formula"; // 값 유형: DB 컬럼 또는 계산식
columnName?: string; // valueType === "column"일 때 사용
formula?: string; // valueType === "formula"일 때 사용 (예: "$input - received_qty")
unit?: string; // 계산식일 때 단위 표시 (예: "EA")
}
주의: columnName이 required에서 optional로 변경됨. 기존 저장 데이터와의 하위 호환 필요.
변경 A-2: CardInputFieldConfig 단순화
현재 코드 (라인 443~453):
export interface CardInputFieldConfig {
enabled: boolean;
columnName?: string;
label?: string;
unit?: string;
defaultValue?: number;
min?: number;
max?: number;
maxColumn?: string;
step?: number;
}
변경 코드:
export interface CardInputFieldConfig {
enabled: boolean;
label?: string;
unit?: string;
limitColumn?: string; // 제한 기준 컬럼 (해당 행의 이 컬럼 값이 최대값)
saveTable?: string; // 저장 대상 테이블
saveColumn?: string; // 저장 대상 컬럼
showPackageUnit?: boolean; // 포장등록 버튼 표시 여부
}
제거 항목:
columnName->saveTable+saveColumn으로 대체 (명확한 네이밍)defaultValue-> 제거 (제한 기준 컬럼 값으로 대체)min-> 제거 (항상 0)max-> 제거 (limitColumn으로 대체)maxColumn->limitColumn으로 이름 변경step-> 제거 (키패드 방식에서 미사용)
변경 A-3: CardCalculatedFieldConfig 제거
삭제: CardCalculatedFieldConfig 인터페이스 전체 (라인 457~464)
삭제: PopCardListConfig에서 calculatedField?: CardCalculatedFieldConfig; 제거
파일 B: frontend/lib/registry/pop-components/pop-card-list/PopCardListConfig.tsx
변경 B-1: 본문 필드 편집기(FieldEditor)에 값 유형 선택 추가
현재: 필드 편집 시 라벨, 컬럼, 텍스트색상만 설정 가능
변경: 값 유형 라디오("DB 컬럼" / "계산식") 추가
- "DB 컬럼" 선택 시: 기존 컬럼 Select 표시
- "계산식" 선택 시: 수식 입력란 + 사용 가능한 컬럼/변수 칩 목록 표시
- 사용 가능한 변수: DB 컬럼명들 +
$input(입력 필드 활성화 시)
하위 호환: 기존 저장 데이터에 valueType이 없으면 "column"으로 기본 처리
변경 B-2: 입력 필드 설정 섹션 개편
현재 설정 항목: 라벨, 단위, 기본값, 최소/최대, 최대값 컬럼, 저장 컬럼
변경 설정 항목:
라벨 [입고 수량 ]
단위 [EA ]
제한 기준 컬럼 [ order_qty v ]
저장 대상 테이블 [ 선택 v ]
저장 대상 컬럼 [ 선택 v ]
─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
포장등록 버튼 [on/off]
변경 B-3: "계산 필드" 섹션 제거
삭제: CalculatedFieldSettingsSection 함수 전체
삭제: 카드 템플릿 탭에서 "계산 필드" CollapsibleSection 제거
변경 B-4: import 정리
삭제: CardCalculatedFieldConfig import
추가: 없음 (기존 import 재사용)
파일 C: frontend/lib/registry/pop-components/pop-card-list/PopCardListComponent.tsx
변경 C-1: FieldRow에서 계산식 필드 지원
현재: const value = row[field.columnName] 로 DB 값만 표시
변경:
function FieldRow({ field, row, scaled, inputValue }: {
field: CardFieldBinding;
row: RowData;
scaled: ScaledConfig;
inputValue?: number; // 입력 필드 값 (계산식에서 $input으로 참조)
}) {
const value = field.valueType === "formula" && field.formula
? evaluateFormula(field.formula, row, inputValue ?? 0)
: row[field.columnName ?? ""];
// ...
}
주의: inputValue를 FieldRow까지 전달해야 하므로 CardItem -> FieldRow 경로에 prop 추가 필요
변경 C-2: 계산식 필드 실시간 갱신
현재: 별도 calculatedValue useMemo가 [calculatedField, row, inputValue]에 반응
변경: FieldRow가 inputValue prop을 받으므로, inputValue가 변경될 때 계산식 필드가 자동으로 리렌더링됨. 별도 useMemo 불필요.
변경 C-3: 기존 calculatedField 관련 코드 제거
삭제 대상:
calculatedFieldprop 전달 (CardItem)calculatedValueuseMemo- 계산 필드 렌더링 블록 (
{calculatedField?.enabled && calculatedValue !== null && (...)}
변경 C-4: 입력 필드 로직 단순화
변경 대상:
effectiveMax:limitColumn사용, 미설정 시 999999 폴백defaultValue자동 초기화 로직 제거 (불필요)NumberInputModal에 포장등록 on/off 전달
변경 C-5: NumberInputModal에 포장등록 on/off 전달
현재: 포장등록 버튼 항상 표시
변경: showPackageUnit prop 추가, false이면 포장등록 버튼 숨김
파일 D: frontend/lib/registry/pop-components/pop-card-list/NumberInputModal.tsx
변경 D-1: showPackageUnit prop 추가
현재 props: open, onOpenChange, unit, initialValue, initialPackageUnit, min, maxValue, onConfirm
추가 prop: showPackageUnit?: boolean (기본값 true)
변경: showPackageUnit === false이면 포장등록 버튼 숨김
3. 구현 순서 (의존성 기반)
| 순서 | 작업 | 파일 | 의존성 | 상태 |
|---|---|---|---|---|
| 1 | A-1: CardFieldBinding 타입 확장 | types.ts | 없음 | [ ] |
| 2 | A-2: CardInputFieldConfig 단순화 | types.ts | 없음 | [ ] |
| 3 | A-3: CardCalculatedFieldConfig 제거 | types.ts | 없음 | [ ] |
| 4 | B-1: FieldEditor에 값 유형 선택 추가 | PopCardListConfig.tsx | 순서 1 | [ ] |
| 5 | B-2: 입력 필드 설정 섹션 개편 | PopCardListConfig.tsx | 순서 2 | [ ] |
| 6 | B-3: 계산 필드 섹션 제거 | PopCardListConfig.tsx | 순서 3 | [ ] |
| 7 | B-4: import 정리 | PopCardListConfig.tsx | 순서 6 | [ ] |
| 8 | D-1: NumberInputModal showPackageUnit 추가 | NumberInputModal.tsx | 없음 | [ ] |
| 9 | C-1: FieldRow 계산식 지원 | PopCardListComponent.tsx | 순서 1 | [ ] |
| 10 | C-3: calculatedField 관련 코드 제거 | PopCardListComponent.tsx | 순서 9 | [ ] |
| 11 | C-4: 입력 필드 로직 단순화 | PopCardListComponent.tsx | 순서 2, 8 | [ ] |
| 12 | 린트 검사 | 전체 | 순서 1~11 | [ ] |
순서 1, 2, 3은 독립이므로 병렬 가능. 순서 8은 독립이므로 병렬 가능.
4. 사전 충돌 검사 결과
새로 추가할 식별자 목록
| 식별자 | 타입 | 정의 파일 | 사용 파일 | 충돌 여부 |
|---|---|---|---|---|
valueType |
CardFieldBinding 속성 | types.ts | PopCardListConfig.tsx, PopCardListComponent.tsx | 충돌 없음 |
formula |
CardFieldBinding 속성 | types.ts | PopCardListConfig.tsx, PopCardListComponent.tsx | 충돌 없음 (기존 CardCalculatedFieldConfig.formula와 다른 인터페이스) |
limitColumn |
CardInputFieldConfig 속성 | types.ts | PopCardListConfig.tsx, PopCardListComponent.tsx | 충돌 없음 |
saveTable |
CardInputFieldConfig 속성 | types.ts | PopCardListConfig.tsx | 충돌 없음 |
saveColumn |
CardInputFieldConfig 속성 | types.ts | PopCardListConfig.tsx | 충돌 없음 |
showPackageUnit |
CardInputFieldConfig 속성 / NumberInputModal prop | types.ts, NumberInputModal.tsx | PopCardListComponent.tsx | 충돌 없음 |
기존 타입/함수 재사용 목록
| 기존 식별자 | 정의 위치 | 이번 수정에서 사용하는 곳 |
|---|---|---|
evaluateFormula() |
PopCardListComponent.tsx 라인 1026 | C-1: FieldRow에서 호출 (기존 함수 그대로 재사용) |
CardFieldBinding |
types.ts 라인 367 | A-1에서 수정, B-1/C-1에서 사용 |
CardInputFieldConfig |
types.ts 라인 443 | A-2에서 수정, B-2/C-4에서 사용 |
GroupedColumnSelect |
PopCardListConfig.tsx | B-1: 계산식 모드에서 컬럼 칩 표시에 재사용 가능 |
사용처 있는데 정의 누락된 항목: 없음
5. 에러 함정 경고
함정 1: 기존 저장 데이터 하위 호환
기존에 저장된 CardFieldBinding에는 valueType이 없고 columnName이 필수였음.
반드시 런타임에서 field.valueType || "column" 폴백 처리해야 함.
Config UI에서도 valueType 미존재 시 "column" 기본값 적용 필요.
함정 2: CardInputFieldConfig 하위 호환
기존 maxColumn이 limitColumn으로 이름 변경됨.
기존 저장 데이터의 maxColumn을 limitColumn으로 읽어야 함.
런타임: inputField?.limitColumn || (inputField as any)?.maxColumn 폴백 필요.
함정 3: evaluateFormula의 inputValue 전달
FieldRow에 inputValue를 전달하려면, CardItem -> body.fields.map -> FieldRow 경로에서 inputValue prop을 추가해야 함.
입력 필드가 비활성화된 경우 inputValue는 0으로 전달.
함정 4: calculatedField 제거 시 기존 데이터
기존 config에 calculatedField 데이터가 남아 있을 수 있음.
타입에서 제거하더라도 런타임 에러는 나지 않음 (unknown 속성은 무시됨).
다만 이전에 계산 필드로 설정한 내용은 사라짐 - 마이그레이션 없이 제거.
함정 5: columnName optional 변경
CardFieldBinding.columnName이 optional이 됨.
기존에 row[field.columnName]으로 직접 접근하던 코드 전부 수정 필요.
field.columnName ?? "" 또는 valueType 분기 처리.
6. 검증 방법
시나리오 1: 기존 본문 필드 (하위 호환)
- 기존 저장된 카드리스트 열기
- 본문 필드에 기존 DB 컬럼 필드가 정상 표시되는지 확인
- 설정 패널에서 기존 필드가 "DB 컬럼" 유형으로 표시되는지 확인
시나리오 2: 계산식 본문 필드 추가
- 본문 필드 추가 -> 값 유형 "계산식" 선택
- 수식:
order_qty - received_qty입력 - 카드에서 계산 결과가 정상 표시되는지 확인
시나리오 3: $input 참조 계산식
- 입력 필드 활성화
- 본문 필드 추가 -> 값 유형 "계산식" -> 수식:
$input - received_qty - 키패드에서 수량 입력 시 계산 결과가 실시간 갱신되는지 확인
시나리오 4: 제한 기준 컬럼
- 입력 필드 -> 제한 기준 컬럼:
order_qty - order_qty=1000인 카드에서 키패드 열기
- MAX 버튼 클릭 시 1000이 입력되고, 1001 이상 입력 불가 확인
시나리오 5: 포장등록 on/off
- 입력 필드 -> 포장등록 버튼: off
- 키패드 모달에서 포장등록 버튼이 숨겨지는지 확인
이전 완료 계획 (아카이브)
pop-dashboard 4가지 아이템 모드 완성 (완료)
- groupBy UI 추가
- xAxisColumn 입력 UI 추가
- 통계카드 카테고리 설정 UI 추가
- 차트 xAxisColumn 자동 보정 로직
- 통계카드 카테고리별 필터 적용
- SQL 빌더 방어 로직
- refreshInterval 최소값 강제
POP 뷰어 스크롤 수정 (완료)
- overflow-hidden 제거
- overflow-auto 공통 적용
- 일반 모드 min-h-full 추가
POP 뷰어 실제 컴포넌트 렌더링 (완료)
- 뷰어 페이지에 레지스트리 초기화 import 추가
- renderActualComponent() 실제 컴포넌트 렌더링으로 교체