나는 소프트웨어 엔지니어는 아니지만, 서버 없이 오프라인 라이선스로 Obsidian 플러그인을 출시했습니다
요약
코딩 지식이 없는 비엔지니어가 AI를 활용해 서버 없이 작동하는 Obsidian 플러그인을 개발하고 출시한 사례를 소개합니다. 데이터 프라이버시를 위해 서버와 데이터베이스를 배제하고, BYOK 방식과 Ed25519 오프라인 서명 검증을 통해 라이선스를 관리하는 독특한 아키텍처를 설명합니다.
핵심 포인트
- AI를 활용하여 비엔지니어도 상업용 소프트웨어 구축 가능
- 서버와 DB 없이 로컬 기기에서만 실행되는 제로 운영 모델 채택
- BYOK(Bring Your Own Key) 방식을 통한 사용자 데이터 프라이버시 보호
- Ed25519 암호화 기술을 이용한 오프라인 라이선스 검증 구현
저는 교육받은 엔지니어이지만, 소프트웨어 엔지니어는 아닙니다. 코딩 배경 지식도 없습니다. 지난 몇 달 동안 저는 전적으로 AI의 도움을 받아 작은 상업용 도구들을 구축하고 출시해 왔으며, 가장 최근의 결과물은 Obsidian 플러그인입니다. 저는 이 과정에서 내린 결정들을 기록하고 싶은데, 그중 몇 가지는 대부분의 유료 AI 플러그인이 구축되는 방식과는 상반되기 때문입니다.
내가 해결하고자 했던 문제
읽기(Reading) 및 개인 지식 관리(PKM) 커뮤니티 전반에서 동일한 불만을 계속 보게 되었습니다. 사람들은 Readwise, Snipd 또는 Kindle에서 수백 개의 하이라이트(highlights)를 자신의 보관함(vault)으로 동기화하지만, 그 폴더를 다시는 열어보지 않습니다. 하이라이트들은 무덤처럼 쌓여만 갑니다. 저장하는 데 들인 노력은 소모되었지만, 아무것도 결과물로 나오지 않습니다.
저 자신은 하이라이트를 많이 만드는 편이 아닙니다. 저는 개인적인 방대한 노트 더미가 아니라 조사를 통해 이 고통을 발견했습니다. 이 차이점은 저에게 중요하기 때문에, 개인적인 탄생 설화를 지어내기보다 솔직하게 밝힙니다.
이 플러그인은 폴더 전체를 읽고 하나의 종합 노트(synthesis note)를 작성합니다. 즉, 소스별 요약, 핵심 주장, 주제 목록을 작성한 뒤, 하나 이상의 소스에서 반복되는 테마와 소스들이 일치하는 부분 및 서로 다른 부분을 정리합니다.
결정 1: 서버를 전혀 사용하지 않음
제가 살펴본 대부분의 유료 AI Obsidian 플러그인들은 백엔드(backend)를 통해 구독을 검증합니다. 전형적인 방식은 Cloudflare Worker를 실행하여 클라우드에서 라이선스를 확인하고 매달 비용을 청구하는 것입니다. 이는 합리적인 비즈니스 모델이지만, 저에게는 운영해야 할 서버, 데이터베이스, 반복적인 비용, 그리고 사용자 데이터가 흐를 수 있는 장소를 의미합니다.
저는 반대 방향을 선택했습니다. 서버 제로, 데이터베이스 제로, 반복 비용 제로입니다. 플러그인은 전적으로 사용자의 기기에서 실행됩니다. 제가 운영해야 할 것도 없고, 제 측에서 유출될 데이터도 없습니다.
결정 2: 사용자의 키 직접 사용 (BYOK, Bring Your Own Key)
이 플러그인은 사용자가 선택한 어떤 제공업체(Anthropic, OpenAI, OpenRouter 또는 모든 OpenAI 호환 엔드포인트)에 대해서도 사용자의 자체 API 키를 사용합니다. 저는 사용자의 키를 절대 볼 수 없으며, 사용자의 요청을 프록시(proxy)하지도 않습니다.
과장하기 쉬운 부분이라 명확히 짚고 넘어가고 싶은 정직한 포인트가 하나 있습니다. BYOK (Bring Your Own Key)가 데이터가 기기에 머문다는 것을 의미하지는 않습니다. 하이라이트를 합성하기 위해, 플러그인은 사용자가 설정한 모델 제공자(model provider)로 하이라이트 텍스트를 전송합니다. 따라서 정확한 개인정보 보호 주장은 "내 쪽에는 서버도, 계정도, 백엔드 데이터 수집도 없다"이지, "당신의 노트가 기기를 절대 떠나지 않는다"가 아닙니다. 호스팅된 모델을 호출하는 모든 BYOK 도구에 대해 두 번째 주장은 사실이 아니기에, 저는 그 주장을 거부합니다.
결정 3: Ed25519를 이용한 오프라인 라이선스 검증
서버가 없다면 Pro 라이선스를 어떻게 판매할까요? 저는 오프라인 서명 검증 (offline signature verification)을 사용했습니다. 각 플러그인은 자체적인 Ed25519 키 쌍 (keypair)을 가집니다. 개인 키 (private key)는 오직 저의 비밀번호 관리자 (password manager)에만 존재합니다. 공개 키 (public key)는 플러그인에 내장되어 있습니다. 라이선스 키는 제품 ID, 이메일, 발행일, 그리고 분리된 서명 (detached signature)이 포함된 작은 서명된 페이로드 (signed payload)입니다.
검증은 tweetnacl을 사용하여 완전히 오프라인으로 이루어집니다:
import nacl from "tweetnacl";
// 플러그인에 내장된 publicKey, 라이선스 키에서 디코딩된 payloadBytes + signature
...
검증이 완료되고 제품 ID가 일치하면 Pro 기능이 활성화됩니다. 네트워크 호출도, 폰 홈 (phone-home)도 없으며, 비행기 안에서도 작동합니다. 이를 시도하려는 분들을 위한 참고 사항: 저의 경우 Obsidian의 Electron 환경에서 @noble/ed25519는 작동하지 않았지만, tweetnacl은 작동했습니다.
무료 티어는 월간 초기화가 아닌 평생 제한입니다
무료 티어는 매월 3회가 아니라, 설치 후 평생 동안 총 3회의 동기화 (syncs)를 허용합니다. 월간 초기화 방식은 사람들이 카운터가 초기화될 때까지 기다렸다가 유료로 전환하지 않게 만듭니다. 평생 제한 방식은 실제적인 결정 지점을 만들어냅니다. 이미 동기화된 하이라이트로부터 보고서를 생성하는 것은 영원히 무료로 유지됩니다.
소프트웨어 엔지니어가 아니면서 이를 구축하는 것에 대하여
전체 코드는 TypeScript로 작성되었으며, 저는 본질적으로 직접 손으로 작성한 코드가 거의 없습니다. Claude가 코드를 작성했고, 저는 제품 및 아키텍처 (Architecture) 결정을 내렸으며, Obsidian 내에서 모든 단계를 테스트하고, 무언가 잘못되었을 때 수정을 요구했습니다. 파싱 (Parsing) 과정은 의도적으로 방어적 (Defensive)으로 설계되었습니다. 왜냐하면 하이라이트 내보내기 방식이 사람들의 템플릿마다 매우 다양하기 때문입니다. 콜아웃 블록 (Callout blocks), 헤딩+불렛 (Heading-plus-bullet), 블록 ID (Block ids), 또는 일반 텍스트 (Plain text)를 모두 읽어야 하며, 마커가 발견되지 않을 경우를 대비해 전체 본문으로 전환되는 폴백 (Fallback) 메커니즘을 갖추고 있습니다.
현재 Obsidian 커뮤니티 플러그인 디렉토리에 등록되어 있습니다. 만약 여러분도 이와 같은 하이라이트 백로그 (Backlog)를 가지고 있다면, 현재 이를 어떻게 처리하고 계신지(수동으로, Dataview 쿼리를 사용하여, 혹은 아예 처리하지 않고 계신지) 진심으로 듣고 싶습니다.
GitHub: https://github.com/ibrh96-prog/obsidian-highlights-synthesizer
Obsidian directory: https://community.obsidian.md/plugins/highlight-inbox-synthesizer
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기