chore: 이전 세션이 남긴 변경을 커밋한다
이번 파이프라인 작업과 무관하게 작업 트리에 남아 있던 것을 그대로 올린다. 사용자가 「전부 커밋」으로 정했고, 이번 작업과 섞이지 않게 커밋만 나눴다. 대부분은 clean-architecture-backend-template 의 그림 정본 재배치다 — final/assets/diagrams/<이름>/ 에 있던 것이 CLAUDE.md 가 적은 배치인 final/assets/<이름>/ 로 옮겨졌고 .techviz/<이름>/ 이 함께 들어왔다. 삽입 줄의 대부분(3.15M)이 그 .techviz context.json 이다. 그 밖에 ca-tmpl·document-haness 의 정리, .claude/agents/ 열한 개, writing-practitioner-guides 스킬, .playwright-mcp 세션 산출물, scripts/check-ssot-facts.py 와 그 시험이 들어 있다. 이 커밋의 내용은 내가 만든 것이 아니라 이전 세션이 남긴 것이고 검증하지 않았다. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
2109f726fe
commit
ab59130196
@@ -93,5 +93,24 @@ mailto:…
|
||||
| `list items must contain exactly one paragraph` | 목록을 중첩했다 |
|
||||
| `unsafe link URL: …` | 허용되지 않는 스킴이나 `//` 주소 |
|
||||
| `duplicate explicit ID: …` | 같은 id를 두 번 썼다 |
|
||||
| `unknown inline directive: 27` | **문단에 시각을 그냥 썼다** — 아래를 본다 |
|
||||
|
||||
거절 메시지에는 줄·칸 번호가 붙는다. 그 줄을 먼저 본다.
|
||||
|
||||
## 문단 안의 시각은 백틱으로 감싼다
|
||||
|
||||
`:` 뒤에 글자가 붙으면 파서가 인라인 directive 로 읽는다. 그래서 문단에 `08:20:27` 을
|
||||
그냥 쓰면 `:27` 에서 막힌다. `00/12:00:00` 같은 설정값도 같다.
|
||||
|
||||
```text
|
||||
새 인증서가 08:20:27 에 기록됐다. ← FAIL unknown inline directive: 27
|
||||
새 인증서가 `08:20:27` 에 기록됐다. ← PASS
|
||||
```
|
||||
|
||||
**이것이 조용한 결함이 되는 경로가 있다.** 막히면 시각을 빼고 넘어가게 되고, 그러면
|
||||
검사기는 통과하는데 **기록에서 수치가 사라진다.** 실제로 한 회차에서 두 편이 각각
|
||||
시각 둘과 타이머 설정값을 빼고 통과시켰다. 수치·날짜·시각은 보호 구간이다 —
|
||||
**빼지 말고 감싼다.**
|
||||
|
||||
표와 코드블록 안은 걸리지 않는다. 그래서 같은 프로젝트의 다른 기록이 통과하는 것이
|
||||
「이 문법이 괜찮다」는 뜻이 아니다 — 그쪽은 시각이 전부 표 안에 있었을 뿐이다.
|
||||
|
||||
@@ -9,11 +9,11 @@
|
||||
|
||||
### 1. 자리가 있는가
|
||||
|
||||
`assets` 는 본문이 있는 두 종류만 갖는다 — **Case 와 Concept**. Reference·Question·Decision 의
|
||||
칸은 평문으로 렌더링돼 그림이 들어갈 자리가 없다.
|
||||
`assets` 는 본문이 있는 세 종류만 갖는다 — **Case·Concept·Setup**. Reference·Question·Decision 의
|
||||
칸은 평문으로 렌더링돼 그림이 들어갈 곳이 없다.
|
||||
|
||||
파생 기록에 그림이 필요해 보이면 그 그림은 **짝이 되는 Case 나 Concept 의 것**이다. 거기 담고
|
||||
`관계`로 가리킨다. 담을 Case 나 Concept 이 없으면 그 그림은 아직 집이 없다 — 계약의
|
||||
파생 기록에 그림이 필요해 보이면 그 그림은 **짝이 되는 Case·Concept·Setup 의 것**이다. 거기 담고
|
||||
`관계`로 가리킨다. 담을 기록이 없으면 그 그림은 아직 집이 없다 — 계약의
|
||||
`assetLedger.unassigned` 에 그렇게 적고, 새 글감을 세울지는 따로 판단한다.
|
||||
|
||||
### 2. 표가 아닌가
|
||||
@@ -40,11 +40,17 @@
|
||||
| **Case** | 이 요청 한 번이 어떤 순서로 무엇을 지나갔나 | `sequence` · `component-flow` |
|
||||
| **Case** (경계가 논지일 때) | 무엇이 어느 경계 안에 있고 무엇이 밖에 있나 | `two-zone-pipeline` |
|
||||
| **Concept** | 남의 것이 어떤 순서·구조로 동작하나 | `sequence` · `component-flow` · `ports-adapters` |
|
||||
| **Setup** | (아직 못 적는다 — 아래) | — |
|
||||
|
||||
Case 는 **내가 돌려서 본 것**이라 대개 순서가 논지다. Concept 은 **남의 것이 어떻게 동작하는지**라
|
||||
구조나 변환 사슬이 논지다. 어느 쪽이든 「무엇이 무엇으로 바뀌는가」를 못 적으면 아직 그릴 것이
|
||||
없다는 뜻이다.
|
||||
|
||||
**Setup 은 담을 곳만 있고 본보기가 없다.** 본문 파서가 Case 와 같아서 그림이 렌더링되기는 한다.
|
||||
다만 2026-09-12 에 Studio 의 환경 구성 문서가 0건이라, 위 두 줄처럼 「반복된 물음」을 셀 자료가
|
||||
없다. 이 줄은 그림을 그리지 말라는 뜻이 아니라 **아직 아무도 안 그려 봤다**는 뜻이다. 그릴 때는
|
||||
세 관문만 그대로 지나고, 무엇을 그렸는지 이 표에 적어 둔다.
|
||||
|
||||
**한 절에 그림 하나.** 같은 절에 구조 그림과 흐름 그림을 둘 다 넣으면 독자가 어느 쪽을 먼저
|
||||
읽어야 하는지 알 수 없다. 둘 다 필요하면 절을 나눈다.
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# 코드·표·다이어그램·이미지
|
||||
|
||||
본문(`bodyMarkdown`)에만 해당한다. 본문이 있는 종류는 Case 와 Concept 이다.
|
||||
본문(`bodyMarkdown`)에만 해당한다. 본문이 있는 종류는 Case·Concept·Setup 셋이다.
|
||||
|
||||
## 코드블록
|
||||
|
||||
|
||||
@@ -99,6 +99,7 @@ Reference의 칸도 반쯤만 맞는 기록이 나온다. 종류를 먼저 정
|
||||
|---|---|---|
|
||||
| 재현한 관측 하나 | 조건을 갖추고 돌려서 얻은 수치·실행계획·로그 | Case |
|
||||
| 남의 것의 동작 하나 | 문서와 코드를 읽어 정리한 규칙·흐름 | Concept |
|
||||
| 남이 따라 할 절차 하나 | 그 환경을 처음 세우는 명령과 구성 값 | Setup |
|
||||
| 반복 적용할 기준 하나 | 다음에도 같게 하기로 한 규칙 | Reference |
|
||||
| 프로젝트가 고른 방향 하나 | 대안을 두고 정한 것 | Decision |
|
||||
| 닫히지 않은 판단 하나 | 아직 모르는 것과 무엇을 하면 닫히는지 | Question |
|
||||
@@ -107,6 +108,8 @@ Reference의 칸도 반쯤만 맞는 기록이 나온다. 종류를 먼저 정
|
||||
|
||||
순서대로 묻는다. 먼저 걸리는 것이 그 글감의 종류다.
|
||||
|
||||
0. **남이 자기 기계에서 따라 할 절차인가** → Setup. 나머지 다섯은 끝난 일을 적고 이것만 실행할
|
||||
순서를 적는다. 명령과 구성 값이 SSOT에 있어야 하고, 프로젝트를 반드시 고른다
|
||||
1. **내가 돌려서 얻은 결과인가** → Case. 수치·실행계획·로그가 SSOT에 있어야 한다. 없으면 Case가 아니다
|
||||
2. **남의 것이 어떻게 동작하는지인가** → Concept. 무엇을 보고 썼는지(버전)가 있어야 한다
|
||||
3. **다음에도 같게 하기로 한 규칙인가** → Reference
|
||||
@@ -131,7 +134,7 @@ Reference 하나로 나누고 `관계`로 잇는다.
|
||||
미리 알아야 하는 구조가 있을 때만 Concept을 만든다. 메커니즘처럼 보이는 절을 훑어 채우면 어느
|
||||
기록도 필요로 하지 않는 개념이 쌓인다.
|
||||
|
||||
**주제 하나에 독자 질문 하나.** Studio는 주제 아래에 다섯 종류를 나눠 보여 준다. 그 주제의
|
||||
**주제 하나에 독자 질문 하나.** Studio는 주제 아래에 여섯 종류를 나눠 보여 준다. 그 주제의
|
||||
기록들이 함께 답하는 물음을 한 줄로 적고, 그 물음에 답하지 않는 글감은 다른 주제로 옮긴다.
|
||||
주제 slug는 Studio의 것을 그대로 쓴다.
|
||||
|
||||
@@ -157,7 +160,7 @@ Reference 하나로 나누고 `관계`로 잇는다.
|
||||
"status": "게시 전", "studioId": "32d0be7d-…", "assets": 1, "evidence": 3 },
|
||||
{ "title": "아직 쓰지 않은 글감" }
|
||||
],
|
||||
"concept": [], "reference": [], "question": [], "decision": []
|
||||
"concept": [], "setup": [], "reference": [], "question": [], "decision": []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,41 @@
|
||||
# 다섯 종류의 칸과 게시 조건
|
||||
# 여섯 종류의 칸과 게시 조건
|
||||
|
||||
칸 이름은 Studio 편집 화면 그대로, 상한과 필수 여부는 `studio-api.openapi.yaml` 그대로다.
|
||||
계약 필드명을 괄호에 적는다. 계약은 `tech-log-frontend/src/features/tech-log/contracts/studio/`
|
||||
에 있고, 이 파일과 계약이 어긋나면 계약이 맞다.
|
||||
|
||||
`RecordKind` 는 다섯이다 — `CASE` · `REFERENCE` · `QUESTION` · `CONCEPT` · `PROJECT_DECISION`.
|
||||
`RecordKind` 는 여섯이다 — `CASE` · `REFERENCE` · `QUESTION` · `PROJECT_DECISION` · `CONCEPT` ·
|
||||
`SETUP` (`studio-api.openapi.yaml:838-840`).
|
||||
|
||||
**이 목록을 손으로 옮길 때마다 종류가 빠졌다.** 이 문서도 한동안 「다섯이다」라고 적고 `SETUP`
|
||||
을 뺐다. 프론트엔드에서 먼저 같은 일이 났고 소스에 적혀 있다
|
||||
(`application/ports/studio-gateway.ts:8-12`).
|
||||
|
||||
> 종류는 계약의 `RecordKind` 를 그대로 쓴다. 여기 손으로 적어 두었던 동안 개념과 환경 구성이
|
||||
> 빠져 있었고, 작업본 목록의 종류 필터는 그 둘을 아예 고를 수 없었다 — 손으로 나열한 목록에
|
||||
> 새 종류를 빠뜨리는 일이 이 저장소에서 반복됐다.
|
||||
|
||||
일곱 번째가 생기면 같은 일이 난다. 이 문서를 고칠 때는 기억으로 세지 말고
|
||||
`studio-api.openapi.yaml` 의 `RecordKind` 를 열어 몇 줄인지부터 센다.
|
||||
|
||||
## 종류별 칸 (`새 문서` 화면이 적어 주는 그대로)
|
||||
|
||||
| 화면 이름 | 계약 `kind` | 그 종류만의 칸 |
|
||||
|---|---|---|
|
||||
| Case | `CASE` | 문제 · 결론 · 환경 · 재현 · 본문 |
|
||||
| Reference | `REFERENCE` | 목적 · 규칙 · 적용 조건 · 예외 · 예시 |
|
||||
| **개념** | `CONCEPT` | 기준 버전 · 본문 |
|
||||
| Question | `QUESTION` | 상태 · 사실 · 가정 · 미지수 · 선택지 |
|
||||
| Decision | `PROJECT_DECISION` | 상태 · 결정일 · 결정문 · 판단 이유 · 영향 · 근거 |
|
||||
| **검증 기록** (Case) | `CASE` | 문제 · 결론 · 환경 · 재현 · 본문 |
|
||||
| **적용 기준** (Reference) | `REFERENCE` | 목적 · 규칙 · 적용 조건 · 예외 · 예시 |
|
||||
| **동작 원리** (Concept) | `CONCEPT` | 기준 버전 · 본문 |
|
||||
| **환경 구성** (Setup) | `SETUP` | 버전 · 본문 |
|
||||
| **열린 질문** (Question) | `QUESTION` | 상태 · 사실 · 가정 · 미지수 · 선택지 |
|
||||
| **설계 결정** (Decision) | `PROJECT_DECISION` | 상태 · 결정일 · 결정문 · 판단 이유 · 영향 · 근거 |
|
||||
|
||||
**화면 이름은 여섯 다 한글이다.** 2026-09-12 에 `/studio/documents/new` 에서 읽었고 작업본
|
||||
목록(`/studio/documents`)의 종류 필터도 같은 여섯 이름을 쓴다. 이 문서의 절 제목과 산문은
|
||||
괄호 안의 이름을 쓴다 — 폴더 이름과 frontmatter 의 `kind` 가 그쪽이기 때문이다.
|
||||
|
||||
여기에 아래 공통 칸이 더해진다.
|
||||
|
||||
## 공통 (다섯 종류 모두 — `WorkingCopyInputBase`)
|
||||
## 공통 (여섯 종류 모두 — `WorkingCopyInputBase`)
|
||||
|
||||
| 칸 | 필드 | 상한 | 게시 조건 |
|
||||
|---|---|---|---|
|
||||
@@ -27,7 +44,7 @@
|
||||
| 요약 | `summary` | **2,000자** | 경고. 목록 카드에는 약 90자까지 보인다 |
|
||||
| Topic | `topicId` | — | 경고 |
|
||||
| 축 | `variantIds` | 8개 | 선택. 고르지 않으면 그 주제의 **공통 기록**이 된다 |
|
||||
| Project | `projectId` | — | `PROJECT_DECISION`은 게시 시 필수 |
|
||||
| Project | `projectId` | — | `PROJECT_DECISION`과 `SETUP`은 필수 |
|
||||
| 관계 | `relations` | 20개 | `PROJECT_DECISION`은 **1개 이상 필수**. 그 종류에서는 절 이름이 「근거」다 |
|
||||
|
||||
편집 화면에서 축은 체크박스 묶음으로 나오고 묶음 이름이 「축 — 고르지 않으면 이 주제의 공통
|
||||
@@ -67,8 +84,8 @@ evidence:
|
||||
- ../../../final/evidence/explain/highlights-child-plan-A.txt
|
||||
```
|
||||
|
||||
**`assets` 는 본문이 있는 Case 와 Concept 에만 둔다.** 나머지 세 종류는 칸이 평문으로
|
||||
렌더링돼 그림을 표시할 자리가 없다. 그림이 필요한 내용은 Case 나 Concept 에 담고 `관계`로
|
||||
**`assets` 는 본문이 있는 Case·Concept·Setup 에만 둔다.** 나머지 세 종류는 칸이 평문으로
|
||||
렌더링돼 그림을 표시할 곳이 없다. 그림이 필요한 내용은 본문이 있는 종류에 담고 `관계`로
|
||||
가리킨다.
|
||||
|
||||
`assets` 는 Studio 에 올릴 파일이다. 아직 안 올렸으면 key 가 파일 이름과 같고, 올린 뒤에는
|
||||
@@ -80,13 +97,35 @@ evidence:
|
||||
|
||||
## 평문 칸 쓰는 법
|
||||
|
||||
본문(`bodyMarkdown`)을 뺀 모든 칸은 평문이다. 백틱·파이프·`#`는 글자 그대로 보이고 줄바꿈만
|
||||
살아난다. 그 줄바꿈이 유일한 서식이므로 아끼지 않는다.
|
||||
본문(`bodyMarkdown`)을 뺀 모든 칸은 **마크다운 블록 파서를 거치지 않는다.** 그렇다고 전부
|
||||
글자 그대로 나오는 것은 아니다. 렌더러가 이 칸들만 따로 그리고(`tech-log-frontend` 의
|
||||
`presentation/shared/public-render/prose-text.tsx`), 거기서 셋이 살아난다.
|
||||
|
||||
**무엇을 지우나.** 백틱·별표·코드펜스는 글자 그대로 보인다. 식별자는 남기고 표시 문자만 뺀다.
|
||||
`InboxCleanupJob:56` 은 InboxCleanupJob:56 으로, `**this is the parameter**` 는 그 문장만 남긴다.
|
||||
코드펜스 안이 `이름 : 값` 꼴이면 펜스 줄만 지우면 그대로 읽힌다. 줄바꿈이 유일한 서식이므로
|
||||
문단 사이 빈 줄은 지킨다.
|
||||
| 이 칸에서 | 어떻게 되나 |
|
||||
|---|---|
|
||||
| 백틱 쌍 | 인라인 `<code>` 로 **살아난다.** 빼지 않는다 |
|
||||
| 백틱이 홀수 개 | 짝이 안 맞으므로 원문 그대로 둔다 — 반쯤 해석하지 않는다 |
|
||||
| 빈 줄 | 문단이 갈린다 |
|
||||
| 한 줄 바꿈 | `<br>` 로 그 자리에 남는다 |
|
||||
| 별표·파이프·`#`·코드펜스·인용 표지 `>` | **글자 그대로 보인다.** 이것들만 뺀다 |
|
||||
|
||||
**옛 판을 기억하지 마라.** 이 칸들은 오래 진짜 평문으로 나갔고 백틱이 백틱째 화면에
|
||||
나왔다 — 어떤 Reference 는 한 문서에 백틱이 32개였고 그 원문이 카드와 검색 결과까지
|
||||
퍼졌다. 그건 **고쳐진 버그**다. 지금 백틱을 빼면 식별자가 본문과 같은 민무늬로 나온다.
|
||||
|
||||
**무엇을 지우나.** 별표·코드펜스·`>` 는 글자 그대로 보인다. 식별자는 남기고 표시 문자만 뺀다.
|
||||
`**this is the parameter**` 는 그 문장만 남긴다. 코드펜스 안이 `이름 : 값` 꼴이면 펜스 줄만
|
||||
지우면 그대로 읽힌다. 백틱은 그대로 두고, 문단 사이 빈 줄도 지킨다.
|
||||
|
||||
**SSOT 를 그대로 옮긴 인용도 `>` 를 못 쓴다.** 인용이라는 것을 표지로 나타낼 방법이 이 칸에는
|
||||
없다 — `>` 도, 들여쓰기도 안 산다. 표지를 빼고 한 문단으로 두거나, 인용이 꼭 인용으로 보여야
|
||||
하면 본문이 있는 종류로 옮긴다. 「」 를 새로 씌우지 않는다. 옮긴 글자는 보호 구간이라 그대로다.
|
||||
|
||||
**코드펜스를 뗄 때 언어 표시 줄을 같이 지운다.** ` ```text ` 에서 펜스만 지우면 `text` 한 줄이
|
||||
남고, 그 낱말이 화면에 그대로 나온다. 실제로 한 기록에서 그렇게 남아 있었다.
|
||||
|
||||
**칸이 어떻게 보이는지는 렌더러가 정본이다.** 이 파일이 아니다. 여기 적힌 것과 화면이
|
||||
다르면 `prose-text.tsx` 와 `public-record-renderer.tsx` 를 열어서 가른다.
|
||||
|
||||
관계(`근거`) 절은 평문 칸이 아니다. 기록을 거는 목록이라 `- **제목**` 표기를 그대로 둔다.
|
||||
|
||||
@@ -116,25 +155,26 @@ issuer · audience : 검증
|
||||
| 검증 환경 | `environment` | 런타임·버전·DB·도구 |
|
||||
| 재현 조건 | `reproduction` | 다른 사람이 같은 결과를 얻는 방법 |
|
||||
| 마지막 검증일 | `lastVerifiedOn` | 실제로 확인한 날. 30일 지나면 경고 |
|
||||
| 본문 Markdown | `bodyMarkdown` | 10만 자. 본문을 갖는 두 종류 중 하나 |
|
||||
| 본문 Markdown | `bodyMarkdown` | 10만 자. 본문을 갖는 세 종류 중 하나 |
|
||||
|
||||
공개 화면에서 `검증 환경`과 `재현 조건`은 `environmentSummary` 배열에 그 순서로 실린다.
|
||||
|
||||
## Concept — 남의 것이 어떻게 동작하는지
|
||||
|
||||
`새 문서` 화면에서 이 종류만 이름이 한글이다. **「개념」을 고른다.** 나머지 넷은 Case·Reference·
|
||||
Question·Decision 으로 적혀 있다. 화면 설명은 「개념의 내부 동작과 아키텍처를 처음부터 풀어 씁니다」다.
|
||||
`새 문서` 화면에서 **「동작 원리」를 고른다.** 화면 설명은 「개념의 내부 동작과 아키텍처를 처음부터
|
||||
풀어 씁니다.」다. 전에 이 절은 「이 종류만 이름이 한글이다」라고 적었는데 2026-09-12 에는 여섯 다
|
||||
한글이었다.
|
||||
|
||||
| 칸 | 필드 | 비고 |
|
||||
|---|---|---|
|
||||
| 본문 Markdown | `bodyMarkdown` | 10만 자. **Case 와 함께 본문을 갖는 두 종류 중 하나** |
|
||||
| 본문 Markdown | `bodyMarkdown` | 10만 자. **Case·Setup 과 함께 본문을 갖는 세 종류 중 하나** |
|
||||
| 기준 버전 | `basisVersion` | 120자. 무엇을 보고 쓴 글인지 한 줄 |
|
||||
|
||||
칸이 둘뿐이다. 문제도 결론도 재현 조건도 없다. 내가 재현한 결과가 아니라 **이미 그렇게 동작하는
|
||||
것**을 적기 때문이다. `Authorization Code Flow 가 code 를 한 번 더 교환하는 이유`, `Forward-Auth
|
||||
subrequest 가 실어 보내는 것` 같은 것이 여기 온다.
|
||||
|
||||
**`lastVerifiedOn` 이 없고 `basisVersion` 이 그 자리를 대신한다.** 개념은 날짜로 낡지 않고 버전으로
|
||||
**`lastVerifiedOn` 이 없고 `basisVersion` 이 낡음을 말한다.** 개념은 날짜로 낡지 않고 버전으로
|
||||
낡기 때문이다. `Keycloak 26.7.0 identity brokering`, `Kubernetes 1.31` 처럼 적는다. 비워도 게시된다.
|
||||
|
||||
공개 주소는 `/concepts/{slug}` 다.
|
||||
@@ -143,8 +183,7 @@ subrequest 가 실어 보내는 것` 같은 것이 여기 온다.
|
||||
검증도 막지 않는다(2026-09-04 에 임시 개념 기록을 만들어 비운 채로 게시해 확인했다). 그래도
|
||||
채우는 편이 낫다 — 개념이 언제 낡았는지 읽는 사람이 알 방법이 이 칸뿐이다.
|
||||
|
||||
편집 화면 오른쪽 `작업 상태` 는 이 종류를 「동작 원리」라고 부른다. `새 문서` 의 「개념」과 같은
|
||||
것이다.
|
||||
편집 화면 오른쪽 `작업 상태` 도 이 종류를 「동작 원리」라고 부른다.
|
||||
|
||||
Case 와 헷갈리면 **내가 무엇을 했는지**를 묻는다. 내가 돌려 보고 수치를 얻었으면 Case, 남의 문서와
|
||||
코드를 읽고 동작을 정리했으면 Concept 이다.
|
||||
@@ -169,6 +208,87 @@ Concept 이 되는 것은 이런 것들이다 — `Spring 조립의 세 경로`,
|
||||
시점`, `커밋 증거 상태 전이`, `fenced lease 와 CAS`, `gRPC flow control 과 backpressure`.
|
||||
여러 Case 가 같은 선수 지식을 요구할 때 그것을 한 번만 설명하려고 만드는 자리다.
|
||||
|
||||
## Setup — 남이 따라 할 절차 (`SETUP`)
|
||||
|
||||
화면 이름은 「환경 구성」이고 설명은 「이 기록을 자기 손으로 재현하는 절차를 남깁니다.」다.
|
||||
편집 화면은 구역 둘로 나뉜다 — 「기본 정보」와 「환경 구성」(eyebrow `SETUP`).
|
||||
|
||||
| 화면 이름 | 필드 | 상한·모양 |
|
||||
|---|---|---|
|
||||
| 고정한 버전 | `pinnedVersions` | 배열 30개. 줄마다 `이름`(1~60자) + `버전`(1~40자) 입력 둘. 「버전 추가」 버튼으로 늘린다 |
|
||||
| 절차 Markdown | `bodyMarkdown` | 10만 자 |
|
||||
|
||||
화면에 붙은 도움말을 그대로 옮기면 이렇다.
|
||||
|
||||
- 고정한 버전 : `“Keycloak” / “26.7.0” 처럼 적습니다. 비우면 화면에 표를 그리지 않습니다.`
|
||||
- 절차 Markdown : `“##” 소제목이 목차가 됩니다. 명령은 코드블록으로 적어야 그대로 복사됩니다.`
|
||||
|
||||
`SetupInput.required` 는 `[kind, bodyMarkdown, pinnedVersions]` 다.
|
||||
|
||||
**작업본을 만들면 본문이 비어 있지 않다.** Studio 가 절 뼈대를 미리 넣어 준다.
|
||||
|
||||
```text
|
||||
## 실행 절차
|
||||
|
||||
## 구성 값
|
||||
|
||||
## 확인 방법
|
||||
```
|
||||
|
||||
계약의 `bodyMarkdown` 설명은 「실행 절차·구성 값·확인 방법을 `##` 절로 적는다. **절 이름을
|
||||
강제하지 않는다 — 프로젝트마다 셋업의 모양이 다르다.**」다. 뼈대는 출발점이고, 절 이름은 그
|
||||
프로젝트가 쓰는 말로 바꿔도 저장과 게시가 막히지 않는다.
|
||||
|
||||
### 왜 이 종류가 따로 있나
|
||||
|
||||
다른 다섯은 끝난 일을 적고 환경 구성만 남이 따라 할 절차를 적는다. 편집 화면 주석
|
||||
(`presentation/studio/components/setup-fields.tsx:44-52`)이 그 차이를 적어 두었다.
|
||||
|
||||
> 다른 다섯 종류는 끝난 일을 적는다. 이 종류만 읽는 사람이 그대로 따라 하는 절차를 적으므로,
|
||||
> 본문에 명령과 표가 들어간다 — Case 의 「검증 환경」 같은 평문 한 칸으로는 담기지 않는다.
|
||||
> … 버전만 본문 밖에 둔다. 이 절차가 어느 버전 위에서 성립했는지는 그 기록의 유효 범위이고,
|
||||
> 목록과 머리말이 본문을 열지 않고 보여 줘야 하는 값이기 때문이다.
|
||||
|
||||
그래서 칸이 둘뿐인데도 Concept 과 다르게 쓴다. 명령·표·그림은 본문에 넣고 버전만 본문 밖에
|
||||
남긴다. 개념의 「기준 버전」도 같은 이유로 본문 밖에 있고, 다른 점은 셋업의 버전이 여럿이라는
|
||||
데 있다.
|
||||
|
||||
**검증일 칸이 없다.** Case 의 `lastVerifiedOn` 도 Reference 의 `verifiedOn` 도 이 종류에는 없다.
|
||||
공개 계약의 `SetupDetailResponse` 가 왜인지 적는다.
|
||||
|
||||
> 환경 구성은 끝난 일이 아니라 따라 하는 절차다. 낡음은 검증일이 아니라
|
||||
> `pinnedVersions` 가 말한다 — 어느 버전 위에서 이 절차가 성립했는지가 유효 범위다.
|
||||
> 주제는 없을 수 있다. 주제 없는 셋업은 그 프로젝트의 공통 구성이다.
|
||||
|
||||
### 프로젝트는 필수, 주제는 선택
|
||||
|
||||
`PROJECT_DECISION` 말고 프로젝트를 요구하는 종류가 하나 더 있다.
|
||||
|
||||
```text
|
||||
if (input.kind === "SETUP" && !project) fail("환경 구성은 프로젝트에 속합니다. 기본 정보에서 프로젝트를 골라 주세요.");
|
||||
```
|
||||
|
||||
`domain/content-format/project-public-render-model.ts:245` 다.
|
||||
|
||||
주제는 비워도 된다. 비우면 그 프로젝트의 공통 구성으로 읽힌다. 다만 2026-09-12 에 빈 초안의
|
||||
미리보기는 `1:1 TOPIC catalog entry is required` 로 막혔다 — 미리보기를 보려면 Topic 을 고른다.
|
||||
|
||||
### 본문 파서와 공개 주소
|
||||
|
||||
본문 파서는 Case 와 같다(`presentation/public/components/setup-document-page.tsx:11`).
|
||||
|
||||
> 환경 구성의 본문도 Case 와 같은 파서를 탄다 — `##` 소제목이 목차가 되고 `:::evidence` 가…
|
||||
|
||||
그래서 코드블록·표·다이어그램·이미지를 쓸 수 있다.
|
||||
|
||||
- 공개 상세 : `/setups/{slug}` (`contracts/tech-log-route-contract.ts:31`, 라우트 제목 「환경 구성」)
|
||||
- 공개 목록 : `/explore/setups` — 설명 「이 기록을 자기 손으로 재현하는 절차를 남깁니다.」
|
||||
(`presentation/public/pages/explore-kind-page.tsx:17`)
|
||||
|
||||
**Studio 에 환경 구성 문서는 아직 0건이다.** 2026-09-12 에 `/studio/documents?kind=SETUP` 이
|
||||
「0개 중 0개 표시 중」이었다. 종류는 있는데 한 번도 쓰이지 않았다. 위의 칸 설명은 계약과 편집
|
||||
화면에서 읽었고, 올라간 기록에서 확인하지 않았다.
|
||||
|
||||
## Reference — 반복 적용할 기준
|
||||
|
||||
| 칸 | 필드 | 비고 |
|
||||
@@ -217,6 +337,10 @@ Concept 이 되는 것은 이런 것들이다 — `Spring 조립의 세 경로`,
|
||||
## 종류 고르기
|
||||
|
||||
```text
|
||||
남이 그대로 따라 할 절차를 적나 ── 예 ──→ Setup
|
||||
│
|
||||
아니오 (끝난 일을 적는다)
|
||||
│
|
||||
내가 직접 돌려 보고 결과를 얻었나 ── 예 ──→ Case
|
||||
│
|
||||
아니오
|
||||
@@ -236,6 +360,11 @@ Concept 이 되는 것은 이런 것들이다 — `Spring 조립의 세 경로`,
|
||||
└──→ Reference
|
||||
```
|
||||
|
||||
첫 갈래가 「끝난 일을 적나, 남이 따라 할 절차를 적나」다. 나머지 다섯은 이미 끝난 일을 적고,
|
||||
Setup 만 읽는 사람이 자기 기계에서 실행할 순서를 적는다. 편집 화면 주석이 그 경계를 「Case 의
|
||||
「검증 환경」 같은 평문 한 칸으로는 담기지 않는다」로 적는다 — 명령이 여러 줄이고 그대로
|
||||
복사돼야 하면 Case 의 평문 칸이 아니라 Setup 의 본문에 들어간다.
|
||||
|
||||
Case 와 Concept 이 가장 자주 헷갈린다. **수치와 재현 조건이 있으면 Case**, 읽고 정리한 동작이면
|
||||
Concept 이다. Concept 과 Reference 는 「무엇이 그런가」와 「우리가 어떻게 할 것인가」로 갈린다 —
|
||||
`PKCE 가 code 가로채기를 막는 방식`은 Concept, `우리는 public client 에 PKCE 를 필수로 쓴다`는
|
||||
|
||||
@@ -27,6 +27,25 @@
|
||||
- [ ] Decision에 근거 기록이 1개 이상 연결됐다
|
||||
- [ ] Decision의 영향에 감수한 비용이 있다
|
||||
- [ ] Reference의 예시가 문장이다. 코드를 밀어 넣지 않았다
|
||||
- [ ] Setup이 끝난 일이 아니라 남이 따라 할 순서를 적었다
|
||||
- [ ] Setup의 명령이 코드블록에 있다. 산문에 섞지 않았다
|
||||
- [ ] Setup의 `pinnedVersions`가 채워졌다. 본문에 날짜를 적어 검증일을 대신하지 않았다
|
||||
|
||||
## 환경 구성의 명령 (`writing-practitioner-guides`)
|
||||
|
||||
명령을 어떤 형태로 쓸지는 그 스킬이 정한다. 여기서는 그 결과가 본문에 남았는지만 센다.
|
||||
|
||||
- [ ] 사람이 내용을 읽고 고쳐야 하는 설정 파일을 에디터로 열게 했다. `printf >`·`echo >>`·`cat <<EOF` 로 만들지 않았다
|
||||
- [ ] 한 명령에 여러 작업이 겹치지 않았다. 접속·리다이렉션·권한·파일 생성을 한 줄에 묶지 않았다
|
||||
- [ ] 그 도메인의 전용 검증 명령이 있는데 `python3 -c` 로 대신하지 않았다
|
||||
- [ ] 다시 따라 해도 같은 줄이 또 붙지 않는다. 두 번 실행하면 늘어나는 명령이 없다
|
||||
- [ ] 조회·진단·실행은 운영자가 쓰는 CLI 를 그대로 썼다. `grep`·`virsh`·`systemctl` 을 에디터로 바꾸지 않았다
|
||||
- [ ] 단계마다 목적·행동·예상 결과·왜 필요한가·문제가 생기면이 같은 순서로 있다
|
||||
- [ ] 셸이 여럿이면 코드블록마다 `label` 로 어디서 치는지 적었다
|
||||
- [ ] 자리표시자가 없다. 값을 찾는 명령이 함께 있다
|
||||
- [ ] 앞 단계가 찍은 값을 옮겨 넣는 자리만 예외다. 그 자리는 `{{NAME}}` 으로 적었다. 한글로 감싸지도 `${NAME}` 으로 적지도 않았다
|
||||
- [ ] 비밀은 길이나 존재 여부까지만 확인하고 값을 찍지 않았다
|
||||
- [ ] 명령의 형태를 고쳤으면 SSOT 를 먼저 고쳤다. `check_evidence.mjs` 가 통과한다
|
||||
|
||||
## 설명
|
||||
|
||||
@@ -80,7 +99,7 @@
|
||||
- [ ] 테스트를 말할 때 무엇을 단정하는지 적었다
|
||||
- [ ] 어미·절·안내 문장의 수치는 참고만 했다. 맞추려고 문장을 넣지 않았다
|
||||
|
||||
## 본문 (Case)
|
||||
## 본문 (Case · Concept · Setup)
|
||||
|
||||
- [ ] raw HTML·각주·체크박스·중첩 목록·취소선이 없다
|
||||
- [ ] 표를 파이프로 썼다. 감쌌다면 세 속성이 다 있다
|
||||
@@ -99,7 +118,8 @@
|
||||
|
||||
## 평문 칸
|
||||
|
||||
- [ ] 본문 밖 칸에 백틱·파이프가 없다
|
||||
- [ ] 본문 밖 칸에 별표·파이프·`#`·코드펜스·인용 표지 `>` 가 없다 (**백틱은 괜찮다** — 인라인 `<code>` 로 산다)
|
||||
- [ ] 코드펜스를 뗀 자리에 언어 표시(` ```text ` 의 `text`)가 남지 않았다
|
||||
- [ ] 나열을 쉼표로 잇지 않고 `이름 : 값`으로 끊었다
|
||||
- [ ] 있음·없음을 `o`·`x`로 적었다
|
||||
- [ ] 한 문장이 화면에서 두 줄을 넘지 않는다
|
||||
@@ -107,7 +127,7 @@
|
||||
## 연결
|
||||
|
||||
- [ ] Topic이 지정됐다
|
||||
- [ ] Project가 필요하면 지정됐고, 그 Project에 slug가 있다
|
||||
- [ ] Project가 필요하면 지정됐고, 그 Project에 slug가 있다 (Decision과 Setup은 필수다)
|
||||
- [ ] 관계의 대상이 실제로 있는 공개 기록이다
|
||||
- [ ] 코드·표·그림이 필요한 내용을 Reference나 Question에 밀어 넣지 않았다
|
||||
- [ ] 본문이 없는 세 종류에 `assets`를 선언하지 않았다
|
||||
|
||||
@@ -73,7 +73,7 @@ section it names exists, and the diagram stage cannot translate the anchor into
|
||||
|
||||
## Topics
|
||||
|
||||
Each Topic has `topic` (its key), `title`, **`readerQuestion`**, and `kinds` with the five
|
||||
Each Topic has `topic` (its key), `title`, **`readerQuestion`**, and `kinds` with the six
|
||||
record kinds.
|
||||
|
||||
```json
|
||||
@@ -81,13 +81,13 @@ record kinds.
|
||||
"topic": "oauth-oidc-auth-boundary",
|
||||
"title": "OAuth 자격증명과 세션의 보관 경계",
|
||||
"readerQuestion": "자격증명과 세션을 누가 보관하고, 누가 API 요청을 만들며, 보호 자원은 무엇을 신뢰하는가?",
|
||||
"kinds": { "case": [], "concept": [], "reference": [], "question": [], "decision": [] }
|
||||
"kinds": { "case": [], "concept": [], "setup": [], "reference": [], "question": [], "decision": [] }
|
||||
}
|
||||
```
|
||||
|
||||
Every node in the Topic must help answer the reader question. Two Topics do not share a
|
||||
question; one Topic does not need two. Empty kinds are allowed — do not manufacture nodes
|
||||
to fill all five.
|
||||
to fill all six.
|
||||
|
||||
## Candidates
|
||||
|
||||
@@ -178,6 +178,26 @@ be stale.
|
||||
A Concept exists because a Case, Decision, or Question needs it to be understood. Absence,
|
||||
call-counts, unwired subsystems, analysis scope, and coverage ledgers are not Concepts.
|
||||
|
||||
### Setup
|
||||
|
||||
`slug` · `readiness` · `source` · `classification` · `pinned-versions` · `relations`.
|
||||
|
||||
Setup is the one kind that does not report a finished result. It is a procedure a reader
|
||||
runs on their own machine, so `pinned-versions` states the versions the procedure was
|
||||
established on — the same job `basis-version` does for a Concept, except there is more than
|
||||
one of them. There is no verification date for this kind.
|
||||
|
||||
A Setup node also needs a project. `SETUP` and `PROJECT_DECISION` are the two kinds Studio
|
||||
refuses to save without one; a Topic is optional, and a Setup with no Topic reads as that
|
||||
project's shared configuration.
|
||||
|
||||
`verify-tech-log-tree.py` checks this kind like the others: `REQUIRED_FIELDS["setup"]` names
|
||||
the six fields above and `GENERATABLE["setup"]` is `READY`. The kind list those tables are
|
||||
keyed on lives in `techlog.KINDS`, which also decides which `<topic>/<kind>/` folders
|
||||
`build-tech-log-tree.py` scans. Add a kind in one place and the tables that key off it go
|
||||
quiet rather than failing — a kind missing from `REQUIRED_FIELDS` is not an error, it is a
|
||||
node nobody asks anything of.
|
||||
|
||||
### Reference
|
||||
|
||||
`slug` · `readiness` · `source` · `classification` · `scope` · `exceptions` · `relations`.
|
||||
|
||||
@@ -7,18 +7,21 @@
|
||||
Question 4·Decision 2), n+1liner 24건(Case 5·Reference 7·Question 5·Decision 7).
|
||||
「대개 이렇게 쓴다」는 말은 그 47건이 그렇게 돼 있다는 뜻이다.
|
||||
|
||||
**Setup 은 그 47건에 없다.** 2026-09-12 에 Studio 의 환경 구성 문서가 0건이었다. 그래서 Setup
|
||||
절은 계약과 편집 화면에서 읽어 썼다. 나머지 다섯처럼 올라간 기록을 세지 않았다.
|
||||
|
||||
`clean-architecture-backend-template` 의 949건은 다른 절 이름으로 쓰여 있었고, 지금 이 기준으로
|
||||
다시 판정하는 중이다. 아직 기준을 만족한 상태가 아니므로 그 949건을 본보기로 삼지 않는다. 올라간
|
||||
적 없는 초안이 아니라 **올라간 것**이 기준이다.
|
||||
|
||||
## 파일 뼈대 — 다섯 종류가 같다
|
||||
## 파일 뼈대 — 여섯 종류가 같다
|
||||
|
||||
```markdown
|
||||
---
|
||||
id · kind · slug · title · topic · topicName · project · status · studio
|
||||
source · sourceRevision
|
||||
(종류별) basisVersion · decisionStatus · questionStatus · lastVerifiedOn
|
||||
(있으면) evidence · assets — assets 는 Case 와 Concept 만
|
||||
(종류별) basisVersion · decisionStatus · questionStatus · lastVerifiedOn · pinnedVersions
|
||||
(있으면) evidence · assets — assets 는 Case · Concept · Setup 만
|
||||
---
|
||||
|
||||
# 제목
|
||||
@@ -27,7 +30,7 @@ source · sourceRevision
|
||||
|
||||
## 관계 ← Decision 만 「근거」다
|
||||
## <칸 이름> ← 종류마다 다르다
|
||||
## 본문 ← Case · Concept 만
|
||||
## 본문 ← Case · Concept · Setup 만
|
||||
<!-- body:start -->
|
||||
...
|
||||
<!-- body:end -->
|
||||
@@ -110,6 +113,159 @@ basisVersion: oauth2-proxy 7.15.2 · Nginx auth_request
|
||||
「확인했다」는 Case 의 말이다. Concept 은 「~한다」로 적는다. 규격이 정한 것과 그 구현이 그렇게 한
|
||||
것을 구분한다.
|
||||
|
||||
## Setup — 0건
|
||||
|
||||
칸은 `관계` · `본문` 둘뿐이고, 고정한 버전은 frontmatter 의 `pinnedVersions` 에 있다. 계약의
|
||||
`PinnedVersion` 은 `name` 과 `version` 을 나눠 담는다 — 이름 1~60자, 버전 1~40자, 30개까지.
|
||||
|
||||
```yaml
|
||||
pinnedVersions:
|
||||
- name: Keycloak
|
||||
version: 26.7.0
|
||||
```
|
||||
|
||||
**절 이름을 강제하지 않는다.** 계약이 그렇게 적는다 — 「실행 절차·구성 값·확인 방법을 `##`
|
||||
절로 적는다. 절 이름을 강제하지 않는다 — 프로젝트마다 셋업의 모양이 다르다.」 그래도 빈 본문에서
|
||||
시작하지는 않는다. 작업본을 만들면 Studio 가 절 셋을 미리 넣어 주므로 거기서 출발한다.
|
||||
|
||||
```markdown
|
||||
## 실행 절차
|
||||
|
||||
## 구성 값
|
||||
|
||||
## 확인 방법
|
||||
```
|
||||
|
||||
**명령은 코드블록으로 적는다.** 절차 Markdown 칸의 도움말이 이유를 적는다 —
|
||||
`“##” 소제목이 목차가 됩니다. 명령은 코드블록으로 적어야 그대로 복사됩니다.` 읽는 사람이
|
||||
자기 기계에서 실행하므로, 산문에 섞어 적으면 복사할 때 프롬프트 기호와 설명이 함께 붙는다.
|
||||
|
||||
Case 와 무엇이 다른지는 **읽는 사람이 무엇을 하는가**로 갈린다. Case 의 「재현 조건」은 내가 잰
|
||||
값을 남이 다시 얻는 순서이고, Setup 의 본문은 그 환경을 처음 세우는 절차다. Case 는 평문 한 칸에
|
||||
그 순서를 담지만 Setup 은 본문을 쓰므로 명령·표·그림이 들어간다.
|
||||
|
||||
**검증일을 쓰지 않는다.** 이 종류에는 그 칸이 없다. 절차가 어느 버전 위에서 성립했는지는
|
||||
`pinnedVersions` 가 말하므로, 본문에 「2026-09-12 기준」 같은 날짜를 적어 대신하지 않는다.
|
||||
|
||||
`project` 는 비울 수 없다. `topic` 은 비워도 되고, 비우면 그 프로젝트의 공통 구성으로 읽힌다.
|
||||
|
||||
### 본문을 쓰기 전에 `writing-practitioner-guides` 를 연다
|
||||
|
||||
`Skill` 도구로 `writing-practitioner-guides` 를 부른다. 명령을 어떤 형태로 쓸지는 그 스킬이
|
||||
정한다 — 한 줄에 어느 계층까지 담는지, 어떤 도구를 먼저 잡는지, 출력을 읽는 형태와 값 하나만
|
||||
뽑는 형태를 어떻게 가르는지, 넓은 명령에서 좁은 명령으로 내려가는 순서, 무엇이 보이면 멈추고
|
||||
다시 쓰는지가 거기 적혀 있다. 그 규칙을 이 문서로 옮겨 적지 않는다. 같은 규칙이 두 곳에 있으면
|
||||
한쪽만 고쳐지고 둘이 갈린다.
|
||||
|
||||
다른 다섯 종류에는 이 절차가 없다. 나머지는 끝난 일을 적으므로 명령이 나와도 그때 무엇을 쳤는지
|
||||
보여 주는 인용이고, 읽는 사람이 자기 기계에서 그것을 치지 않는다. 환경 구성은 읽는 사람이 그대로
|
||||
따라 치므로 명령의 형태가 내용의 일부다. `echo 'export ...' >> ~/.bashrc` 는 결과를 만들지만
|
||||
읽는 사람이 `~/.bashrc` 를 한 번도 열어 보지 못하고, 같은 가이드를 다시 따라 하면 같은 줄이
|
||||
하나 더 붙는다.
|
||||
|
||||
기계적으로 바꾸는 방향도 틀린다. 조회·진단·실행은 운영자가 쓰는 CLI 를 그대로 쓴다 —
|
||||
`grep`·`lsmod`·`virsh`·`systemctl`·`journalctl`·`kubectl` 이 들어갔다는 것 자체는 문제가
|
||||
아니다. 사람이 내용을 읽고 고쳐야 하는 설정 파일을 만드는 대목에서만 에디터로 연다.
|
||||
|
||||
### 단계 하나의 모양
|
||||
|
||||
`writing-practitioner-guides` 의 「Shape of one step」은 상태를 읽는 단계의 모양이다. 환경 구성의
|
||||
본문은 상태를 바꾸는 단계가 대부분이고, 그쪽은 칸이 다섯이다.
|
||||
|
||||
```text
|
||||
### N. <이 단계가 무엇을 만드는가>
|
||||
|
||||
목적 한 줄. 이 단계가 끝나면 무엇이 달라지나
|
||||
행동 번호를 매긴 명령. 한 번호에 한 가지 일
|
||||
예상 결과 그때 화면에 나오는 것
|
||||
왜 필요한가 건너뛰거나 어긋나면 무엇이 깨지나
|
||||
문제가 생기면 어느 명령부터 다시 보나
|
||||
```
|
||||
|
||||
번호는 행동을 세려고 매긴다. 한 번호가 접속과 파일 생성과 권한 설정을 함께 하면 읽는 사람은
|
||||
어디까지 왔는지 셀 수 없고, 실패해도 그 줄의 어느 대목에서 실패했는지 모른다. 다섯 칸이 단계마다
|
||||
같은 순서로 오면 처음 따라 하는 사람이 단계마다 같은 곳에서 같은 것을 찾는다.
|
||||
|
||||
채운 예는 `writing-practitioner-guides` 에 있다 — libvirt 연결 URI 를 `qemu:///system` 으로
|
||||
고정하는 단계다.
|
||||
|
||||
### 자리표시자
|
||||
|
||||
**원칙은 자리표시자를 두지 않는 것이다.** `writing-practitioner-guides` 의 「No placeholders」가
|
||||
이유를 적는다 — `<토큰>` 이라고 적어 두면 그 값을 어디서 가져오는지가 문서 밖으로 나간다. 값을
|
||||
뽑는 명령을 먼저 주는 것이 먼저다.
|
||||
|
||||
**예외는 하나다 — 같은 기록의 앞 단계가 화면에 찍은 값을 뒤 단계에 옮겨 넣을 때.** 세션 `sid` 는
|
||||
로그인할 때마다 새로 생기고 클라이언트 UUID 는 렐름을 만들 때 정해져서 읽는 사람의 실험대에서
|
||||
다르다. 앞 단계가 탐침 파드 안에서 돌았으면 그 셸의 변수가 뒤 단계의 셸에 없어서 변수로 넘길
|
||||
수도 없다. 값을 만드는 명령은 이미 같은 문서 안에 있으므로 전역 스킬의 빨간 깃발
|
||||
(`<placeholder>` with no command that produces it)에는 걸리지 않는다.
|
||||
|
||||
**그때 쓰는 꼴은 `{{NAME}}` 하나다.** `NAME` 은 대문자로 시작하고 대문자·숫자·밑줄만 쓴다.
|
||||
|
||||
```bash label="[kc-lab-1] ② 읽은 값을 그대로 넣어 행을 찾는다"
|
||||
kubectl -n keycloak-lab exec deploy/postgres -- psql -U keycloak -d keycloak \
|
||||
-c "select user_session_id, created_on, last_session_refresh from offline_user_session
|
||||
where offline_flag='0' and user_session_id='{{SID}}'"
|
||||
```
|
||||
|
||||
**`${SID}` 로 쓰지 않는다.** 같은 가이드들이 `$SID`·`$K0`·`$TOK`·`$PW` 를 진짜 셸 변수로 쓴다.
|
||||
자리표시자를 셸 변수 꼴로 적으면 읽는 사람이 「이 변수는 이미 셸에 있다」로 읽고 그대로 붙여
|
||||
넣는다. `{{ }}` 는 셸 문법이 아니라서 붙여 넣으면 반드시 틀리고, 틀린 자리가 화면에 보인다.
|
||||
|
||||
**한글로 감싸지 않는다.** `'<① 이 찍은 sid>'` 는 사람에게는 읽히지만 검사기가 그 줄을 흐름도로
|
||||
오인하기 쉽고, 무엇보다 자리표시자 바깥의 SQL 이 SSOT 와 갈려도 드러나지 않는다. 어느 단계가 그
|
||||
값을 찍었는지는 코드블록 바로 위 산문에 적는다 — 「sid 는 ③ 이 `SID=` 로 화면에 찍은 값을 옮겨
|
||||
넣는다」처럼.
|
||||
|
||||
**검사기는 그 자리만 와일드카드로 본다.** `{{SID}}` 는 따옴표도 공백도 넘지 않는 값 하나로
|
||||
열리고 나머지는 한 글자씩 SSOT 와 대조된다. 그래서 `user_session_id` 를 `user_session_idx` 로
|
||||
잘못 적으면 그대로 걸린다.
|
||||
|
||||
### 이 저장소에서만 걸리는 것 셋
|
||||
|
||||
전역 스킬은 Tech Log 의 검사기도 SSOT 도 모른다.
|
||||
|
||||
**① 명령의 형태를 고치려면 SSOT 를 먼저 고친다.** `check_evidence.mjs` 가 본문 코드블록의 줄을
|
||||
`final/document.md` 와 대조한다. `bash`·`yaml`·`nginx` 처럼 언어를 적은 펜스는 줄 단위로 보고,
|
||||
`text`·`txt`·`console`·`diff` 펜스와 언어를 안 적은 펜스는 그 안의 경로·URL·점 있는 식별자만
|
||||
본다. 그래서 `sudo nano /etc/letsencrypt/cloudflare.ini` 를 SSOT 에 없는 채로 넣으면 「인용한
|
||||
코드가 SSOT 에 없다」로 막힌다.
|
||||
|
||||
대조에서 빠지는 줄도 있다. 20자 미만인 줄, `#`·`//`·`|`·`>` 로 시작하는 줄, 그리고 한글과 흐름
|
||||
글리프(`─`·`▶`·`→`·`←`)가 함께 있는 줄 — 필자가 그린 흐름도 — 을 건너뛴다. `nano ~/.bashrc` 는
|
||||
14자라 대조 없이 통과한다. 통과했다는 것과 SSOT 에 있다는 것은 다르므로 짧은 명령도 사람이
|
||||
SSOT 에서 찾아 대조한다.
|
||||
|
||||
**한글이 섞였다는 것만으로는 안 빠진다.** 예전에는 그랬고, 그래서 자리표시자를 한글로 감싼
|
||||
`psql -c "…"` 한 줄이 통째로 대조에서 빠졌다. 지금은 흐름 글리프까지 있어야 흐름도로 본다.
|
||||
|
||||
순서는 SSOT 가 먼저다. 구축 절차를 담은 부(virtualization 은 제6부 §184~§194)에 사람이 치는
|
||||
형태를 적고, 그 형태도 원 가이드나 저장소에서 확인한 뒤에 적는다. 기록을 먼저 고치고 검사기가
|
||||
막을 때 SSOT 를 맞추면 SSOT 가 근거이기를 그만두고 기록의 사본이 된다. CLAUDE.md 의 「보강은
|
||||
상류 원문으로 한다」가 같은 말이다.
|
||||
|
||||
형태를 바꾸는 것과 사실을 바꾸는 것은 다르다. 원 가이드가 `printf ... > meta-kc-lab-1` 로
|
||||
적었다면 그 파일에 무엇이 들어가는지는 원문이 이미 갖고 있으므로, SSOT 에는 그 내용을 파일
|
||||
목록으로 옮기고 파일을 여는 명령을 앞에 둔다. 원문이 만들지 않은 파일이나 재지 않은 출력을
|
||||
새로 만들지 않는다.
|
||||
|
||||
**② 셸이 여럿인 실험대에서는 코드블록마다 어디서 치는지 붙인다.** 산문에 한 번 적어 두면 따라
|
||||
하는 도중에는 안 보인다. 본문 파서가 코드블록의 `label` 을 받으므로 거기에 적는다.
|
||||
|
||||
```bash label="[lab host] 저장소 루트에서 친다"
|
||||
kubectl apply -f deploy/lab/k8s/keycloak-cluster.yaml
|
||||
```
|
||||
|
||||
virtualization 의 SSOT §185 ③ 이 그 표시를 다섯으로 정해 두었다 — `[워크스테이션]` ·
|
||||
`[lab host]` · `[kc-lab-edge]` · `[kc-lab-1]` · `[kc-lab-2]`. 표시가 없으면 같은 명령이 다른
|
||||
기계에서 다른 결과를 낸다.
|
||||
|
||||
**③ 비밀은 길이와 존재 여부까지만 적는다.** 값을 찍는 명령을 본문에 두지 않는다. 토큰이 필요한
|
||||
단계는 값을 찾는 명령을 주고 `echo "${#TOKEN} 자"` 로 끝낸다. `final/evidence/` 에 올리는 원문에도
|
||||
값이 들어가지 않도록 명령을 짜는 것이 먼저다. 터미널 렌더러가 Bearer·Cookie·token·password 를
|
||||
`[REDACTED]` 로 바꾸지만 그 앞에서 막는다.
|
||||
|
||||
## Reference — 14건
|
||||
|
||||
칸은 `관계` · `목적` · `규칙` · `적용 조건` · `예외` · `예시`. 14건 모두 여섯 칸을 채웠다. 본문이 없다.
|
||||
@@ -124,7 +280,8 @@ basisVersion: oauth2-proxy 7.15.2 · Nginx auth_request
|
||||
|
||||
규칙 제목만 읽어도 무엇을 금지하는지 알아야 한다. 「지표를 정확히 읽는다」보다
|
||||
「지표 이름이 뜻하는 것을 그대로 읽는다」가 낫다. 코드가 필요하면 그 코드가 있는 Case 를 만들고
|
||||
`관계`로 가리킨다 — Reference 칸은 평문이라 백틱이 글자로 보인다.
|
||||
`관계`로 가리킨다 — Reference 칸은 마크다운 블록 파서를 안 거쳐서 코드펜스가 글자로 보인다.
|
||||
낱말 하나짜리 식별자는 백틱으로 감싸면 인라인 `<code>` 로 살아난다. 여러 줄짜리 코드가 문제다.
|
||||
|
||||
## Question — 9건
|
||||
|
||||
@@ -151,7 +308,7 @@ basisVersion: oauth2-proxy 7.15.2 · Nginx auth_request
|
||||
|
||||
## Decision — 9건
|
||||
|
||||
칸은 **`근거`** · `결정문` · `판단 이유` · `영향`. **다른 넷과 달리 관계 절 이름이 「근거」다.**
|
||||
칸은 **`근거`** · `결정문` · `판단 이유` · `영향`. **다른 다섯과 달리 관계 절 이름이 「근거」다.**
|
||||
`decisionStatus` 는 frontmatter 에 있다. 근거가 1개 이상 없으면 게시가 거절된다.
|
||||
|
||||
| 칸 | 무엇을 |
|
||||
@@ -163,14 +320,14 @@ basisVersion: oauth2-proxy 7.15.2 · Nginx auth_request
|
||||
대안을 적고 왜 고르지 않았는지 적는다. 대안이 없으면 결정이 아니라 사실이다. 자료가 뒷받침하지
|
||||
않는 이유를 만들지 않는다.
|
||||
|
||||
## 본문이 있는 두 종류의 공통 규칙
|
||||
## 본문이 있는 세 종류의 공통 규칙
|
||||
|
||||
- **그림이 필요한지와 무엇을 그릴지는 `choosing-a-diagram.md` 가 정한다** — 종류마다 그림이
|
||||
답해야 할 물음이 다르다. Case 는 순서, Concept 은 구조나 변환 사슬이 대개 논지다
|
||||
- 그림은 `technical-visualizer` 로 만든다. 손으로 SVG 를 그리지 않는다
|
||||
- 그림 안에는 이름만 넣는다. 문장은 `<desc>` 와 옆 문단에 둔다
|
||||
- 그림과 증거는 frontmatter 의 `assets` · `evidence` 로 잇는다. 같은 파일을 기록 옆에 복사하지 않는다
|
||||
- `assets` 는 본문이 있는 두 종류만 갖는다. Reference·Question·Decision 은 그림을 렌더링할 자리가
|
||||
- `assets` 는 본문이 있는 세 종류만 갖는다. Reference·Question·Decision 은 그림을 렌더링할 곳이
|
||||
없어서 선언해도 화면에 나오지 않는다
|
||||
- 본문은 `<!-- body:start -->` 와 `<!-- body:end -->` 사이다. 그 밖은 Studio 로 가지 않는다
|
||||
|
||||
|
||||
Reference in New Issue
Block a user