228 lines
5.6 KiB
Markdown
228 lines
5.6 KiB
Markdown
# 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모드 반응형 유지
|
|
✅ **비율 기반 강제**: 고정 픽셀 제거
|
|
✅ **하위 호환**: 구버전 데이터 자동 보정
|
|
✅ **안정성 향상**: 타입 일관성 확보
|