# 코드·표·다이어그램·이미지 본문(`bodyMarkdown`)에만 해당한다. 본문이 있는 종류는 Case·Concept·Setup 셋이다. ## 코드블록 ````text ```java @Query("select fi from FeedItem fi join fetch fi.user") List findFeed(Pageable pageable); ``` ```` 언어는 `^[A-Za-z0-9][A-Za-z0-9_.+-]*$`만 쓴다 — `java`, `kotlin`, `sql`, `yaml`, `bash`, `text`. 언어를 모르면 `text`. 설명을 붙이려면 `label` 하나만 쓴다. 다른 속성은 거절된다. ````text ```sql label="N+1이 발생하는 조회" SELECT * FROM highlights WHERE feed_item_id = ?; ``` ```` **코드에 자격증명·토큰·내부 호스트를 남기지 않는다.** 지울 때는 지웠다는 사실이 보이게 한다 — `Authorization: Bearer <생략>`처럼. 조용히 빼면 다음 사람이 그 헤더가 없었다고 읽는다. 붙여넣은 코드는 원문 그대로 둔다. 줄바꿈과 들여쓰기를 손보면 재현이 달라진다. ## 표 파이프로 그냥 쓴다. **감싸지 않는다.** ```text | N | 초기화 컬렉션 | 총 쿼리 | |---|---|---| | 10 | 10 | 25 | | 100 | 100 | 222 | | 1,000 | 1,000 | 2,022 | ``` 설명이나 행 머리글이 필요할 때만 `:::table`로 감싼다. 세 속성이 전부 있어야 한다. ```text :::table id="direct-measurement" caption="N별 직접 측정값" rowHeaderColumn="1" | N | 초기화 컬렉션 | 총 쿼리 | |---|---|---| | 10 | 10 | 25 | ::: ``` - `id` — 문서 안에서 유일해야 한다. 제목 id와도 겹치면 안 된다 - `rowHeaderColumn` — `"1"`이면 첫 열이 행 머리글, 아니면 `"none"` - 정렬은 구분줄로 준다: `|---:|` 오른쪽, `|:---:|` 가운데 **측정값과 파생값을 한 표에 섞지 않는다.** 섞어야 한다면 성격 열을 두어 어느 것이 잰 값이고 어느 것이 계산한 값인지 밝힌다. ### 머리글이 질문이면 행이 답이 된다 열 이름을 명사로 두면 독자가 표를 훑는다. 질문으로 두면 읽고 답을 얻는다. | 쓰지 않는다 | 쓴다 | |---|---| | `memory-only가 줄이는가` | `memory-only가 위험을 막아주나..?` | | `남는 데이터` · `reload 뒤` | `reload 전` · `reload 후` | | `확인함` · `확인 안 함` | `o` · `x` | 비교 표의 축은 **시점이나 상태**로 못 박는다. `전`·`후`, `켬`·`끔`처럼 어느 때의 값인지 열 이름이 말해야 한다. `남는 데이터` 같은 두루뭉술한 이름을 쓰면 그 열이 언제 얘긴지 본문을 다시 봐야 한다. 있음·없음을 가르는 열은 `o`·`x`로 채운다. 열이 좁아지고 값이 눈에 띄게 갈린다. 문장 안이 아니라 값 자리에서만 쓴다. **열을 줄인다.** 감싸개가 `--body-copy`(672px)에 묶여 있고 표에는 `min-width: 780px`이 걸려 있어서, 열이 몇 개든 오른쪽 108px은 늘 잘린다. 3열을 2열로 줄일 수 있으면 줄이고, 첫 열 문구를 짧게 해서 값 열을 왼쪽으로 당긴다. ```text 3열 2열로 | 방어선 | 무엇을 막나 | 뚫리면 | → | 위치 | 여기서 어떻게 막지? | ``` 세 번째 열에 있던 내용은 표 다음 문단에서 이어 쓴다. ## 다이어그램·SVG ### 그림에 문장을 넣지 않는다 가장 흔한 실패다. 설명을 그림 안으로 밀어 넣으면 라벨이 길어지고, 글자는 작아지고, 검색도 복사도 화면 낭독도 안 되는 텍스트가 된다. 그림은 **관계**를 보이고 문장은 그 옆 문단에 쓴다. 지킬 선: | 항목 | 기준 | |---|---| | 상자 | 7개 이하. 넘으면 그림을 나눈다 | | 라벨 | 한 줄 40자 이하. 문장이 아니라 이름 | | 글자 크기 | 2종 (제목·보조). 3종부터는 위계가 아니라 소음이다 | | 색 | 의미를 색에만 싣지 않는다. 빗금·테두리·위치를 함께 쓴다 | | 화살표 | 방향이 논지일 때만. 장식으로 긋지 않는다 | | 숫자 | 넣지 않는다. 산문에 쓴다 | 빨강·초록 조합은 피한다. 색각 이상에서 구분되지 않는다. **자가 점검.** 올리기 전에 ``를 전부 뽑아 읽는다. ```bash grep -o ']*>[^<]*' 그림.svg ``` 하나라도 아래에 걸리면 문장이므로 뺀다. 길이가 아니라 **서술하느냐**가 기준이다 — 40자 이하여도 문장은 문장이다. - 마침표나 물음표로 끝난다 - 서술어가 있다 — `~있다`, `~막는다`, `~바꿔도` - 조사로 두 대상을 잇는다 — `A를 B로`, `A에서 B까지` `세 가지가 한 영역 안에 있다`는 그림이 이미 보여 주는 것을 글로 다시 쓴 것이다. 상자를 한 영역 안에 그렸으면 그 문장은 필요 없다. 지우면 그림이 더 명확해진다. ``과 `<desc>`는 예외다. 화면을 못 보는 사람이 듣는 자리이므로 여기에는 문장을 쓴다. 그림 안에서 뺀 설명이 갈 곳이기도 하다. ### 무엇을 그릴지 정하는 법 그림 하나에 주장 하나다. "이 그림이 없으면 독자가 무엇을 못 보나"에 한 문장으로 답할 수 없으면 그리지 않는다. 표로 되는 것을 그림으로 그리지 않는다 — 표는 값을 비교하고, 그림은 **포함·순서·경계**처럼 자리로만 보이는 것을 맡는다. Studio는 다이어그램을 그려 주지 않는다. **파일로 만들어 Asset으로 올린다.** 1. `본문에 Asset 삽입` → `업로드 종류`를 **다이어그램**으로 → `Asset 업로드` 2. 목록에서 고르면 커서 자리에 `:::evidence` 구문이 삽입된다 SVG는 `image/svg+xml`로 올라가고 다른 이미지와 같게 다뤄진다. 벡터라 확대해도 깨지지 않으니 구조도·흐름도에 맞다. 올리기 전에 SVG에서 지울 것: - `<script>` 요소와 `on*` 속성 - 외부 폰트·이미지 참조 — 열람자 환경에서 안 불러온다. 글자는 path로 변환하거나 일반 폰트만 - 절대 좌표에 의존하는 고정 크기 — `viewBox`를 두어 늘어나게 한다 ## 증거 이미지 ```text :::evidence key="asset-key" alt="무엇을 보여 주는 그림인가" caption="설명" zoom="true" ::: ``` - 네 속성이 전부 있어야 한다. 본문은 비운다 - `key`는 `^[a-z0-9]+(?:-[a-z0-9]+)*$` - `zoom="true"`면 눌러서 확대할 수 있다. 표·로그처럼 글자가 작으면 켠다 - `alt`는 화면을 못 보는 사람이 읽는 문장이다. "스크린샷"이 아니라 **무엇이 보이는지** 쓴다 - 장식용 그림은 Asset의 `decorative`를 켜고 `alt`를 비운다 `READY`가 아닌 Asset은 게시 시 거절된다. ### 저장소의 `.md` 에는 `:::evidence` 를 쓰지 않는다 `:::evidence`는 Studio 렌더러의 구문이다. 저장소의 `.md`를 그 형태로 쓰면 편집기에서 그림이 보이지 않고 구문이 글자로 남는다. **저장소는 읽는 형태로 쓴다.** ```markdown ![브라우저 SPA, Keycloak, Resource Server 사이에서 …](../../../final/assets/ap1-browser-bearer-flow/ap1-browser-bearer-flow.svg) ``` `alt`는 그림의 `alt`를 그대로 쓰고, 경로는 frontmatter `assets`의 `file`과 같아야 한다. Studio 로 보낼 때만 `:::evidence` 로 바꾼다. 손으로 고치지 않는다. ```bash python3 scripts/studio-body.py <기록.md> -o /tmp/x.md # check_body 는 이 파일에 돌린다 python3 scripts/studio-body.py <기록.md> --body-only # Studio 에 붙여넣을 본문 python3 scripts/studio-body.py <기록.md> --key a=a-1a2b3c4d # 서버가 준 키로 ``` Studio 파서는 상대 경로 이미지를 `unsafe image URL`로 거절하므로 `check_body.mjs`는 **바꾼 파일**에 돌린다. 저장소 파일에 그대로 돌리면 그림 자리에서 실패한다. ## 일반 이미지 Asset이 아닌 그림은 Markdown으로 쓴다. ```text ![요청 흐름 네 단계](/api/v1/public/media/72f1f9c6-6fc1-4b57-9297-808d026f5fb9) ``` **문단 하나가 그림 하나로만 이루어져야** 그림으로 인식된다. 글과 섞으면 인라인 이미지가 되어 거절된다. 설명이 필요하면 Markdown title을 쓰지 말고 — 거절된다 — `:::evidence`의 `caption`을 쓰거나 그림 다음 문단에 쓴다. ## 무엇을 어디에 쓰나 | 담을 것 | 쓸 것 | |---|---| | 명령어·설정·소스 | 코드블록 | | 숫자 비교 | 표 | | 구조·흐름 | SVG 다이어그램 Asset | | 화면·로그 캡처 | 이미지 Asset + `zoom="true"` | | 놓치면 안 되는 단서 | `:::warning` | | 곁가지 설명 | `:::note` | 캡처로 표를 대신하지 않는다. 그림 속 숫자는 검색도 복사도 안 되고 화면 낭독기가 읽지 못한다.