refactor(desktop): IME composition 가드 helper 추출 + 8곳 Enter 핸들러 통합 (빅뱅 Phase 5 Part 5)

Bug 10 fix(MeetingModePage 인라인 가드)를 isImeComposingEvent helper로 추출하고,
한글 위험도 있는 나머지 7개 Enter 핸들러에 일괄 적용. 총 8곳이 이제 동일 helper 경유.

신규:
- apps/desktop/src/renderer/utils/keyboard.ts — isImeComposingEvent(e)
  JSDoc에 Bug 10 원리(Chromium이 IME 조합 중 Enter를 2번 발화) + 권장 사용 패턴 포함

적용 8곳:
- pages/MeetingModePage.tsx:164 회의 메모 (기존 인라인 가드 4줄 교체)
- pages/KnowledgeBasePage.tsx:84 RAG 쿼리
- pages/VoiceConversationPage.tsx:113 텍스트 채팅
- pages/CommandsPage.tsx:336 키워드 추가 (Enter+Esc)
- components/meeting/MeetingChatPanel.tsx:111 미팅 챗
- components/meeting/EditableSegment.tsx:70 전사 세그먼트 편집 (Enter+Esc)
- components/meeting/MeetingDetailTabs.tsx:242 미팅 타이틀 (인라인 arrow → 블록)
- components/shared/HistoryEntryCard.tsx:64 태그 추가 (Enter+Esc)

/simplify 패스 품질 리뷰:
- Phase 3.3 CloudSyncService.pushOne 훅 8곳은 이미 fire-and-forget 1줄로 일관.
  내부 try-catch가 에러 삼켜 로컬 write 차단 금지 철학 준수 → 수정 없음, 현 상태가 최적.

검증:
- desktop tsc --noEmit EXIT=0
- Vite HMR로 dev 프로세스 자동 반영 (재기동 없음)
- 한글 Enter 시연은 사용자 실측 대기 (VoiceConversationPage / MeetingDetailTabs 대표 2곳)
This commit is contained in:
윤찬 2026-04-11 22:06:16 +09:00
parent c0c6206cbe
commit 3b77be01bc
10 changed files with 86 additions and 4 deletions

View file

@ -208,6 +208,48 @@ OAuth provider도 아직 Supabase에 설정 안 된 상태. 강제 게이트는
- `~/Library/Application Support/d3ro-voice/users/${uuid}/d3ro.db` 파일 생성 확인
- 기존 `d3ro-voice.db`가 있는 환경에서 archive rename 동작 확인
### SaaS [12] /simplify 패스 — IME 가드 helper 추출 + 8곳 일괄 적용 (Phase 5 Part 5, 2026-04-11)
> **Bug 10의 한글 IME Enter 중복 가드를 `isImeComposingEvent` helper로 추출**. MeetingModePage 기존 인라인 가드 교체 + 7개 사이트 신규 적용 → 총 8곳 통합. Phase 3.3 훅 8곳은 품질 리뷰 결과 이미 최적 상태로 판정(수정 없음).
**신규 helper** — `apps/desktop/src/renderer/utils/keyboard.ts`
```ts
export function isImeComposingEvent(e: KeyboardEvent): boolean {
return e.nativeEvent.isComposing || e.keyCode === 229
}
```
JSDoc에 Bug 10 원리(Chromium이 IME 조합 중 Enter를 2번 발화) + 권장 사용 패턴 포함.
**적용 8곳 (`isImeComposingEvent(e) return` 1줄 삽입)**
| 파일 | 라인 | 용도 | 변경 전 |
|---|---|---|---|
| `pages/MeetingModePage.tsx` | 164 | 회의 메모 입력 | 인라인 가드 4줄 (Bug 10 fix) |
| `pages/KnowledgeBasePage.tsx` | 84 | RAG 쿼리 | 가드 없음 |
| `pages/VoiceConversationPage.tsx` | 113 | 텍스트 채팅 | 가드 없음 |
| `components/meeting/MeetingChatPanel.tsx` | 111 | 미팅 챗 | 가드 없음 |
| `components/meeting/EditableSegment.tsx` | 70 | 전사 편집 (Enter+Esc) | 가드 없음 |
| `components/meeting/MeetingDetailTabs.tsx` | 242 | 미팅 타이틀 (인라인 arrow) | 인라인 `onKeyDown={(e)=>e.key==='Enter'&&...}` 1줄 → 블록 확장 |
| `components/shared/HistoryEntryCard.tsx` | 64 | 태그 추가 (Enter+Esc) | 가드 없음 |
| `pages/CommandsPage.tsx` | 336 | 키워드 추가 (Enter+Esc) | 가드 없음 |
**Phase 3.3 훅 품질 리뷰 결론 — 수정 없음**
- `HistoryService.create/updateTitle`, `DictionaryService.add/update`, `MeetingModeService.startRecording/addMemo/_runPostProcessing/generateDocument`, `MeetingSummaryService.generateAndSave` 8곳 전부 `void getCloudSyncService().pushOne(table, id)` + `// Phase 3.3: fire-and-forget` 주석 일관.
- `CloudSyncService.pushOne` 내부가 try-catch로 warn만 찍고 삼킴 → 호출자는 무조건 안전, 로컬 write 차단 금지 철학 준수.
- helper 추출 후보 없음(이미 1줄). 일관성 OK, DRY OK, 에러 흡수 OK → **현 상태가 최적, 리팩터 불필요**.
**검증**
- desktop `tsc --noEmit` ✅ EXIT=0
- Vite HMR 자동 반영(기존 dev 프로세스 살아있음) — 별도 재기동 없이 적용
- 대표 2곳 한글 Enter 실측 (VoiceConversationPage 채팅 / MeetingDetailTabs 타이틀) — 사용자 수동 검증 대기
**U5 해소, 남은 미해결 이슈**
- U1 — Realtime TIMED_OUT (블로커 아님)
- U3 — Refresh token 간헐적 소진 (블로커 아님)
- U4 — `package-lock.json` optional dep 정리
- Phase 3.2 — PREMIUM_LLM quota 게이트 (Anthropic/OpenAI key 주입 대기)
---
### SaaS [11] Meeting pre-push 직접 실증 + IME Enter 중복 addMemo 픽스 (Phase 5 Part 4, 2026-04-11)
> **U2 해소.** Meeting 모드 녹음을 직접 돌려 Fix 1(startRecording pre-push) + addMemo hook을 실시간 로그로 증명. 부수적으로 발견된 한글 IME Enter 중복 addMemo 버그(Bug 10)를 `isComposing` 가드로 픽스.