# POP 레이아웃 canvasGrid.rows 버그 수정 ## 문제점 ### 1. 데이터 불일치 - **DB에 저장된 데이터**: `canvasGrid.rowHeight: 20` (고정 픽셀) - **코드에서 기대하는 데이터**: `canvasGrid.rows: 24` (비율 기반) - **결과**: `rows`가 `undefined`로 인한 렌더링 오류 ### 2. 타입 정의 불일치 - **PopCanvas.tsx 타입**: `{ columns: number; rowHeight: number; gap: number }` - **실제 사용**: `canvasGrid.rows`로 계산 - **결과**: 타입 안정성 저하 ### 3. 렌더링 오류 - **디자이너**: `rowHeight = resolution.height / undefined` → `NaN` - **뷰어**: `gridTemplateRows: repeat(undefined, 1fr)` → CSS 무효 - **결과**: 섹션이 매우 작게 표시됨 --- ## 수정 내용 ### 1. ensureV2Layout 강화 **파일**: `frontend/components/pop/designer/types/pop-layout.ts` ```typescript export const ensureV2Layout = (data: PopLayoutData): PopLayoutDataV2 => { let result: PopLayoutDataV2; if (isV2Layout(data)) { result = data; } else if (isV1Layout(data)) { result = migrateV1ToV2(data); } else { console.warn("알 수 없는 레이아웃 버전, 빈 v2 레이아웃 생성"); result = createEmptyPopLayoutV2(); } // ✅ canvasGrid.rows 보장 (구버전 데이터 호환) if (!result.settings.canvasGrid.rows) { console.warn("canvasGrid.rows 없음, 기본값 24로 설정"); result.settings.canvasGrid = { ...result.settings.canvasGrid, rows: DEFAULT_CANVAS_GRID.rows, // 24 }; } return result; }; ``` **효과**: DB에서 로드한 구버전 데이터도 자동으로 `rows: 24` 보장 --- ### 2. PopCanvas.tsx 타입 수정 및 fallback **파일**: `frontend/components/pop/designer/PopCanvas.tsx` **타입 정의 수정**: ```typescript interface DeviceFrameProps { canvasGrid: { columns: number; rows: number; gap: number }; // rowHeight → rows // ... } ``` **fallback 추가**: ```typescript // ✅ rows가 없으면 24 사용 const rows = canvasGrid.rows || 24; const rowHeight = Math.floor(resolution.height / rows); ``` **효과**: - 타입 일관성 확보 - `NaN` 방지 --- ### 3. PopLayoutRenderer.tsx fallback **파일**: `frontend/components/pop/designer/renderers/PopLayoutRenderer.tsx` ```typescript style={{ display: "grid", gridTemplateColumns: `repeat(${canvasGrid.columns}, 1fr)`, // ✅ fallback 추가 gridTemplateRows: `repeat(${canvasGrid.rows || 24}, 1fr)`, gap: `${canvasGrid.gap}px`, padding: `${canvasGrid.gap}px`, }} ``` **효과**: 뷰어에서도 안전하게 렌더링 --- ### 4. 백엔드 저장 로직 강화 **파일**: `backend-node/src/services/screenManagementService.ts` ```typescript if (isV2) { dataToSave = { ...layoutData, version: "pop-2.0", }; // ✅ canvasGrid.rows 검증 및 보정 if (dataToSave.settings?.canvasGrid) { if (!dataToSave.settings.canvasGrid.rows) { console.warn("canvasGrid.rows 없음, 기본값 24로 설정"); dataToSave.settings.canvasGrid.rows = 24; } // ✅ 구버전 rowHeight 필드 제거 if (dataToSave.settings.canvasGrid.rowHeight) { console.warn("구버전 rowHeight 필드 제거"); delete dataToSave.settings.canvasGrid.rowHeight; } } } ``` **효과**: 앞으로 저장되는 모든 데이터는 올바른 구조 보장 --- ## 원칙 준수 여부 ### 1. 데스크톱과 완전 분리 ✅ - POP 전용 파일만 수정 - 데스크톱 코드 0% 영향 ### 2. 4모드 반응형 디자인 ✅ - 변경 없음 ### 3. 비율 기반 그리드 시스템 ✅ - **오히려 원칙을 바로잡는 수정** - 고정 픽셀(`rowHeight`) → 비율(`rows`) 강제 --- ## 해결된 문제 | 문제 | 수정 전 | 수정 후 | |------|---------|---------| | 섹션 크기 | 매우 작게 표시 | 정상 크기 (24x24 그리드) | | 디자이너 렌더링 | `NaN` 오류 | 정상 계산 | | 뷰어 렌더링 | CSS 무효 | 비율 기반 렌더링 | | 타입 안정성 | `rowHeight` vs `rows` 불일치 | `rows`로 통일 | | 구버전 데이터 | 호환 불가 | 자동 보정 | --- ## 테스트 방법 ### 1. 기존 화면 확인 (screen_id: 3884) ```bash # 디자이너 접속 http://localhost:9771/screen-management/pop-designer/3884 # 저장 후 뷰어 확인 http://localhost:9771/pop/screens/3884 ``` **기대 결과**: - 섹션이 화면 전체 크기로 정상 표시 - 가로/세로 모드 전환 시 비율 유지 ### 2. 새로운 화면 생성 - POP 디자이너에서 새 화면 생성 - 섹션 추가 및 배치 - 저장 후 DB 확인 **DB 확인**: ```sql SELECT screen_id, layout_data->'settings'->'canvasGrid' as canvas_grid FROM screen_layouts_pop WHERE screen_id = 3884; ``` **기대 결과**: ```json { "gap": 4, "rows": 24, "columns": 24 } ``` --- ## 추가 조치 사항 ### 1. 기존 DB 데이터 마이그레이션 (선택) 만약 프론트엔드 자동 보정이 아닌 DB 마이그레이션을 원한다면: ```sql UPDATE screen_layouts_pop SET layout_data = jsonb_set( jsonb_set( layout_data, '{settings,canvasGrid,rows}', '24' ), '{settings,canvasGrid}', (layout_data->'settings'->'canvasGrid') - 'rowHeight' ) WHERE layout_data->'settings'->'canvasGrid'->>'rows' IS NULL AND layout_data->>'version' = 'pop-2.0'; ``` ### 2. 모드별 컴포넌트 위치 반대 문제 **별도 이슈**: `activeModeKey` 상태 관리 점검 필요 - DeviceFrame 클릭 시 모드 전환 - 저장 시 올바른 `modeKey` 전달 확인 --- ## 결론 ✅ **원칙 준수**: 데스크톱 분리, 4모드 반응형 유지 ✅ **비율 기반 강제**: 고정 픽셀 제거 ✅ **하위 호환**: 구버전 데이터 자동 보정 ✅ **안정성 향상**: 타입 일관성 확보