fix: 앱 채팅 "대화 지우기" 버튼이 실제로는 안 지워지던 버그

DELETE /api/chat/sessions/:id가 세션 파일만 unlink하고 session.ts의
in-memory Map은 그대로 둬서, 같은 세션ID를 계속 재사용하는 앱(투자자·의사·
날씨·회계사·변호사·마음·작업실·탐정, 총 8개)에서 삭제 후 같은 세션에 새
메시지를 보내면 다음 saveSession() 때 메모리에 남아있던 옛 대화가 파일로
그대로 부활했음.

파일 삭제 후 clearHistory()(메모리+파일 둘 다 제대로 비우는 기존 함수)도
호출하도록 수정. 실제로 메시지→삭제→같은 세션 새 메시지 시나리오로 재현
검증(부활 안 됨 확인).

워크숍 앱 채팅 헤더 CSS도 방어적으로 수정 — 삭제 버튼에 flex-shrink:0이
없어서 좁은 폭에서 라벨/모델pill에 밀려 안 보일 수 있던 것 고침.

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
kim
2026-09-22 16:19:35 +09:00
co-authored by Claude Code
parent a2439583b3
commit 71afd45959
2 changed files with 11 additions and 1 deletions
@@ -3,6 +3,7 @@ import fs from 'fs';
import fsp from 'fs/promises';
import path from 'path';
import { getConfig } from '../../config/config';
import { clearHistory } from '../session';
// Session-file browsing for the main chat sidebar. The POST /api/chat handler
// itself (the actual message/tool-execution loop) stays in server-v2.ts —
@@ -124,6 +125,15 @@ export function registerChatSessionRoutes(app: express.Application): void {
: path.join(configDir, 'sessions');
const filePath = path.join(sessDir, `${sessionId}.json`);
await fsp.unlink(filePath).catch(() => {});
// session.ts는 session.ts의 in-memory Map에 세션을 캐시해두고 다음 저장 때 그걸로
// 파일을 다시 쓴다 — 파일만 unlink하면, 이 세션이 여전히 메모리에 캐시돼있는 한
// (투자자/의사/날씨/회계사/변호사/마음/작업실/탐정 앱처럼 같은 세션ID를 계속 재사용하는
// 앱들이 전형적으로 이 상태) 다음 메시지가 saveSession()을 부르는 순간 방금 지운 파일이
// 예전 대화 그대로 부활한다(2026-09-22, 작업실 앱 "대화 지우기" 버튼이 안 먹힌다는
// 신고로 발견). clearHistory()가 메모리 쪽 history도 비우고 다시 저장하므로 — 그 결과
// 파일은 남지만 빈 히스토리라 목록 API(GET /api/chat/sessions)의 "user 메시지 0개면
// 제외" 필터에 걸려 사이드바에도 안 보인다. 사실상 삭제와 동일한 효과.
clearHistory(sessionId, username);
res.json({ success: true });
} catch (e: any) {
res.status(500).json({ success: false, error: String(e?.message || e) });
+1 -1
View File
@@ -43,7 +43,7 @@ body{background:var(--bg);color:var(--text);font-family:system-ui,sans-serif;dis
.rb-chat{width:340px;flex-shrink:0;display:flex;flex-direction:column;border-left:1px solid var(--line);background:var(--panel);min-height:0;}
.rb-chat-hdr{display:flex;align-items:center;padding:6px 10px;border-bottom:1px solid var(--line);flex-shrink:0;gap:6px;}
.rb-chat-label{font-size:10px;font-weight:700;color:#f59e0b;text-transform:uppercase;letter-spacing:.07em;flex-shrink:0;}
.rb-chat-clear{background:none;border:none;cursor:pointer;font-size:14px;color:var(--muted);padding:2px 4px;transition:.12s;}
.rb-chat-clear{background:none;border:none;cursor:pointer;font-size:14px;color:var(--muted);padding:2px 4px;transition:.12s;flex-shrink:0;}
.rb-chat-clear:hover{color:#ef4444;}
.rb-msgs{flex:1;overflow-y:auto;padding:10px;display:flex;flex-direction:column;gap:8px;}
.rb-msgs::-webkit-scrollbar{width:3px;}