v0.1.69
v0.1.69 — 채팅 메시지 프로젝트별 격리 (멀티-프로젝트 누수 차단)
사용자 보고
- "ViewWork 프로그램에서 프로젝트를 불러오지 않았는데도 AI채팅 이력이 표시되고 있고, 불러온 프로젝트마다 정확한 채팅세션이 표시되어야 함"
원인
chatStore.messages가 전역 단일 배열 (ChatMessage[]) 로 저장돼 모든 프로젝트의 채팅이 섞임. localStorageviewwork:chat-state-v1도 unscoped.- #### 1)
chatStore.ts데이터 모델 변경 messages: ChatMessage[]→messagesByProject: Record<string, ChatMessage[]>(key =rootPathabs).- 신규 필드
activeProjectId: string | null— App.tsx 가 projectStore.rootPath 변경 시 sync. persist 안 함 (transient). - 신규 selector
selectActiveMessages(s)— activeProjectId 의 메시지만 반환. null 이면EMPTY_MESSAGES(stable frozen ref) → 다른 프로젝트 메시지 절대 누수 안 됨. appendMessage— activeProjectId 가 null 이면 silent drop + console.warn. (sendChatMessage 가 사전 차단)clearMessages— activeProjectId 의 메시지만 비움 (다른 프로젝트 보호).setActiveProjectId(id)신규 액션.- #### 2) 마이그레이션 — 기존 사용자 데이터 무손실 보존
loadPersisted()가 0.1.68 이하의parsed.messages를 발견하면_legacyMessages로 백업 (최대 200)._legacyMessages는 UI 에 노출 안 함 (어느 프로젝트에 속하는지 알 수 없음). 향후 release 에서 "복구 → 특정 프로젝트로 이동" 도구 추가 가능.- 신규 persist 형식:
{ providers, activeProviderId, messagesByProject, _legacyMessages? }. - #### 3)
sendChatMessage()차단 로직 - 호출 직후 첫 체크:
state.activeProjectId가 null →lastError: "프로젝트를 먼저 불러오세요. 채팅은 프로젝트별 격리..."설정 후 return. - API history 빌드 시
useChatStore.getState().messages→selectActiveMessages(useChatStore.getState())로 교체. CLI 분기의 historyText 도 동일. - 결과: 한 프로젝트의 대화가 다른 프로젝트의 API 호출 prompt 에 prepend 되는 누수 차단.
- #### 4)
App.tsx프로젝트↔채팅 동기화 - 기존
rootPathuseEffect (agentStore.setActiveProject + activityStore.setActiveProject) 에useChatStore.getState().setActiveProjectId(rootPath)한 줄 추가. - #### 5)
AgentFollowPanel.tsx변경 useChatStore((s) => s.messages)→useChatStore(selectActiveMessages).chatActiveProjectId신규 selector 추가.getChatDisabledReason()의 첫 체크에 "프로젝트 미로드" 케이스 — 다른 모든 분기보다 우선해서 안내.- 결과: 시작 화면에선 채팅 input 자동 비활성 + amber banner.
- #### 6)
ChatPanel.tsx변경 (우측 사이드바 'AI 채팅' 탭) - 동일 selector 교체.
- 메시지 영역 첫 분기:
noProject면 AlertCircle 아이콘 + "프로젝트를 먼저 불러오세요" empty state (max-w-260, 한국어 안내). - textarea / Send 버튼: noProject 면 disable + amber border + placeholder/title 안내.
- #### 7) 파일 변경
src/store/chatStore.ts(+85, -28 lines) — 핵심 재구조src/App.tsx(+2 lines) — syncsrc/components/Avatars/AgentFollowPanel.tsx(+10 lines) — selector + 분기src/components/Chat/ChatPanel.tsx(+40 lines) — selector + empty state + disablepackage.json0.1.68 → 0.1.69- #### 8) 검증
npx tsc --noEmitexit=0- 기대 동작:
- 첫 시작 (프로젝트 미로드) → 두 채팅 패널 모두 비활성 + 안내 메시지
- 프로젝트 A 로드 → A 의 채팅만 표시 (없으면 empty)
- 프로젝트 B 로 탭 전환 → B 의 채팅만 표시 (A 의 메시지 사라짐 — 격리)
- 다시 A 로 → A 의 채팅 복원
- 기존 사용자: 0.1.68 이하 메시지는
_legacyMessages로 백업, UI 에선 안 보임 - --
📦 GitHub 릴리스 노트: v0.1.69