ERP-node/popdocs/decisions/006-auto-wrap-review-system.md

6.2 KiB

ADR 006: v5.1 자동 줄바꿈 + 검토 필요 시스템

날짜: 2026-02-06
상태: 채택
의사결정자: 시스템 아키텍트


상황 (Context)

v5 반응형 레이아웃에서 "화면 밖" 개념으로 컴포넌트를 처리했으나, 다음 문제가 발생했습니다:

문제 1: 정보 손실

12칸 모드:
┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐
│  A   │            B (col=5, 6칸)                        │
└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘

4칸 모드 (기존):
┌────┬────┬────┬────┐   화면 밖:
│  A   │             │   - B
└────┴────┴────┴────┘
         ↑ A만 보임      ↑ 뷰어에서 안 보임!

문제 2: 사용자 의도 불일치

사용자가 기대한 "화면 밖" 역할:

  • 컴포넌트 숨김 (현재 동작)
  • "이 컴포넌트 검토 필요" 알림

결정 (Decision)

채택: 자동 줄바꿈 + 검토 필요 시스템

col > maxCol → 자동으로 맨 아래에 배치 (줄바꿈)
오버라이드 없음 → "검토 필요" 알림

구현 (Implementation)

1. 자동 줄바꿈 로직

파일: gridUtils.ts - convertAndResolvePositions()

// 단계별 처리:
1. 비율 변환 + 원본 col 보존
   converted = components.map(comp => ({
     id: comp.id,
     position: convertPositionToMode(comp.position, targetMode),
     originalCol: comp.position.col,  // ⭐ 원본 보존
   }))

2. 정상 vs 초과 분리
   normalComponents = originalCol  targetColumns
   overflowComponents = originalCol > targetColumns

3. 초과 컴포넌트 자동 배치
   maxRow = normalComponents의 최대 row
   overflowComponents  col=1, row=맨아래+1

4. 겹침 해결
   resolveOverlaps([...normalComponents, ...wrappedComponents])

2. 검토 필요 판별

파일: gridUtils.ts - needsReview()

function needsReview(
  currentMode: GridMode,
  hasOverride: boolean
): boolean {
  // 12칸 모드는 기본 모드이므로 검토 불필요
  if (GRID_BREAKPOINTS[currentMode].columns === 12) return false;
  
  // 오버라이드가 있으면 이미 편집함 → 검토 완료
  if (hasOverride) return false;
  
  // 오버라이드 없으면 → 검토 필요
  return true;
}

판단 기준 (최종): "이 모드에서 편집했냐 안 했냐"

3. 검토 필요 패널

파일: PopCanvas.tsx - ReviewPanel

// 필터링
const reviewComponents = visibleComponents.filter(comp => {
  const hasOverride = !!layout.overrides?.[currentMode]?.positions?.[comp.id];
  return needsReview(currentMode, hasOverride);
});

// UI
<ReviewPanel
  components={reviewComponents}
  onSelectComponent={onSelectComponent}  // 클릭  선택
/>

변경 사항:

  • 기존: OutOfBoundsPanel (주황색, 드래그로 복원)
  • 변경: ReviewPanel (파란색, 클릭으로 선택)

결과 (Consequences)

긍정적 효과

효과 설명
정보 손실 방지 모든 컴포넌트가 항상 그리드 안에 표시됨
사용자 부담 감소 자동 배치를 먼저 제공, 필요시에만 편집
의도 명확화 "숨김" ≠ "검토 필요" (기능 분리)
뷰어 호환 자동 배치가 뷰어에도 적용됨

트레이드오프

항목 설명
스크롤 증가 아래로 자동 배치되면 페이지가 길어질 수 있음
자동 배치 품질 사용자가 원하지 않는 위치에 배치될 수 있음

사용자 시나리오

시나리오 1: 수용 (자동 배치 그대로)

1. 12칸에서 컴포넌트 A, B, C 배치
2. 4칸 모드로 전환
3. 시스템: 자동 배치 + "검토 필요 (3개)" 알림
4. 사용자: 확인 → "괜찮네" → 아무것도 안 함
5. 결과: 자동 배치 유지 (오버라이드 없음)

시나리오 2: 편집 (오버라이드 저장)

1. 12칸에서 컴포넌트 A, B, C 배치
2. 4칸 모드로 전환
3. 시스템: 자동 배치 + "검토 필요 (3개)" 알림
4. 사용자: A 클릭 → 드래그/리사이즈
5. 결과: A 오버라이드 저장 → A 검토 완료
6. "검토 필요 (2개)" (B, C만 남음)

시나리오 3: 보류 (나중에)

1. 12칸에서 컴포넌트 A, B, C 배치
2. 4칸 모드로 전환
3. 시스템: 자동 배치 + "검토 필요 (3개)" 알림
4. 사용자: 다른 모드로 전환 또는 저장
5. 결과: 자동 배치 유지, 나중에도 "검토 필요" 표시

기능 비교

구분 역할 뷰어에서 판단 기준
검토 필요 자동 배치 알림 보임 오버라이드 없음
숨김 의도적 숨김 안 보임 hidden 배열에 ID

대안 (Alternatives Considered)

A안: 완전 자동 (채택 )

  • 모든 초과 컴포넌트 자동 배치
  • "검토 필요" 알림으로 확인 유도
  • 업계 표준 (Webflow, Retool)

B안: 선택적 자동 (미채택)

  • 첫 전환 시만 자동 배치
  • 사용자가 원하면 "화면 밖"으로 드래그
  • 복잡성 증가

C안: 수동 배치 유지 (미채택)

  • 기존 "화면 밖" 패널 유지
  • 사용자가 모든 모드 수동 편집
  • 사용자 부담 과다

참고 자료

업계 표준 (2026년 기준)

  • Grafana, Tableau: Masonry Layout (조적식)
  • Retool, PowerApps: Vertical Stacking (수직 스택)
  • Webflow, Framer: CSS Grid Auto-Placement

공통점: "Fluid Reflow (유동적 재배치)" - 정보 손실 방지


관련 파일

파일 변경 내용
gridUtils.ts convertAndResolvePositions, needsReview 추가
PopCanvas.tsx ReviewPanel로 변경
PopRenderer.tsx isOutOfBounds import 제거
pop-layout.ts 타입 변경 없음 (기존 구조 유지)

결론: 자동 줄바꿈 + 검토 필요 시스템으로 정보 손실 방지 및 사용자 부담 최소화