Skip to main content
Glama
para-zettelkasten-integration.test.ts20.2 kB
/** * PARA + Zettelkasten 통합 테스트 * 두 방법론을 함께 사용하는 복합 시나리오 검증 */ import { executeTool } from '../../src/tools'; import { createTestContext, cleanupTestContext } from '../test-helpers'; import type { ToolExecutionContext } from '../../src/tools/types'; describe('PARA + Zettelkasten Integration Tests', () => { let context: ToolExecutionContext; beforeEach(() => { context = createTestContext(); }); afterEach(() => { cleanupTestContext(context); }); describe('프로젝트 기반 지식 구축', () => { it('프로젝트 진행 중 Zettelkasten 방식으로 지식을 축적할 수 있다', async () => { // 1. 프로젝트 허브 생성 const projectHub = await executeTool( 'create_note', { title: '프로젝트: AI 추천 시스템 구축', content: '## 목표\n협업 필터링 기반 추천 엔진 구현\n\n## 기간\n2025-01 ~ 2025-03', category: 'Projects', project: 'ai-recommender', tags: ['ai', 'machine-learning', 'recommender'], }, context ); const hubUid = projectHub._meta?.metadata?.id; // 2. 프로젝트 중 발견한 개념들을 Resources에 Zettelkasten 노트로 기록 const coldStartNote = await executeTool( 'create_note', { title: '협업 필터링의 Cold Start 문제', content: '신규 사용자나 아이템에 대한 데이터가 없어 추천이 어려움\n\n## 해결책\n- 콘텐츠 기반 필터링 보완\n- 인기도 기반 추천', category: 'Resources', // 재사용 가능한 지식 tags: ['collaborative-filtering', 'cold-start', 'recommender'], links: [hubUid], }, context ); const matrixNote = await executeTool( 'create_note', { title: '행렬 분해를 통한 잠재 요인 추출', content: '사용자-아이템 행렬을 저차원 잠재 요인으로 분해\n\n## 알고리즘\n- SVD\n- ALS', category: 'Resources', tags: ['matrix-factorization', 'machine-learning'], links: [hubUid, coldStartNote._meta?.metadata?.id], }, context ); const metricsNote = await executeTool( 'create_note', { title: '추천 시스템 평가 지표', content: '## 정확도\n- RMSE, MAE\n\n## 랭킹\n- Precision@K\n- Recall@K', category: 'Resources', tags: ['evaluation', 'metrics', 'recommender'], links: [hubUid], }, context ); // 3. 프로젝트 작업 노트 const implementationNote = await executeTool( 'create_note', { title: '추천 엔진 구현 로그', content: '## 2025-01-15\n- ALS 알고리즘 선택\n- Cold Start 해결을 위해 하이브리드 방식 적용', category: 'Projects', project: 'ai-recommender', tags: ['implementation', 'log'], links: [ matrixNote._meta?.metadata?.id, coldStartNote._meta?.metadata?.id, ], }, context ); // 4. 프로젝트 허브 업데이트 await executeTool( 'update_note', { uid: hubUid, content: '## 목표\n협업 필터링 기반 추천 엔진 구현\n\n## 기간\n2025-01 ~ 2025-03\n\n## 축적된 지식\n- Cold Start 문제 이해\n- 행렬 분해 기법\n- 평가 지표', links: [ coldStartNote._meta?.metadata?.id, matrixNote._meta?.metadata?.id, metricsNote._meta?.metadata?.id, implementationNote._meta?.metadata?.id, ], }, context ); // 검증 // 프로젝트 노트들 const projectNotes = await executeTool( 'list_notes', { project: 'ai-recommender' }, context ); expect(projectNotes._meta?.metadata?.total).toBe(2); // hub + implementation // 축적된 리소스들 (프로젝트와 무관하게 재사용 가능) const aiResources = await executeTool( 'search_memory', { query: 'recommender', category: 'Resources' }, context ); const resourceText = aiResources.content[0]?.text || ''; expect(resourceText.toLowerCase()).toContain('recommender'); // 링크 그래프 확인 const hubLinks = await executeTool( 'read_note', { uid: hubUid, includeLinks: true }, context ); const hubMetadata = hubLinks._meta?.metadata as any; expect(hubMetadata?.links?.length).toBe(4); }); }); describe('영역 기반 전문성 구축', () => { it('지속적인 영역에서 Zettelkasten으로 전문성을 구축할 수 있다', async () => { // 1. Areas 영역 정의 const backendArea = await executeTool( 'create_note', { title: '백엔드 개발 전문성', content: '## 핵심 역량\n- API 설계\n- 데이터베이스 최적화\n- 시스템 확장성', category: 'Areas', tags: ['backend', 'expertise', 'ongoing'], }, context ); const areaUid = backendArea._meta?.metadata?.id; // 2. 세부 지식 노트들 (Resources에 Zettelkasten 스타일) const cacheNote = await executeTool( 'create_note', { title: '캐시 전략 패턴들', content: '## Cache-Aside\n애플리케이션이 캐시를 직접 관리\n\n## Write-Through\n데이터 변경 시 캐시와 DB 동시 업데이트', category: 'Resources', tags: ['caching', 'patterns', 'performance'], links: [areaUid], }, context ); const indexNote = await executeTool( 'create_note', { title: '데이터베이스 인덱스 전략', content: '## B-Tree\n범위 쿼리에 적합\n\n## Hash\n동등 비교에 최적', category: 'Resources', tags: ['database', 'indexing', 'optimization'], links: [areaUid], }, context ); const scalingNote = await executeTool( 'create_note', { title: '수평적 vs 수직적 확장', content: '## 수평적 (Scale-Out)\n- 서버 추가\n- 로드 밸런싱 필요\n\n## 수직적 (Scale-Up)\n- 서버 스펙 향상\n- 한계 존재', category: 'Resources', tags: ['scaling', 'architecture'], links: [areaUid, cacheNote._meta?.metadata?.id], }, context ); // 3. 크로스 링크 (개념 연결) await executeTool( 'update_note', { uid: cacheNote._meta?.metadata?.id, links: [areaUid, scalingNote._meta?.metadata?.id], }, context ); await executeTool( 'update_note', { uid: indexNote._meta?.metadata?.id, links: [areaUid, cacheNote._meta?.metadata?.id], }, context ); // 4. 실제 프로젝트에서 지식 활용 const perfProject = await executeTool( 'create_note', { title: '프로젝트: API 성능 개선', content: '## 현재 문제\n- 응답 시간 2초\n\n## 목표\n- 200ms 이하\n\n## 적용할 지식\n- 캐시 전략\n- DB 인덱싱', category: 'Projects', project: 'api-performance', tags: ['performance', 'optimization'], links: [ cacheNote._meta?.metadata?.id, indexNote._meta?.metadata?.id, scalingNote._meta?.metadata?.id, ], }, context ); // 검증 // Areas 확인 const areas = await executeTool( 'list_notes', { category: 'Areas' }, context ); expect(areas._meta?.metadata?.total).toBe(1); // Resources 확인 const resources = await executeTool( 'list_notes', { category: 'Resources' }, context ); expect(resources._meta?.metadata?.total).toBe(3); // 프로젝트에서 리소스 참조 확인 const projectLinks = await executeTool( 'read_note', { uid: perfProject._meta?.metadata?.id, includeLinks: true }, context ); const projectMetadata = projectLinks._meta?.metadata as any; expect(projectMetadata?.links?.length).toBe(3); // 리소스의 다중 참조 확인 (front matter links만) const cacheLinks = await executeTool( 'read_note', { uid: cacheNote._meta?.metadata?.id }, context ); const cacheMetadata = cacheLinks._meta?.metadata as any; // cacheNote는 areaUid와 scalingNote를 참조함 expect(cacheMetadata?.links?.length).toBeGreaterThanOrEqual(2); }); }); describe('AI 에이전트 메모리 시뮬레이션', () => { it('AI 에이전트가 대화를 통해 PARA+Zettelkasten으로 지식을 축적한다', async () => { // Session 1: React 관련 질문 const reactBasics = await executeTool( 'create_note', { title: '사용자 질문: React 컴포넌트 생명주기', content: '## 대화 요약\n사용자가 React 클래스 컴포넌트의 생명주기를 물음\n\n## 제공한 답변\n- componentDidMount: 마운트 후\n- componentDidUpdate: 업데이트 후', category: 'Areas', // 사용자 지원 영역 tags: ['react', 'conversation', 'user-support'], }, context ); // Session 2: 이전 대화 이어서 Hooks 질문 const reactHooks = await executeTool( 'create_note', { title: '사용자 질문: useEffect와 생명주기 비교', content: '## 대화 요약\n이전 대화를 이어서 Hooks 방식 질문\n\n## 연결\nuseEffect = componentDidMount + componentDidUpdate + componentWillUnmount', category: 'Areas', tags: ['react', 'hooks', 'conversation'], links: [reactBasics._meta?.metadata?.id], }, context ); // Session 3: 성능 문제 프로젝트화 const reactPerf = await executeTool( 'create_note', { title: '사용자 프로젝트: React 리렌더링 최적화', content: '## 문제\n불필요한 리렌더링으로 성능 저하\n\n## 제안한 해결책\n- React.memo 사용\n- useMemo/useCallback', category: 'Projects', project: 'user-react-optimization', tags: ['react', 'performance', 'optimization'], links: [ reactBasics._meta?.metadata?.id, reactHooks._meta?.metadata?.id, ], }, context ); // 지식 검색 (이전 대화 참조) const reactKnowledge = await executeTool( 'search_memory', { query: 'React 생명주기' }, context ); expect(reactKnowledge.content[0]?.text).toContain('React'); // 관련 노트 추천 (연결된 노트 탐색) const relatedToHooks = await executeTool( 'read_note', { uid: reactHooks._meta?.metadata?.id }, context ); const hooksMetadata = relatedToHooks._meta?.metadata as any; // reactHooks는 reactBasics를 참조함 expect(hooksMetadata?.links).toContain( reactBasics._meta?.metadata?.id ); // reactPerf가 reactHooks를 참조하지만, 백링크 추적은 인덱싱 필요 // 대화 히스토리 조회 (conversation 태그) const conversations = await executeTool( 'list_notes', { tags: ['conversation'] }, context ); expect(conversations._meta?.metadata?.total).toBe(2); }); }); describe('지식 아카이빙 워크플로우', () => { it('프로젝트 완료 시 관련 리소스 지식은 보존되고 프로젝트만 아카이빙된다', async () => { // 1. 공통 리소스 생성 (프로젝트와 무관하게 재사용) const designResource = await executeTool( 'create_note', { title: 'UI 디자인 원칙', content: '## 핵심 원칙\n- 일관성\n- 피드백\n- 접근성', category: 'Resources', tags: ['design', 'ui', 'principles'], }, context ); const resourceUid = designResource._meta?.metadata?.id; // 2. 프로젝트에서 리소스 활용 const projectA = await executeTool( 'create_note', { title: '프로젝트 A: 웹 리디자인', content: 'UI 디자인 원칙을 적용', category: 'Projects', project: 'web-redesign', tags: ['web', 'active'], links: [resourceUid], }, context ); const projectB = await executeTool( 'create_note', { title: '프로젝트 B: 모바일 앱', content: 'UI 디자인 원칙을 적용', category: 'Projects', project: 'mobile-app', tags: ['mobile', 'active'], links: [resourceUid], }, context ); // 3. 프로젝트 A 완료 및 아카이빙 await executeTool( 'update_note', { uid: projectA._meta?.metadata?.id, category: 'Archives', tags: ['web', 'completed'], }, context ); // 4. 검증 // 리소스는 여전히 Resources에 남아있음 const resources = await executeTool( 'list_notes', { category: 'Resources' }, context ); expect(resources.content[0]?.text).toContain('UI 디자인 원칙'); // 프로젝트 B는 여전히 활성화 const activeProjects = await executeTool( 'list_notes', { category: 'Projects' }, context ); expect(activeProjects.content[0]?.text).toContain('프로젝트 B'); // 프로젝트 A는 Archives에 const archives = await executeTool( 'list_notes', { category: 'Archives' }, context ); expect(archives.content[0]?.text).toContain('프로젝트 A'); // 리소스 노트 확인 (프로젝트들이 리소스를 참조) const resourceLinks = await executeTool( 'read_note', { uid: resourceUid }, context ); const resourceMetadata = resourceLinks._meta?.metadata as any; // 리소스 노트 자체는 다른 노트를 참조하지 않음 expect(resourceMetadata?.links?.length || 0).toBe(0); // 대신 프로젝트 노트들이 리소스를 참조하는지 확인 const projectNotes = await executeTool( 'list_notes', { category: 'Projects' }, context ); const projectText = projectNotes.content[0]?.text || ''; expect(projectText).toContain('프로젝트 B'); // 아직 활성화된 프로젝트 }); }); describe('복합 검색 및 필터링', () => { it('PARA 카테고리와 Zettelkasten 태그를 조합하여 검색할 수 있다', async () => { // 다양한 조합의 노트 생성 await executeTool( 'create_note', { title: 'Python 백엔드 프로젝트', content: 'Python으로 API 구축', category: 'Projects', project: 'python-api', tags: ['python', 'backend', 'api'], }, context ); await executeTool( 'create_note', { title: 'Python 데이터 분석', content: 'Pandas와 NumPy 활용', category: 'Resources', tags: ['python', 'data-analysis', 'pandas'], }, context ); await executeTool( 'create_note', { title: 'Python 학습 영역', content: '지속적인 Python 역량 개발', category: 'Areas', tags: ['python', 'learning', 'ongoing'], }, context ); await executeTool( 'create_note', { title: '완료된 Python 튜토리얼', content: '기초 튜토리얼 완료', category: 'Archives', tags: ['python', 'tutorial', 'completed'], }, context ); // 키워드 검색 const pythonSearch = await executeTool( 'search_memory', { query: 'Python' }, context ); const searchText = pythonSearch.content[0]?.text || ''; expect(searchText.toLowerCase()).toContain('python'); // 카테고리 + 태그 조합 필터링 const pythonResources = await executeTool( 'list_notes', { category: 'Resources', tags: ['python'] }, context ); expect(pythonResources.content[0]?.text).toContain('데이터 분석'); // 프로젝트별 필터링 const pythonProjects = await executeTool( 'list_notes', { project: 'python-api' }, context ); expect(pythonProjects._meta?.metadata?.total).toBe(1); // 완료된 항목 const completedNotes = await executeTool( 'list_notes', { category: 'Archives', tags: ['completed'] }, context ); expect(completedNotes.content[0]?.text).toContain('튜토리얼'); }); }); describe('지식 그래프 구축', () => { it('여러 PARA 카테고리에 걸친 지식 그래프를 구축할 수 있다', async () => { // 중심 개념 (Resources) const coreConceptNote = await executeTool( 'create_note', { title: 'TDD (Test-Driven Development)', content: '테스트를 먼저 작성하는 개발 방법론', category: 'Resources', tags: ['tdd', 'methodology', 'core-concept'], }, context ); const coreUid = coreConceptNote._meta?.metadata?.id; // Areas에서 참조 const devPracticeArea = await executeTool( 'create_note', { title: '개발 프랙티스', content: '지속적으로 개선해야 할 개발 습관', category: 'Areas', tags: ['practices', 'ongoing'], links: [coreUid], }, context ); // Projects에서 참조 const refactoringProject = await executeTool( 'create_note', { title: '레거시 코드 리팩토링', content: 'TDD 적용하여 안전하게 리팩토링', category: 'Projects', project: 'legacy-refactor', tags: ['refactoring', 'legacy'], links: [coreUid], }, context ); // Archives에서도 참조 (과거 경험) const pastExperience = await executeTool( 'create_note', { title: '2024년 TDD 도입 회고', content: 'TDD 도입 초기 어려움과 극복 과정', category: 'Archives', tags: ['retrospective', 'tdd', 'experience'], links: [coreUid], }, context ); // 핵심 개념 노트 확인 const coreLinks = await executeTool( 'read_note', { uid: coreUid }, context ); const coreMetadata = coreLinks._meta?.metadata as any; // 핵심 개념 노트 자체는 다른 노트를 참조하지 않음 expect(coreMetadata?.links?.length || 0).toBe(0); // 각 카테고리에서 참조됨 확인 const categories = ['Areas', 'Projects', 'Archives']; for (const category of categories) { const categoryNotes = await executeTool( 'list_notes', { category }, context ); expect(categoryNotes._meta?.metadata?.total).toBeGreaterThan(0); } // TDD 검색 시 모든 관련 노트 발견 const tddSearch = await executeTool( 'search_memory', { query: 'TDD' }, context ); expect(tddSearch.content[0]?.text).toContain('TDD'); }); }); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/inchan/memory-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server