ERP-node/popdocs/sessions/2026-02-10.md

22 KiB

2026-02-10 작업 기록

요약

pop-dashboard 컴포넌트 17단계 코딩 완료 + 검수 + 팔레트 미노출 버그 수정

작업 내역

1. pop-dashboard 전체 구현 (17단계 코딩)

계획서 기반으로 15개 신규 파일 생성, 3개 기존 파일 수정:

단계 파일 핵심 내용
Step 1 types.ts Phase 0 공통 타입 + 대시보드 전용 타입 25개 추가
Step 2 utils/formula.ts 재귀 하강 파서 기반 수식 계산, abbreviateNumber
Step 3 utils/dataFetcher.ts @INFRA-EXTRACT 직접 API 호출, SQL 생성 + 인젝션 방지
Step 4 items/KpiCard.tsx CSS Container Query 반응형 KPI 카드
Step 5 items/ChartItem.tsx Recharts 통합 (bar/pie/line)
Step 6 items/GaugeItem.tsx SVG 반원형 게이지 자체 구현
Step 7 items/StatCard.tsx 카테고리별 건수 표시
Step 8 modes/ArrowsMode.tsx 좌우 화살표 + 터치 최적화
Step 9 modes/AutoSlideMode.tsx 자동 슬라이드 + 터치 일시정지 + 자동 재개
Step 10 modes/GridMode.tsx CSS Grid + @container 셀 배치
Step 11 modes/ScrollMode.tsx scroll-snap 가로 스크롤
Step 12 PopDashboardComponent.tsx 메인 뷰어 컴포넌트, Promise.allSettled 병렬 로딩
Step 13 PopDashboardPreview.tsx 디자이너 미리보기 (더미 데이터)
Step 14 PopDashboardConfig.tsx 3탭 설정 패널 (기본/아이템/레이아웃)
Step 15 pop-dashboard/index.tsx PopComponentRegistry 등록
Step 16 pop-components/index.ts import 추가
Step 17 pop-text.tsx datetime isRealtime 기본값 버그 수정

2. 코딩 후 자체 검수

검수 항목 결과
린트 에러 0개 (기존 경고만)
중복 정의 없음
미사용 import 1건 발견 (AggregatedResult)
import 누락 없음
props 불일치 없음

3. 팔레트 미노출 버그 수정

문제: pop-dashboard를 레지스트리에 등록했지만 디자이너 팔레트에 표시되지 않음

원인: 디자이너가 PopComponentRegistry를 읽지 않고 하드코딩된 배열/타입을 사용

수정 (4개 파일):

파일 수정 내용
pop-layout.ts PopComponentType 유니온에 "pop-dashboard" 추가, DEFAULT_COMPONENT_GRID_SIZE에 6x3 기본 크기 추가
ComponentPalette.tsx PALETTE_ITEMS 배열에 대시보드 항목 추가 (아이콘: BarChart3)
PopRenderer.tsx COMPONENT_TYPE_LABELS"pop-dashboard": "대시보드" 추가
PopDashboardComponent.tsx 미사용 type AggregatedResult import 제거

이번 작업에서 배운 것

에러 패턴: 컴포넌트 등록 누락

POP 시스템에서 새 컴포넌트를 추가할 때 등록해야 하는 곳이 5곳이다:

  1. PopComponentRegistry.registerComponent() - 레지스트리 등록 (index.tsx)
  2. pop-components/index.ts - side-effect import 추가
  3. PopComponentType 유니온 - 타입 시스템 (pop-layout.ts)
  4. PALETTE_ITEMS 배열 - 팔레트 UI (ComponentPalette.tsx)
  5. DEFAULT_COMPONENT_GRID_SIZE - 기본 크기 (pop-layout.ts)
  6. COMPONENT_TYPE_LABELS - 라벨 표시 (PopRenderer.tsx)

계획서에서 1~2번만 포함하고 3~6번을 누락했다. 레지스트리와 디자이너가 자동 연동되지 않는 구조적 문제.

다음에 비슷한 작업할 때 주의할 점

  • 새 POP 컴포넌트 추가 시 위 6곳 체크리스트를 반드시 확인
  • 계획서 작성 시 "디자이너 연동" 단계를 별도 Step으로 포함
  • 코딩 후 브라우저에서 실제 동작 확인 필수 (팔레트 노출, 드래그, 설정 패널)
  • 장기적으로 디자이너가 PopComponentRegistry를 직접 읽도록 리팩토링 고려

수정된 파일 전체 목록

신규 생성 (15개)

frontend/lib/registry/pop-components/pop-dashboard/
├── index.tsx
├── PopDashboardComponent.tsx
├── PopDashboardConfig.tsx
├── PopDashboardPreview.tsx
├── items/
│   ├── KpiCard.tsx
│   ├── ChartItem.tsx
│   ├── GaugeItem.tsx
│   └── StatCard.tsx
├── modes/
│   ├── ArrowsMode.tsx
│   ├── AutoSlideMode.tsx
│   ├── GridMode.tsx
│   └── ScrollMode.tsx
└── utils/
    ├── formula.ts
    └── dataFetcher.ts

수정 (6개)

파일 변경
pop-components/types.ts Phase 0 공통 + 대시보드 전용 타입 25개 추가
pop-components/index.ts import "./pop-dashboard" 1줄 추가
pop-text.tsx isRealtime 기본값 버그 수정
pop-layout.ts PopComponentType, DEFAULT_COMPONENT_GRID_SIZE 수정
ComponentPalette.tsx PALETTE_ITEMS에 대시보드 추가
PopRenderer.tsx COMPONENT_TYPE_LABELS에 대시보드 추가


4. pop-dashboard 페이지(슬라이드) 구조 재설계 (6단계 코딩)

기존 평면 아이템 리스트를 "페이지" 단위 독립 그리드 레이아웃으로 재구성:

단계 파일 핵심 내용
Step 1 types.ts DashboardPage 인터페이스 추가, PopDashboardConfig에서 grid* 속성 삭제 -> pages 추가
Step 2 PopDashboardComponent.tsx migrateConfig() 함수 추가 (레거시 config 런타임 변환), 페이지 기반 렌더링으로 전환
Step 3 PopDashboardPreview.tsx migrateConfig 적용, 첫 페이지 그리드 미리보기 + "N페이지" 배지
Step 4 PopDashboardConfig.tsx "레이아웃" 탭 -> "페이지" 탭 교체, PageEditor 컴포넌트 신규, 아이템 삭제 시 모든 페이지 셀 정리
Step 5 index.tsx defaultProps에서 useGridLayout 제거, pages: [] 추가
Step 6 린트 + 검수 린트 0, 중복 0, 잔여 참조 0

5. pop-dashboard 설정 패널 UI/UX 개선 (3건)

항목 파일 변경
아이템 라벨 인라인 편집 PopDashboardConfig.tsx ItemEditor 헤더의 <span> -> <Input> 교체, 확장 영역 중복 라벨 입력 제거
아이템 간격(gap) 의미 설명 (대화에서 설명) 페이지 내 그리드 셀 간격 (CSS Grid gap)
페이지 탭 세로 스크롤 불가 ComponentEditorPanel.tsx Tabs/TabsContent에 min-h-0 추가 (Flexbox min-height:auto 문제)

6. 설정 탭 스크롤 버그 수정

문제: POP 디자이너에서 대시보드 선택 -> 설정 탭 -> 페이지 3개 이상 추가 시 아래 잘림, 세로 스크롤 불가

잘못된 접근: PopDashboardConfigPanel(자식)에서 flex h-full / overflow-y-auto 시도 -> 부모 스크롤 깨짐

근본 원인: ComponentEditorPanel.tsxTabsTabsContentmin-h-0 누락. Flexbox에서 flex 자식의 기본 min-height: auto가 콘텐츠 축소를 막아 overflow-auto 미작동

해결: ComponentEditorPanel.tsx 수정

  • Tabsmin-h-0 추가
  • TabsListshrink-0 추가
  • 4개 TabsContentmin-h-0 추가

이번 작업에서 배운 것

새로 알게 된 기술 개념: Flexbox min-height:auto 함정

Flexbox에서 overflow-auto가 작동하려면, 해당 요소와 모든 flex 조상에 min-h-0(또는 min-w-0)이 필요하다.

  • flex-1만으로는 높이가 제한되지 않음
  • flex 자식의 기본 min-height: auto가 콘텐츠 크기 이하로 축소를 막기 때문
  • 스크롤 문제 발생 시 자식이 아니라 부모 flex 체인부터 위로 추적해야 함

에러 패턴: 잘못된 수정 위치

스크롤 문제를 자식 컴포넌트(PopDashboardConfigPanel)에서 해결하려고 시도했으나, 실제 문제는 부모(ComponentEditorPanel.tsx)의 높이 제약 전파 누락이었음.

  • 부모가 높이를 확정해주지 않으면 자식의 overflow 설정은 무의미
  • CSS 레이아웃 문제는 항상 위에서 아래로 추적

다음에 비슷한 작업할 때 주의할 점

  • 스크롤 문제가 발생하면 DevTools에서 flex 체인의 각 노드에 min-h-0이 있는지 확인
  • overflow-auto를 설정한 요소의 높이가 확정(px 또는 flex 제약)되어 있는지 확인
  • Radix UI TabsContent의 기본 flex-1min-h-0을 포함하지 않으므로 수동 추가 필요

수정된 파일 (이번 대화 추가분)

파일 변경
ComponentEditorPanel.tsx Tabs/TabsList/TabsContent에 min-h-0, shrink-0 추가 (스크롤 수정)
popdocs/PROBLEMS.md 설정 탭 스크롤 버그 상세 기록 추가

(이전 대화에서 이미 수정된 파일: types.ts, PopDashboardComponent.tsx, PopDashboardPreview.tsx, PopDashboardConfig.tsx, index.tsx)


다음 작업

  • 브라우저에서 pop-dashboard 페이지 기반 동작 확인 (페이지 추가/삭제/편집)
  • 기존 config 마이그레이션 정상 동작 확인
  • 디자이너에서 설정 탭 스크롤 정상 동작 확인
  • Phase 2: pop-button, pop-icon 구현

작성: 2026-02-10 (오후 세션 추가)


7. pop-dashboard 아이템 모드 완성 + 방어 로직 (야간 세션)

대시보드 컴포넌트의 4가지 아이템 모드(KPI, Chart, Gauge, Stat Card)가 실제 데이터와 연동되어 정상 작동하도록 설정 UI 보강, SQL 빌더 방어 로직, 렌더링 버그 수정을 수행.

7-1. 설정 패널 UI 보강 (PopDashboardConfig.tsx)

항목 변경
A-1: groupBy 설정 DataSourceEditor에 "그룹핑(X축)" Combobox 추가. 집계 활성 시 X축 카테고리 컬럼 선택 가능
A-2: 차트 축 설정 Chart 아이템에 xAxisColumn / yAxisColumn 입력 필드 추가
A-3: 통계 카드 카테고리 StatCard에 카테고리 인라인 편집기 추가 (라벨/필터 조건/색상)

7-2. 뷰어 컴포넌트 로직 수정 (PopDashboardComponent.tsx)

항목 변경
B-1: 차트 xAxisColumn 자동 보정 groupBy 있으면 첫 번째 groupBy 컬럼을 xAxisColumn으로 자동 설정
B-2: 통계 카드 카테고리 필터링 rows를 카테고리별 filter 조건으로 필터링하여 독립 건수 계산
useEffect 의존성 수정 visibleItems 배열 참조 대신 visibleItemIds(JSON 문자열)로 안정화

7-3. SQL 빌더 방어 로직 (dataFetcher.ts)

항목 변경
C-1: validateDataSourceConfig 테이블/컬럼/조인 미완료 상태에서 SQL 생성 차단
buildWhereClause 빈 컬럼명 필터 무시 (설정 중간 상태 방어)
buildAggregationSQL COUNT 컬럼 없으면 COUNT(*), 불완전한 조인 건너뜀
C-2: refreshInterval 최소값 5초 미만 설정 시 5초로 강제

7-4. fetchTableColumns 수정 (dataFetcher.ts)

항목 변경
API 우선순위 변경 tableManagementApi(axios) 우선 시도, 실패 시 dashboardApi(fetch) 폴백

7-5. 그리드 레이아웃 + 라벨 잘림 수정

항목 파일 변경
2열이 1열로 렌더링 GridMode.tsx MIN_CELL_WIDTH 160px -> 80px
라벨 잘림 (truncate) KpiCard.tsx truncate 제거, text-[10px] -> text-xs, hidden 조건 제거
라벨 잘림 GaugeItem.tsx truncate 제거, hidden 조건 제거
라벨 잘림 StatCard.tsx truncate 제거, hidden 조건 제거
라벨 잘림 ChartItem.tsx truncate 제거, 폰트 크기 상향
패딩 부족 4개 아이템 모두 p-2 -> p-3 (KPI/Gauge/Stat), p-1 -> p-2 (Chart)

이번 작업에서 배운 것

에러 패턴: 불완전한 폼 상태가 백엔드 장애를 유발

대시보드 설정에서 집계 유형(SUM/AVG 등)만 선택하고 대상 컬럼을 아직 선택하지 않은 "중간 상태"에서 SUM(), COUNT() 같은 빈 괄호 SQL이 백엔드로 전송됨. 이 에러가 반복 발생하면 백엔드가 unhealthy 상태가 되고, 인증 API(/auth/me) 등 다른 요청도 30초 타임아웃 발생. 결과적으로 브라우저가 멈추는 증상.

원인 체인: 폼 중간 상태 -> 잘못된 SQL 생성 -> 백엔드 에러 폭주 -> API 타임아웃 -> 브라우저 멈춤

해결: validateDataSourceConfig() 함수로 SQL 생성 전 필수값 검증. 미완료 시 에러 메시지만 반환하고 SQL 전송 차단.

에러 패턴: CSS 반응형 열 축소 + 초기 containerWidth

GridModeComponent에서 MIN_CELL_WIDTH = 160으로 설정한 반응형 열 축소 로직이, 초기 containerWidth = 300(ResizeObserver 발동 전 기본값)에서 (300-8)/2 = 146 < 160으로 판단하여 2열을 1열로 강제 축소함. 사용자가 2열로 설정했는데 1열로 보이는 문제.

해결: MIN_CELL_WIDTH를 80px로 변경. 초기 300px 너비에서도 2열 유지.

에러 패턴: Tailwind truncate + Container Query 조합

truncate 클래스(text-overflow: ellipsis + overflow: hidden + white-space: nowrap)와 @container 기반 조건부 텍스트 크기(@[150px]:text-xs)를 함께 사용하면, 컨테이너가 작을 때 텍스트가 완전히 잘리거나 hidden 조건으로 아예 안 보일 수 있음. 대시보드처럼 셀 크기가 동적인 경우 truncate는 피하고, hidden도 최소한으로 사용해야 함.

다음에 비슷한 작업할 때 주의할 점

  • 설정 폼에서 "중간 상태"(일부만 선택)를 항상 고려하고, SQL/API 호출 전에 validate 함수를 반드시 배치
  • 반응형 열 축소 로직에서 초기 렌더링 시점의 containerWidth가 실제 크기가 아닐 수 있음 (ResizeObserver 지연)
  • 아이템 컴포넌트 라벨에는 truncate 대신 줄바꿈을 허용하거나, 최소한 text-xs 이상의 폰트 크기 보장
  • Docker unhealthy 상태가 반드시 서비스 장애를 의미하지 않음 - healthcheck 설정(curl 미설치 등) 확인 필요

수정된 파일 (야간 세션)

파일 변경
PopDashboardConfig.tsx groupBy Combobox, 차트 축 입력, 통계 카테고리 편집기 추가
PopDashboardComponent.tsx 차트 xAxisColumn 자동 보정, StatCard 카테고리 필터링, useEffect 의존성 안정화, refreshInterval 최소 5초
utils/dataFetcher.ts validateDataSourceConfig, buildWhereClause 빈 필터 무시, buildAggregationSQL COUNT(*) 처리, fetchTableColumns API 우선순위 변경
modes/GridMode.tsx MIN_CELL_WIDTH 160 -> 80
items/KpiCard.tsx truncate 제거, hidden 조건 제거, 폰트 크기 상향, p-2 -> p-3
items/GaugeItem.tsx truncate 제거, hidden 조건 제거, p-2 -> p-3
items/StatCard.tsx truncate 제거, hidden 조건 제거, p-2 -> p-3
items/ChartItem.tsx truncate 제거, 폰트 크기 상향, p-1 -> p-2

다음 작업

  • 브라우저 새로고침 후 2열 레이아웃 + 라벨 표시 정상 확인
  • 차트 groupBy / 통계카드 카테고리 동작 확인
  • SQL 빌더 방어 로직 동작 확인 (설정 중간 상태에서 에러 없음)
  • Phase 2: pop-button, pop-icon 계획 수립

작성: 2026-02-10 (야간 세션 추가)


8. pop-dashboard 차트/게이지/UI 디자인 개선 (심야 세션)

대시보드 컴포넌트의 차트 렌더링, 게이지 비율, 네비게이션 디자인, 카드 정렬 등 UX/UI 개선.

8-1. 차트 데이터 및 렌더링 수정

항목 파일 변경
apiClient 우선 사용 dataFetcher.ts fetchAggregatedData에서 apiClient(axios) 우선, dashboardApi(fetch) 폴백
PostgreSQL bigint 문자열 변환 dataFetcher.ts 쿼리 결과 rows에서 숫자형 문자열을 Number()로 변환 (PieChart 필수)
파이 차트 라벨/레전드 추가 ChartItem.tsx Legend 컴포넌트 추가, label 커스텀 포맷 (name value (percent%))
X/Y축 입력 필드 제거 PopDashboardConfig.tsx 혼동 유발하는 수동 입력 제거, 자동 설정 안내 텍스트로 교체

8-2. 게이지 설정/렌더링 수정

항목 파일 변경
gaugeConfig 스프레드 순서 버그 PopDashboardConfig.tsx ...item.gaugeConfig를 앞으로, 새 값(min/max/target)을 뒤로 배치. 이전: 새 값이 이전 값으로 덮어쓰임
게이지 SVG 비율 (가로 레이아웃) GaugeItem.tsx max-w-[200px] 고정 -> h-full w-auto max-w-full 높이 기반 스케일링. SVG 래퍼를 flex-1 min-h-0으로 변경

8-3. 네비게이션 디자인 개선

항목 파일 변경
좌우 버튼 오버레이 ArrowsMode.tsx px-12 패딩 제거, 버튼이 콘텐츠 위에 겹침. bg-background/70 backdrop-blur-sm
인디케이터 오버레이 ArrowsMode.tsx, AutoSlideMode.tsx 별도 영역 -> absolute bottom-1로 콘텐츠 하단에 겹침
상하 마진 불균형 해소 ArrowsMode.tsx, AutoSlideMode.tsx 버튼/인디케이터가 별도 영역 차지하지 않아 균형 맞춤

8-4. 카드 정렬 통일

항목 파일 변경
KPI 카드 가운데 정렬 KpiCard.tsx items-center 추가 (기존: 수직만 가운데)
통계 카드 가운데 정렬 StatCard.tsx items-center justify-center 추가 (기존: 좌상단)

이번 작업에서 배운 것

에러 패턴: JavaScript 스프레드 연산자 순서

// 버그: 새 값이 이전 값으로 덮어쓰임
gaugeConfig: { max: newValue, ...item.gaugeConfig }  // 이전 max가 새 max를 덮어씀

// 수정: 이전 값 먼저, 새 값 나중
gaugeConfig: { ...item.gaugeConfig, max: newValue }  // 새 max가 이전 max를 덮어씀

JavaScript 객체 스프레드에서 나중에 오는 속성이 우선. 상태 업데이트 시 ...기존값은 항상 앞에, 새 값은 뒤에 배치해야 한다.

에러 패턴: PostgreSQL bigint -> JS 문자열

PostgreSQL COUNT(), SUM() 반환값은 bigint 타입. Node.js pg 드라이버가 이를 문자열("79")로 변환. Recharts BarChart/LineChart는 문자열을 암묵적으로 처리하지만, PieChart는 명시적 숫자가 필수. 쿼리 결과를 UI에 전달하기 전에 Number() 변환 필수.

에러 패턴: fetch vs axios (iframe 컨텍스트)

Pop 대시보드가 iframe 내에서 렌더링될 때, fetch 기반 API(dashboardApi)가 간헐적으로 실패. axios 기반 apiClient는 인증 인터셉터와 세션 관리가 안정적이어서 우선 사용하고 fetch를 폴백으로 구성.

다음에 비슷한 작업할 때 주의할 점

  • 상태 업데이트에서 스프레드 연산자 사용 시 순서 반드시 확인 (...기존값 먼저)
  • PostgreSQL 집계 함수 결과를 프론트엔드에서 사용할 때 반드시 Number() 변환
  • fetch vs axios 선택 시 iframe/인증 컨텍스트 고려
  • 네비게이션 UI(버튼/인디케이터)는 absolute 오버레이가 공간 효율적
  • 아이템 컴포넌트 정렬은 4개 모드(KPI/Chart/Gauge/Stat) 모두 통일해야 일관성 유지

수정된 파일 (심야 세션)

파일 변경
PopDashboardConfig.tsx gaugeConfig 스프레드 순서 수정, X/Y축 입력 제거 + 안내 텍스트
utils/dataFetcher.ts apiClient 우선 사용, bigint 문자열 -> 숫자 변환
items/ChartItem.tsx PieChart에 Legend/custom label 추가
items/GaugeItem.tsx SVG 스케일링 높이 기반으로 변경, 패딩 조정
items/KpiCard.tsx items-center 추가 (가운데 정렬)
items/StatCard.tsx items-center justify-center 추가 (가운데 정렬)
modes/ArrowsMode.tsx 좌우 버튼 + 인디케이터 오버레이 디자인
modes/AutoSlideMode.tsx 인디케이터 오버레이 디자인

다음 작업

  • 게이지/통계카드 테스트 시나리오 동작 확인
  • Phase 2: pop-button, pop-icon 계획 수립

9. 디자이너 캔버스 UX 개선

배경

사용자가 디자이너 캔버스와 실제 뷰어 간의 차이를 지적:

  1. 디자이너에서 각 컴포넌트마다 5px 헤더 바가 표시되어 실제 뷰어와 다름
  2. 대시보드가 더미 아이콘(PreviewComponent)으로만 표시됨 -> 실제 데이터 렌더링 요청
  3. 헤더 제거 후 컴포넌트 식별이 어려워짐 -> 왼쪽 패널에 컴포넌트 목록 추가 요청

변경 사항

파일 변경
PopRenderer.tsx 디자인모드 헤더(5px) + 위치 정보 div 삭제. PreviewComponent 대신 ActualComp(실제 컴포넌트)로 렌더링. pointer-events-none으로 내부 클릭 차단
ComponentEditorPanel.tsx Props 3개 추가(allComponents, onSelectComponent, selectedComponentId). "위치" 탭에 배치된 컴포넌트 목록 UI 추가. Layers 아이콘 import. COMPONENT_TYPE_LABELS 타입 변경 + 키 보강
PopDesigner.tsx ComponentEditorPanelallComponents={Object.values(layout.components)}, onSelectComponent={setSelectedComponentId}, selectedComponentId 전달

검수에서 발견된 문제

문제 원인 해결
PopComponentType 미사용 import COMPONENT_TYPE_LABELS 타입을 Record<string, string>으로 변경하면서 유일한 참조 사라짐 import에서 제거

이번 작업에서 배운 것

  • 타입 변경 시 import 정리 필수: 타입을 변경하거나 제거할 때, 해당 타입이 import된 것이라면 변경 후 파일 내 다른 참조가 남아있는지 Grep으로 확인해야 함
  • pointer-events-none 범위 주의: 디자인 모드에서 내부 인터랙션만 차단하려면 ComponentContent 내부에만 적용. 부모 div의 onClick(컴포넌트 선택)은 정상 작동
  • React의 ActualComp 패턴: 레지스트리에서 가져온 컴포넌트를 디자인 모드에서도 렌더링하면 마운트 시 API 호출이 발생할 수 있음. 현재는 refreshInterval/limit으로 제어되어 수용 가능

작성: 2026-02-10 (디자이너 캔버스 UX 개선 세션 추가)