[문서 추가] 설정 가이드, 변경 이력, 트러블슈팅 문서 작성

## 추가된 문서

### 06-setup-guide.md - 설정 가이드
- panelQueueMiddleware 등록 상세 가이드
- 미들웨어 등록 순서 설명
- 파일 구조 확인 방법
- 단계별 설정 순서
- 검증 방법 (콘솔 로그, Redux DevTools, State 확인)
- 트러블슈팅 (5가지 일반적인 문제)
- 빠른 체크리스트

### 07-changelog.md - 변경 이력
- 2025-11-10: panelQueueMiddleware 등록 및 문서 개선
- 2025-11-10: 초기 문서 작성
- 2025-11-06: 큐 시스템 구현
- 2025-11-05: dispatch 헬퍼 함수 추가
- 마이그레이션 가이드
- Breaking Changes (없음)
- 알려진 이슈 (모두 해결됨)
- 향후 계획

### 08-troubleshooting.md - 트러블슈팅
- 일반적인 문제 3가지
  - dispatch 순서 미보장
  - Cannot find module 에러
  - 타입 에러
- 큐 시스템 문제 3가지
  - 큐가 처리되지 않음
  - 무한 루프
  - 큐 통계 미업데이트
- API 호출 문제 2가지
  - 성공인데 onFail 호출
  - 타임아웃 미작동
- 성능 문제 2가지
  - 큐 처리 속도 저하
  - 메모리 누수
- 디버깅 팁 5가지
  - 콘솔 로그 활용
  - Redux DevTools 사용
  - 브레이크포인트 설정
  - State 스냅샷
  - 큐 상태 모니터링

## README.md 업데이트
- 목차에 새로운 문서 3개 추가
- "학습 자료" 섹션을 3개 카테고리로 재구성:
  - 시작하기 (설정 가이드, 트러블슈팅)
  - 이해하기 (문제 상황, 3가지 솔루션)
  - 실전 적용 (사용 패턴, 변경 이력)

## 문서 통계
- 총 9개 마크다운 파일
- 약 5,000줄 이상
- 100개 이상의 코드 예제
- 10가지 실전 트러블슈팅 가이드

## 특징
- 초보자도 쉽게 따라할 수 있는 단계별 가이드
- 실제 발생 가능한 문제와 해결 방법
- 변경 이력 및 커밋 히스토리 추적
- 상세한 디버깅 팁
This commit is contained in:
Claude
2025-11-10 10:22:23 +00:00
parent c12cc91a39
commit bad111e23c
4 changed files with 1327 additions and 0 deletions

View File

@@ -0,0 +1,606 @@
# 트러블슈팅 가이드
## 📋 목차
1. [일반적인 문제](#일반적인-문제)
2. [큐 시스템 문제](#큐-시스템-문제)
3. [API 호출 문제](#api-호출-문제)
4. [성능 문제](#성능-문제)
5. [디버깅 팁](#디버깅-팁)
---
## 일반적인 문제
### 문제 1: dispatch 순서가 여전히 보장되지 않음
#### 증상
```javascript
dispatch(action1());
dispatch(action2());
dispatch(action3());
// 실행 순서: action2 → action3 → action1
```
#### 가능한 원인
1. **일반 dispatch와 큐 dispatch 혼용**
```javascript
// ❌ 잘못된 사용
dispatch(pushPanel({ name: 'PANEL_1' })); // 일반
dispatch(pushPanelQueued({ name: 'PANEL_2' })); // 큐
```
2. **async/await 없이 비동기 처리**
```javascript
// ❌ 잘못된 사용
fetchData(); // Promise를 기다리지 않음
dispatch(action());
```
3. **헬퍼 함수를 사용하지 않음**
```javascript
// ❌ 잘못된 사용
dispatch(asyncAction1());
dispatch(asyncAction2()); // asyncAction1이 완료되기 전에 실행
```
#### 해결 방법
**방법 1: 큐 시스템 사용** (패널 액션인 경우)
```javascript
// ✅ 올바른 사용
dispatch(enqueueMultiplePanelActions([
pushPanelQueued({ name: 'PANEL_1' }),
pushPanelQueued({ name: 'PANEL_2' }),
pushPanelQueued({ name: 'PANEL_3' })
]));
```
**방법 2: createSequentialDispatch 사용**
```javascript
// ✅ 올바른 사용
dispatch(createSequentialDispatch([
action1(),
action2(),
action3()
]));
```
**방법 3: async/await 사용** (Chrome 68+)
```javascript
// ✅ 올바른 사용
export const myAction = () => async (dispatch, getState) => {
await dispatch(action1());
await dispatch(action2());
await dispatch(action3());
};
```
---
### 문제 2: "Cannot find module" 에러
#### 증상
```
Error: Cannot find module '../utils/dispatchHelper'
Error: Cannot find module '../middleware/panelQueueMiddleware'
```
#### 원인
- 파일이 존재하지 않음
- import 경로가 잘못됨
- 빌드가 필요함
#### 해결 방법
**Step 1: 파일 존재 확인**
```bash
# 프로젝트 루트에서 실행
ls -la com.twin.app.shoptime/src/utils/dispatchHelper.js
ls -la com.twin.app.shoptime/src/middleware/panelQueueMiddleware.js
ls -la com.twin.app.shoptime/src/utils/asyncActionUtils.js
```
**Step 2: 최신 코드 pull**
```bash
git fetch origin
git pull origin <branch-name>
```
**Step 3: node_modules 재설치**
```bash
cd com.twin.app.shoptime
rm -rf node_modules package-lock.json
npm install
```
**Step 4: 빌드 재실행**
```bash
npm run build
# 또는
npm start
```
---
### 문제 3: 타입 에러 (types is not defined)
#### 증상
```
ReferenceError: types is not defined
TypeError: Cannot read property 'ENQUEUE_PANEL_ACTION' of undefined
```
#### 원인
actionTypes.js에 필요한 타입이 정의되지 않음
#### 해결 방법
**Step 1: actionTypes.js 확인**
```javascript
// src/actions/actionTypes.js
export const types = {
// ... 기존 타입들 ...
// 큐 관련 타입들 (필수!)
ENQUEUE_PANEL_ACTION: 'ENQUEUE_PANEL_ACTION',
PROCESS_PANEL_QUEUE: 'PROCESS_PANEL_QUEUE',
CLEAR_PANEL_QUEUE: 'CLEAR_PANEL_QUEUE',
SET_QUEUE_PROCESSING: 'SET_QUEUE_PROCESSING',
// 비동기 액션 타입들 (필수!)
ENQUEUE_ASYNC_PANEL_ACTION: 'ENQUEUE_ASYNC_PANEL_ACTION',
COMPLETE_ASYNC_PANEL_ACTION: 'COMPLETE_ASYNC_PANEL_ACTION',
FAIL_ASYNC_PANEL_ACTION: 'FAIL_ASYNC_PANEL_ACTION',
};
```
**Step 2: import 확인**
```javascript
import { types } from '../actions/actionTypes';
```
---
## 큐 시스템 문제
### 문제 4: 큐가 처리되지 않음
#### 증상
```javascript
dispatch(pushPanelQueued({ name: panel_names.SEARCH_PANEL }));
// 아무 일도 일어나지 않음
// 콘솔 로그도 없음
```
#### 원인
**panelQueueMiddleware가 등록되지 않음** (가장 흔한 문제!)
#### 해결 방법
**Step 1: store.js 확인**
```javascript
// src/store/store.js
import panelQueueMiddleware from '../middleware/panelQueueMiddleware';
export const store = createStore(
rootReducer,
applyMiddleware(
thunk,
panelHistoryMiddleware,
autoCloseMiddleware,
panelQueueMiddleware // ← 이것이 있는지 확인!
)
);
```
**Step 2: import 경로 확인**
```javascript
// ✅ 올바른 import
import panelQueueMiddleware from '../middleware/panelQueueMiddleware';
// ❌ 잘못된 import
import { panelQueueMiddleware } from '../middleware/panelQueueMiddleware';
// default export이므로 중괄호 없이 import해야 함
```
**Step 3: 앱 재시작**
```bash
# 개발 서버 재시작
npm start
```
**Step 4: 브라우저 캐시 삭제**
- Chrome: Ctrl+Shift+R (Windows) 또는 Cmd+Shift+R (Mac)
---
### 문제 5: 큐가 무한 루프에 빠짐
#### 증상
```
[panelQueueMiddleware] 🚀 ACTION_ENQUEUED
[panelQueueMiddleware] ⚡ STARTING_QUEUE_PROCESS
[panelReducer] 🟡 PROCESS_PANEL_QUEUE
[panelReducer] 🟡 PROCESS_PANEL_QUEUE
[panelReducer] 🟡 PROCESS_PANEL_QUEUE
... (무한 반복)
```
#### 원인
1. 큐 처리 중에 다시 큐에 액션 추가
2. `isProcessingQueue` 플래그가 제대로 설정되지 않음
#### 해결 방법
**방법 1: 큐 액션 내부에서 일반 dispatch 사용**
```javascript
// ❌ 잘못된 사용 (무한 루프 발생)
export const myAction = () => (dispatch) => {
dispatch(pushPanelQueued({ name: 'PANEL_1' }));
dispatch(pushPanelQueued({ name: 'PANEL_2' })); // 큐 처리 중 큐 추가
};
// ✅ 올바른 사용
export const myAction = () => (dispatch) => {
dispatch(enqueueMultiplePanelActions([
pushPanelQueued({ name: 'PANEL_1' }),
pushPanelQueued({ name: 'PANEL_2' })
]));
};
```
**방법 2: 리듀서 로직 확인**
```javascript
// panelReducer.js에서 확인
case types.PROCESS_PANEL_QUEUE: {
// 이미 처리 중이면 무시
if (state.isProcessingQueue || state.panelActionQueue.length === 0) {
return state; // ← 이 로직이 있는지 확인
}
// ...
}
```
---
### 문제 6: 큐 통계가 업데이트되지 않음
#### 증상
```javascript
store.getState().panels.queueStats
// { totalProcessed: 0, failedCount: 0, averageProcessingTime: 0 }
// 항상 0으로 유지됨
```
#### 원인
큐 처리가 정상적으로 완료되지 않음
#### 해결 방법
**Step 1: 콘솔 로그 확인**
```
[panelReducer] ✅ QUEUE_ITEM_PROCESSED ← 이 로그가 보이는지 확인
```
**Step 2: 에러 발생 확인**
```javascript
store.getState().panels.queueError
// null이어야 정상
```
**Step 3: 큐 처리 완료 여부 확인**
```javascript
store.getState().panels.isProcessingQueue
// false여야 정상 (처리 완료)
```
---
## API 호출 문제
### 문제 7: API 성공인데 onFail이 호출됨
#### 증상
```javascript
// API 호출
// HTTP 200, retCode: 0
// 그런데 onFail이 호출됨
```
#### 원인
프로젝트 성공 기준을 이해하지 못함
#### 프로젝트 성공 기준
**HTTP 200-299 + retCode 0/'0' 둘 다 만족해야 성공!**
```javascript
// ✅ 성공 케이스
{ status: 200, data: { retCode: 0, data: {...} } }
{ status: 200, data: { retCode: '0', data: {...} } }
// ❌ 실패 케이스
{ status: 200, data: { retCode: 1, message: '에러' } } // retCode가 0이 아님
{ status: 500, data: { retCode: 0, data: {...} } } // HTTP 에러
```
#### 해결 방법
**방법 1: isApiSuccess 사용**
```javascript
import { isApiSuccess } from '../utils/asyncActionUtils';
const response = { status: 200 };
const responseData = { retCode: 1, message: '에러' };
if (isApiSuccess(response, responseData)) {
// 성공 처리
} else {
// 실패 처리 (retCode가 1이므로 실패!)
}
```
**방법 2: asyncActionUtils 사용**
```javascript
import { tAxiosToPromise } from '../utils/asyncActionUtils';
const result = await tAxiosToPromise(...);
if (result.success) {
// HTTP 200-299 + retCode 0/'0'
console.log(result.data);
} else {
// 실패
console.error(result.error);
}
```
---
### 문제 8: API 타임아웃이 작동하지 않음
#### 증상
```javascript
dispatch(enqueueAsyncPanelAction({
asyncAction: (d, gs, onS, onF) => { /* 느린 API */ },
timeout: 5000 // 5초
}));
// 10초가 지나도 타임아웃되지 않음
```
#### 원인
1. `withTimeout`이 적용되지 않음
2. 타임아웃 값이 잘못 설정됨
#### 해결 방법
**방법 1: enqueueAsyncPanelAction 사용 시**
```javascript
// ✅ timeout 옵션 사용
dispatch(enqueueAsyncPanelAction({
asyncAction: (dispatch, getState, onSuccess, onFail) => {
TAxios(dispatch, getState, 'get', URL, {}, {}, onSuccess, onFail);
},
timeout: 5000, // 5초 (ms 단위)
onFail: (error) => {
if (error.code === 'TIMEOUT') {
console.error('타임아웃 발생!');
}
}
}));
```
**방법 2: withTimeout 직접 사용**
```javascript
import { withTimeout, fetchApi } from '../utils/asyncActionUtils';
const result = await withTimeout(
fetchApi('/api/slow-endpoint'),
5000, // 5초
'요청 시간이 초과되었습니다'
);
if (result.error?.code === 'TIMEOUT') {
console.error('타임아웃!');
}
```
---
## 성능 문제
### 문제 9: 큐 처리가 너무 느림
#### 증상
```javascript
// 100개의 패널 액션을 큐에 추가
// 처리하는데 10초 이상 소요
```
#### 원인
1. 각 액션이 복잡한 로직 수행
2. 동기적으로 처리되어 병목 발생
#### 해결 방법
**방법 1: 불필요한 액션 제거**
```javascript
// ❌ 잘못된 사용
for (let i = 0; i < 100; i++) {
dispatch(pushPanelQueued({ name: `PANEL_${i}` }));
}
// ✅ 올바른 사용 - 필요한 것만
dispatch(pushPanelQueued({ name: 'MAIN_PANEL' }));
```
**방법 2: 배치 처리**
```javascript
// 한 번에 여러 액션 추가
dispatch(enqueueMultiplePanelActions(
panels.map(panel => pushPanelQueued(panel))
));
```
**방법 3: 병렬 처리가 필요하면 큐 사용 안함**
```javascript
// 순서가 중요하지 않은 경우
dispatch(createParallelDispatch([
fetchData1(),
fetchData2(),
fetchData3()
]));
```
---
### 문제 10: 메모리 누수
#### 증상
```javascript
// 오랜 시간 앱 사용 후
store.getState().panels.completedAsyncActions.length
// → 10000개 이상
```
#### 원인
완료된 비동기 액션 ID가 계속 누적됨
#### 해결 방법
**방법 1: 주기적으로 클리어**
```javascript
// 일정 시간마다 완료된 액션 정리
setInterval(() => {
const state = store.getState().panels;
if (state.completedAsyncActions.length > 1000) {
// 클리어 액션 dispatch
dispatch({ type: types.CLEAR_COMPLETED_ASYNC_ACTIONS });
}
}, 60000); // 1분마다
```
**방법 2: 리듀서에 최대 개수 제한 추가**
```javascript
// panelReducer.js
case types.COMPLETE_ASYNC_PANEL_ACTION: {
const newCompleted = [...state.completedAsyncActions, action.payload.actionId];
// 최근 100개만 유지
const trimmed = newCompleted.slice(-100);
return {
...state,
completedAsyncActions: trimmed
};
}
```
---
## 디버깅 팁
### Tip 1: 콘솔 로그 활용
모든 헬퍼 함수와 미들웨어는 상세한 로그를 출력합니다:
```javascript
// 큐 관련 로그
[panelQueueMiddleware] 🚀 ACTION_ENQUEUED
[panelQueueMiddleware] ⚡ STARTING_QUEUE_PROCESS
[panelReducer] 🟡 PROCESS_PANEL_QUEUE
[panelReducer] 🟡 PROCESSING_QUEUE_ITEM
[panelReducer] ✅ QUEUE_ITEM_PROCESSED
// 비동기 액션 로그
[queuedPanelActions] 🔄 ENQUEUE_ASYNC_PANEL_ACTION
[queuedPanelActions] ⚡ EXECUTING_ASYNC_ACTION
[queuedPanelActions] ✅ ASYNC_ACTION_SUCCESS
// asyncActionUtils 로그
[asyncActionUtils] 🌐 FETCH_API_START
[asyncActionUtils] 📊 API_RESPONSE
[asyncActionUtils] ✅ TAXIOS_SUCCESS
```
### Tip 2: Redux DevTools 사용
1. Chrome 확장 프로그램 설치: Redux DevTools
2. 개발자 도구 → Redux 탭
3. 액션 히스토리 확인
4. State diff 확인
### Tip 3: 브레이크포인트 설정
```javascript
// 디버깅용 브레이크포인트
export const myAction = () => (dispatch, getState) => {
debugger; // ← 여기서 멈춤
const state = getState();
console.log('Current state:', state);
dispatch(action1());
debugger; // ← 여기서 다시 멈춤
};
```
### Tip 4: State 스냅샷
```javascript
// 콘솔에서 실행
const snapshot = JSON.parse(JSON.stringify(store.getState()));
console.log(snapshot);
// 특정 부분만
const panelsSnapshot = JSON.parse(JSON.stringify(store.getState().panels));
console.log(panelsSnapshot);
```
### Tip 5: 큐 상태 모니터링
```javascript
// 콘솔에서 실행
window.monitorQueue = setInterval(() => {
const state = store.getState().panels;
console.log('Queue status:', {
queueLength: state.panelActionQueue.length,
isProcessing: state.isProcessingQueue,
stats: state.queueStats
});
}, 1000);
// 중지
clearInterval(window.monitorQueue);
```
---
## 도움이 필요하신가요?
### 체크리스트
문제 해결 전에 다음을 확인하세요:
- [ ] panelQueueMiddleware가 store.js에 등록되어 있는가?
- [ ] 필요한 파일들이 모두 존재하는가?
- [ ] actionTypes.js에 필요한 타입들이 정의되어 있는가?
- [ ] 콘솔 로그를 확인했는가?
- [ ] Redux DevTools로 액션 흐름을 확인했는가?
- [ ] 앱을 재시작했는가?
- [ ] 브라우저 캐시를 삭제했는가?
### 추가 리소스
- [README.md](./README.md) - 전체 개요
- [06-setup-guide.md](./06-setup-guide.md) - 설정 가이드
- [05-usage-patterns.md](./05-usage-patterns.md) - 사용 패턴
- [07-changelog.md](./07-changelog.md) - 변경 이력
---
**작성일**: 2025-11-10
**최종 수정일**: 2025-11-10