diff --git a/.DS_Store b/.DS_Store index b79cf129..5837927b 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/00_Raw/2026-04-25-Datacollector_Bridge_Connection_Refused_Run_Script_Fix.md b/00_Raw/2026-04-25-Datacollector_Bridge_Connection_Refused_Run_Script_Fix.md new file mode 100644 index 00000000..be733f6c --- /dev/null +++ b/00_Raw/2026-04-25-Datacollector_Bridge_Connection_Refused_Run_Script_Fix.md @@ -0,0 +1,72 @@ +# Datacollector Bridge Connection Refused Run Script Fix + +Date: 2026-04-25 21:07:52 KST +Project: Datacollector +Repository: `/Volumes/Data/project/Antigravity/Datacollector` + +## Summary + +사용자가 앱 실행 후 `POST http://127.0.0.1:3002/api/check-connection net::ERR_CONNECTION_REFUSED` 오류를 확인했다. +이는 NotebookLM 인증 실패가 아니라 MCP Bridge 서버가 실행되지 않아 브라우저가 `3002` 포트에 연결하지 못한 상태였다. + +## Root Cause + +실행 경로가 여러 개였고 일부 경로는 프런트엔드 Vite 서버만 실행했다. + +- `run_mac.command`: Bridge와 Vite를 함께 실행 +- `run_app.sh`: Vite만 실행 +- `npm run dev`: Vite만 실행 + +따라서 `run_app.sh` 또는 `npm run dev`로 앱을 켜면 UI는 열리지만 `/api/check-connection` 요청을 받을 Bridge 서버가 없어 `ERR_CONNECTION_REFUSED`가 발생했다. + +## Changes Made + +수정 파일: + +- `/Volumes/Data/project/Antigravity/Datacollector/run_app.sh` +- `/Volumes/Data/project/Antigravity/Datacollector/README.md` +- `/Volumes/Data/project/Antigravity/Datacollector/src/lib/api.ts` +- `/Volumes/Data/project/Antigravity/Datacollector/src/components/AgentDashboard.tsx` +- `/Volumes/Data/project/Antigravity/Datacollector/src/lib/engine.ts` + +핵심 변경: + +- `run_app.sh`가 Bridge 서버와 Vite 서버를 함께 실행하도록 변경 +- `run_app.sh` 시작 시 기존 `3000`, `3002` 포트 프로세스를 정리 +- 종료 시 Bridge 백그라운드 프로세스도 함께 종료하도록 trap 추가 +- README의 실행 안내를 `npm run dev` 단독에서 `./run_mac.command` 또는 `npm run start-full`로 변경 +- `src/lib/api.ts`에 `bridgeFetch()` 추가 +- Bridge 연결 실패 시 `Failed to fetch` 대신 “Bridge 서버가 실행되지 않았다”는 안내 메시지를 표시하도록 변경 +- `VITE_BRIDGE_URL`로 Bridge 주소를 override할 수 있게 함 + +## Verification + +실행한 검증: + +```bash +node --check scripts/mcp_bridge.mjs +npm run lint +npm run build +``` + +검증 결과: + +- 브리지 문법 체크 통과 +- TypeScript 타입체크 통과 +- Vite 프로덕션 빌드 통과 + +## Operational Note + +앞으로 앱은 아래 방식으로 실행해야 한다. + +```bash +./run_mac.command +``` + +또는 수동으로 두 서버를 같이 실행한다. + +```bash +npm run start-full +``` + +`npm run dev`만 실행하면 프런트엔드만 뜨므로 NotebookLM, Wiki save, 인증 복구 API가 동작하지 않는다. diff --git a/00_Raw/2026-04-25-Datacollector_Codebase_Structure_Review_and_Initial_Risk_Assessment.md b/00_Raw/2026-04-25-Datacollector_Codebase_Structure_Review_and_Initial_Risk_Assessment.md new file mode 100644 index 00000000..6e023d98 --- /dev/null +++ b/00_Raw/2026-04-25-Datacollector_Codebase_Structure_Review_and_Initial_Risk_Assessment.md @@ -0,0 +1,177 @@ +# Datacollector Codebase Structure Review and Initial Risk Assessment + +Date: 2026-04-25 20:38:01 KST +Project: Datacollector +Repository: `/Volumes/Data/project/Antigravity/Datacollector` +Knowledge Vault: `/Volumes/Data/project/Antigravity/Wiki/00_Raw` + +## Summary + +이 문서는 Datacollector 프로젝트의 첫 구조 파악 및 초기 코드 리뷰 결과를 정리한 기록이다. +이번 검토의 목적은 이후 기능 개발 전에 현재 시스템의 책임 분리, 실행 흐름, 외부 의존성, 그리고 우선적으로 손봐야 할 위험 요소를 이해하는 데 있다. + +현재 프로젝트는 단순한 프런트엔드 앱이 아니라, React 기반 UI와 Zustand 상태 저장소, 자율 실행 엔진, 그리고 NotebookLM MCP 및 로컬 LM을 연결하는 Express 브리지 서버가 결합된 자동화 연구 도구 형태로 구성되어 있다. + +## High-Level Architecture + +전체 흐름은 아래와 같다. + +`React UI -> Zustand Store -> KnowledgeEngine -> Express Bridge -> NotebookLM MCP / Local LM / GitHub / Wiki Storage` + +핵심 책임 분리는 다음과 같이 이해했다. + +- `src/components/AgentDashboard.tsx` + 사용자 인터페이스, 미션 시작/중지/재개, 설정 입력, 로그 표시, 수동 커밋 등 상호작용 담당 +- `src/store/agentStore.ts` + 앱 전체 설정값과 실행 상태를 보관하는 단일 전역 상태 저장소 +- `src/lib/engine.ts` + 큐를 소비하며 연구, 합성, 링크 추출, 다음 토픽 확장을 반복하는 자율 엔진 +- `src/lib/gemini.ts` + NotebookLM 미연결 시 사용하는 로컬 LM 프롬프트 생성 및 응답 파싱 +- `src/lib/github.ts` + 결과 Markdown을 GitHub 저장소의 `00_Raw/` 경로로 업로드 +- `scripts/mcp_bridge.mjs` + NotebookLM MCP 서버와 통신하는 지속 프로세스형 브리지 서버 + +## Execution Flow + +실행 흐름은 다음 순서로 이해했다. + +1. 사용자가 `AgentDashboard`에서 주제를 입력하고 미션을 시작한다. +2. 주제와 설정이 `agentStore`에 기록되고 상태가 `running`으로 바뀐다. +3. `status` 변경을 감지한 UI가 `KnowledgeEngine` 싱글톤을 시작한다. +4. `KnowledgeEngine`는 큐의 첫 항목을 읽고 현재 깊이와 루트 주제를 기준으로 처리 여부를 결정한다. +5. NotebookLM 연결 상태가 좋으면 브리지 서버를 통해 리서치와 합성을 수행한다. +6. NotebookLM이 없으면 로컬 LM 프록시(`/api/lm`)를 통해 대체 연구를 진행한다. +7. 생성된 Markdown에서 위키 링크를 추출해 다음 큐를 구성한다. +8. 결과는 pending commits, completed 목록, 로컬 위키 Raw 저장소 등에 반영된다. + +## Current Structure Notes + +이번 시점에서 구조적으로 눈에 띈 특징은 다음과 같다. + +- 상태 관리가 거의 전부 Zustand store 하나에 집중되어 있어 흐름 추적은 쉽다. +- 대신 엔진과 UI가 store를 매우 직접적으로 공유해서 결합도가 높다. +- NotebookLM 경로와 Local LM 경로가 모두 존재해 fallback 전략은 분명하다. +- 브리지 서버가 프런트엔드 백엔드이자 외부 도구 래퍼 역할까지 함께 맡고 있어 책임이 넓다. +- 문서 저장 흐름이 GitHub 업로드와 로컬 위키 저장으로 이중화되어 있다. + +## Review Findings + +### 1. Sensitive secrets are persisted in browser storage + +`githubToken`과 `notebookLmCookies`가 Zustand persist 설정에 포함되어 있어 브라우저 localStorage에 평문으로 저장된다. +이 방식은 세션 쿠키나 GitHub 토큰 같은 민감 정보의 저장 위치로는 안전하지 않다. + +관련 파일: + +- `/Volumes/Data/project/Antigravity/Datacollector/src/store/agentStore.ts` + +영향: + +- 같은 브라우저 프로필을 사용하는 다른 코드나 도구가 정보에 접근할 수 있다. +- 장기적으로 토큰 유출 위험이 커진다. + +### 2. Bridge server is exposed too broadly + +브리지 서버는 `0.0.0.0:3002`로 열리고 CORS도 전부 허용한다. +또한 `/api/lm`은 클라이언트가 전달한 임의의 URL로 요청을 프록시할 수 있다. + +관련 파일: + +- `/Volumes/Data/project/Antigravity/Datacollector/scripts/mcp_bridge.mjs` + +영향: + +- 로컬 개발용으로는 편하지만, 같은 네트워크 안에서 예상하지 않은 접근 통로가 될 수 있다. +- 사실상 무인증 프록시처럼 동작할 여지가 있다. + +### 3. Environment portability is weak + +MCP 실행 파일 경로와 위키 저장 경로가 절대경로로 하드코딩되어 있다. + +관련 파일: + +- `/Volumes/Data/project/Antigravity/Datacollector/scripts/mcp_bridge.mjs` + +영향: + +- 다른 개발자 머신, 다른 사용자 계정, 다른 운영체제에서 그대로 실행하기 어렵다. +- 배포보다는 특정 개인 작업 환경에 강하게 종속된다. + +### 4. Manual handoff state is not fully cleared + +`resolveManualNext`가 store에 함수 형태로 저장되는데, `clearState()`에서 정리되지 않는다. +수동 합성 대기 중 reset 또는 새 미션 시작이 발생하면 상태 꼬임 가능성이 있다. + +관련 파일: + +- `/Volumes/Data/project/Antigravity/Datacollector/src/store/agentStore.ts` +- `/Volumes/Data/project/Antigravity/Datacollector/src/lib/engine.ts` + +영향: + +- 이전 미션의 대기 상태가 다음 미션에 잔존할 수 있다. +- UI 버튼 상태와 실제 엔진 대기 상태가 어긋날 수 있다. + +### 5. API endpoint usage is duplicated and hardcoded + +프런트엔드에는 이미 Vite 프록시가 설정되어 있지만, UI와 엔진 코드 곳곳에서 `http://127.0.0.1:3002`를 직접 호출하고 있다. + +관련 파일: + +- `/Volumes/Data/project/Antigravity/Datacollector/src/components/AgentDashboard.tsx` +- `/Volumes/Data/project/Antigravity/Datacollector/src/lib/engine.ts` +- `/Volumes/Data/project/Antigravity/Datacollector/vite.config.ts` + +영향: + +- 포트 변경이나 배포 환경 변경 시 수정 지점이 늘어난다. +- 런타임 경로 설정이 한 군데에서 관리되지 않는다. + +## Validation Performed + +이번 검토 중 아래 확인을 수행했다. + +- 저장소 파일 구조 및 진입점 확인 +- UI, store, engine, bridge, GitHub, Local LM 계층 코드 확인 +- `npm run lint` 실행 + +검증 결과: + +- TypeScript 타입체크는 현재 통과했다. + +## Suggested Next Priorities + +우선순위는 아래 순서가 적절하다. + +1. 민감 정보 저장 방식을 localStorage 바깥으로 이동하거나 최소한 분리 +2. 브리지 서버 바인딩 범위와 CORS 정책 축소 +3. 절대경로를 환경변수 또는 설정 파일로 치환 +4. `resolveManualNext`를 포함한 미션 종료 정리 로직 강화 +5. API 베이스 URL을 단일 설정 지점으로 통합 + +## Working Agreement For Future Notes + +사용자 요청에 따라, 앞으로 Datacollector 관련 조사/분석/리뷰 결과는 가능하면 이 지식 창고 경로에 계속 기록한다. + +기본 원칙: + +- 위치: `/Volumes/Data/project/Antigravity/Wiki/00_Raw` +- 파일명: `YYYY-MM-DD-_.md` 또는 기존 저장소 관례와 유사한 읽기 쉬운 영어 제목 +- 내용: 작업 목적, 파악한 구조, 핵심 발견사항, 다음 액션을 포함 + +## Source Files Reviewed + +- `/Volumes/Data/project/Antigravity/Datacollector/README.md` +- `/Volumes/Data/project/Antigravity/Datacollector/package.json` +- `/Volumes/Data/project/Antigravity/Datacollector/vite.config.ts` +- `/Volumes/Data/project/Antigravity/Datacollector/src/main.tsx` +- `/Volumes/Data/project/Antigravity/Datacollector/src/App.tsx` +- `/Volumes/Data/project/Antigravity/Datacollector/src/components/AgentDashboard.tsx` +- `/Volumes/Data/project/Antigravity/Datacollector/src/store/agentStore.ts` +- `/Volumes/Data/project/Antigravity/Datacollector/src/lib/engine.ts` +- `/Volumes/Data/project/Antigravity/Datacollector/src/lib/gemini.ts` +- `/Volumes/Data/project/Antigravity/Datacollector/src/lib/github.ts` +- `/Volumes/Data/project/Antigravity/Datacollector/scripts/mcp_bridge.mjs` +- `/Volumes/Data/project/Antigravity/Datacollector/scripts/mcp_caller.py` diff --git a/00_Raw/2026-04-25-Datacollector_Local_Wiki_Save_Only_Output_Mode.md b/00_Raw/2026-04-25-Datacollector_Local_Wiki_Save_Only_Output_Mode.md new file mode 100644 index 00000000..43abb976 --- /dev/null +++ b/00_Raw/2026-04-25-Datacollector_Local_Wiki_Save_Only_Output_Mode.md @@ -0,0 +1,74 @@ +# Datacollector Local Wiki Save Only Output Mode + +Date: 2026-04-25 20:50:41 KST +Project: Datacollector +Repository: `/Volumes/Data/project/Antigravity/Datacollector` + +## Summary + +Datacollector의 생성 결과 저장 방식을 GitHub 업로드 중심에서 로컬 Wiki 저장 전용으로 정리했다. +앞으로 앱에서 생성되는 연구 문서는 `/Volumes/Data/project/Antigravity/Wiki/00_Raw`에 저장되고, Git 업로드는 사용자가 나중에 별도로 한 번에 처리하는 운영 방식으로 둔다. + +## Previous Behavior + +기존 흐름은 결과 생성 후 두 경로가 동시에 존재했다. + +- 로컬 Wiki Raw 폴더에 자동 저장 +- `pendingCommits`에 결과를 쌓고 UI의 `BATCH COMMIT` 버튼으로 GitHub 업로드 가능 + +이 방식은 앱 안에 GitHub 토큰과 저장소 설정을 유지해야 했고, 사용자가 의도하지 않아도 Git 업로드 기능이 계속 노출되는 구조였다. + +## New Behavior + +새 흐름은 다음과 같다. + +1. 연구 결과 Markdown 생성 +2. `savedReports`에 프리뷰용 로컬 캐시 저장 +3. 브리지 서버의 `/api/wiki/save`를 통해 `/Volumes/Data/project/Antigravity/Wiki/00_Raw`에 Markdown 파일 저장 +4. GitHub 업로드 버튼이나 토큰 설정 없이 완료 + +GitHub 업로드는 앱이 수행하지 않는다. + +## Changes Made + +수정 파일: + +- `/Volumes/Data/project/Antigravity/Datacollector/src/store/agentStore.ts` +- `/Volumes/Data/project/Antigravity/Datacollector/src/lib/engine.ts` +- `/Volumes/Data/project/Antigravity/Datacollector/src/components/AgentDashboard.tsx` +- `/Volumes/Data/project/Antigravity/Datacollector/.env.example` + +삭제 파일: + +- `/Volumes/Data/project/Antigravity/Datacollector/src/lib/github.ts` + +핵심 변경: + +- `githubToken`, `githubRepoUrl` 상태 제거 +- `pendingCommits` 제거 +- `addPendingCommit`, `clearPendingCommits` 제거 +- `savedReports`와 `addSavedReport` 추가 +- `BATCH COMMIT` 버튼 제거 +- 설정 모달의 GitHub Wiki Sync 섹션 제거 +- `.env.example`의 GitHub 설정 제거 +- 생성 결과는 기존 Wiki 저장 API를 통해 로컬 Raw 폴더에만 저장 + +## Verification + +실행한 검증: + +```bash +npm run lint +npm run build +``` + +검증 결과: + +- TypeScript 타입체크 통과 +- Vite 프로덕션 빌드 통과 + +## Notes + +로컬 Wiki 저장은 기존 브리지 서버의 `/api/wiki/save` 라우트를 그대로 사용한다. +저장 대상 경로는 현재 브리지 서버에 하드코딩된 `/Volumes/Data/project/Antigravity/Wiki/00_Raw`이다. +추후 이 경로도 `.env` 설정으로 분리하면 다른 머신이나 폴더 구조에서도 더 쉽게 운영할 수 있다. diff --git a/00_Raw/2026-04-25-Datacollector_Mac_Windows_Launcher_Scripts.md b/00_Raw/2026-04-25-Datacollector_Mac_Windows_Launcher_Scripts.md new file mode 100644 index 00000000..d0d2f728 --- /dev/null +++ b/00_Raw/2026-04-25-Datacollector_Mac_Windows_Launcher_Scripts.md @@ -0,0 +1,50 @@ +# Datacollector Mac Windows Launcher Scripts + +Date: 2026-04-25 21:09:42 KST +Project: Datacollector +Repository: `/Volumes/Data/project/Antigravity/Datacollector` + +## Summary + +Datacollector 실행 시 Vite 프런트엔드만 뜨고 MCP Bridge 서버가 뜨지 않아 `ERR_CONNECTION_REFUSED`가 발생할 수 있었다. +이를 막기 위해 맥용과 윈도우용 실행 파일을 명확히 정리했다. + +## Main Launchers + +- macOS: `/Volumes/Data/project/Antigravity/Datacollector/run_mac.command` +- Windows: `/Volumes/Data/project/Antigravity/Datacollector/run_win.bat` + +두 실행 파일 모두 아래를 수행한다. + +1. 프로젝트 폴더로 이동 +2. `node_modules`가 없으면 `npm install` +3. 기존 `3000`, `3002` 포트 프로세스 정리 +4. MCP Bridge 서버 실행 +5. Vite 앱 실행 + +## Compatibility Wrappers + +기존 실행 파일과의 호환성을 위해 아래 파일은 메인 실행 파일로 위임하도록 단순화했다. + +- `run_app.sh` -> `run_mac.command` +- `run_app.bat` -> `run_win.bat` + +## Verification + +실행한 검증: + +```bash +bash -n run_mac.command +bash -n run_app.sh +npm run lint +``` + +검증 결과: + +- macOS shell script 문법 통과 +- TypeScript 타입체크 통과 + +## Operational Note + +앞으로 맥에서는 `run_mac.command`, 윈도우에서는 `run_win.bat`만 실행하면 된다. +`npm run dev` 단독 실행은 프런트엔드만 켜므로 NotebookLM, Wiki save, 인증 복구 API가 동작하지 않는다. diff --git a/00_Raw/2026-04-25-Datacollector_NotebookLM_Auth_Browser_and_Stale_Env_Cookie_Fix.md b/00_Raw/2026-04-25-Datacollector_NotebookLM_Auth_Browser_and_Stale_Env_Cookie_Fix.md new file mode 100644 index 00000000..e09fb0d9 --- /dev/null +++ b/00_Raw/2026-04-25-Datacollector_NotebookLM_Auth_Browser_and_Stale_Env_Cookie_Fix.md @@ -0,0 +1,68 @@ +# Datacollector - NotebookLM 인증 브라우저 유지 및 오래된 .env 쿠키 우선순위 문제 해결 + +- 작성 시각: 2026-04-25 21:31:00 KST +- 프로젝트: `/Volumes/Data/project/Antigravity/Datacollector` +- 관련 파일: `scripts/mcp_bridge.mjs`, `auth_mac.command`, `auth_win.bat`, `.env.example` + +## 상황 + +앱에서 `/api/check-connection` 호출이 500으로 실패했고, 화면에는 다음과 같은 메시지가 반복되었다. + +- `Authentication expired` +- `인증 자동 복구 실패. 브라우저 로그인이 필요한 상태일 수 있습니다.` +- `MCP initialized: true, pending: 0` + +사용자는 NotebookLM 인증 중 Chrome이 열렸다가 닫히는 점을 보고, 인증 브라우저를 유지해야 하는 것 아니냐고 질문했다. + +## 확인한 내용 + +`notebooklm-mcp-auth` 소스 확인 결과, 기본 자동 실행 모드는 인증 후 자신이 띄운 Chrome 프로세스를 종료한다. 반면 `--no-auto-launch --port ... --user-data-dir ...` 모드는 이미 떠 있는 Chrome 디버깅 세션에 붙기 때문에 인증 브라우저를 유지할 수 있다. + +브리지에서 Chrome을 유지하도록 바꾼 뒤 인증 CLI는 성공했다. 하지만 MCP 서버의 `notebook_list`는 여전히 `Authentication expired`를 반환했다. + +추가 확인 결과, `.env`에 예전 `NOTEBOOKLM_COOKIES` 값이 남아 있었다. `scripts/mcp_bridge.mjs`가 `dotenv/config`를 로드한 뒤 MCP 서버를 자식 프로세스로 실행하면서 이 오래된 환경변수 쿠키가 `~/.notebooklm-mcp/auth.json`의 최신 인증 캐시보다 우선 적용되고 있었다. + +즉 실제 핵심 원인은 다음 조합이었다. + +- 인증 CLI는 최신 쿠키를 `~/.notebooklm-mcp/auth.json`에 정상 저장함. +- 브리지는 `.env`의 오래된 `NOTEBOOKLM_COOKIES`를 MCP 자식 프로세스에 전달함. +- MCP 서버는 캐시 파일보다 환경변수를 우선 사용함. +- 결과적으로 새 인증 후에도 MCP는 계속 오래된 쿠키로 NotebookLM API를 호출함. + +## 조치 + +`scripts/mcp_bridge.mjs`에서 기본적으로 MCP 자식 프로세스와 인증 CLI 자식 프로세스에 `NOTEBOOKLM_COOKIES`, `NOTEBOOKLM_CSRF_TOKEN`, `NOTEBOOKLM_SESSION_ID`를 넘기지 않도록 수정했다. + +명시적으로 환경변수 인증을 사용해야 할 경우에는 `.env`에 아래 값을 둔다. + +```env +USE_NOTEBOOKLM_ENV_AUTH="true" +``` + +기본값은 `false`이며, 이 경우 `notebooklm-mcp-auth`가 생성한 `~/.notebooklm-mcp/auth.json` 캐시를 우선 사용한다. + +또한 `auth_mac.command`, `auth_win.bat`는 별도 Chrome 프로필과 디버깅 포트를 사용해 NotebookLM 인증 브라우저를 열어두는 방식으로 변경했다. + +## 검증 + +다음 검증을 완료했다. + +```bash +node --check scripts/mcp_bridge.mjs +npm run lint +curl -sS -X POST http://127.0.0.1:3002/api/check-connection +``` + +결과: + +```json +{"success":true,"count":0} +``` + +직접 Python MCP 클라이언트로도 같은 인증 캐시를 사용해 `list_notebooks` 호출이 성공했고, 노트북 89개를 읽는 것을 확인했다. + +## 운영 메모 + +앞으로는 `.env`에 오래된 `NOTEBOOKLM_COOKIES`가 남아 있어도 기본 브리지 실행에는 영향을 주지 않는다. 다만 혼란을 줄이려면 장기적으로 `.env`에서 `NOTEBOOKLM_COOKIES` 줄을 삭제하거나 주석 처리하는 것이 좋다. + +NotebookLM 인증용 Chrome 창은 닫지 않는 것이 좋다. 인증이 풀렸을 때 브리지가 같은 디버깅 포트의 Chrome 세션에 붙어 자동 복구를 시도할 수 있다. diff --git a/00_Raw/2026-04-25-Datacollector_NotebookLM_Automatic_Auth_Recovery.md b/00_Raw/2026-04-25-Datacollector_NotebookLM_Automatic_Auth_Recovery.md new file mode 100644 index 00000000..7781e83c --- /dev/null +++ b/00_Raw/2026-04-25-Datacollector_NotebookLM_Automatic_Auth_Recovery.md @@ -0,0 +1,85 @@ +# Datacollector NotebookLM Automatic Auth Recovery + +Date: 2026-04-25 20:47:05 KST +Project: Datacollector +Repository: `/Volumes/Data/project/Antigravity/Datacollector` + +## Summary + +컴퓨터 포맷 이후 NotebookLM MCP 인증이 자주 실패하고, 20-30분마다 `auth_mac.command`를 수동 실행해야 하는 문제가 있었다. +이번 작업에서는 인증 만료 시 브리지 서버가 자동으로 복구를 시도하도록 개선했다. + +## Root Cause Hypothesis + +기존 구조는 MCP 서버의 `refresh_auth` 도구 호출에만 의존했다. +하지만 포맷 이후 로컬 토큰 저장 위치나 Chrome 세션 상태가 달라지면서 `refresh_auth`만으로 복구되지 않는 상황이 발생할 수 있다. + +사용자가 직접 실행하던 파일은 다음 명령의 래퍼였다. + +```bash +/Users/g1nation_mac/.local/bin/notebooklm-mcp-auth +``` + +따라서 자동 복구 흐름에도 이 CLI 인증 명령을 포함시키는 것이 가장 직접적인 개선 방향이다. + +## Changes Made + +수정 파일: + +- `/Volumes/Data/project/Antigravity/Datacollector/scripts/mcp_bridge.mjs` +- `/Volumes/Data/project/Antigravity/Datacollector/src/components/AgentDashboard.tsx` +- `/Volumes/Data/project/Antigravity/Datacollector/.env.example` + +핵심 변경: + +- 브리지 서버가 `.env`를 읽도록 `dotenv/config`를 추가했다. +- `AUTH_PATH`, `AUTH_ARGS`, `AUTH_TIMEOUT_MS`, `AUTH_REFRESH_INTERVAL_MS` 설정을 추가했다. +- MCP 인증 에러 발생 시 `refresh_auth`를 먼저 시도한다. +- `refresh_auth` 실패 시 MCP 프로세스를 재시작하고 다시 갱신을 시도한다. +- 그래도 실패하면 `notebooklm-mcp-auth` CLI를 브리지 서버가 직접 실행한다. +- CLI 인증 후 MCP 프로세스를 재시작해 새 토큰을 읽게 만든다. +- 장시간 실행 중에는 15분 간격으로 요청이 없는 시점에 인증 상태를 사전 갱신한다. +- UI 안내 문구를 수동 재인증 중심에서 자동 복구 중심으로 수정했다. + +## Runtime Behavior + +새 인증 복구 순서: + +1. NotebookLM MCP 요청 실패 +2. 에러 메시지가 인증 관련인지 판단 +3. `refresh_auth` 호출 +4. MCP 프로세스 재시작 후 `refresh_auth` 재시도 +5. `notebooklm-mcp-auth` CLI 자동 실행 +6. MCP 프로세스 재시작 +7. 원래 실패했던 NotebookLM 요청 재시도 + +주기적 갱신: + +- 기본 간격: 15분 +- 설정값: `AUTH_REFRESH_INTERVAL_MS=900000` +- 진행 중인 MCP 요청이 있을 때는 건드리지 않고 건너뛴다. + +## Verification + +실행한 검증: + +```bash +node --check scripts/mcp_bridge.mjs +npm run lint +npm run bridge +curl -s http://127.0.0.1:3002/api/health +``` + +검증 결과: + +- `node --check` 통과 +- TypeScript 타입체크 통과 +- 브리지 서버 시작 성공 +- MCP 서버 초기화 성공 +- `/api/health`에서 `connected: true`, `version: 3.3.0`, `authPath` 확인 + +## Notes + +완전히 백그라운드 인증이 가능한지는 Google/Chrome 세션 상태에 의존한다. +브라우저 로그인이 만료되어 실제 사용자 로그인이 필요한 상태라면 자동 CLI 실행도 브라우저 로그인을 요구할 수 있다. +다만 기존처럼 매번 사용자가 batch 파일을 직접 실행하는 흐름보다, 일반적인 토큰 만료와 MCP refresh 실패 상황은 브리지 서버가 먼저 복구하도록 개선되었다. diff --git a/00_Raw/2026-04-25-Datacollector_NotebookLM_Connection_Guard_and_MCP_Restart_Fix.md b/00_Raw/2026-04-25-Datacollector_NotebookLM_Connection_Guard_and_MCP_Restart_Fix.md new file mode 100644 index 00000000..b5bae4e2 --- /dev/null +++ b/00_Raw/2026-04-25-Datacollector_NotebookLM_Connection_Guard_and_MCP_Restart_Fix.md @@ -0,0 +1,84 @@ +# Datacollector NotebookLM Connection Guard and MCP Restart Fix + +Date: 2026-04-25 21:02:35 KST +Project: Datacollector +Repository: `/Volumes/Data/project/Antigravity/Datacollector` + +## Summary + +실행 중 NotebookLM 연결 체크가 500 에러를 반환한 뒤에도 미션이 계속 시작되어 Local LM fallback으로 넘어가고, 결국 `Local LM returned an empty or invalid response` 에러가 발생했다. +또한 브리지의 MCP 재시작 로직에서 자동 재시작과 수동 재시작이 겹쳐 여러 `notebooklm-mcp` 프로세스가 남는 문제가 확인되었다. + +## Observed Errors + +브라우저 콘솔: + +```text +:3000/favicon.ico 404 (Not Found) +127.0.0.1:3002/api/check-connection 500 (Internal Server Error) +``` + +앱 로그: + +```text +NotebookLM 연결 실패: 인증 자동 복구 실패... +GENERAL MODE +ENGINE ERROR Local LM returned an empty or invalid response. +``` + +## Root Causes + +1. `testNotebookLmConnection()`이 성공 여부를 반환하지 않았다. +2. `handleStart`, `handleResume`, `handleGlobalResume`이 연결 실패 후에도 그대로 `running` 상태로 넘어갔다. +3. `restart()`가 MCP 프로세스 종료 이벤트를 기다리지 않고 바로 새 프로세스를 띄울 수 있었다. +4. `close` 이벤트의 자동 재시작이 수동 재시작과 겹쳐 MCP 하위 프로세스가 누적될 수 있었다. +5. favicon 파일이 없어서 브라우저가 `/favicon.ico` 기본 요청을 404로 표시했다. + +## Changes Made + +수정 파일: + +- `/Volumes/Data/project/Antigravity/Datacollector/scripts/mcp_bridge.mjs` +- `/Volumes/Data/project/Antigravity/Datacollector/src/components/AgentDashboard.tsx` +- `/Volumes/Data/project/Antigravity/Datacollector/index.html` + +추가 파일: + +- `/Volumes/Data/project/Antigravity/Datacollector/public/favicon.svg` + +핵심 변경: + +- `testNotebookLmConnection()`이 `Promise`을 반환하도록 변경 +- NotebookLM 연결 실패 시 신규 미션 시작, 개별 재개, 전체 재개를 보류 +- 연결 실패 후 Local LM fallback으로 자동 진행되는 흐름 차단 +- MCP 프로세스를 종료할 때 `close` 이벤트를 기다리는 `_stopCurrentProcess()` 추가 +- 재시작 중 자동 재시작이 중복 실행되지 않도록 제어 +- 재시작 테스트 후 MCP 하위 프로세스가 하나만 남는지 확인 +- SVG favicon 추가 및 `index.html`에 명시 + +## Verification + +실행한 검증: + +```bash +node --check scripts/mcp_bridge.mjs +npm run lint +npm run build +npm run bridge +curl -s http://127.0.0.1:3002/api/health +curl -s -X POST http://127.0.0.1:3002/api/restart +``` + +검증 결과: + +- 브리지 문법 체크 통과 +- TypeScript 타입체크 통과 +- Vite 빌드 통과 +- 브리지 시작 성공 +- `/api/health` 응답 정상 +- `/api/restart` 후 `notebooklm-mcp` 프로세스가 하나만 남는 것 확인 + +## Operational Note + +현재 실행 중이던 오래된 브리지와 누적된 MCP 하위 프로세스는 종료했다. +앱은 다시 실행해야 새 브리지 로직이 적용된다. diff --git a/00_Raw/2026-04-25-Datacollector_NotebookLM_Progress_Visibility_and_Auth_Diagnosis.md b/00_Raw/2026-04-25-Datacollector_NotebookLM_Progress_Visibility_and_Auth_Diagnosis.md new file mode 100644 index 00000000..235bc8ac --- /dev/null +++ b/00_Raw/2026-04-25-Datacollector_NotebookLM_Progress_Visibility_and_Auth_Diagnosis.md @@ -0,0 +1,70 @@ +# Datacollector NotebookLM Progress Visibility and Auth Diagnosis + +Date: 2026-04-25 21:17:24 KST +Project: Datacollector +Repository: `/Volumes/Data/project/Antigravity/Datacollector` + +## Summary + +사용자가 UI에서 `NotebookLM 연결 상태 점검 중...` 로그만 반복되고 실제 진행 상황을 알 수 없다고 보고했다. +확인 결과 앱이 프로젝트 생성 단계까지 가지 못하고 있었으며, 원인은 NotebookLM 연결 확인 단계에서 MCP 인증이 만료 상태로 판단되기 때문이었다. + +## Observed State + +확인한 상태: + +- Vite 서버 `3000` 실행 중 +- MCP Bridge 서버 `3002` 실행 중 +- `notebooklm-mcp` 프로세스 실행 중 +- `/api/health` 응답 가능 +- `/api/check-connection`은 NotebookLM 인증 만료 오류 반환 + +브리지 로그상 자동 인증 CLI는 Chrome을 열고 로그인 및 토큰 추출까지 수행했다. +그러나 MCP 서버는 이후에도 `Authentication expired`로 판단하여 NotebookLM notebook list 호출에 실패했다. + +## Changes Made + +수정 파일: + +- `/Volumes/Data/project/Antigravity/Datacollector/scripts/mcp_bridge.mjs` +- `/Volumes/Data/project/Antigravity/Datacollector/src/components/AgentDashboard.tsx` + +핵심 변경: + +- MCP 초기화 타임아웃 추가: `MCP_INIT_TIMEOUT_MS` +- NotebookLM 연결 확인 타임아웃 추가: `MCP_HEALTH_TIMEOUT_MS` +- `/api/health`에 상세 상태 추가 +- `initialized`, `processRunning`, `processPid`, `pendingRequests`, `authStatus` 노출 +- 인증 CLI 진행 단계(`starting`, `running`, `restarting`, `success`, `failed`) 추적 +- UI 연결 점검 중 5초마다 Bridge/MCP/auth 진행 상태 로그 출력 +- 중복 연결 점검 요청은 기존 Promise를 재사용하도록 변경 + +## Verification + +실행한 검증: + +```bash +node --check scripts/mcp_bridge.mjs +npm run lint +npm run build +curl -sS --max-time 5 http://127.0.0.1:3002/api/health +curl -sS --max-time 25 -X POST -H 'Content-Type: application/json' -d '{}' http://127.0.0.1:3002/api/check-connection +``` + +검증 결과: + +- 브리지 문법 체크 통과 +- TypeScript 타입체크 통과 +- Vite 빌드 통과 +- Bridge/MCP 프로세스는 실행됨 +- NotebookLM 연결 확인은 인증 만료 오류로 실패 + +## Current Diagnosis + +현재 문제는 앱 실행이나 Bridge 연결 문제가 아니라 NotebookLM MCP 인증 상태 문제다. +자동 인증 CLI가 토큰을 저장해도 MCP 서버가 계속 만료로 판단하므로, 다음 단계에서는 NotebookLM MCP 패키지의 인증 저장 형식 또는 권장 인증 방식(`--file` 모드 등)을 확인해야 한다. + +## Operational Note + +확인용으로 실행했던 Bridge/Vite/MCP 프로세스는 종료했다. +새 진행 상태 로그를 보려면 앱을 `run_mac.command`로 다시 실행해야 한다. diff --git a/00_Raw/Automatic Batching.md b/00_Raw/Automatic Batching.md new file mode 100644 index 00000000..378663c8 --- /dev/null +++ b/00_Raw/Automatic Batching.md @@ -0,0 +1,25 @@ +# [[Automatic Batching]] + +## 📌 Brief 시 Summary +Automatic Batching(자동 배칭)은 React 18에 도입된 기능으로, 여러 상태(State) 업데이트를 하나의 리렌더링으로 그룹화하여 처리하는 성능 최적화 기법입니다 [1-3]. 이전 버전에서는 React의 네이티브 이벤트 핸들러 내의 업데이트만 배칭되었으나, React 18부터는 프로미스(Promise), setTimeout, 비동기 작업 등 출처와 무관하게 모든 상태 업데이트를 자동으로 배칭합니다 [2, 4-6]. 이를 통해 불필요한 리렌더링과 Virtual DOM의 비교 연산(diffing)을 최소화하여 애플리케이션의 성능과 UI 응답성을 크게 향상시킵니다 [4, 7]. + +## 📖 Core Content +* **작동 원리 및 도입 배경:** + React 18 이전에는 `onClick`과 같은 React 내부 이벤트 핸들러에서 발생하는 상태 업데이트만 배칭 처리가 되었습니다 [2, 6]. 따라서 `setTimeout`이나 비동기 API 호출 내에서 상태를 여러 번 업데이트할 경우, 각 업데이트마다 개별적인 리렌더링이 발생하여 성능 저하의 원인이 되었습니다 [2, 8]. React 18의 자동 배칭 기능은 이벤트 출처와 상관없이 모든 상태 업데이트를 하나로 묶어(Batch) 단 한 번의 렌더링과 DOM 업데이트만 트리거합니다 [3, 7, 9, 10]. + +* **렌더링 성능 최적화 효과 ("React가 빠른 이유"):** + 자동 배칭은 여러 상태 변경이 짧은 시간 안에 연속적으로 발생할 때 불필요한 리렌더링의 수를 줄여줍니다 [10, 11]. 리렌더링 횟수가 감소하면 Virtual DOM의 비교 연산(Diffing)과 CPU 작업량이 최소화됩니다 [1, 4]. 실제로 데이터 집약적인 대시보드 환경에서 자동 배칭을 적용한 결과, 전체 렌더링 횟수가 약 40% 감소하고 피크 로드 시 프레임 속도가 25% 향상되는 등 눈에 띄는 성능 개선을 보여주었습니다 [1, 12]. 이는 "Reflow"와 "Repaint"를 유발하는 브라우저의 DOM 조작 빈도를 줄이는 핵심적인 최적화 원리 중 하나입니다 [7]. + +* **자동 배칭 제어 및 예외 처리 (Opt-Out):** + 개발자가 의도적으로 자동 배칭을 우회하고 상태 업데이트 즉시 DOM에 반영해야 하는 상황이 존재할 수 있습니다. 예를 들어, 사용자의 폼 입력에 즉각적인 피드백을 주거나 렌더링 직후 DOM 요소의 크기를 측정해야 하는 경우입니다 [13]. 이때는 React DOM에서 제공하는 `flushSync` API를 사용하여 강제로 즉각적인 동기적 리렌더링을 발생시킬 수 있습니다 [12-15]. 반대로, 긴급하지 않은 대규모 업데이트(예: 리스트 필터링)의 경우 `startTransition`을 사용하여 우선순위를 낮추고 UI 차단을 방지할 수 있습니다 [12, 13]. + +* **주의사항 및 디버깅:** + 자동 배칭은 기본적으로 제공되는 최적화지만, 일부 서드파티 상태 관리 도구나 UI 라이브러리가 React의 이벤트 시스템을 우회하는 방식으로 동작할 경우 배칭이 제대로 적용되지 않을 수 있습니다 [16, 17]. 이러한 예외 상황을 식별하기 위해서는 React DevTools Profiler를 사용하여 컴포넌트의 렌더링 횟수와 업데이트 트리거를 모니터링하는 것이 권장됩니다 [16]. + +## 🔗 Knowledge Connections +- **Related Topics:** [[Virtual DOM]], [[React가 빠른 이유]], [[Reflow / Repaint 최소화 방법]] +- **Projects/Contexts:** [[React 18]], [[Performance Optimization]] +- **Contradictions/Notes:** 자동 배칭은 성능을 크게 향상시키지만 무조건적으로 유용한 것은 아닙니다. 폼의 입력 값 업데이트나 요소 포커싱처럼 사용자에게 지연 없는 즉각적 피드백을 제공해야 하는 필수적인 상황에서는 `flushSync`를 사용해 배칭을 해제해야 하며, 이를 남용할 경우 배칭으로 얻는 성능 이점을 상쇄할 수 있으므로 주의해야 합니다 [13, 18]. 또한 서드파티 라이브러리 통합 시 React 이벤트 시스템을 우회하면 자동 배칭이 무력화될 수 있다는 함정이 존재합니다 [17]. + +--- +*Last updated: 2026-04-25* \ No newline at end of file diff --git a/00_Raw/Critical Rendering Path.md b/00_Raw/Critical Rendering Path.md new file mode 100644 index 00000000..7d2ddd7d --- /dev/null +++ b/00_Raw/Critical Rendering Path.md @@ -0,0 +1,20 @@ +# [[Critical Rendering Path]] + +## 📌 Brief Summary +Critical Rendering Path (CRP)는 브라우저가 HTML, CSS, JavaScript를 수신하여 화면의 픽셀로 변환하기 위해 거치는 일련의 단계적 과정을 의미합니다[1]. 이 과정은 DOM 트리 및 CSSOM 트리 구축, Render Tree 합성, Layout(Reflow), 그리고 Paint(Repaint) 및 Compositing 단계로 진행됩니다[1, 2]. CRP를 이해하고 최적화하는 것은 렌더링 차단 요소를 줄이고 불필요한 Reflow 및 Repaint를 최소화하여 빠른 초기 렌더링과 매끄러운 사용자 상호작용을 보장하는 프론트엔드 성능 엔지니어링의 핵심입니다[3, 4]. + +## 📖 Core Content +* **DOM (Document Object Model) 구축:** 브라우저는 서버로부터 HTML 데이터를 점진적으로 파싱하여 DOM 트리를 구축합니다[2, 5]. 수신된 바이트는 토큰 및 노드로 변환되어 계층 구조를 형성하며, 노드의 수가 많을수록 이후 렌더링 경로의 연산 시간이 길어집니다[2, 5, 6]. +* **CSSOM (CSS Object Model) 구축:** DOM과 달리 CSSOM 구축은 점진적으로 이루어지지 않으며, 파싱이 완료될 때까지 렌더링을 차단(Render-blocking)합니다[6-8]. 이는 스타일이 뒤늦게 덮어씌워지면서 스타일이 적용되지 않은 콘텐츠가 화면에 번쩍이는 현상(FOUC)을 방지하기 위함입니다[6, 7]. +* **Render Tree 합성:** DOM과 CSSOM이 완성되면, 브라우저는 이 둘을 결합해 화면에 실제로 그려지는 가시적 노드(Visible nodes)만 포함하는 Render Tree를 만듭니다[9-11]. `