Cloudwiki

Claude 보고서/기능 제안/Mermaid 다이어그램

[[Claude 보고서/기능 제안]] 의 *Mermaid 다이어그램* 항목 심화 분석입니다. 기능 상세와 함께, **코드펜스를 코드 전용으로 유지하기 위해 `:::` 블록 문법으로 대체 가능한지**를 검토합니다.

## 무엇이 추가되나

텍스트 DSL 로 다이어그램을 그리는 라이브러리입니다. 지원 범위가 넓습니다.

| 분류 | 다이어그램 |
| --- | --- |
| 흐름/관계 | flowchart, sequenceDiagram, classDiagram, stateDiagram, erDiagram, C4 |
| 일정/계획 | gantt, timeline, journey |
| 데이터 | pie, quadrantChart, sankey |
| 기타 | gitGraph, mindmap, requirementDiagram |

팁: 위키에서의 가치
아키텍처도 · ACL 권한 흐름 · MCP draft→승인 워크플로우 · DB 스키마(ER) · 릴리즈 타임라인을 **본문 안에서 텍스트로 버전 관리**할 수 있습니다. 현재는 외부에서 이미지로 만들어 R2 에 올려야 하므로 diff·검색·편집이 불가능합니다.


## 렌더 파이프라인 (현 구조 기준 구현안)


1. 렌더 진입점
`src/client/render.ts`(marked + DOMPurify 코어)에서 `walkTokens`/커스텀 렌더러로 다이어그램 블록을 잡아 placeholder `<div class="mermaid-figure" data-src="...">` 로 치환 → 렌더 후 `mermaid.run()` 으로 SVG 생성.

2. 지연 로드
Mermaid 는 수백 KB 로 무거움. **문서에 다이어그램 블록이 있을 때만** esm.sh 에서 동적 import (CodeMirror importmap 지연 로드 패턴과 동일). 다이어그램 없는 문서는 비용 0.

3. 테마 동기화
`data-theme`(light/dark)에 맞춰 Mermaid `themeVariables` 를 `--wiki-primary` 등 CSS 변수와 매핑. 테마 토글 시 재렌더.

4. 보안
`securityLevel: 'strict'` + 생성 SVG 를 **DOMPurify** 로 재정화(기존 정책 일관성). XSS 차단.

5. 에러·접근성
잘못된 다이어그램은 페이지를 깨지 않고 인라인 에러 박스로. `accTitle`/`accDescr` + `role="img"`/`aria-label`.



노트: 선택적 고도화 (SSR 사전렌더)
SEO·no-JS 가 필요하면 저장 시 Browser Rendering 으로 SVG 를 미리 만들어 R2 에 캐시 → 본문에 인라인. MVP 는 클라이언트 렌더로 충분. → [[Claude 보고서/외부 서비스 연동]] 의 Browser Rendering 연계.


## 검토: `:::` 블록 vs 코드펜스

의도("코드펜스를 코드 전용으로 유지")는 타당하지만, **Mermaid 에 한해서는 코드펜스 방식이 기술적으로 우월**합니다. 핵심은 *토큰 충돌* 입니다.

### `:::mermaid` 가 위험한 이유

`:::card`·`:::callout` 같은 블록 디렉티브의 **본문은 위키 인라인 문법이 그대로 처리**됩니다(`{br}`·`{bg:}`·`[[링크]]`·`==강조==` 동작). 그런데 Mermaid DSL 은 이 토큰들과 정면 충돌합니다.

| Mermaid 문법 | Cloudwiki 에서의 오작동 |
| --- | --- |
| `C{결정?}` (마름모 노드) | `{...}` → `{bg:}`/컴포넌트 토큰으로 오인 |
| `A -->|예| B` (엣지 라벨) | `|예|` → 표/토큰 파싱 간섭 |
| `A ==> B` (굵은 화살표) | `==...==` → 형광펜 강조와 충돌 |
| `A ~~~ B` (투명 링크) | `~~...~~` → 취소선과 충돌 |
| 라벨 내 `*`, `_` | 굵게/기울임으로 변형 |
| `A:::className` (Mermaid 클래스) | `:::` 시퀀스 의미 중첩 |

즉 `:::mermaid` 로 가면 **본문 인라인 처리를 통째로 끄는 verbatim 모드를 새로 구현**해야 하는데, 그건 **코드펜스가 이미 공짜로 제공하는 동작**입니다. (문법 가이드: "코드 블록 내부에 들어간 모든 내용은 위키 문법으로 작동하지 않습니다.")

### "코드펜스 = 코드 전용" 우려에 대한 답

우려는 *문법 선택* 이 아니라 *구현* 으로 해소됩니다.

- 펜스는 **"원문 그대로 캡처" 구분자**일 뿐이고, 렌더러는 언어 태그가 `mermaid` 면 **Prism 보다 먼저 분기**시킵니다. → Mermaid 블록은 **Prism(코드 하이라이트)에 도달하지 않습니다.** 하이라이팅 경로는 깨끗하게 유지됩니다.
- 출력도 `<pre><code>` 가 아니라 `<figure>`(다이어그램)로 렌더 → 화면상 "코드 블록" 으로 보이지도 않음.
- ` FENCED_CODE_0mermaid ` 코드펜스로 유지**하고, 렌더러에서 언어 태그로 조기 분기해 Prism 이 아닌 Mermaid 경로로 보냅니다. 출력은 `<figure>`. → "코드펜스는 코드 전용" 정신은 *구현 분기* 로 충족되고, 충돌 문제는 펜스의 verbatim 특성으로 자동 해결됩니다.


`:::` 패밀리와의 시각적 일관성을 정말 원한다면, 차선으로 **`:::mermaid` 를 "verbatim 전용 블록"(본문 원문 캡처, 인라인 처리 0)으로 한정 도입하는 별칭** 정도가 안전합니다. 단 펜스 동작의 재구현이라 비용 대비 이득이 적고 비표준입니다. → **펜스 1순위, `:::mermaid` 별칭은 선택.**

정보: 동일 논리: 수식
같은 충돌·해법 논리가 **KaTeX 수식**에도 적용됩니다 — `$$...$$` 또는 ` ```math ` 가 토큰 충돌을 피합니다. 다이어그램·수식 모두 "verbatim 캡처가 필요한 비텍스트 블록" 이라는 같은 부류입니다.