1. 교원 연구실과 국방 연구소의 마크다운 딜레마: "노션(Notion)에 쓴 시험 문제, 옵시디언 동기화로 날아간 연구노트"
마크다운(Markdown)은 서식이 깨지지 않고 장기 보존성이 뛰어난 표준 문서 포맷으로 교육계와 연구 기관에서 널리 활용되고 있습니다. 그러나 이를 다루는 소프트웨어 환경은 심각한 보안 및 안정성 취약점을 드러내고 있습니다:
- 클라우드 동기화에 따른 원안 유출 사고: 내신 지필평가 문항이나 학생부 종합전형 평가 기준표를 클라우드 기반 웹 메모장에 임시 작성하다 계정 해킹이나 공유 링크 실수로 외부로 누출되어 교육청 감사를 받는 사고가 끊이지 않습니다.
- 망분리(Air-Gap) 폐쇄망에서의 실행 불능: 수능 출제장, 임용고시 합숙소, 군 비밀 연구실 등 물리적으로 외부 인터넷이 단절된 환경에서는 클라우드 SaaS 에디터가 라이선스 인증 실패를 일으키며 실행 자체가 차단됩니다.
- 파일 잠금(Locking)과 비정상 종료 시 데이터 증발: 오픈소스 마크다운 에디터들이 단일 파일에 비동기 저장을 수행하다 PC가 갑자기 꺼지면 파일 크기가 0바이트(Null-fill)로 깨지는 데이터 파괴 현상이 발생합니다.
2. 일렉트론(Electron) 에디터의 치명적 결함: "1GB 메모리 잠식, 폐쇄망 미지원, 클라우드 종속"
현존하는 대다수 모던 마크다운 에디터(Notion 데스크톱, Obsidian, Logseq 등)는 크로미움(Chromium) 브라우저를 내장한 일렉트론 프레임워크로 제작되었습니다:
- 과도한 RAM 및 CPU 자원 낭비: 단순 텍스트 파일을 열었음에도 6~8개의 백그라운드 렌더러 프로세스가 실행되어 기본 800MB~1.2GB의 메모리를 잠식합니다. 이는 8GB RAM의 교단 선진화 PC에서 심각한 버벅임을 초래합니다.
- 로컬 파일 시스템 접근의 보안 샌드박스 장벽: 웹 브라우저 기반 렌더러는 로컬 하드디스크의 절대 경로 이미지(
C:\Images\chart.png)에 직접 접근하는 것을 CORS 정책으로 차단하므로, 로컬 삽입 이미지가 엑스박스(Broken Image)로 깨져 보입니다. - 유료 플러그인과 비공개 동기화 요금: 팀 단위 문서 암호화나 안정적인 버전 관리를 위해 매달 사용자당 수만 원의 추가 구독을 요구합니다.
(c.zelinote.local ➔ C:\)"] DIFF_DOM["WebView2 인프로세스 DOM 증분 주입
(ExecuteScriptAsync)"] end subgraph PREVIEW_LAYER["🖥️ Microsoft.Web.WebView2 실시간 렌더링"] RENDER["HTML 본문 + Syntax Highlighting (hljs)"] MERMAID["Mermaid 10.6 다이어그램 인프로세스 렌더링"] TASK_SYNC["체크박스 클릭 ➔ WebMessageReceived ➔ 원문 역동기화"] end subgraph STORAGE_LAYER["💾 8KB 한계 돌파 원자적 파일 교체 엔진"] CHECK{"데이터 크기 판별
(< 7.5KB vs > 7.5KB)"} LOCAL_SET["ApplicationData LocalSettings 직렬화"] ATOMIC_FILE["zelinote_data.tmp.json 쓰기 ➔ Move 원자적 교체"] BACKUP["손상 감지 시 최근 5개 타임스탬프 백업 자동 보존"] end TXT --> MARKDIG & TIMER & TELEMETRY MARKDIG --> CORS_MAP --> DIFF_DOM --> RENDER & MERMAID & TASK_SYNC TIMER --> CHECK CHECK -->|경량| LOCAL_SET CHECK -->|대용량| ATOMIC_FILE ATOMIC_FILE -.->|예외 발생 시| BACKUP
3. Markdig 네이티브 파이프라인: C# 인프로세스 컴파일과 무손실 HTML 변환 구조
자바스크립트 엔진에 의존하는 웹 기반 파서와 달리, ZeliNote는 .NET 환경에서 가장 빠르고 메모리 할당이 적은 Markdig 네이티브 파이프라인을 채택하였습니다.
GitHub Flavored Markdown(GFM), 고급 표(Tables), 할 일 체크박스(TaskLists), 수식 블록, 그리고 Mermaid 다이어그램까지 단 1ms의 딜레이 없이 순수 C# 메모리 내에서 HTML DOM 트리로 직접 컴파일합니다:
private void RebuildMarkdownPipeline()
{
var builder = new MarkdownPipelineBuilder()
.UseAutoLinks()
.UseTaskLists()
.UsePipeTables()
.UseGridTables()
.UseEmphasisExtras()
.UseListExtras()
.UseFootnotes()
.UseGenericAttributes(); // CSS 클래스 및 스타일 태그 확장 지원
_pipeline = builder.Build();
}
// ── 에디터 텍스트 변경 시 200ms 디바운스 후 고속 컴파일 ──
string htmlContent;
try
{
htmlContent = Markdig.Markdown.ToHtml(markdown, _pipeline);
// WebView2 보안 우회를 위해 로컬 드라이브 경로를 가상 매핑 도메인으로 변환
htmlContent = System.Text.RegularExpressions.Regex.Replace(
htmlContent,
@"src=""([a-zA-Z]):[\\/]([^""]+)""",
match => $"src=\"http://{match.Groups[1].Value.ToLower()}.zelinote.local/{match.Groups[2].Value.Replace("\\", "/")}\""
);
}
catch
{
htmlContent = "<pre>" + WebUtility.HtmlEncode(markdown) + "</pre>";
}
4. WebView2 인프로세스 DOM 증분 업데이트 & Mermaid·체크박스 양방향 동기화
일반적인 마크다운 미리보기 창은 글자 하나를 칠 때마다 전체 HTML 페이지를 새로고침(NavigateToString)합니다. 이 경우 화면이 하얗게 깜빡이며 스크롤 위치가 맨 위로 튀어버려 장문의 문서를 작성할 때 극심한 피로감을 줍니다.
ZeliNote는 인프로세스 DOM 증분 주입(Incremental DOM Injection) 기술을 적용하여, 초기 로드 후에는 스크립트를 통해 document.body.innerHTML만 교체합니다. 스크롤 위치를 1픽셀도 흔들리지 않고 유지하면서 Mermaid 차트 컴파일과 구문 강조(highlight.js)를 비동기로 실행합니다:
// ── 프리뷰 화면의 체크박스를 클릭했을 때 호스트(C#) 에디터 원문을 즉각 수정 ──
window.wireTasks = function() {
var boxes = document.querySelectorAll('input[type=checkbox]');
for (var i = 0; i < boxes.length; i++) {
(function(index) {
boxes[index].onclick = function(e) {
// 클릭된 체크박스의 순번을 C# WebView2 수신기로 전송
window.chrome.webview.postMessage({
type: 'taskToggle',
index: index,
checked: this.checked
});
};
})(i);
}
};
// ── C# 호스트 수신부 (WebMessageReceived) ──
private void Preview_WebMessageReceived(object sender, CoreWebView2WebMessageReceivedEventArgs e)
{
try
{
using var doc = JsonDocument.Parse(e.WebMessageAsJson);
var root = doc.RootElement;
if (root.GetProperty("type").GetString() == "taskToggle")
{
int taskIndex = root.GetProperty("index").GetInt32();
bool isChecked = root.GetProperty("checked").GetBoolean();
// 에디터 본문 텍스트 내 taskIndex번째 '- [ ]' ➔ '- [x]'로 양방향 원자적 치환!
ToggleMarkdownTaskInEditor(taskIndex, isChecked);
}
}
catch { }
}
5. SetVirtualHostNameToFolderMapping: CORS 보안 제약을 우회하는 로컬 이미지 가상화
웹 브라우저 보안 규정(Same-Origin Policy)상, 웹뷰 내에서 <img src="C:\Test\diagram.png">과 같은 로컬 파일 시스템의 절대 경로를 직접 호출하면 브라우저 보안 에러가 발생하며 이미지가 차단됩니다.
ZeliNote는 WebView2의 최고급 호스트 가상화 API인 SetVirtualHostNameToFolderMapping을 선제 구성하여, 각 드라이브(C~F)를 가상 로컬 호스트 네임(c.zelinote.local)으로 바인딩합니다:
- 가상 도메인 바인딩:
C:\드라이브 ➔http://c.zelinote.local/가상 호스트로 내부 매핑. - 자동 URL 정규화: 사용자가 마크다운에
를 입력하면 파서가 이를http://c.zelinote.local/.../model.png로 실시간 치환. - 완전한 오프라인 렌더링: 외부 웹 서버를 띄우지 않고 운영체제 파일 I/O 레벨에서 가상 호스트 스트림을 제공하므로 폐쇄망에서도 로컬 캡처 이미지와 다이어그램이 100% 정상 표시됩니다.
6. LocalSettings 8KB 극복과 원자적 파일 교체(.tmp ➔ Move) 및 스냅샷 복구 엔진
Windows의 ApplicationData.Current.LocalSettings는 레지스트리 기반으로 동작하므로 데이터 크기가 8KB를 초과하면 저장이 거부되는 치명적 한계가 있습니다.
ZeliNote는 적응형 듀얼 스토리지 파이프라인을 구축하여, 노트 크기가 7,500바이트를 초과하는 순간 자동으로 ApplicationData.Current.LocalFolder 내의 파일 기반 영속화로 매끄럽게 전환합니다. 이때 전원 차단이나 충돌 시 파일 손상을 방지하기 위해 임시 파일(.tmp) 작성 후 Move 원자적 교체 기법을 엄격히 적용합니다:
private void SaveNotes()
{
try
{
var settings = ApplicationData.Current.LocalSettings;
string json = JsonSerializer.Serialize(_notes);
// 저장 직전 무결성 검증: 직렬화된 JSON을 다시 디코딩하여 건수 대조
var roundTrip = JsonSerializer.Deserialize<List<NoteEntry>>(json);
if (roundTrip == null || roundTrip.Count != _notes.Count)
throw new InvalidOperationException("무결성 대조 실패: 원본과 직렬화 개수 불일치");
if (json.Length > 7500)
{
// 8KB 초과 시 파일 기반 원자적 저장소로 자동 승격
SaveNotesToFileSync(json);
settings.Values.Remove("ZeliNote_Notes"); // 레지스트리 비우기
}
else
{
settings.Values["ZeliNote_Notes"] = json;
CleanupNoteFile(); // 고스트 파일 방지
}
}
catch (Exception ex)
{
TxtStatus.Text = $"⚠ 저장 실패: {ex.Message}";
}
}
private void SaveNotesToFileSync(string json)
{
var folder = ApplicationData.Current.LocalFolder;
string targetPath = Path.Combine(folder.Path, "zelinote_data.json");
string tempPath = Path.Combine(folder.Path, "zelinote_data.tmp.json");
// 1단계: 임시 파일에 먼저 완벽히 기록
File.WriteAllText(tempPath, json);
// 2단계: OS 파일시스템 커널의 Move(원자적 교체)로 타겟 파일 교체 ➔ 쓰기 도중 정전돼도 원본 보존!
File.Move(tempPath, targetPath, true);
}
7. 동적 목차(TOC) 트리 앵커링 및 세션 타이핑 텔레메트리(WPM/글자수)
단순 텍스트 편집을 넘어 전문 학술 논문 및 교안 작성을 지원하기 위해, ZeliNote는 실시간 헤딩 파서와 텔레메트리 엔진을 내장하고 있습니다:
- 헤딩 정규식 파싱 및 동적 TOC 트리: 본문 내의
#,##,###헤더를 200ms 단위로 파싱하여 우측 사이드바에TOC(목차)를 자동 렌더링합니다. 항목을 클릭하면 에디터 캐럿과 스크롤이 해당 헤딩 라인으로 0초 이동합니다. - 타이핑 속도 및 생산성 텔레메트리: 타이핑 입력 이벤트를 감지하여 세션 내 작성 글자 수, 타이핑 시간, 그리고 분당 타자수(WPM, Words Per Minute)를 실시간으로 계측하여 교원의 집필 리듬을 보조합니다.
- 세션 스냅샷 자동 백업: 앱이 구동될 때 직전 세션의 모든 노트를
zelinote_session_snapshot.json으로 백업하여, 사용자가 본문을 실수로 전체 선택 후 삭제했더라도 단 1초 만에 복원할 수 있습니다.
8. 마크다운 편집기 4대 솔루션 비교 (Notion vs Obsidian vs Typora vs ZeliNote)
| 비교 항목 | 노션 (Notion) | 옵시디언 (Obsidian) | 타이포라 (Typora) | ZeliDesk ZeliNote 온디바이스 |
|---|---|---|---|---|
| 데이터 소유권 및 저장 위치 | 해외 퍼블릭 클라우드 전송 | 로컬 파일 (동기화 유료) | 로컬 파일 | 완전 격리 로컬 OS 샌드박스 + 원자적 쓰기 |
| 망분리 / 오프라인 지원 | 불가 (로그인 필수) | 지원 (단, 플러그인 제한) | 지원 | 100% 완전 오프라인 Zero-Telemetry |
| 런타임 아키텍처 | 일렉트론 (Chrome 엔진) | 일렉트론 (Chrome 엔진) | 일렉트론 (Chrome 엔진) | 순수 C# Markdig + WebView2 인프로세스 |
| 메모리 점유율 (RAM) | 800MB ~ 1.5GB | 500MB ~ 900MB | 300MB ~ 600MB | 유휴 시 35MB / 렌더링 시 80MB 이하 |
| 로컬 절대경로 이미지 | 불가 (클라우드 업로드) | 상대 경로 제한적 | 지원 | VirtualHostMapping 가상 호스트 무손실 |
| 체크박스 양방향 동기화 | 단방향 블록 방식 | 뷰 모드 한정 | 라이브 프리뷰 | WebView2 ➔ C# 원문 정규식 역동기화 |
| 라이선스 및 도입 비용 | 월 구독료 발생 | 상업적 이용 시 연간 $50 | 단일 구매 유료 | 전국 공교육·국방·공공 전산실 무상 |
9. 결론: "외부 유출 걱정 없는 공교육·국방 표준 온디바이스 연구노트 생태계"
선생님의 교육 연구와 국방 연구원의 기술 개발은 조직의 미래를 만드는 가장 가치 있는 지적 자산입니다. 이 귀중한 기록이 클라우드 서버의 장애로 사라지거나, 상용 플랫폼의 라이선스 단속에 휘말리거나, 외부로 유출되어 보안 감사의 대상이 되어서는 안 됩니다.
ZeliDesk의 ZeliNote는 네트워크가 완전히 단절된 시험 출제실에서도, 최고 등급 보안이 요구되는 국방 사령부에서도, 사용자가 키보드를 두드리는 순간 가장 빠르고 안전하게 문서를 보호합니다. 가볍고 빠른 네이티브 C#과 WebView2 기술이 완성한 ZeliNote를 통해 대한민국 공교육과 국방 전산망은 가장 신뢰할 수 있는 디지털 지식 거버넌스를 확보하게 되었습니다.