Frontend Framework: React 19.1.1 + TypeScript 5.9.3
Build Tool: Vite 7.1.7
Routing: React Router DOM 7.9.4
Backend: Firebase (Authentication + Firestore)
Internationalization: i18next + react-i18next
Styling: Bootstrap 5 (via CDN) + CSS
State Management: React Context API (Theme)todo-app/
├── public/                      # 정적 파일
│   └── vite.svg
├── src/
│   ├── components/              # React 컴포넌트
│   │   ├── AddTodoForm.tsx      # Todo 추가 폼
│   │   ├── TodoItem.tsx         # Todo 단일 아이템
│   │   └── TodoList.tsx         # Todo 목록 컨테이너
│   ├── context/                 # React Context
│   │   └── ThemeContext.tsx     # 다크모드 테마 관리
│   ├── firebase/                # Firebase 설정 및 서비스
│   │   ├── config.ts            # Firebase 초기화
│   │   └── services.ts          # Firestore CRUD 함수
│   ├── hooks/                   # Custom React Hooks
│   │   ├── useAuth.ts           # 인증 상태 관리
│   │   └── useTodos.ts          # Todo 목록 관리
│   ├── locales/                 # 다국어 번역 파일
│   │   ├── en/translation.json  # 영어
│   │   ├── ko/translation.json  # 한국어
│   │   └── ja/translation.json  # 일본어
│   ├── pages/                   # 페이지 컴포넌트
│   │   ├── HomePage.tsx         # 메인 페이지 (Todo 관리)
│   │   └── LoginPage.tsx        # 로그인/회원가입 페이지
│   ├── App.tsx                  # 앱 라우팅
│   ├── main.tsx                 # 앱 진입점
│   ├── i18n.ts                  # i18next 설정
│   ├── App.css                  # 앱 스타일
│   └── index.css                # 전역 스타일
├── firestore.rules              # Firestore 보안 규칙
├── firestore.indexes.json       # Firestore 인덱스
├── firebase.json                # Firebase 설정
├── .firebaserc                  # Firebase 프로젝트 ID
├── package.json                 # 의존성 관리
├── tsconfig.json                # TypeScript 설정
└── vite.config.ts               # Vite 설정{
  "dependencies": {
    "firebase": "^12.4.0",
    "i18next": "^25.6.0",
    "i18next-browser-languagedetector": "^8.2.0",
    "react": "^19.1.1",
    "react-dom": "^19.1.1",
    "react-i18next": "^16.1.0",
    "react-router-dom": "^7.9.4"
  },
  "devDependencies": {
    "@types/node": "^24.6.0",
    "@types/react": "^19.1.16",
    "@types/react-dom": "^19.1.9",
    "@vitejs/plugin-react": "^5.0.4",
    "firebase-tools": "^14.20.0",
    "typescript": "~5.9.3",
    "vite": "^7.1.7"
  }
}App (라우팅)
├── LoginPage (비인증)
│   └── 로그인/회원가입 폼
└── HomePage (인증 후)
    ├── Header
    │   ├── 제목
    │   ├── 언어 선택기
    │   ├── 테마 토글 버튼
    │   └── 로그아웃 버튼
    ├── AddTodoForm
    │   ├── 텍스트 입력
    │   └── 추가 버튼
    └── TodoList
        └── TodoItem[] (반복)
            ├── 체크박스
            ├── 텍스트
            └── 삭제 버튼┌─────────────────────────────────────────────────────────────┐
│                     Firebase Cloud                           │
│  ┌────────────────┐              ┌─────────────────┐        │
│  │ Authentication │              │   Firestore DB  │        │
│  │   (Auth SDK)   │              │  (todos 컬렉션) │        │
│  └────────────────┘              └─────────────────┘        │
└──────────┬──────────────────────────────┬──────────────────┘
           │                              │
           │ onAuthStateChanged           │ onSnapshot (실시간)
           │                              │
┌──────────▼──────────────────────────────▼──────────────────┐
│                    Frontend (React)                         │
│  ┌───────────────────────────────────────────────────────┐ │
│  │  main.tsx (전역 AbortError 차단 시스템)              │ │
│  └───────────────────────────────────────────────────────┘ │
│  ┌───────────────────────────────────────────────────────┐ │
│  │  App.tsx (React Router)                               │ │
│  │    ├─ useAuth() → user, loading                       │ │
│  │    └─ Route 분기 (인증/비인증)                        │ │
│  └───────────────────────────────────────────────────────┘ │
│  ┌───────────────────────────────────────────────────────┐ │
│  │  HomePage                                              │ │
│  │    ├─ useTodos() → todos[], loading                   │ │
│  │    ├─ ThemeContext → theme, toggleTheme               │ │
│  │    ├─ i18next → t(), i18n                             │ │
│  │    └─ Components: AddTodoForm, TodoList               │ │
│  └───────────────────────────────────────────────────────┘ │
│  ┌───────────────────────────────────────────────────────┐ │
│  │  Firebase Services (CRUD)                             │ │
│  │    ├─ addTodo(userId, text)                           │ │
│  │    ├─ getTodos(userId, callback) → unsubscribe        │ │
│  │    ├─ toggleTodoCompleted(id, completed)              │ │
│  │    └─ deleteTodo(id)                                  │ │
│  └───────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘// useAuth Hook
사용자 인증 상태를 실시간으로 추적
- onAuthStateChanged 리스너 등록
- user, loading 상태 반환
- cleanup 함수로 메모리 누수 방지
// LoginPage
- 이메일/비밀번호 입력
- 회원가입: createUserWithEmailAndPassword
- 로그인: signInWithEmailAndPassword
- 에러 핸들링: AbortError 필터링// Firestore 데이터 구조
interface Todo {
  id: string;
  text: string;
  completed: boolean;
  createdAt: Timestamp;
  userId: string;
}
// 보안 규칙
- allow list: 인증된 사용자만 쿼리 가능
- allow get: 자신의 문서만 읽기 가능
- allow create: 자신의 userId로만 생성
- allow update/delete: 자신의 문서만 수정/삭제// useTodos Hook
- getTodos() → onSnapshot 리스너 등록
- userId로 필터링된 쿼리
- createdAt 기준 내림차순 정렬
- 실시간 업데이트 자동 반영
- cleanup 시 unsubscribe() 호출// 지원 언어: en (영어), ko (한국어), ja (일본어)
// 브라우저 언어 자동 감지
// 사용자가 수동으로 언어 변경 가능
// 모든 UI 텍스트 번역 파일로 관리// ThemeContext
- localStorage에 테마 저장
- Bootstrap 5의 data-bs-theme 속성 활용
- light/dark 토글
- 앱 전체에 Context로 제공// 3단계 방어 시스템
1. fetch 오버라이드: AbortError를 소스에서 차단
2. unhandledrejection: 놓친 에러 캐치
3. console.error 필터링: inspector.js 로그 차단React + TypeScript + Vite로 Todo 앱을 만들고 싶어요. 다음 요구사항을 충족하는 프로젝트를 생성해주세요:
1. React 19 + TypeScript 5 + Vite 7 사용
2. Firebase Authentication + Firestore 사용
3. React Router DOM으로 라우팅
4. i18next로 다국어 지원 (영어, 한국어, 일본어)
5. Bootstrap 5 스타일링 (CDN 사용)
다음 명령어로 프로젝트를 생성하고 필요한 패키지를 설치해주세요:
npm create vite@latest todo-app -- --template react-ts
cd todo-app
npm install
그리고 다음 패키지들을 추가 설치해주세요:
npm install firebase react-router-dom i18next react-i18next i18next-browser-languagedetector
개발 도구도 설치해주세요:
npm install -D firebase-tools @types/node
package.json을 확인하고 모든 의존성이 올바르게 설치되었는지 확인해주세요.Firebase 프로젝트를 설정하고 싶어요. 다음 파일들을 생성해주세요:
1. src/firebase/config.ts - Firebase 초기화 파일
   - Vite 환경 변수 (import.meta.env.VITE_*) 사용
   - getAuth, getFirestore import
   - 환경 변수 검증 로직 포함
2. src/firebase/services.ts - Firestore CRUD 서비스
   - Todo 인터페이스 정의 (id, text, completed, createdAt, userId)
   - addTodo(userId, text) - 새 Todo 추가
   - getTodos(userId, callback) - 실시간 리스너 (where userId, orderBy createdAt desc)
   - toggleTodoCompleted(docId, completed) - 완료 상태 토글
   - deleteTodo(docId) - Todo 삭제
   - 모든 함수에 AbortError 처리 포함 (error.name === 'AbortError'면 조용히 반환)
   - permission-denied 에러는 명확한 메시지로 로깅
3. firestore.rules - Firestore 보안 규칙
   - todos 컬렉션에 대해:
     - allow list: 인증된 사용자만
     - allow get: 자신의 문서만
     - allow create: 자신의 userId로만
     - allow update, delete: 자신의 문서만
4. firebase.json - Firebase 프로젝트 설정
   - firestore rules 및 indexes 경로 지정
5. .env.local 템플릿 생성
   - VITE_API_KEY, VITE_AUTH_DOMAIN, VITE_PROJECT_ID 등 환경 변수 예시
각 파일의 전체 코드를 TypeScript와 Firebase v10+ 최신 문법으로 작성해주세요.
React 17+ 에서는 JSX 변환 시 `import React`가 불필요하므로 포함하지 마세요.
type import는 `import type { ... }`나 `type ReactNode` 형식으로 작성해주세요.React Custom Hooks를 만들고 싶어요. 다음 두 개의 hook을 생성해주세요:
1. src/hooks/useAuth.ts
   - Firebase Authentication 상태를 관리하는 hook
   - onAuthStateChanged 리스너 등록
   - user (User | null)와 loading (boolean) 상태 반환
   - useEffect cleanup에서 unsubscribe 호출
   - TypeScript 타입 안전성 보장
2. src/hooks/useTodos.ts
   - useAuth hook 사용하여 현재 사용자 가져오기
   - getTodos 서비스 사용하여 실시간 리스너 등록
   - todos (Todo[])와 loading (boolean) 상태 반환
   - user가 없으면 빈 배열 반환
   - useEffect cleanup에서 리스너 해제
주의사항:
- React 17+이므로 `import React` 불필요
- type import는 `import type { User }` 형식 사용
- dependency array 정확히 설정
- 메모리 누수 방지를 위한 cleanup 함수 필수다크모드를 지원하는 ThemeContext를 만들고 싶어요.
src/context/ThemeContext.tsx 파일을 생성해주세요:
요구사항:
1. Theme 타입: 'light' | 'dark'
2. ThemeContextType 인터페이스: { theme: Theme, toggleTheme: () => void }
3. ThemeProvider 컴포넌트:
   - localStorage에서 초기 테마 로드 (기본값: 'light')
   - theme이 변경되면 document.documentElement.setAttribute('data-bs-theme', theme) 실행
   - localStorage에 theme 저장
4. useTheme 커스텀 hook:
   - ThemeContext 사용
   - context가 undefined면 에러 발생
주의사항:
- type ReactNode는 `import { type ReactNode }` 형식으로 import
- React import 불필요
- children props 타입 명시다국어 지원 설정을 해주세요.
1. src/i18n.ts 파일 생성:
   - i18next, react-i18next, i18next-browser-languagedetector import
   - 영어(en), 한국어(ko), 일본어(ja) 번역 파일 import
   - LanguageDetector 사용하여 브라우저 언어 자동 감지
   - fallbackLng: 'en'
   - interpolation.escapeValue: false
2. 번역 파일 생성:
   - src/locales/en/translation.json
   - src/locales/ko/translation.json
   - src/locales/ja/translation.json
번역 키:
- loginTitle: "Login or Sign Up" / "로그인 또는 회원가입" / "ログインまたはサインアップ"
- emailPlaceholder: "Email" / "이메일" / "Eメール"
- passwordPlaceholder: "Password" / "비밀번호" / "パスワード"
- loginButton, signupButton, logoutButton
- todoTitle: "Todo List" / "할 일 목록" / "Todoリスト"
- addTaskButton, taskPlaceholder, deleteButton
- noTasks: "No tasks yet. Add one above!"
- loading: "Loading..." / "로딩 중..." / "読み込み中..."
- adding, deleting (로딩 상태 텍스트)
모든 파일을 JSON 형식으로 작성해주세요.Todo 추가 폼 컴포넌트를 만들고 싶어요.
src/components/AddTodoForm.tsx 파일을 생성해주세요:
요구사항:
1. Props: { userId: string }
2. 로컬 상태:
   - text (string) - 입력 텍스트
   - isAdding (boolean) - 추가 중 상태
3. handleSubmit 함수:
   - e.preventDefault() 호출
   - text.trim() 검증
   - isAdding이면 early return
   - setIsAdding(true) 설정
   - try-catch-finally로 addTodo 호출
   - 성공 시 setText('') 로 입력 필드 초기화
   - permission-denied 에러는 명확히 로깅
   - AbortError는 조용히 처리
   - finally에서 setIsAdding(false)
4. UI:
   - form onSubmit={handleSubmit}
   - Bootstrap input-group 사용
   - input: type="text", placeholder={t('taskPlaceholder')}
   - button: type="submit", {isAdding ? t('adding') : t('addTaskButton')}
   - isAdding 중에는 input과 button disabled
주의사항:
- useTranslation() hook 사용
- React import 불필요
- async/await 사용개별 Todo 아이템 컴포넌트를 만들고 싶어요.
src/components/TodoItem.tsx 파일을 생성해주세요:
요구사항:
1. Props: { todo: Todo }
2. 로컬 상태:
   - isToggling (boolean) - 토글 중
   - isDeleting (boolean) - 삭제 중
3. handleToggle 함수:
   - isToggling이면 early return
   - setIsToggling(true)
   - try-catch-finally로 toggleTodoCompleted 호출
   - permission-denied와 AbortError 처리
   - finally에서 setIsToggling(false)
4. handleDelete 함수:
   - isDeleting이면 early return
   - setIsDeleting(true)
   - try-catch-finally로 deleteTodo 호출
   - permission-denied와 AbortError 처리
   - finally에서 setIsDeleting(false)
5. UI:
   - li.list-group-item
   - checkbox: checked={todo.completed}, onChange={handleToggle}
   - label: todo.completed이면 text-decoration-line-through, text-muted 클래스
   - button: onClick={handleDelete}, {isDeleting ? t('deleting') : t('deleteButton')}
   - isToggling이나 isDeleting 중에는 모든 컨트롤 disabled
주의사항:
- useTranslation() hook 사용
- async/await 사용
- 중복 클릭 방지 필수Todo 목록을 렌더링하는 간단한 컨테이너 컴포넌트를 만들어주세요.
src/components/TodoList.tsx 파일을 생성해주세요:
요구사항:
1. Props: { todos: Todo[] }
2. UI:
   - ul.list-group
   - todos.map()으로 TodoItem 렌더링
   - key={todo.id}로 설정
주의사항:
- React import 불필요
- React.FC<TodoListProps> 타입 명시
- TodoItem import로그인/회원가입 페이지를 만들어주세요.
src/pages/LoginPage.tsx 파일을 생성해주세요:
요구사항:
1. 로컬 상태:
   - email (string)
   - password (string)
   - error (string | null)
2. handleSignUp 함수:
   - React.MouseEvent<HTMLButtonElement> 타입
   - e.preventDefault() 호출
   - email, password 검증
   - try-catch로 createUserWithEmailAndPassword 호출
   - AbortError는 조용히 처리
   - 다른 에러는 setError(err.message)
3. handleLogIn 함수:
   - handleSignUp과 유사하지만 signInWithEmailAndPassword 사용
4. UI:
   - Bootstrap card 레이아웃
   - h2: {t('loginTitle')}
   - input email: placeholder={t('emailPlaceholder')}
   - input password: placeholder={t('passwordPlaceholder')}
   - button 로그인: onClick={handleLogIn}, type="submit"
   - button 회원가입: onClick={handleSignUp}, type="button"
   - error가 있으면 alert 표시
주의사항:
- useTranslation() hook 사용
- React 19의 event handler 타입 사용
- async/await 사용메인 페이지 (Todo 관리)를 만들어주세요.
src/pages/HomePage.tsx 파일을 생성해주세요:
요구사항:
1. Hooks:
   - useAuth() → user
   - useTodos() → todos, loading
   - useTheme() → theme, toggleTheme
   - useTranslation() → t, i18n
2. handleLogout 함수:
   - signOut(auth).catch()
   - AbortError 조용히 처리
3. handleLanguageChange 함수:
   - i18n.changeLanguage(lng) 호출
4. UI 구조:
   - card.card-header:
     - h1: {t('todoTitle')}
     - select: 언어 선택 (EN, KO, JA)
     - button: 테마 토글 ({theme === 'dark' ? '🌙' : '☀️'})
     - button: 로그아웃 {t('logoutButton')}
   - card.card-body:
     - AddTodoForm (user가 있을 때만)
     - loading이면 spinner 표시
     - todos.length === 0이고 loading이 아니면 {t('noTasks')}
     - todos.length > 0이면 TodoList
주의사항:
- 모든 컴포넌트와 hook import
- Bootstrap 클래스 사용
- 조건부 렌더링 정확히 구현앱의 라우팅을 설정해주세요.
src/App.tsx 파일을 생성해주세요:
요구사항:
1. useAuth() hook으로 user, loading 가져오기
2. loading이면 "Loading..." 표시
3. BrowserRouter 사용:
   - Route "/" - user가 있으면 HomePage, 없으면 /login으로 Navigate
   - Route "/login" - user가 없으면 LoginPage, 있으면 /로 Navigate
4. 전체를 div.container.mt-5로 감싸기
주의사항:
- React Router DOM의 Navigate 컴포넌트 사용
- 인증 상태에 따른 리다이렉트 정확히 구현
- App.css import (빈 파일이어도 됨)앱의 진입점 파일을 만들어주세요. 특히 AbortError 차단 시스템을 포함해야 합니다.
src/main.tsx 파일을 생성해주세요:
요구사항:
1. 전역 AbortError 차단 시스템 (3단계):
   1단계 - fetch 오버라이드:
   - const originalFetch = window.fetch 저장
   - window.fetch를 새 함수로 오버라이드
   - .catch()에서 AbortError 또는 code === 'cancelled' 체크
   - AbortError면 new Promise(() => {}) 반환 (완전히 삼킴)
   - 다른 에러는 throw
   2단계 - unhandledrejection 핸들러:
   - window.addEventListener('unhandledrejection', ...)
   - AbortError면 event.preventDefault()
   - 다른 에러는 console.error로 로깅
   3단계 - console.error 필터링:
   - const originalConsoleError = console.error 저장
   - console.error를 새 함수로 오버라이드
   - 메시지에 'AbortError' 또는 'user aborted' 포함 체크
   - AbortError 관련이면 return (로그 출력 안 함)
   - 다른 에러는 originalConsoleError로 로깅
2. React 앱 렌더링:
   - createRoot(document.getElementById('root')!)
   - StrictMode로 감싸기
   - ThemeProvider로 감싸기
   - App 컴포넌트 렌더링
3. 필요한 import:
   - React StrictMode, createRoot
   - './index.css', './i18n' (부수효과 import)
   - App, ThemeProvider
주의사항:
- 3단계 AbortError 차단 시스템이 가장 중요
- 주석으로 각 단계 명확히 표시
- originalFetch, originalConsoleError 변수 사용스타일링 파일들을 설정해주세요.
1. src/index.css:
   - body의 background-color를 #f0f2f5로 설정
   - !important 플래그 사용하여 Bootstrap 오버라이드
2. src/App.css:
   - 빈 파일 또는 필요한 앱별 스타일 추가
3. index.html:
   - Bootstrap 5 CSS CDN 추가 (<link> 태그)
   - Bootstrap 5 JS CDN 추가 (<script> 태그, body 끝)
   - 타이틀을 "Todo App"으로 변경
주의사항:
- Bootstrap 5.3+ 버전 사용
- dark mode 지원을 위한 data-bs-theme 속성 지원 버전TypeScript 설정을 검증하고 필요하면 수정해주세요.
tsconfig.app.json 파일을 확인하고:
1. verbatimModuleSyntax가 true로 설정되어 있는지 확인
2. 이 설정 때문에 type import는 반드시 `import type { ... }` 또는 inline `import { type ... }` 형식 사용
3. React 17+ JSX transform 사용 확인 (jsx: "react-jsx")
모든 .tsx 파일에서:
1. `import React`가 없는지 확인 (JSX 변환이므로 불필요)
2. type-only import는 올바른 형식인지 확인
3. 사용하지 않는 import가 없는지 확인 (TS6133 에러 방지)
npm run build를 실행하여 에러가 없는지 확인해주세요.Firebase 프로젝트를 설정하고 환경 변수를 구성해주세요.
1. Firebase Console에서 새 프로젝트 생성 (또는 기존 프로젝트 사용)
2. Authentication 활성화:
   - Email/Password 로그인 활성화
3. Firestore Database 생성:
   - 테스트 모드로 시작
4. Web 앱 추가하여 Firebase 설정 가져오기
5. .env.local 파일 생성:
   VITE_API_KEY=your-api-key
   VITE_AUTH_DOMAIN=your-project-id.firebaseapp.com
   VITE_PROJECT_ID=your-project-id
   VITE_STORAGE_BUCKET=your-project-id.firebasestorage.app
   VITE_MESSAGING_SENDER_ID=your-sender-id
   VITE_APP_ID=your-app-id
6. Firebase CLI로 보안 규칙 배포:
   npx firebase login
   npx firebase init firestore (기존 파일 덮어쓰지 않도록 주의)
   npx firebase deploy --only firestore:rules
또는 Firebase Console에서 수동으로 firestore.rules 내용을 복사하여 배포
주의사항:
- .env.local은 .gitignore에 포함
- .env.example 파일을 만들어 변수 이름만 공유프로젝트를 빌드하고 테스트해주세요.
1. 빌드 테스트:
   npm run build
   - 에러가 없어야 함
   - dist 폴더 생성 확인
2. 로컬 개발 서버 실행:
   npm run dev
   - http://localhost:5173 접속
   - 브라우저 콘솔에 에러가 없어야 함
3. 기능 테스트 체크리스트:
   - [ ] 회원가입 정상 작동
   - [ ] 로그인 정상 작동
   - [ ] Todo 추가 정상 작동
   - [ ] Todo 체크/언체크 정상 작동
   - [ ] Todo 삭제 정상 작동
   - [ ] 다크모드 토글 정상 작동
   - [ ] 언어 전환 정상 작동 (EN, KO, JA)
   - [ ] 로그아웃 정상 작동
   - [ ] 브라우저 콘솔에 AbortError 없음
   - [ ] 브라우저 콘솔에 permission-denied 없음
4. 보안 규칙 테스트:
   - [ ] 비로그인 사용자는 데이터 접근 불가
   - [ ] 사용자 A는 사용자 B의 Todo 볼 수 없음
문제가 있으면 콘솔 에러를 확인하고 해당 단계로 돌아가 수정해주세요.TS6133: 'React' is declared but never used
→ import React 제거
TS1484: 'ReactNode' must be imported using type-only import
→ import { type ReactNode } 사용
TS2307: Cannot find module
→ npm install 재실행permission-denied
→ Firestore 보안 규칙 확인 및 배포
AbortError in console
→ main.tsx의 3단계 차단 시스템 확인
Missing environment variables
→ .env.local 파일 생성 및 변수 설정Cannot resolve module
→ package.json 의존성 확인
TypeScript compilation errors
→ tsconfig.json 설정 확인# 1. Git 저장소 생성
git init
git add .
git commit -m "Initial commit: Firebase Todo App"
# 2. GitHub에 푸시
git remote add origin <your-repo-url>
git push -u origin main
# 3. Netlify 설정
- Build command: npm run build
- Publish directory: dist
- Environment variables: VITE_* 변수들 설정# 1. Firebase Hosting 초기화
npx firebase init hosting
# 2. 설정
- Public directory: dist
- Single-page app: Yes
- GitHub Actions: No (선택)
# 3. 빌드 및 배포
npm run build
npx firebase deploy --only hosting1. 프로젝트 초기화 (Vite + React + TS)
   ↓
2. Firebase 설정 (config, services, rules)
   ↓
3. Custom Hooks (useAuth, useTodos)
   ↓
4. Context (ThemeContext)
   ↓
5. i18n 설정 (다국어)
   ↓
6. Components (AddTodoForm, TodoItem, TodoList)
   ↓
7. Pages (LoginPage, HomePage)
   ↓
8. App 라우팅
   ↓
9. main.tsx (AbortError 차단 시스템 포함)
   ↓
10. CSS 및 스타일링
   ↓
11. TypeScript 설정 검증
   ↓
12. Firebase 프로젝트 설정
   ↓
13. 빌드 및 테스트