# 세션: 2026-02-11 ## 작업 요약 **대시보드 스타일 정리 + 페이지 미리보기 + 차트 디자인 개선 + .next 캐시 이슈 해결** --- ## 수행한 작업 ### 1. 대시보드 스타일 정리 (글자 크기 제거 + 라벨 정렬만 유지) 이전 작업에서 구현했던 글자 크기 3그룹(라벨/메인값/보조) 커스텀 기능이 `@container` 반응형 자동 크기 조절과 충돌하여 정보가 잘리는 문제 발생. 분석 후 글자 크기 커스텀을 제거하고 라벨 정렬만 유지하기로 결정. **변경 파일**: - `types.ts`: `ItemStyleConfig` 단순화 (`labelAlign`만 유지) - `KpiCard.tsx`, `StatCard.tsx`, `GaugeItem.tsx`, `ChartItem.tsx`: `FONT_SIZE_PX` 제거, 반응형 복원, `labelAlignClass` 적용 - `PopDashboardConfig.tsx`: `ItemStyleEditor` 단순화 (글자 크기 Select 3개 제거, 접기/펼치기 지원) - `PopDashboardComponent.tsx`: `setRenderTick`/`itemStyleKey` 불필요 코드 제거 - `PopDesigner.tsx`: `handleUpdateComponent` stale closure 수정 (함수적 setState) ### 2. 페이지 미리보기 기능 디자이너 캔버스에서 특정 페이지의 실제 데이터를 렌더링하는 미리보기 기능 추가. - `PopDashboardConfig.tsx`: 각 페이지 옆에 Eye(미리보기) 버튼 추가 - `PopDashboardComponent.tsx`: `previewPageIndex` prop으로 특정 페이지만 단독 렌더링 - `PopDesigner.tsx` -> `PopCanvas.tsx` -> `PopRenderer.tsx` -> `ComponentEditorPanel.tsx`: previewPageIndex 전달 체인 ### 3. 차트 디자인 개선 - `CartesianGrid` 추가 (얇은 격자선으로 수치 읽기 개선) - `abbreviateNumber` 적용 (큰 숫자 K/M 약어 표시) - X축 라벨 7자 이상 시 대각선 표시 - Y축 숫자 자동 약어 처리 - 긴 라벨 시 하단 여백 자동 확보 ### 4. .next 빌드 캐시 이슈 해결 라벨 정렬 코드가 브라우저에 반영되지 않는 문제 발생. 디버그 로그 추가로 분석한 결과, `ChartItem.tsx`의 디버그 로그가 콘솔에 전혀 나타나지 않아 **Next.js Turbopack 빌드 캐시** 문제로 확인. Docker 설정에서 `.next`가 익명 볼륨(`/app/.next`)으로 분리되어 있어, 호스트의 `.next` 삭제만으로는 해결 불가. `docker-compose down -v`로 볼륨까지 제거 후 `--build`로 재시작하여 해결. ### 5. 디버그 로그 정리 문제 해결 과정에서 추가한 `console.log("[DEBUG]...")` 8개를 커밋 전 전부 제거. --- ## 커밋 | 해시 | 메시지 | |------|--------| | `960b1c99` | feat(pop-dashboard): 라벨 정렬 + 페이지 미리보기 + 차트 디자인 개선 | --- ## 발견된 문제 및 해결 | 문제 | 원인 | 해결 | |------|------|------| | 글자 크기 커스텀이 반응형과 충돌 | 절대 px(12~64px)가 유동적 그리드 셀 크기와 충돌 | 글자 크기 커스텀 제거, `@container` 반응형 자동 적용 유지 | | Select 기본값 미발동 | Shadcn Select의 `onValueChange`가 같은 값 선택 시 미발동 | 글자 크기 제거로 해결 (근본 원인 소멸) | | stale closure (handleUpdateComponent) | `useCallback`이 `layout` state를 직접 참조하여 빠른 연속 변경 시 이전 값 유실 | `setLayout(prev => ...)` 함수적 업데이트로 수정 | | setRenderTick 불필요 이중 렌더링 | 글자 크기 강제 반영용이었으나 제거 후 불필요 | state + useEffect 삭제 | | ChartItem.tsx 코드가 브라우저에 반영 안됨 | Docker 익명 볼륨에 캐시된 .next가 호스트 삭제와 독립적 | `docker-compose down -v`로 볼륨 포함 삭제 후 재빌드 | --- ## 이번 작업에서 배운 것 ### 새로 알게 된 기술 개념 - **Docker 익명 볼륨과 호스트 파일시스템의 독립성**: `docker-compose.yml`에서 `/app/.next`처럼 익명 볼륨으로 지정된 경로는 호스트의 동일 경로와 완전히 독립적. 호스트에서 `rm -rf .next`를 해도 컨테이너 내부 캐시에는 영향 없음. `docker-compose down -v`로 볼륨까지 제거해야 함. - **Shadcn/Radix Select 동작**: `onValueChange`는 현재 값과 동일한 값을 선택하면 발동하지 않음. 기본값이 있는 Select에서 이를 인지하지 못하면 "설정이 안 됨" 버그로 보임. ### 발생했던 에러와 원인 패턴 - **stale closure 패턴**: React의 `useCallback`에서 외부 state를 직접 참조하면 의존성 배열이 변경될 때까지 이전 값이 캡처됨. 빠른 연속 호출(정렬 버튼 클릭 등) 시 이전 state로 덮어씌워져 변경이 유실됨. **해결 패턴**: `setState(prev => ...)` 함수적 업데이트. - **빌드 캐시 꼬임 패턴**: 파일을 여러 번 수정하고 구조 변경이 많으면 Turbopack/Webpack의 모듈 캐시가 특정 파일의 변경을 인식하지 못하는 경우 발생. 디버그 로그가 콘솔에 안 나오면 캐시 문제를 먼저 의심. ### 다음에 비슷한 작업할 때 주의할 점 1. **`useCallback` 안에서 state 직접 참조하지 않기** - 항상 `setState(prev => ...)`로 최신 state 접근 2. **Docker 익명 볼륨 인지하기** - `.next` 캐시 초기화가 필요하면 `docker-compose down -v` 사용 3. **대시보드 같은 고밀도 정보 컴포넌트에서 절대 크기 지양** - `@container` 반응형 자동 크기가 더 안정적 4. **디버그 console.log는 커밋 전 반드시 제거** - Grep으로 `[DEBUG]` 검색하여 확인 --- --- ## 작업 요약 (2차 - Phase 0 공통 인프라 구현) **usePopEvent + useDataSource 공통 훅 구현 + 검수 + 커밋/병합/푸시** --- ## 수행한 작업 (2차) ### 1. 프로젝트 현황 파악 + 기존 코드 분석 대시보드의 `dataFetcher.ts` 조회 로직과 `dataApi` CRUD를 분석하여 공통 훅 설계의 기반을 마련. 기존 백엔드 API(`getTableData`, `createRecord`, `updateRecord`, `deleteRecord`, `executeQuery`)가 모두 완성되어 있어 프론트 래핑만 필요함을 확인. ### 2. usePopEvent 훅 구현 (STEP 1) **파일**: `frontend/hooks/pop/usePopEvent.ts` (신규) 화면(screenId) 단위로 격리된 이벤트 버스. 전역 Map 2개(`screenBuses`, `sharedDataStore`)를 모듈 스코프에 두고, SSR 환경 대응(`typeof window !== "undefined"` 가드). - `publish(eventName, payload)`: 같은 화면의 구독자에게 이벤트 전파 - `subscribe(eventName, callback)`: 이벤트 구독, unsubscribe 함수 반환 - `getSharedData(key)` / `setSharedData(key, value)`: screenId별 격리된 key-value 저장소 - `cleanupScreen(screenId)`: 화면 언마운트 시 전체 정리 (메모리 누수 방지) ### 3. popSqlBuilder 유틸 구현 (STEP 2) **파일**: `frontend/hooks/pop/popSqlBuilder.ts` (신규) `dataFetcher.ts`에서 SQL 빌더 로직 5개 함수를 추출 (로직 변경 없이 복사): - `escapeSQL`, `sanitizeIdentifier`, `validateDataSourceConfig`, `buildWhereClause`, `buildAggregationSQL` 대시보드 `dataFetcher.ts`는 미수정 (안정성 우선, 향후 교체 예정). ### 4. useDataSource 훅 구현 (STEP 3) **파일**: `frontend/hooks/pop/useDataSource.ts` (신규) `DataSourceConfig` 기반 DB 테이블 CRUD 통합 훅: - **조회 분기**: 집계/조인이면 SQL 빌더 + executeQuery, 단순이면 dataApi.getTableData - **CRUD**: `save` -> dataApi.createRecord, `update` -> dataApi.updateRecord, `remove` -> dataApi.deleteRecord - **자동 새로고침**: `refreshInterval` 기반 (최소 5초) - **refetch 필터 병합**: overrideFilters가 config.filters에 추가/덮어쓰기 ### 5. 배럴 파일 (STEP 4) **파일**: `frontend/hooks/pop/index.ts` (신규) public API re-export: `usePopEvent`, `cleanupScreen`, `useDataSource`, `MutationResult`, `DataSourceResult`, `buildAggregationSQL`, `validateDataSourceConfig` ### 6. 종합 검수 - 린트 에러: 0건 - 중복 정의: 0건 (20개 함수/타입 전수 Grep) - 미사용 import: 0건 - 누락 import: 0건 - interface props 불일치: 0건 - 가상 시뮬레이션 8가지 시나리오: 전부 정상 ### 7. Git 작업 - `ksh-button` 브랜치에서 커밋 - `ksh-v2-work`로 fast-forward merge - `origin/ksh-v2-work`로 push 완료 --- ## 커밋 (2차) | 해시 | 메시지 | |------|--------| | `300542d9` | feat(pop): usePopEvent, useDataSource 공통 훅 구현 | --- ## 발견된 문제 및 해결 (2차) 이번 작업에서는 코드 품질 문제가 발견되지 않았습니다. 사전 충돌 검사에서 `buildAggregationSQL`과 `validateDataSourceConfig`이 `dataFetcher.ts`에도 존재하지만, 이는 의도적 복사이며 런타임 충돌은 없음을 확인. 향후 대시보드 교체 시 import 경로만 변경 예정. --- ## 이번 작업에서 배운 것 (2차) ### 새로 알게 된 기술 개념 - **전역 Map 기반 이벤트 버스**: React 외부(모듈 스코프)에 전역 Map을 두면 컴포넌트 마운트/언마운트와 무관하게 이벤트 리스너가 유지됨. 단, `cleanupScreen`으로 명시적 정리 필요. - **SSR 가드 패턴**: Next.js에서 전역 변수 초기화 시 `typeof window !== "undefined"` 조건이 필수. 서버 렌더링 시 window 참조 에러 방지. ### 다음에 비슷한 작업할 때 주의할 점 1. **subscribe는 반드시 useEffect 안에서 호출** - cleanup에서 unsubscribe 반환값을 호출해야 메모리 누수 방지 2. **dataFetcher.ts를 복사할 때 import 경로 주의** - types.ts 경로가 상대적으로 달라짐 3. **useRef로 config 최신값 유지** - useCallback 안에서 config를 직접 참조하면 stale closure 발생, configRef.current 사용 --- ## 다음 작업 1. Phase 2: pop-button 컴포넌트 구현 계획 수립 2. Phase 2: pop-icon 컴포넌트 검토/개선 3. 브라우저 확인: 대시보드 라벨 정렬, 페이지 미리보기, 차트 디자인