← 기술 블로그 목록으로 돌아가기
#942 • Markdown Governance & On-Device WebView2 Rendering Architecture

노션(Notion) 없는 교원 연구노트와 국방 마크다운 보안 거버넌스: ZeliNote의 Markdig 파이프라인과 WebView2 실시간 렌더링 아키텍처

"학교 시험 출제 원안이나 국방 무기체계 연구 일지가 외산 클라우드 협업 도구의 동기화 결함으로 소실되거나 해외 서버로 유출되는 참사를 어떻게 방어하십니까?" 무거운 일렉트론 에디터의 메모리 폭식과 계정 강제를 종식하는 Zero-Telemetry 온디바이스 마크다운 런타임, Markdig 기반의 초고속 네이티브 파싱과 WebView2 인프로세스 실시간 양방향 프리뷰(Mermaid 다이어그램·체크박스 역동기화), 가상 호스트 매핑(c.zelinote.local)을 통한 CORS 제약 없는 로컬 이미지 렌더링, LocalSettings 8KB 한계를 돌파하는 임시 파일(.tmp) ➔ Move 원자적(Atomic) 파일 교체 엔진, 3초 디바운스 자동 저장 및 세션 타이핑(WPM/글자수) 텔레메트리 아키텍처 백서.

"학교 내신 지필평가 출제 원안, 교원 연구 연수 보고서, 그리고 군 과학화 훈련 체계의 설계 문서는 최고 등급의 기밀성을 요구합니다. 하지만 많은 교사와 연구원들이 화려한 서식과 프리뷰 기능에 이끌려 노션(Notion)이나 옵시디언(Obsidian) 등의 도구에 비공개 원문을 입력합니다. 그 결과 인터넷이 차단된 망분리 출제실에서는 프로그램이 켜지지 않고, 원격 서버와 동기화되다 다른 기기에서 덮어쓰여 작성 중이던 50페이지 연구노트가 순식간에 백지화되는 참극이 발생합니다. ZeliNote는 외부 통신을 100% 차단한 상태에서, 네이티브 C#의 극한 성능과 WebView2의 미려한 렌더링을 결합하여 완벽한 온디바이스 문서 무결성을 수호합니다."

1. 교원 연구실과 국방 연구소의 마크다운 딜레마: "노션(Notion)에 쓴 시험 문제, 옵시디언 동기화로 날아간 연구노트"

마크다운(Markdown)은 서식이 깨지지 않고 장기 보존성이 뛰어난 표준 문서 포맷으로 교육계와 연구 기관에서 널리 활용되고 있습니다. 그러나 이를 다루는 소프트웨어 환경은 심각한 보안 및 안정성 취약점을 드러내고 있습니다:

2. 일렉트론(Electron) 에디터의 치명적 결함: "1GB 메모리 잠식, 폐쇄망 미지원, 클라우드 종속"

현존하는 대다수 모던 마크다운 에디터(Notion 데스크톱, Obsidian, Logseq 등)는 크로미움(Chromium) 브라우저를 내장한 일렉트론 프레임워크로 제작되었습니다:

  1. 과도한 RAM 및 CPU 자원 낭비: 단순 텍스트 파일을 열었음에도 6~8개의 백그라운드 렌더러 프로세스가 실행되어 기본 800MB~1.2GB의 메모리를 잠식합니다. 이는 8GB RAM의 교단 선진화 PC에서 심각한 버벅임을 초래합니다.
  2. 로컬 파일 시스템 접근의 보안 샌드박스 장벽: 웹 브라우저 기반 렌더러는 로컬 하드디스크의 절대 경로 이미지(C:\Images\chart.png)에 직접 접근하는 것을 CORS 정책으로 차단하므로, 로컬 삽입 이미지가 엑스박스(Broken Image)로 깨져 보입니다.
  3. 유료 플러그인과 비공개 동기화 요금: 팀 단위 문서 암호화나 안정적인 버전 관리를 위해 매달 사용자당 수만 원의 추가 구독을 요구합니다.
flowchart TD subgraph UI_INPUT["⌨️ WinUI 3 네이티브 에디터 레이어"] TXT["실시간 텍스트 스트림 (TxtEditor)"] TIMER["3초 디바운스 자동 저장 타이머"] TELEMETRY["세션 타이핑 텔레메트리 (글자수 / WPM / 시간)"] end subgraph ENGINE_CORE["⚙️ ZeliNote 온디바이스 렌더링 파이프라인"] MARKDIG["Markdig C# 인프로세스 파이프라인 (GFM + Tables + TaskList)"] CORS_MAP["가상 호스트 매핑
(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
▲ [그림 1] ZeliDesk ZeliNote의 Markdig 파이프라인, WebView2 실시간 증분 렌더링 및 원자적 영속화 구조

3. Markdig 네이티브 파이프라인: C# 인프로세스 컴파일과 무손실 HTML 변환 구조

자바스크립트 엔진에 의존하는 웹 기반 파서와 달리, ZeliNote는 .NET 환경에서 가장 빠르고 메모리 할당이 적은 Markdig 네이티브 파이프라인을 채택하였습니다.

GitHub Flavored Markdown(GFM), 고급 표(Tables), 할 일 체크박스(TaskLists), 수식 블록, 그리고 Mermaid 다이어그램까지 단 1ms의 딜레이 없이 순수 C# 메모리 내에서 HTML DOM 트리로 직접 컴파일합니다:

C# (RebuildMarkdownPipeline) ZeliNote/Views/ZeliNoteWindow.xaml.cs
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)를 비동기로 실행합니다:

JavaScript & C# (양방향 체크박스 동기화 인터페이스) ZeliNote/Views/ZeliNoteWindow.xaml.cs
// ── 프리뷰 화면의 체크박스를 클릭했을 때 호스트(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 { }
}
sequenceDiagram autonumber actor User as 교원 / 연구원 participant Editor as C# 텍스트 에디터 (TxtEditor) participant Core as Markdig 컴파일러 participant WV2 as WebView2 실시간 뷰 participant Host as CoreWebView2 Host Bridge User->>WV2: 프리뷰 화면의 체크박스 클릭 WV2->>Host: window.chrome.webview.postMessage({taskIndex, checked}) Host->>Editor: ToggleMarkdownTaskInEditor 호출 Editor->>Editor: 원문 텍스트 내 '- [ ]' ➔ '- [x]' 정규식 치환 Editor->>Core: 3초 디바운스 자동 저장 트리거 Editor->>WV2: 증분 innerHTML 갱신 (스크롤 위치 완벽 보존) Note over User,WV2: 마우스 클릭 한 번으로 원문과 프리뷰가 0초 동기화!
▲ [그림 2] WebView2와 C# 에디터 간의 양방향 할 일(Task) 체크박스 역동기화 시퀀스

5. SetVirtualHostNameToFolderMapping: CORS 보안 제약을 우회하는 로컬 이미지 가상화

웹 브라우저 보안 규정(Same-Origin Policy)상, 웹뷰 내에서 <img src="C:\Test\diagram.png">과 같은 로컬 파일 시스템의 절대 경로를 직접 호출하면 브라우저 보안 에러가 발생하며 이미지가 차단됩니다.

ZeliNote는 WebView2의 최고급 호스트 가상화 API인 SetVirtualHostNameToFolderMapping을 선제 구성하여, 각 드라이브(C~F)를 가상 로컬 호스트 네임(c.zelinote.local)으로 바인딩합니다:

6. LocalSettings 8KB 극복과 원자적 파일 교체(.tmp ➔ Move) 및 스냅샷 복구 엔진

Windows의 ApplicationData.Current.LocalSettings는 레지스트리 기반으로 동작하므로 데이터 크기가 8KB를 초과하면 저장이 거부되는 치명적 한계가 있습니다.

ZeliNote는 적응형 듀얼 스토리지 파이프라인을 구축하여, 노트 크기가 7,500바이트를 초과하는 순간 자동으로 ApplicationData.Current.LocalFolder 내의 파일 기반 영속화로 매끄럽게 전환합니다. 이때 전원 차단이나 충돌 시 파일 손상을 방지하기 위해 임시 파일(.tmp) 작성 후 Move 원자적 교체 기법을 엄격히 적용합니다:

C# (원자적 파일 교체 및 무결성 Round-Trip 검증) ZeliNote/Views/ZeliNoteWindow.xaml.cs
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는 실시간 헤딩 파서와 텔레메트리 엔진을 내장하고 있습니다:

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를 통해 대한민국 공교육과 국방 전산망은 가장 신뢰할 수 있는 디지털 지식 거버넌스를 확보하게 되었습니다.

← 이전 기술 백서 #943 공교육 교무행정과 군 연구실 태스크 유출 0초 차단: ZeliTodo의 온디바이스 로컬 태스크 거버넌스와 비동기 일정 영속화 아키텍처 다음 기술 백서 → #941 디지털교과서(AIDT) 수업 몰입과 수능·임용 실전 시뮬레이션: ZeliTimer의 100ms 델타 보정 타이머와 뽀모도로 세션 거버넌스 아키텍처
📝 ZeliDesk ZeliNote 온디바이스 마크다운 런타임 체험하기
Notion이나 Obsidian 없이 0초 만에 마크다운과 Mermaid 차트를 렌더링하고, 완전한 오프라인 문서 보안을 누리세요.
72종 유틸리티 전체 둘러보기 →