<div align="center">
<h1>마크다운 리더(Markdown Reader)</h1>
<p><b>오픈 소스이며, 로컬 우선(local-first) 방식을 채택한 네이티브 AI 기능의 마크다운 에디터입니다.</b></p>
macOS Apple Silicon
Windows x64
Linux x64
<br />
<img width="1177" height="646" alt="Image" src="https://raw.githubusercontent.com/petertzy/markdown-reader/HEAD/docs/markdown-reader.webp" />
</div>
목차 (Table of Contents)
🌟 Markdown Reader를 사용해야 하는 이유? (Why Markdown Reader?)
대부분의 최신 글쓰기 앱들은 **프라이버시(privacy)**와 강력한 기능(power) 중 하나를 선택하도록 강요합니다. 클라우드 기반 AI 에디터는 사용자 데이터를 학습에 사용하며, 반면 로컬 에디터는 지능형 기능이 부족한 경우가 많습니다.
Markdown Reader가 이 간극을 메웁니다. 이는 Tauri를 기반으로 구축된 네이티브 데스크톱 애플리케이션이며, 파일들이 사용자의 장치 내부에 로컬로 유지되도록 보장합니다. 하지만 동시에 OpenAI, Anthropic, OpenRouter, 그리고 로컬 LLM과 원활하게 통합되어 강력한 AI 지원 글쓰기를 오프라인 작업 흐름에 직접 가져다줍니다.
주요 기능 (Key Features)
- 🔒 로컬 우선 아키텍처 (Local-First Architecture): 사용자가 외부 AI API를 명시적으로 호출하지 않는 한 파일은 절대 기기를 벗어나지 않습니다.
- 🤖 사용자 지정 AI 연결 (Bring-Your-Own-AI): OpenAI, Anthropic, OpenRouter, OpenAI 호환 제공업체 또는 로컬 모델을 설정할 수 있습니다.
- ✍️ 지능형 편집 (Intelligent Editing): AI 지원 번역, 문장별 비교, 요약, 서식 지정 및 코드 블록 정리 기능을 제공합니다.
- ⚡ 슬래시 명령어 (Slash Commands): 에디터에서
/를 입력하여 AI 작업을 실행하거나 AI 패널을 열지 않고 인라인으로 표를 삽입할 수 있습니다.
- 🛡️ 감사 및 롤백 (Audit & Rollback): 모든 AI 제안 사항을 적용하기 전에 검토합니다. 단 한 번의 클릭으로 변경 사항을 거부하거나 롤백할 수 있습니다.
- 🖥️ 네이티브 데스크톱 경험 (Native Desktop Feel): Next.js로 구축되었으며 Tauri를 통해 패키징되어 매우 빠른 성능을 제공합니다.
- 📊 문서 통계 (Document Statistics): 현재 문서의 단어 수, 문자 수, 제목 개수 및 예상 독서 시간(분당 238단어 기준)을 확인할 수 있습니다.
🚀 빠른 시작 (Quick Start)
1분 이내에 로컬 개발 환경에서 앱을 실행하세요:
git clone https://github.com/petertzy/markdown-reader.git
cd markdown-reader
...
개발 도우미는 해당 포트가 사용 가능한 경우 127.0.0.1:8000에서 FastAPI 백엔드를 시작합니다. 만약 포트 8000이 다른 프로세스에 의해 이미 점유되어 있다면, 자동으로 사용 가능한 로컬 포트를 선택하여 Tauri 셸로 전달합니다. 특정 백엔드 포트를 요청하려면 다음을 실행하세요:
MARKDOWN_READER_BACKEND_PORT=8010 ./scripts/dev-tauri.sh
macOS PDF 내보내기 종속성 (Dependencies)
PDF 내보내기는 네이티브 라이브러리가 사용 가능한 경우 WeasyPrint를 사용합니다. macOS에서는 WeasyPrint가 libgobject-2.0, Pango, Cairo를 찾을 수 있도록 아래 Homebrew 라이브러리를 설치하세요:
brew install glib pango cairo libffi
⚠️ [IMG:N] 형식 토큰은 이미지 placeholder 입니다. 번역하지 말고 원래 위치에 그대로 유지하세요.
./scripts/dev-tauri.sh는 Apple Silicon Homebrew 설치의 경우 /opt/homebrew/lib를 DYLD_FALLBACK_LIBRARY_PATH에 자동으로 추가합니다. WeasyPrint가 사용 불가능할 경우, Markdown Reader는 PyMuPDF로 대체하여 PDF 내보내기(export)를 완료할 수 있지만, 일반적으로 WeasyPrint가 더 나은 레이아웃 충실도(layout fidelity)를 제공합니다.
macOS 종속성(dependencies)에 대한 전체적인 안내는 셸 설정(shell configuration)을 포함하여 docs/PrepareForMacUser.md를 참조하세요.
Windows PDF 내보내기 종속성 (Windows PDF Export Dependencies)
Windows에서는 WeasyPrint가 기본적으로 제공되지 않는 네이티브 시스템 라이브러리(Cairo, Pango)를 필요로 합니다. docs/PrepareForWindowsUser.md의 단계를 따라 MSYS2를 통해 설치하세요.
WeasyPrint가 사용 불가능할 경우, PDF 내보내기는 macOS와 마찬가지로 더 단순한 레이아웃을 가진 PyMuPDF로 대체됩니다.
기여자(Contributors) 참고: 클론(cloning) 후에는 uv sync --extra dev 및 uv run pre-commit install을 실행하여 린팅 후크(linting hooks)를 설정하세요.
로컬에서 릴리스 아티팩트 빌드하기 (Build release artifacts locally)
GitHub Actions를 사용하지 않고 데스크톱 앱을 패키징하려면, 프로젝트 루트에서 플랫폼별 헬퍼 스크립트를 실행하세요:
./scripts/package-linux.sh
...
각 스크립트는 Python 백엔드 사이커드(sidecar)를 스테이징하고, 프론트엔드 종속성을 설치하며, 일치하는 Tauri 릴리스 빌드를 실행한 다음, 최종 번들(bundle)을 release-artifacts/<target>/에 복사하여 쉬운 배포가 가능하게 합니다.
macOS의 경우, 기본 명령어는 .app 번들을 빌드합니다. DMG 설치 프로그램도 함께 빌드하려면 다음을 실행하세요:
./scripts/package-macos.sh --dmg
특정 빌드 대상을 명시적으로 설정하려면:
./scripts/package-linux.sh --target x86_64-unknown-linux-gnu
...
플랫폼별 옵션을 보려면:
./scripts/package-linux.sh --help
...
📦 데스크톱 다운로드 (Desktop Downloads)
GitHub Actions를 통해 공식 데스크톱 릴리스 빌드를 제공합니다.
| OS | Architecture | Download |
|---|
| macOS | Apple Silicon | Download .dmg |
| ... | | |
| (참고: 고급 PDF 종속성 제약으로 인해 macOS Intel 빌드는 현재 지원되지 않습니다). | | |
🏗 아키텍처 (Architecture)
Markdown Reader는 최대 성능과 유지보수성을 보장하기 위해 세 가지 주요 레이어로 분할되었습니다:
- 백엔드 (
/backend): 렌더링, 내보내기(export), 모든 AI API 통신을 처리하는 매우 빠른 FastAPI 애플리케이션입니다.
- 프론트엔드 (
/frontend): 풍부한 에디터 경험을 제공하는 Next.js UI이며, Tauri 데스크톱 쉘 안에 패키징되어 있습니다.
데스크톱 사용을 위해 패키징될 때, Python 백엔드는 사이렌(silent) Tauri 사이드카 프로세스로 번들링되며, 충돌을 방지하기 위해 런타임에 동적으로 포트를 할당합니다. 개발 중에는 ./scripts/dev-tauri.sh가 로컬 포트 충돌을 피해야 할 때 동일한 포트 핸드오프(port-handoff) 경로를 사용합니다.
로컬 백엔드 보안 (Local Backend Security)
패키징된 데스크톱 사이드카는 실행할 때마다 무작위 인증 토큰을 생성합니다. 모든 API 요청에는 이 토큰이 포함되어야 하며, 메모리에만 보관되고 디스크에 기록되지 않습니다. 독립형 개발 백엔드는 로컬 개발 시 기본적으로 인증되지 않은 상태로 유지됩니다. 시작하기 전에 MARKDOWN_READER_BACKEND_TOKEN을 설정하여 동일한 요청 헤더(X-Markdown-Reader-Token)를 요구할 수 있습니다. Tauri 개발 모드는 이 토큰을 Rust에서 전달하며 WebView JavaScript에 노출하지 않습니다. 브라우저 전용 개발의 경우, NEXT_PUBLIC_BACKEND_TOKEN에 동일한 값을 설정하십시오.
데스크톱 콘텐츠 보안 정책 (Desktop Content Security Policy)
패키징된 Tauri WebView는 기본적으로 거부(default-deny) 정책을 사용하며, 앱 오리진과 루프백 백엔드로의 네트워크 연결만 허용합니다. object-src는 비활성화되었고 base-uri는 애플리케이션 오리진으로 제한됩니다.
script-src 'unsafe-inline'은 Next.js 정적 내보내기(static export)가 하이드레이션 페이로드(hydration payload)를 인라인 스크립트로 포함하기 때문에 여전히 필요합니다. 정적 파일은 요청별 nonce를 받을 수 없기 때문입니다. style-src 'unsafe-inline'는 React UI 레이아웃 업데이트와 격리된 마크다운 미리 보기의 인라인 스타일을 위해 여전히 필요합니다. Monaco는 에디터 워커(editor workers)를 blob:에서 로드하므로, worker-src가 명시적으로 blob:을 허용합니다. Monaco 에셋은 개발 및 프로덕션 빌드 전에 설치된 종속성에서 public/monaco로 복사되어 /monaco/vs에서 로드되며, CDN에 접속하지 않습니다. wasm-unsafe-eval은 별도의 패키지 런타임 감사(audit)를 기다리며 현재 유지되고 있습니다. 에디터 로딩 실패는 기본 CDN 로더 때문에 발생한 것이지 WebAssembly 요구 사항의 증거가 아닙니다. 이 정책은 더 광범위한 JavaScript unsafe-eval 지시문은 허용하지 않습니다. 원격 http: 및 https: 이미지 소스는 마크다운 미리 보기에서 참조되는 이미지에 대해서만 사용할 수 있습니다.
⚡ 슬래시 명령어 (Slash Commands)
에디터에서 줄의 시작 부분(또는 공백 문자 뒤)에 /를 입력하여 인라인 명령어 메뉴를 열 수 있습니다:
| 명령어 | 동작 방식 |
|---|
/summarize | AI를 통해 문서 요약 |
| ... | 사용하려면 화살표 키로 탐색하고, Enter를 눌러 명령을 실행하거나, Escape를 눌러 메뉴를 닫으세요. |
🧠 로컬 모델 지원 (Local Model Support)
Markdown Reader는 로컬에서 호스팅되는 OpenAI와 호환되는 모델 서버를 호출할 수 있습니다. AI 설정 패널에서 **로컬 모델(Local Model)**을 선택하고, LM Studio, Ollama 또는 **사용자 정의(Custom)**를 선택한 후, 사용 가능한 모델을 가져오고 사용할 모델을 저장하세요. 로컬 엔드포인트는 로컬 서버가 API 키를 요구하도록 구성되지 않은 한 API 키가 필요하지 않습니다.
📥 범용 파일 가져오기 (Universal File Import)
Markdown Reader는 Markdown/텍스트 파일을 직접 가져와서, 내장된 MarkItDown 컨버터를 통해 HTML, PDF, DOCX, Office 파일, CSV, EPUB, XML, 아카이브, 이미지, 오디오, Outlook 메시지, 그리고 Jupyter 노트북을 Markdown으로 변환할 수 있습니다. 현재 일부 MarkItDown 선택적 종속성(optional dependencies)이 Python 3.14용 wheel을 아직 게시하지 않았기 때문에 Python 3.14는 지원되지 않습니다.
📚 학술 인용 (Academic Citations)
Cite 패널을 사용하여 BibTeX .bib 라이브러리를 로드하고, 인용 키(citation key), 저자(author), 제목(title), 연도(year), 출판 장소(publication venue), 또는 항목 유형(entry type)별로 검색한 후, 현재 커서 위치에 [@doe2024]와 같은 인용 참조를 삽입할 수 있습니다. 데스크톱 앱에서는 Select를 클릭하여 네이티브 파일 피커(native file picker)로 .bib 파일을 선택합니다. 브라우저 개발 모드에서는 동일한 버튼을 사용하여 선택된 .bib 파일을 로컬 백엔드에 업로드하고 활성 인용 라이브러리(active citation library)로 저장합니다.
Markdown Reader는 HTML, DOCX, PDF 출력 등 편집 및 내보내기 과정에서 인용 구문(citation syntax)을 유지합니다.
🤝 기여 (Contributing)
기여를 환영합니다! 버그 수정이든, 기능 제안이든, 문서 작성 도움이든 상관없이 저희와 함께해 주시면 감사하겠습니다.
시작하는 방법:
git checkout -b your-feature-branch
- 린팅(linting) 실행:
uv run ruff check .
- 테스트 실행:
uv run python -m unittest discover -s tests
- 풀 리퀘스트(Pull Request) 열기!
자세한 내용은 전체 Contribution Guidelines를 참고하세요.
<div align="center">
MIT 라이선스 하에 배포되었습니다. 자세한 내용은 <a href="LICENSE.md">LICENSE.md</a>를 참조하세요.
</div>