50 lines
2.5 KiB
Markdown
50 lines
2.5 KiB
Markdown
# 구현 계획: 채팅 이미지 입력
|
|
|
|
## 기술 배경
|
|
|
|
- React 19 + TypeScript + Zustand 기반 `features/snap`
|
|
- 기존 SSE 전송기 `streamLLM`과 `/chat/stream` JSON 요청
|
|
- Tauri 화면 캡쳐가 만드는 PNG data URL
|
|
- 브라우저 Clipboard API가 제공하는 PNG/JPEG/WebP Blob
|
|
- Vitest + Testing Library
|
|
|
|
## 규칙 확인
|
|
|
|
- `CLAUDE.md`를 유일한 작업 규칙으로 적용함
|
|
- 기존 `Composer`, `useSnapChat`, `snapStream`을 재사용함
|
|
- 서버 DTO는 `features/snap/contract/types.ts`의 기존 계약 위치에 둠
|
|
- 테스트를 먼저 실패시킨 뒤 최소 구현함
|
|
- 새 라이브러리는 추가하지 않음
|
|
|
|
## 설계
|
|
|
|
1. `SnapImageInput`을 `mediaType`과 data URL `data`로 정의하고 `SnapStreamRequest.images`에 연결한다.
|
|
2. `Composer`가 캡쳐와 클립보드 이미지를 같은 첨부 목록으로 관리한다.
|
|
3. 첨부 시 형식, 개수, 개별 크기, 전체 크기를 검사한다.
|
|
4. `onSend`는 텍스트와 이미지 목록을 받아 새 대화와 기존 대화에서 같은 전송 경로를 쓴다.
|
|
5. 새 대화는 세션 생성 뒤 route state로 텍스트와 이미지를 넘기고, 세션 화면이 한 번 소비한다.
|
|
6. `useSnapChat`은 로컬 user 메시지를 만든 뒤 백엔드 요청에 `images`를 포함한다.
|
|
7. 과거 메시지 DTO에는 이미지 정보를 추가하지 않는다. 원본이 저장되지 않는 백엔드 계약을 따른다.
|
|
|
|
## 변경 파일
|
|
|
|
- `2_frontend/src/features/snap/contract/types.ts`
|
|
- `2_frontend/src/features/snap/components/Composer.tsx`
|
|
- `2_frontend/src/features/snap/components/Composer.test.tsx`
|
|
- `2_frontend/src/features/snap/hooks/useSnapChat.ts`
|
|
- `2_frontend/src/features/snap/hooks/useSnapChat.test.tsx`
|
|
- `2_frontend/src/features/snap/pages/NewChatPage.tsx`
|
|
- `2_frontend/src/features/snap/pages/SessionChatPage.tsx`
|
|
- `2_frontend/src/features/snap/api/snap.stream.test.ts`
|
|
|
|
## 위험과 대응
|
|
|
|
- base64 크기를 문자열 길이로 잘못 계산할 수 있음 → data URL 본문을 디코딩한 byte 길이로 검사
|
|
- 새 대화 이동 중 이미지가 사라질 수 있음 → 텍스트와 이미지 모두 route state 한 묶음으로 전달
|
|
- 요청 실패 때 작성 내용이 사라질 수 있음 → 전송이 시작되기 전 검증 실패에는 입력과 첨부를 보존함
|
|
|
|
## 검증
|
|
|
|
- 단위 테스트: 이미지 계약, 캡쳐 수신, 클립보드 첨부, 이미지-only, 제한 차단, 요청 body
|
|
- 전체: `npm run format`, `npm run lint`, `npm run test`, `npm run build`
|