docs(feedback): add F5 — 마크다운 일괄 export (RAG 활용)
dogfood 외부 회수 채널 부재. RAG 친화 형식으로
notes/{date}-{id8}-{slug}.md (frontmatter+본문) +
index.jsonl + manifest.json + media/ 트리 권장. 스키마는
현행으로 충분, ExportService 신규 + 트레이 메뉴 1개. F4-H5
(외부 회수) 측정의 dependency 가 됨.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -418,6 +418,165 @@ strategy.md 가 다루는 cue 는:
|
||||
|
||||
---
|
||||
|
||||
## F5. 마크다운 일괄 export (RAG 활용 가정) (🌱 raw)
|
||||
|
||||
**발견:** 2026-04-26 dogfood 시작 직전 사고 실험. 슬라이스 v0.4 는 노트가 SQLite + 로컬 미디어 폴더에만 존재. 외부 도구 (Obsidian, RAG 파이프라인, 로컬 LLM 컨텍스트, 검색 엔진) 로 빼낼 통로가 0.
|
||||
|
||||
### 관찰
|
||||
|
||||
스키마에 이미 export 에 필요한 모든 정보가 있다 (`m001_initial.ts:7~57`):
|
||||
- `notes` — id, raw_text, ai_{title,summary}, *_edited_by_user, user_intent, intent_prompted_at, created_at, updated_at, ai_provider, ai_generated_at
|
||||
- `note_tags` (+`tags`) — 태그 + source(ai/user)
|
||||
- `media` — note 첨부 이미지 메타 (`rel_path` 가 MediaStore 의 프로필 디렉터리 기준)
|
||||
- (F1 promoted 시) `due_date`, `due_date_edited_by_user`
|
||||
|
||||
내보낼 자산은 두 종류:
|
||||
1. **노트 본문 + 메타데이터** — 텍스트
|
||||
2. **첨부 이미지** — 바이너리 파일 (현재는 `<profile>/media/<rel_path>`)
|
||||
|
||||
RAG 파이프라인 (LangChain, LlamaIndex, ChromaDB, 로컬 embedding) 의 표준 입력은 **YAML frontmatter 가 붙은 단일-노트-단일-파일 마크다운** + 안정 ID + 카테고리/태그 메타. 본 export 는 이 형식에 정렬해야 후속 의사결정 (RAG 도입, Confluence 동기화, Obsidian vault 사용) 모두 한 형식으로 흡수 가능.
|
||||
|
||||
### 제안 방향
|
||||
|
||||
**1차 권장 — 디렉터리 트리 + frontmatter 마크다운 + index.jsonl + 미디어 동봉.**
|
||||
|
||||
```
|
||||
inkling-export-2026-04-26/
|
||||
notes/
|
||||
2026-04-25-014a3b9c-주간회고-PR-리뷰.md
|
||||
2026-04-25-02f17de8-새-디버깅-패턴.md
|
||||
...
|
||||
media/
|
||||
014a3b9c__1.png # MediaStore rel_path 평탄화
|
||||
02f17de8__1.jpg
|
||||
index.jsonl # RAG 친화 1줄=1노트 메타
|
||||
manifest.json # 스키마 버전, 내보낸 시각, 노트 수, 검증 해시
|
||||
README.md # 형식 설명, RAG 적용 가이드
|
||||
```
|
||||
|
||||
**노트 파일 포맷** (one file per note, RAG 친화):
|
||||
|
||||
```markdown
|
||||
---
|
||||
id: 014a3b9c-...
|
||||
created_at: 2026-04-25T14:23:11+09:00
|
||||
updated_at: 2026-04-25T14:24:02+09:00
|
||||
title: 주간 회고 PR 리뷰
|
||||
title_source: ai # ai | user (edited 면 user)
|
||||
summary: 회고 양식 통일을 위한 PR 리뷰 메모.
|
||||
summary_source: ai
|
||||
tags:
|
||||
- { name: pr, source: ai }
|
||||
- { name: review, source: user }
|
||||
user_intent: 팀에서 회고 양식 통일
|
||||
intent_prompted_at: 2026-04-25T14:24:02+09:00
|
||||
due_date: 2026-05-01 # F1 promoted 시
|
||||
due_date_source: ai
|
||||
ai_provider: local-ollama/gemma4:e4b
|
||||
ai_generated_at: 2026-04-25T14:23:34+09:00
|
||||
images:
|
||||
- rel: media/014a3b9c__1.png
|
||||
mime: image/png
|
||||
bytes: 152834
|
||||
inkling_export_version: 1
|
||||
---
|
||||
|
||||
# 주간 회고 PR 리뷰
|
||||
|
||||
> 회고 양식 통일을 위한 PR 리뷰 메모.
|
||||
|
||||
내일 까지 PR 리뷰 마무리하고, 회고 양식은 팀에 공유.
|
||||
오후 미팅 중에 떠올랐음.
|
||||
|
||||

|
||||
```
|
||||
|
||||
**index.jsonl** (RAG 인덱싱용 1줄=1노트):
|
||||
|
||||
```json
|
||||
{"id":"014a3b9c-...","path":"notes/2026-04-25-014a3b9c-주간회고-PR-리뷰.md","created_at":"2026-04-25T14:23:11+09:00","tags":["pr","review"],"due_date":"2026-05-01","embedding_text":"주간 회고 PR 리뷰\n\n내일 까지 PR 리뷰 마무리하고..."}
|
||||
```
|
||||
|
||||
`embedding_text` 는 title + raw_text + tags 를 결합한 임베딩 입력 후보. 사용자가 별도 가공 없이 LangChain `JSONLoader` 또는 LlamaIndex `JSONReader` 로 바로 적재 가능.
|
||||
|
||||
**파일명 컨벤션:** `YYYY-MM-DD-{id8}-{slugified-title}.md`. 충돌 회피 + 인간 가독 + 디렉터리 정렬 친화.
|
||||
- `id8` = UUIDv7 의 처음 8자리. 시간 정렬 + 충돌 0.
|
||||
- `slugified-title` = title 의 한글 보존, 공백→하이픈, 파일시스템 금지 문자 제거 (`/\\:*?"<>|`), 32자 제한.
|
||||
- title 비어있으면 `untitled` 폴백.
|
||||
|
||||
**트리거 (1차 권장):** 트레이 메뉴 → "마크다운으로 내보내기..." → Electron `dialog.showOpenDialog({ properties: ['openDirectory'] })` 로 사용자가 폴더 선택 → 진행 토스트 → 완료 토스트 (성공 시 노트 수 + "폴더 열기" 버튼).
|
||||
|
||||
**증분 vs 전체:** 1차는 전체 덮어쓰기만. 증분(변경된 노트만 갱신)은 후속.
|
||||
|
||||
### 결정 대기
|
||||
|
||||
1. **포맷 1차안 확정**: one-file-per-note + frontmatter + index.jsonl 트리플 vs 단일 monolithic .md vs 두 형식 동시 출력? → RAG 우선이면 트리플이 압도적이지만 사용자 선호 확인 필요.
|
||||
2. **미디어 포함 기본값**: 항상 동봉 vs 사용자 선택 (체크박스). 슬라이스 §1.1 의 "raw_text 본문에 민감정보 가능" 정책 — 이미지가 스크린샷인 경우 export 가 의도치 않은 노출 통로가 될 수 있음. **기본 동봉 + export 시 다이얼로그에 "이미지 N개 포함됩니다" 명시** 가 안전.
|
||||
3. **삭제된 노트 처리**: SQLite 에 soft-delete 컬럼이 없음. 현재는 hard delete. export 결과는 *현 시점* 스냅샷만 — 삭제 이력 없음. 충분한가, 별 issue 인가?
|
||||
4. **필드 정책 — provenance 표현**: `title_source: ai|user` 같은 단일 enum vs `title: { value, source, edited_at }` 객체. RAG 파이프라인의 frontmatter parser 마다 다름 — 평탄한 enum 이 호환성 좋음.
|
||||
5. **embedding_text 합성 규칙**: title + raw_text + tags 단순 결합 vs raw_text 만 (가장 untouched) vs title + summary + raw_text. 본인 RAG 사용 패턴 미정 — 1차는 raw_text 단독으로 시작 + 옵션화.
|
||||
6. **파일명에서 raw_text vs ai_title 사용**: ai_title 사용이 가독성 좋지만 AI 변경 시 파일명도 변하는 안티패턴. **ai_title 사용 + 사용자가 수동 export 트리거 시점 기준** 으로 동결 (재 export 시 새 파일명). 파일명 안정성 vs 가독성 트레이드오프 명시.
|
||||
7. **트리거 표면**: 트레이 메뉴만 vs Inbox 헤더 버튼도 추가 vs CLI 플래그 (`--export <dir>`). 자동화 사용자라면 CLI 가 매력. 슬라이스 후속 미니 spec 으로 분리 가능.
|
||||
8. **export 형식 버전 정책**: `inkling_export_version: 1` 박아두고 후속 변경 시 마이그레이션 가이드 동봉. 처음부터 박는 게 깔끔.
|
||||
9. **민감정보 표시 경고**: 본 사용자는 `dlsrks0734@gmail.com` 계정 본인 단일 사용자라 위험 낮지만, export 후 폴더가 어디 가는지에 따라 위험 발생. 트레이 export 다이얼로그에 "이 export 는 평문이며 raw_text 가 그대로 포함됩니다" 명시 필요.
|
||||
|
||||
### 가설·측정
|
||||
|
||||
| # | 가설 | 측정 |
|
||||
|---|------|------|
|
||||
| H1 | dogfood 1주 후 본인이 export 한 마크다운 더미를 LlamaIndex 기본 markdown loader 로 직접 적재 가능 (사이즈 변환 0) | 실측 — 1회 시도 |
|
||||
| H2 | export 결과의 frontmatter 가 Obsidian 의 frontmatter renderer 에도 호환 | 실측 — Obsidian 에 폴더 import 후 메타 표시 확인 |
|
||||
| H3 | 노트당 평균 raw_text 길이 ≤ 200 토큰 → RAG chunking 불필요 | 표본 50건 토크나이저 통계 |
|
||||
| H4 | export 누적 사이즈가 1MB / 100 노트 이하 (미디어 제외) | 측정 |
|
||||
| H5 | 본인이 export → 외부 도구 적재 → 적어도 1번 의미 있는 회수 (검색·RAG·재방문) 발생, dogfood 2주 내 | 본인 라벨링 |
|
||||
|
||||
### 범위
|
||||
|
||||
- **In:**
|
||||
- `ExportService` 신규 — DB 쿼리 + 파일 쓰기 + 미디어 복사
|
||||
- 트레이 메뉴 항목 1개 추가 ("마크다운으로 내보내기...")
|
||||
- Electron `dialog` 디렉터리 선택
|
||||
- frontmatter 합성 + 파일명 슬러그
|
||||
- `index.jsonl` + `manifest.json` + `README.md` 동시 생성
|
||||
- 미디어 평탄화 복사 (rel_path → `media/{id8}__{n}.{ext}`)
|
||||
- 진행 상태 토스트 (노트 수 ≥ 100 시 진행률)
|
||||
- 단위 테스트 — frontmatter 합성, 슬러그, JSON 직렬화
|
||||
- **Out (후속 미니 spec):**
|
||||
- 증분 export
|
||||
- 자동 export (cron / watch)
|
||||
- CLI 플래그
|
||||
- import (역방향)
|
||||
- 다중 형식 (CSV, JSON 단일 파일, OPML)
|
||||
- 외부 SaaS 동기화 (Confluence, Notion)
|
||||
- export 시 raw_text 마스킹·익명화
|
||||
|
||||
### 영향
|
||||
|
||||
- **Schema:** 없음 — 현 스키마로 충분
|
||||
- **신규 파일:**
|
||||
- `src/main/services/ExportService.ts`
|
||||
- `src/main/ipc/exportApi.ts`
|
||||
- 테스트 `tests/unit/ExportService.spec.ts`
|
||||
- **변경 파일:**
|
||||
- `src/main/index.ts` — 등록
|
||||
- `src/main/tray.ts` — 메뉴 항목 추가
|
||||
- `src/preload/index.ts` — IPC expose
|
||||
- **외부 의존:**
|
||||
- 없음 — Node `fs/promises` + `path` + `node:crypto` (해시) 만 사용
|
||||
- YAML 직렬화는 frontmatter 가 단순 하므로 자체 구현 (외부 dep 추가 불필요)
|
||||
- **로깅:**
|
||||
- export 시작·완료·노트 수만 기록. raw_text·title·summary 미기록 (slice §1.1 invariant 4 그대로)
|
||||
- **문서:**
|
||||
- 본 항목 promoted 시 `2026-04-26-markdown-export.md` (가칭) 으로 추출
|
||||
- 추출 후 README 의 doc map 갱신
|
||||
- export 폴더 안의 `README.md` — RAG 적재 예시 코드 포함
|
||||
|
||||
### 비고
|
||||
|
||||
본 항목은 **읽기 전용** 이라 dogfood 안전성 영향 0 (raw_text 변경 없음, AI 호출 없음, 네트워크 0). 우선순위 측면에선 F1·F2·F3 보다 후순위지만 **F4 의 H5 (외부 도구로 회수) 평가 자체가 export 없이는 측정 불가** — 즉 F4-H5 = F5 dependency. F4 의 데이터 수집을 위해 F5 가 먼저 promoted 되는 경로도 있음.
|
||||
|
||||
---
|
||||
|
||||
## (다음 항목 자리)
|
||||
|
||||
새 피드백 추가 시 `## F5. 짧은 제목 (🌱 raw)` 헤더로 시작. 표준 슬롯 6개 채우거나 비워둔 채 시작 가능.
|
||||
새 피드백 추가 시 `## F6. 짧은 제목 (🌱 raw)` 헤더로 시작. 표준 슬롯 6개 채우거나 비워둔 채 시작 가능.
|
||||
|
||||
Reference in New Issue
Block a user