# InsuRo 이미지 편집기 — fabric.js + React DOM 충돌 근본 해결

## 작업 레벨: Lv.2

## 프로젝트 시스템 3문서
- InsuRo: `/home/jay/workspace/memory/plans/insuro-system/plan.md`

## 배경
이미지 편집기에서 파일 업로드 시 `insertBefore` DOM 에러로 흰 화면 크래시. task-2201, task-2203에서 두 번 수정 시도했으나 해결 안 됨.

## 근본 원인
fabric.js `new Canvas()`가 React가 관리하는 `<canvas>` 엘리먼트의 DOM을 직접 조작(wrapper div 생성, canvas 복제 등)하면서 React의 virtual DOM reconciliation과 충돌. `requestAnimationFrame`이나 `setTimeout` 패치로는 해결 불가.

## 해결 방향: React DOM 밖에서 Canvas 마운트

### 핵심 전략
fabric.js Canvas를 React의 JSX 트리가 아닌, `useRef`로 잡은 컨테이너 div에 **동적으로 생성한 canvas 엘리먼트**를 삽입하여 React의 DOM 관리에서 완전히 분리.

### 구현 방법
```tsx
// 변경 전 (문제):
// JSX에 <canvas ref={canvasElRef} /> 직접 렌더 → React가 관리
// fabric.js가 이 canvas의 DOM을 조작 → React와 충돌

// 변경 후 (해결):
const containerRef = useRef<HTMLDivElement>(null);

useEffect(() => {
  if (!containerRef.current) return;
  
  // React JSX가 아닌, JS로 canvas 엘리먼트 동적 생성
  const canvasEl = document.createElement('canvas');
  containerRef.current.appendChild(canvasEl);
  
  // fabric.js가 이 canvas를 자유롭게 조작 — React는 모름
  const canvas = new fabric.Canvas(canvasEl, { width, height });
  fabricRef.current = canvas;
  
  return () => {
    canvas.dispose();
    // 동적 생성한 엘리먼트 정리
    while (containerRef.current?.firstChild) {
      containerRef.current.removeChild(containerRef.current.firstChild);
    }
  };
}, []);

// JSX에서는 빈 div만 렌더
// <div ref={containerRef} className="..." />
```

### 추가 안전장치
1. ErrorBoundary 컴포넌트로 ImageEditor 감싸기 — 크래시 시 에러 메시지 표시 (흰 화면 방지)
2. 이미지 로드 시 상태 변경(setImageLoaded 등)은 `flushSync` 사용하지 않고 일반 setState만 사용
3. canvas 관련 DOM 조작과 React 상태 변경을 같은 이벤트 핸들러에서 동시에 하지 않기

## affected_files
- `src/pages/ImageEditor.tsx` (수정 — canvas 마운트 방식 변경)

## 검증 시나리오 (★ 반드시 실 브라우저에서 확인)
1. `npm run dev`로 dev 서버 실행
2. /tools/image-editor 접근 → UI 정상 표시 (크래시 없음)
3. 이미지 파일 업로드 → Canvas에 이미지 정상 표시 (★ 핵심)
4. 크롭 도구 → 동작
5. 필터 적용 → 동작
6. `npm run build` 성공
7. 빌드된 dist에서도 이미지 업로드 정상 동작 확인

## 주의사항
- 기존 기능(크롭/필터/오버레이/AI/콜라주/일괄처리) 회귀 없어야 함
- 수정 후 반드시 `npm run build` 실행하여 dist 갱신
- ★ L1 스모크테스트: 실제 브라우저에서 이미지 업로드 + 크롭 + 다운로드 확인 필수

## goal_assertions (auto-generated)
- `npm run dev`
- `npm run build`
- `npm run build`
