---
description:
globs:
alwaysApply: false
---
# Univer CE 초기화 및 인스턴스 관리 규칙

## **핵심 원칙**
- **단일 인스턴스**: 컴포넌트당 하나의 Univer 인스턴스만 유지
- **중복 방지**: 플러그인 등록과 초기화 중복 실행 방지
- **적절한 정리**: 메모리 누수 방지를 위한 dispose 패턴

## **초기화 패턴**

### ✅ DO: 안전한 초기화
```typescript
// 인스턴스 존재 확인 후 초기화
useEffect(() => {
  if (!univerRef.current) {
    initializeUniver();
  }
}, []);

// 처리 중 상태 확인으로 중복 방지
const processFile = useCallback(async (file: File) => {
  if (isProcessing) {
    console.log("이미 파일 처리 중입니다.");
    return;
  }
  
  setIsProcessing(true);
  // ... 파일 처리 로직
}, [isProcessing]);
```

### ❌ DON'T: 중복 초기화 유발
```typescript
// 조건 없는 초기화 (중복 실행 위험)
useEffect(() => {
  initializeUniver(); // 매번 실행됨
}, []);

// 상태 확인 없는 처리
const processFile = useCallback(async (file: File) => {
  // isProcessing 확인 없이 바로 실행
  setIsProcessing(true);
}, []);
```

## **인스턴스 관리**

### ✅ DO: 적절한 dispose 패턴
```typescript
// 새 인스턴스 생성 전 기존 인스턴스 정리
if (univerRef.current) {
  univerRef.current.dispose();
  univerRef.current = null;
}

// 컴포넌트 언마운트 시 정리
useEffect(() => {
  return () => {
    if (univerRef.current) {
      univerRef.current.dispose();
      univerRef.current = null;
    }
  };
}, []);
```

### ❌ DON'T: 메모리 누수 위험
```typescript
// dispose 없이 새 인스턴스 생성
univerRef.current = univer.createUnit(UnitType.UNIVER_SHEET, workbook);

// 정리 로직 없는 컴포넌트
// useEffect cleanup 누락
```

## **파일 처리 최적화**

### ✅ DO: 중복 처리 방지
```typescript
// 파일 입력 초기화로 재선택 가능
finally {
  if (event.target) {
    event.target.value = "";
  }
}

// 의존성 배열에 상태 포함
const processFile = useCallback(async (file: File) => {
  // ... 로직
}, [isProcessing]);
```

## **REDI 중복 로드 방지**

### ✅ DO: 라이브러리 중복 확인
```typescript
// 개발 환경에서 REDI 중복 로드 경고 모니터링
// 동일한 라이브러리 버전 사용 확인
// 번들링 시 중복 제거 설정
```

### ❌ DON'T: 무시하면 안 되는 경고
```typescript
// REDI 중복 로드 경고 무시
// 서로 다른 버전의 동일 라이브러리 사용
// 번들 중복 제거 설정 누락
```

## **디버깅 및 로깅**

### ✅ DO: 의미있는 로그
```typescript
console.log("초기화할 워크북 데이터:", workbookData);
console.log("Univer 인스턴스 생성 완료");
console.log("플러그인 등록 완료");
```

### ❌ DON'T: 과도한 로깅
```typescript
// 매 렌더링마다 로그 출력
// 민감한 데이터 로깅
// 프로덕션 환경 디버그 로그 유지
```

## **성능 최적화**

- **useCallback**: 이벤트 핸들러 메모이제이션
- **의존성 최적화**: 필요한 의존성만 포함
- **조건부 실행**: 불필요한 재실행 방지
- **메모리 관리**: 적절한 dispose와 cleanup

이 규칙을 따르면 Univer CE가 안정적으로 작동하고 메모리 누수 없이 파일 처리가 가능합니다.

# Univer CE REDI 중복 로드 오류 완전 방지 규칙

## **문제 원인**
- Univer CE의 REDI 시스템에서 "Identifier already exists" 오류는 동일한 서비스가 중복으로 등록될 때 발생
- 컴포넌트 재마운트, HMR(Hot Module Reload), 또는 동시 초기화 시도로 인한 중복 인스턴스 생성
- 브라우저 캐시에 잔존하는 이전 REDI 등록 정보

## **필수 해결 패턴**

### **1. 전역 인스턴스 관리자 패턴 사용**
```typescript
// ✅ DO: 모듈 레벨에서 단일 인스턴스 보장
let globalUniver: Univer | null = null;
let globalInitializing = false;
let globalDisposing = false;

const UniverseManager = {
  async createInstance(container: HTMLElement): Promise<Univer> {
    if (globalUniver) return globalUniver;
    
    if (globalInitializing) {
      // 초기화 완료까지 대기
      while (globalInitializing) {
        await new Promise((resolve) => setTimeout(resolve, 50));
      }
      if (globalUniver) return globalUniver;
    }
    
    globalInitializing = true;
    try {
      // Univer 인스턴스 생성 로직
      globalUniver = new Univer({...});
      return globalUniver;
    } finally {
      globalInitializing = false;
    }
  },
  
  getInstance(): Univer | null {
    return globalUniver;
  }
};

// ❌ DON'T: 컴포넌트마다 개별 인스턴스 생성
const MyComponent = () => {
  const [univer, setUniver] = useState<Univer | null>(null);
  
  useEffect(() => {
    const newUniver = new Univer({...}); // 중복 생성 위험
    setUniver(newUniver);
  }, []);
};
```

### **2. 상태 기반 중복 초기화 방지**
```typescript
// ✅ DO: 강화된 상태 확인으로 중복 실행 완전 차단
const processFile = useCallback(async (file: File) => {
  if (
    isProcessing ||
    UniverseManager.isInitializing() ||
    UniverseManager.isDisposing()
  ) {
    console.log("처리 중이거나 상태 변경 중입니다.");
    return; // 중복 실행 차단
  }
  
  setIsProcessing(true);
  try {
    // 파일 처리 로직
  } finally {
    setIsProcessing(false);
  }
}, [isProcessing]); // 의존성 배열에 상태 포함

// ❌ DON'T: 간단한 상태 확인만으로는 불충분
const processFile = useCallback(async (file: File) => {
  if (isProcessing) return; // 다른 상태는 확인하지 않음
}, []);
```

### **3. 컴포넌트 마운트 시 기존 인스턴스 재사용**
```typescript
// ✅ DO: 기존 전역 인스턴스 우선 재사용
useEffect(() => {
  const existingUniver = UniverseManager.getInstance();
  if (existingUniver && !UniverseManager.isInitializing()) {
    setIsInitialized(true);
    return; // 재사용으로 중복 초기화 방지
  }
  
  if (containerRef.current && !UniverseManager.isInitializing()) {
    initializeUniver();
  }
}, []);

// ❌ DON'T: 매번 새로운 초기화 시도
useEffect(() => {
  initializeUniver(); // 기존 인스턴스 무시하고 새로 생성
}, []);
```

### **4. 디버깅을 위한 전역 상태 제공**
```typescript
// ✅ DO: 전역 디버그 객체로 상태 추적 가능
if (typeof window !== "undefined") {
  (window as any).__UNIVER_DEBUG__ = {
    getGlobalUniver: () => globalUniver,
    getGlobalInitializing: () => globalInitializing,
    clearGlobalState: () => {
      globalUniver = null;
      globalInitializing = false;
      globalDisposing = false;
    },
  };
}
```

### **5. 기존 워크북 정리 시 API 호환성 처리**
```typescript
// ✅ DO: try-catch로 API 버전 차이 대응
try {
  const existingUnits = 
    (univer as any).getUnitsForType?.(UniverInstanceType.UNIVER_SHEET) || [];
  for (const unit of existingUnits) {
    (univer as any).disposeUnit?.(unit.getUnitId());
  }
} catch (error) {
  console.log("기존 워크북 정리 시 오류 (무시 가능):", error);
}

// ❌ DON'T: API 호환성 고려하지 않은 직접 호출
univer.getUnitsForType(UniverInstanceType.UNIVER_SHEET); // 버전에 따라 실패 가능
```

## **브라우저 캐시 완전 삭제**

### **개발 환경에서 REDI 오류 발생 시 필수 작업**
```bash
# ✅ DO: 브라우저 캐시 완전 삭제
rm -rf node_modules/.vite && rm -rf dist

# 추가적으로 브라우저에서:
# - 강제 새로고침 (Ctrl+Shift+R 또는 Cmd+Shift+R)
# - 개발자 도구 > Application > Storage > Clear storage
```

## **오류 패턴 및 해결책**

### **"Identifier already exists" 오류**
- **원인**: REDI 시스템에서 동일한 식별자의 서비스가 중복 등록
- **해결**: 전역 인스턴스 관리자 패턴으로 단일 인스턴스 보장

### **컴포넌트 재마운트 시 중복 초기화**
- **원인**: useEffect가 매번 새로운 초기화 시도
- **해결**: 기존 전역 인스턴스 존재 확인 후 재사용

### **HMR 환경에서 상태 불안정**
- **원인**: 모듈 재로드 시 전역 상태 초기화
- **해결**: 브라우저 캐시 삭제 + window 객체 기반 상태 추적

## **성능 최적화**

### **초기화 대기 로직**
```typescript
// ✅ DO: Promise 기반 비동기 대기
while (globalInitializing) {
  await new Promise((resolve) => setTimeout(resolve, 50));
}

// ❌ DON'T: 동기 대기나 긴 interval
setInterval(() => { /* 체크 로직 */ }, 1000); // 너무 느림
```

### **메모리 누수 방지**
```typescript
// ✅ DO: 컴포넌트 언마운트 시 상태만 정리
useEffect(() => {
  return () => {
    setIsInitialized(false);
    // 전역 인스턴스는 앱 종료 시에만 정리
  };
}, []);
```

## **참고사항**
- 이 패턴은 Univer CE의 REDI 아키텍처 특성상 필수적임
- 전역 인스턴스 관리로 브라우저 재로드 없이 안정적 운용 가능
- 개발 환경에서 오류 발생 시 반드시 캐시 삭제 후 재시작
