chore(요구): 요구서 359 고침(요구 360) — 가이드 한 벌 A05 · [?] = 그 페이지 링크 · 더블클릭 바로 고침 · 그림 더블클릭 파일 지정 · 재조사 둘

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-26 08:08:01 +09:00
co-authored by Claude Opus 5.5
parent e679de2933
commit 0dc66e1666
3 changed files with 298 additions and 31 deletions
@@ -0,0 +1,151 @@
# 360-A 사용자 가이드 재조사 — 한 가이드 · 페이지 링크 · 더블클릭 바로 고침
조사일 2026-10-26 · 코드 고침 없음 · 359-A(Altair Flux · 라이브러리 표) 되풀이 안 함 · 요구 360 기준.
지금 코드 확인 — `ui_template/ui_template_help.ts`(모달 · 자체 변환기 `renderHelpMarkdown` = HTML 먼저 막음 · `data-help-topic`) · `common_util/common_util_help_router.py`(`GET /api/help/{page}` = 그 페이지 md 통째) · 깔린 것 `python-multipart 0.0.6` · `pillow 12.3.0`.
---
## ① 결론 다섯 줄
1. 한 가이드 + 페이지 링크 = 공학 프로그램 공통 꼴 — Feko · MicroStation · Civil 3D · GeoStudio 모두 F1/[?] = 한 도움말의 그 주제 자리로 바로 · 주제 없으면 첫 화면. 우리 = 기존 [?] 모달을 「가이드 통째 한 두루마리 + 왼쪽 차례 + 그 페이지 자리로 스크롤」로 바꿈 · 자리 이름 = `B05` · `B05/02_구조물`(파일 이름 그대로).
2. 더블클릭 고침 = 그 덩어리(제목 · 문단 · 목록 · 표 · 그림 줄)를 그 덩어리의 마크다운 원문 `<textarea>` 로 바꿔 끼움 — contenteditable 은 고친 HTML 을 마크다운으로 되돌리는 변환이 필요하고 표 · 그림 · 굵게가 깨짐 · textarea 는 한글 조합 · 붙여넣기(늘 글만) · Ctrl+Z 가 브라우저 기본.
3. 저장 = 지금 마크다운 파일에 바로 덮음(요구 360-1 · 덧층 · 초안 없음) — 변환기가 덩어리마다 원문 줄 범위(`data-src`)를 달고 고친 줄만 갈아 끼워 파일 통째 PUT · 판 확인(If-Match → 412) · HTML 저장 · 소독기(nh3) 불필요 — 변환기가 원 HTML 을 먼저 막음.
4. 그림 더블클릭 = 숨은 `<input type="file" accept="image/png,image/jpeg,image/webp">` — showOpenFilePicker 는 Chromium 만 · 보안 문맥(HTTPS · localhost)만 → 임시 배포 주소(http + Tailscale IP)에서 못 씀. 「경로와 파일 지정」 = 내 PC 어느 폴더든 파일 고름 · 서버 쪽은 지금 이름 그대로 덮음(글 고칠 일 0) · Pillow 로 진짜 그림 확인 · WebP 로 바꿔 씀 · 주소 `?v=판` 으로 바로 보임.
5. 새 라이브러리 0 — 깔린 python-multipart(Apache-2.0) · Pillow(MIT-CMU)만 · 베낄 것 = 「원문 줄 번호를 덩어리에 다는」 생각(markdown-it-inject-linenumbers · MIT)뿐 · pell(HTML 출력) · OverType(그림 · 표 안 그림) · 무거운 편집기 안 맞음.
---
## ② 한 가이드 + 페이지 링크
### 사례
| 프로그램 | 여는 길 | 어디에 뜸 | 이어지는 단위 | 주제 없을 때 | 출처 |
| --- | --- | --- | --- | --- | --- |
| Altair Feko(CADFEKO) | F1 | 웹 도움말 | 고른 대화상자 · 패널 · 보기의 주제 | 도움말 첫 화면(찾기 · 둘러보기) | https://help.altair.com/feko/topics/feko/bank/help_feko_c-cadfeko.htm |
| Altair Flux | Supervisor [?] | 로컬 / 온라인 설명서 고름 | — | — | 359-A |
| Bentley MicroStation(OpenRoads 바탕) | F1 · 도구 쓰는 중 `help` 입력 | 기본 웹 브라우저 | 입력 초점 대화상자 · 쓰는 도구 | — | https://docs.bentley.com/LiveContent/web/MicroStation%20Help-v28/en/GUID-402FD14A-5395-A006-1988-CBBDFB93E9F7.html · https://communities.bentley.com/products/microstation/w/microstation__wiki/62892/quickly-display-help-for-the-active-command |
| Bentley OpenRoads Designer | (위와 같은 틀) | docs.bentley.com 한 사이트 · 왼쪽 차례 | 주제 = `GUID-….html` | — | https://docs.bentley.com/LiveContent/web/OpenRoads%20Designer%20Help-v19/en/GUID-1B18BC16-7361-4DA1-BC57-D8A9EEF3F9E7.html |
| Autodesk Civil 3D | Help 단추 · F1 | 웹 도움말(인터넷 없으면 내려받은 판) | 주제 = `…/files/GUID-….htm` | — | https://help.autodesk.com/cloudhelp/2026/ENU/Civil3D-Installation/files/GUID-7884E19E-8363-4B78-A71F-2042310271D2.htm |
| Seequent GeoStudio | F1 | GeoStudio Help | 열린 창마다 주제(예 그래프 창 → 그래프 주제) | — | https://www.seequent.com/10-geostudio-tips-in-10-minutes/ |
| McNeel Rhino | F1 · Help 패널 | Help 패널 · Dynamic Help = 쓰는 명령 주제를 자동으로 바꿔 보임 | 명령 · 대화상자 | — | https://docs.mcneel.com/rhino/8/help/en-us/commands/help.htm |
| Rocscience Slide2 · RS2 | 웹 사용자 안내서 | 한 사이트 · 왼쪽 차례 나무 · 안내서 안 찾기 | 쪽 = `/help/slide2/documentation/<절>/<쪽>` | — | https://www.rocscience.com/help/slide2/documentation/slide-model/general-features/sidebar (프로그램 F1 연결은 확인 못 함) |
공통 꼴
- 문서는 하나 · 주제마다 바뀌지 않는 자리 이름(GUID · 경로) · 프로그램은 「화면 → 자리 이름」만 가짐.
- 주제 없으면 첫 화면으로 · 왼쪽 차례 + 이전/다음 · 찾기.
- 띄우는 곳은 거의 「브라우저 새 창」 — 데스크톱 프로그램이라 그럼 · 우리는 이미 브라우저 안 → 모달 · 새 탭 둘 다 가능.
### 두 꼴 견줌
| | 모달 — 가이드 통째 · 그 자리로 스크롤 | 따로 가이드 페이지 — 새 탭 `#/guide?at=B05/02_구조물` |
| --- | --- | --- |
| 작업 흐름 | 화면 위에 덮음 · 닫으면 하던 자리 | 작업 창 옆에 띄워 둘 수 있음 |
| 있는 코드 | `ui_template_help.ts` + `openModal` 그대로 키움 | 새 주소 · 라우터 · 로그인 막이 · 틀 |
| 그림 크기 | 모달 폭(약 90vw)까지 | 화면 폭 다 |
| 링크 | 모달 안 자리 이름(주소창 안 바뀜) | 주소창 · 즐겨찾기 · 뒤로 |
| sessionStorage | 그대로 | 새 탭 = 따로(가이드엔 필요 없음 · 로그인 쿠키는 같이 씀) |
| 관리자 고침 | 같음 | 같음 |
**권함 = 모달 · 가이드 통째 한 두루마리 · 그 페이지 자리로 스크롤(걸러 내지 않음).** 이미 있는 틀 · 작업 화면을 안 떠남 · 「링크로 그 페이지」는 자리 이름으로 충족. 새 탭이 필요해지면 같은 그리기 함수를 쓰는 주소 하나만 더함(지금 안 함).
### 짜임
- 자리 이름 = `B05`(페이지) · `B05/02_구조물`(주제 = 파일 이름) · 절 = `B05/02_구조물/<제목 글>` → 요소 id · `scrollIntoView({block: "start"})` + CSS `scroll-margin-top`.
- [?] → 지금 보이는 `data-help-topic`(이미 있음)의 주제 자리 → 없으면 페이지 자리 → 없으면 맨 앞(Feko 꼴). B05 · B06 짝(`PAIR`)은 통째 두루마리라 필요 없어짐.
- 차례 = 그룹(설계 · 예정노선 · 평가) → 페이지 → 주제 3단 · 주제 끝 [이전] [다음] · 덤 = 스크롤 따라 지금 자리 밝힘(IntersectionObserver).
- 양 = 페이지 19 × 파일 몇 개 · 그림 150장 → 그림 `loading="lazy"` + 페이지 절 CSS `content-visibility: auto` 로 통째 그려도 가벼움.
- 서버 = 모든 페이지를 한 번에 주는 `GET /api/help` 하나 더함(또는 페이지별 병렬 부름).
- 가이드 안 다른 주제 링크 = `[글](#B06/01_표준횡단)` → 모달 안 이동.
---
## ③ 더블클릭 바로 고침
### 방식 비교
| | A. contenteditable(그린 글 위에서) | B. 덩어리를 원문 textarea 로 바꿔 끼움 |
| --- | --- | --- |
| 저장 | 고친 HTML → 마크다운 되돌림 변환 필요 · 표 · 그림 · 굵게 · 목록 깨지기 쉬움 | textarea 값 = 원문 · 그 줄만 갈아 끼움 |
| 한글 조합 | Enter 가로챌 때마다 조합 확인 · 브라우저마다 다름 | 기본 동작 그대로 · 가로채는 키만 확인 |
| 붙여넣기 | `true` = 서식째 들어옴 · `plaintext-only` = 글만(Firefox 136 · 2025-03부터) | 늘 글만 |
| 되돌리기 | innerHTML 다시 쓰면 Ctrl+Z 사라짐 · Safari 는 묶어 되돌림 | 브라우저 기본 Ctrl+Z |
| 보임 | 고칠 때도 완성 모양 | 고칠 때만 원문(`**` · `\|` · `![]()`) 보임 |
| 코드 | 많음 | 적음 |
**권함 = B.** 단점(원문이 보임)은 관리자 한 사람 · 지금도 메모장으로 마크다운을 고쳐 옴 → 견딜 만함.
출처 — https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/contenteditable · https://caniuse.com/mdn-html_global_attributes_contenteditable_plaintext-only · https://meta.discourse.org/t/add-better-undo-support-when-inserting-formatted-text/214821 · https://lists.w3.org/Archives/Public/public-webapps-github/2016Sep/1412.html
### 덩어리 = 변환기 한 출력 단위
- 제목 한 줄 · 문단 · 목록 통째 · 표 통째 · 그림 한 줄 — 변환기가 덩어리 여는 태그에 `data-src="시작-끝"`(원문 줄 번호) · `data-key="B05/02_구조물"` 을 닮.
- 지금 `renderHelpMarkdown` 은 줄 단위 반복이라 몇 줄로 됨 · 같은 생각 = markdown-it `token.map` 으로 `data-source-line` 다는 플러그인(https://github.com/digitalmoksha/markdown-it-inject-linenumbers · MIT · 코드는 안 가져옴).
- 더블클릭 → 그 줄들로 textarea(높이 자동 · 둘레 덩어리 그대로) → 저장하면 그 덩어리만 다시 그림.
### 키 · 저장 · 취소
| 동작 | 결과 |
| --- | --- |
| 바깥 누름(blur) · Ctrl+Enter | 저장 — 바뀐 것 없으면 안 보냄 |
| Esc | 취소 · 원래 글 |
| Enter | 줄 바꿈(목록 · 표는 여러 줄) — 제목 한 줄 덩어리만 Enter = 저장 |
| 한글 조합 중 Enter · Esc | 무시 — `e.isComposing \|\| e.keyCode === 229` |
| 다 지우고 저장 | 그 덩어리 지움 — 물음 한 번 |
### 걸림 · 막이
- 한글 IME — Safari 는 조합을 끝내는 Enter 를 `isComposing = false` 로 보냄 · `compositionend` 플래그 직접 관리도 실패 → keyCode 229 를 같이 봄(MDN 권함). https://developer.mozilla.org/en-US/docs/Web/API/Element/keydown_event · https://bugs.webkit.org/show_bug.cgi?id=165004 · https://azukiazusa.dev/en/blog/ime-enter-submit
- 붙여넣기 — textarea 는 서식이 못 들어옴 · 할 일 없음.
- 실수 고침 — 더블클릭 손잡이는 시스템 관리자에게만 붙임(일반 사용자 = 단어 고르기 그대로) · 바뀐 것 없으면 저장 안 함 · 저장 뒤 알림 「저장됨 [되돌리기]」(직전 원문을 화면 메모리에 한 번만) · 그 뒤 되돌리기 = git(설명서 = git 추적).
- 둘이 같이 고침 — GET 이 파일마다 판(내용 해시 앞 12자) 줌 → PUT 머리 `If-Match` → 다르면 `412` → 「다른 관리자가 먼저 고침 · 새로 불러옴」 · 내 글은 textarea 에 남김(잃지 않음). https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/If-Match
- 보내는 꼴 — 화면이 원문 전체를 가짐 → 화면이 줄을 갈아 끼워 파일 통째 + 판을 PUT · 서버 = 관리자 확인(`require_system_admin`) · 페이지 · 파일 이름 정규식(`PAGE_RE` 그대로) · 크기 한도 · 임시 파일 쓰고 `os.replace`(반쯤 쓴 파일 막음).
- XSS — 저장은 마크다운 · 변환기가 모든 글을 `escapeHtml` 먼저 → 원 HTML 못 들어옴. 새로 받는 문법 둘만 막음: 그림 주소 = 파일 이름만(`[가-힣A-Za-z0-9_-]+\.webp` · 서버 그림 주소로 붙임) · 링크 = `#` 가이드 자리 또는 `https://` 만(`javascript:` 막음).
- HTML 로 저장하는 길(A 그대로 저장)은 서버 소독 필수 — nh3(MIT)가 답이나 마크다운 파일 · git 비교 · 메모장 고침 · 명사형 시험(`test_54_2_help_files.py`)을 다 잃음 → 안 권함. bleach 는 2023-01 폐기 예고 · 표준 `html.parser` 로 허용 목록 직접 짜기는 라이센스는 되나(PSF) 소독기 손수 만들기는 위험.
---
## ④ 그림 더블클릭 바꾸기
- 고르기 창 = 숨은 `<input type="file" accept="image/png,image/jpeg,image/webp">` 를 dblclick 안에서 `.click()` — 마우스 누름이 사용자 활성으로 쳐져 창 뜸(https://developer.mozilla.org/en-US/docs/Web/Security/User_activation).
- showOpenFilePicker 안 씀 — Chrome · Edge 105+ 만 · Firefox · Safari 없음 · 실험 표시 · 보안 문맥만 → 임시 배포(http://100.65…)에서 막힘 · 얻는 것(파일 핸들 · 같은 파일에 다시 쓰기)도 필요 없음. https://developer.mozilla.org/en-US/docs/Web/API/Window/showOpenFilePicker · https://caniuse.com/native-filesystem-api · https://web.dev/articles/files/open-one-or-multiple-files
- 「경로와 파일 지정」 실제 뜻 — 브라우저는 내 PC 경로를 안 줌(`C:\fakepath\이름`) · 서버 폴더를 고르는 창도 없음(https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input/file).
- 내 PC 쪽 = 창에서 어느 폴더 · 어느 파일이든 고름 → 이것이 경로 · 파일 지정.
- 서버 쪽 = 그 그림 지금 이름 그대로 덮음 → 글 `![](이름)` 고칠 일 없음 · 자동 캡처가 안 덮게 `_manual.json` 에 이름 적음(359 그대로).
- 고른 파일 이름으로 새로 두는 길 = 글 줄도 고쳐야 함 · 이름 겹침 · 남는 옛 그림 정리 생김 → 안 권함.
- 새 그림 넣기 — 따로 단추 없이 글 textarea 에 `![설명](새이름.webp)` 한 줄 써 넣음 → 빈 그림 자리가 그려짐 → 더블클릭으로 파일 고름(같은 손잡이 · 서버는 정규식 맞는 새 이름 받음).
- 서버 검사(accept 는 힌트일 뿐) — 크기 한도(5 MB · 읽으며 셈) → Pillow `Image.open` 으로 진짜 그림 확인(확장자 · MIME 안 믿음) · 픽셀 폭탄 = Pillow 기본 막이(`MAX_IMAGE_PIXELS`) · png · jpg 도 WebP 로 바꿔 같은 이름에(형식 하나 · 메타정보 빠짐) · 폭 상한 1800 px(2배 · 표시 900) · 임시 파일 → `os.replace`.
- 바로 보임 — 응답에 새 판(수정 시각) → `img.src = 주소?v=판` · 글 내려줄 때도 그림 주소에 `?v=수정시각` 붙임 → 옛 캐시 안 씀 · 다른 사람 화면은 다음에 열 때.
- 되돌리기 — 그림도 git 추적 → git · 직전 그림을 서버에 따로 두지 않음(요구 360-1).
- 덤(안 함) — 끌어다 놓기 · Ctrl+V 붙여넣기로 바꾸기.
---
## ⑤ 라이센스 표
상용 가능 = BSD · MIT · Apache · ISC · PSF 만 ○.
| 이름 | 쓰는 곳 | 라이센스 | 상용 | 판정 | 출처 |
| --- | --- | --- | --- | --- | --- |
| python-multipart 0.0.6 | 그림 올리기 받기(FastAPI `UploadFile`) | Apache-2.0 | ○ | 씀 · 설치됨 | https://pypi.org/project/python-multipart/ |
| Pillow 12.3 | 그림 확인 · WebP · 줄임 | MIT-CMU(HPND) | ○ | 씀 · 설치됨 | https://github.com/python-pillow/Pillow |
| Python `html.parser` | HTML 저장 때 허용 목록 | PSF | ○ | 안 씀(마크다운 저장) | 표준 라이브러리 |
| nh3 | HTML 소독(ammonia) | MIT | ○ | 안 씀 · HTML 저장으로 바뀌면 이것 | https://pypi.org/project/nh3/ |
| bleach 6 | HTML 소독 | Apache-2.0 | ○ | 안 씀 · 2023-01 폐기 예고 | https://pypi.org/project/bleach/6.2.0 · https://github.com/mozilla/bleach/issues/698 |
| markdown-it-inject-linenumbers | 덩어리에 원문 줄 번호 | MIT | ○ | 생각만 빌림 · markdown-it 전제 | https://github.com/digitalmoksha/markdown-it-inject-linenumbers |
| pell 1.0.6 | 1.4 KB 위지윅 | MIT | ○ | 안 맞음 · HTML 출력 · execCommand | https://www.npmjs.com/package/pell |
| OverType 2.4 | textarea 겹침 마크다운 편집 | MIT | ○ | 안 맞음 · 그림 · 표 안 그림 · 약 117 KB | https://cdn.jsdelivr.net/npm/overtype@2.4.0/README.md |
| DOMPurify 3 | 화면 HTML 소독 | MPL-2.0 / Apache-2.0 | ○ | 불필요(변환기가 HTML 막음) | 359-A |
---
## ⑥ 정할 거리
| 번호 | 정할 거리 | 권함 | 다른 길 |
| --- | --- | --- | --- |
| 1 | 가이드 그릇 | 모달(넓힘) | 새 탭 가이드 페이지 |
| 2 | 모달에 보일 범위 | 가이드 통째 · 그 페이지 자리로 스크롤 | 그 페이지만 + 차례로 이동 |
| 3 | 고침 방식 | 덩어리 원문 textarea | contenteditable 위지윅(+ 되돌림 변환 · 소독) |
| 4 | 저장 · 취소 키 | 바깥 누름 · Ctrl+Enter 저장 · Esc 취소 · 제목만 Enter 저장 | [저장] 단추 |
| 5 | 저장 직후 되돌리기 | 알림의 [되돌리기] 한 번 + 그 뒤 git | git 만 |
| 6 | 둘이 같이 고침 | 판 확인 412 · 내 글 남김 | 나중 것이 이김 |
| 7 | 그림 이름 | 지금 이름에 덮음 · WebP 로 바꿈 | 고른 파일 이름으로 새로 |
| 8 | 그림 한도 | 5 MB · 폭 1800 px 로 줄임 | 원본 그대로 |
| 9 | 새 그림 넣기 | 글에 그림 줄 써 넣고 그 자리 더블클릭 | [그림 넣기] 단추 |
| 10 | 저장 자리 | git 안 `resources/help` 파일 직접(359 정함 1 · 359-A 의 덧층 권함은 요구 360-1 로 버림) · 임시 배포에서 고친 것은 전역 깃 싱크가 올림 | DB · storage |
| 11 | 명사형 시험과 화면 고침 | 서버는 안 막음 · 시험이 잡으면 그때 고침 | 저장 때 서버가 검사해 막음 |
@@ -0,0 +1,110 @@
# 요구 360-B 코드 현황 — 한 가이드 · [?] 링크 · 더블클릭 바로 고침 · 그림 바로 바꿈
조사 = 읽기만 · 코드 · 문서 · DB · storage 고침 0 · 앞 조사 `docs/raw/요구_1025/_분석_359-B_코드현황.md` 위에 바뀐 것만.
## ① 결론 다섯 줄
1. 글 · 그림 한 폴더 `A05_EduDetail/guide/<페이지>/`(지금 `resources/help` 56 파일 git mv) · 꼴 = 페이지 폴더 · 기능 파일 그대로(파일 이름 = 고정 닻 `B05/구조물_배관`) · 큰 한 파일은 창 병행 충돌 · 700 줄 · 판 단위 탓에 안 씀 · D · E 의 00 · 10 · 20 · 30 문서는 손 안 대고 페이지 아래 절로 들어감.
2. [?] = 지금 모달을 「한 가이드」로 — 서버가 모든 페이지를 한 번에 주고 모달이 묶음 → 페이지 → 기능 차례 + 그 페이지(보이는 주제) 자리로 스크롤 · 해시 주소는 `?인자` 만 되고 `#닻` 은 안 됨 · 같은 탭 가이드 페이지 = 설계 화면 떠남 물음 · 3D 다시 세움 · iframe = 앱 통째 다시 띄움 → 둘 다 안 권함.
3. 더블클릭 고침 = `renderHelpMarkdown` 블록마다 원문 줄 범위를 달고 그 블록만 textarea(마크다운 원문 · 한글 조합 안전)로 바꿈 → `PUT` 이 판(sha256 16자) 맞을 때만 그 줄만 바꿔 원자 쓰기 · 다르면 409 · 권한 = 서버 `require_system_admin` + GET 응답 칸 · textarea 안 Esc 가 모달째 닫는 흠(`ui_template_modal.ts:58`) 막을 것.
4. 그림 더블클릭 = 자리(페이지 폴더 · 이름 칸) + 파일 고르기 → `POST` 가 그 폴더에 씀(B01 자산 선례 · 확장자 · 크기 · 경로 탈출 막음) · 같은 이름 = 덮음 · 다른 이름 = 그 그림 줄도 고침 · 새 그림 = 글에 `![설명](이름)` 쓰고 빈 자리 더블클릭 · 캐시 = `no-cache` + 바꾼 뒤 `?t=`.
5. 「따로 저장 없음」= 서버 폴더의 git 파일을 바로 고침 → 랩탑 메인은 미커밋으로 싱크 멈춤(`git-sync-all.ps1:62-65`) · 데스크탑 임시 배포는 전역 때 DIRTY 로 멈춤(`:106` · `:116`) → 두 자리에 「가이드 폴더만 커밋 · push」 몇 줄이 가장 작은 길 · 충돌 때 사용자 판 우선은 지금 지침(랩탑 쪽)과 달라 예외 한 줄 필요 · 캡처 도구(Playwright 1.62 · Pillow 12.3 WebP 됨 · Edge 있음) · 가이드 프로젝트 계획은 그대로.
## ② 항목별 현황(근거)
### 1. 한 가이드 짜임
- 지금 파일 = 페이지 폴더 19 · 56 파일 · 열쇠 = 파일 이름(`common_util_help_router.py:28` `path.stem`) · 차례 = 이름 순(`:25`) · 제목 = 첫 `# `(`:27`) · 글 = UTF-8 · BOM 없음 · LF(E02 · B05 · D04 표본 CR 0).
- 지금도 「페이지 → 기능」 꼴 — B05 `구조물_<종류>.md` 12 · B06 `표준_횡단면.md` · D · E `00_설명서` · `10_칸_뜻` · `20_쓰인_방법과_근거` · `30_사용자_확정_전_값` · B02 · B04 · B05 · B07~B09 `00_설명서` = 제목 네 줄 뼈대(9 줄).
- 서버 페이지 규칙 `^(B0[2-9]|D0[1-4]|E0[1-7])$`(`:17`) · 한 번에 한 페이지(`:32-34`) · 매번 파일 읽음 → 「한 가이드」 = 폴더 전부를 차례대로 한 응답(새 저장 꼴 아님).
- 쓰는 창 나눔 = 페이지 단위(PLAN `540-1` sub4 B01~B04 · `540-2` sub5 B05 · B06 · `540-3` sub6 B07~B09 · `541-1` sub7 · `541-2` sub8 · `542-1` sub3 · `PLAN.md:124-139`) → 페이지 폴더 · 기능 파일이면 창끼리 같은 파일 안 만짐 · 큰 한 파일이면 모든 창이 한 파일 → 합치기 충돌 · 700 줄 넘김(지금 합 ≈ 2 천 줄 · B 채우면 더 큼) · 관리자 저장 판이 가이드 통째 하나라 남의 페이지 고침에도 409.
- 글 자리 갈래 — `resources/help` 그대로면 글 · 그림 뿌리 둘(서버 상수 둘 · 싱크 경로 둘 · 그림 이름이 다른 폴더를 가리킴) · A05 로 옮기면 한 폴더(글 · 그림 · `_scenes.json` · `_manual.json`). 옮김 값 = git mv 56 + 참조 다섯: `common_util_help_router.py:16` · `test_54_2_help_files.py:42-43` · `resources/tester/ui_checks/54-2_도움말.js:7`(`resources/help/B04/99_임시.md`) · `B03_FileInput_UI_Guide.ts:5`(주석) · `ui_template_help.ts:4`(주석).
- Vite 영향 없음 — `root: "A00_Common"` · `publicDir: false`(`vite.config.ts:20-21`) · md · webp 는 import 안 되어 묶음 밖 · 서버 재시작 감시 = `*.py` 만(`config/config_dev_server.py:200-232`).
- 시험 `test_54_2_help_files.py` — B02~B09 첫 항목 00_설명서(`:13-16`) · 이름 순 · 고침 즉시 반영(`:19-29`) · 나쁜 페이지에 B01 · B10 들어 있음(`:32-35` · B01 가이드 넣으면 고침) · 뿌리 = `resources/help`(`:42-43`) · 명사형 검사 = D · E 만(`:46-58`). 사용자가 바로 고친 글이 「~합니다」면 이 시험이 빨개짐 → 글 내용 검사는 지킴 시험과 안 맞음.
### 2. [?] → 링크
- 페이지 열쇠 — `currentPage()` 가 주소 머리 `#/[bde]0N` → `B05`(`ui_template_help.ts:40-43`) · `?` 뒤가 있어도 맞음.
- 여는 길 — `openHelp`(`:132-168`) = 제 페이지 + 짝(B05 ↔ B06 · `:130` · `:134-136`) 둘을 불러 → 보이는 `[data-help-topic]` 마지막(`:114-119` · `:137-138`)부터 → 모달 한 항목씩 `innerHTML`(`:146-153`) · 차례 = 그 페이지 파일만(`:154-163`).
- 해시 주소 — `currentRoute()` = `?` 앞만(`A00_Common/router.ts:144-147`) · `currentQuery()` = `?이름=값`(`:149-152`) · `navigateTo(route, query)`(`:155-163`) → `#/a05-guide?page=B05&topic=구조물_배관` 은 됨 · 둘째 `#B05-route` 는 `URLSearchParams` 가 값에 붙여 버림 → 닻은 `?topic=` 으로만.
- 새 길 선언 — `draft/*_Route.ts` 글롭(`router.ts:79-95`) · `protected: true` 면 로그인 가드(`:186-190`) · 선례 `B09_Estimation/draft/B09_Draft_Print_Route.ts:9-15`(문자열 길 · ROUTES 상수 없이).
- (a) 모달 한 가이드 — 같은 탭 · 화면 그대로 · 로그인 API 그대로 · 큰 창 = `openModal({ wide: true })`(96vw × 94vh · `ui_template_modal.ts:21-22`) · 그림 폭 900 에 맞음.
- (b) 가이드 페이지 길 — 같은 탭이면 설계 화면 떠남 물음(`A00_Common/main.ts:89-100` · `A00_Common/design/design_leave.ts:102-129`) + 페이지 정리 · 3D 다시 세움(`router.ts:181-183`) · 새 탭 = `window.open` 선례 0 · ORCA 검증 탭 하나 규칙과 부딪힘 · A05 공개 길(`config_frontend.ts:100` · `PROTECTED_ROUTES :161-176` 밖)인데 help API 는 로그인(`main.py:553`).
- (c) 모달 + iframe — 셸 · 머리 · 세션 확인까지 앱 통째 다시 띄움 · 더블클릭 고침 · 캡처 · ORCA 가 프레임 안으로 한 겹 더.
- 권함 = (a) · 같은 그리기 함수를 뒤에 길(b)에도 붙일 수 있음(지금은 안 만듦).
- `data-help-topic` — 있는 둘(`B05_Profile_UI_Structures_Panel.ts:243` · `B06_Section_UI_Standard_Panel.ts:315`)은 「그 기능 절로 스크롤」로 그대로 살림 · 새로 다는 것은 필수 아님(요구 = 페이지 자리) · 다는 일은 각 페이지 코드 고침이라 쓰는 창 충돌 거리.
- 짝 처리(`:129-136`) 걷음 — 한 가이드에 다 있음 · B06 구조물 주제는 「제 페이지 먼저 · 없으면 모든 페이지」에서 찾음.
### 3. 더블클릭 바로 고침
- 그리기 짜임 — `renderHelpMarkdown`(`:59-112`) = 줄 고리(`:78-109`) · 표 = 줄 범위 `index` 로 읽음(`:81-92`) · 제목 한 줄(`:93-98`) · 목록 = 이어진 줄(`:99-104`) · 문단 = 이어진 줄(`:105-108`) · 문단 · 목록은 서로 배타(`:101` · `:106`) · 내보냄은 `flush`(`:72-77`) → 블록 시작 줄만 기억하면 블록마다 `data-src="시작-끝"` 달기 쉬움(목록은 `<ul>` 를 flush 때 한꺼번에 내야 끝 줄을 앎).
- 같은 함수 쓰는 곳 하나 더 — B01 지식 채팅(`B01_Dashboard_UI_Knowledge_Chat.ts:2` · `:167`) → 줄 범위 · 그림은 페이지를 넘긴 때만(지금 꼴 유지).
- 고침 꼴 — contenteditable 은 HTML → 마크다운 되돌림이 표 · 굵게 · 코드에서 깨짐(선례도 `B06_Section_UI_Cross_Detail.ts:106` 한 칸) → 블록 원문을 textarea 로 바꿔 끼움이 맞음 · 더블클릭 → 입력 칸 바꿔 끼움 선례 `A00_Common/spreadsheet/spreadsheet_tabs.ts:69` · `:98-113` · 누름 · 더블클릭 가름(250 ms) 선례 `B08_Quantity_UI_Milestone_Diagram.ts:446-456` · 손가락 두 번 톡 = dblclick(`A00_Common/touch_bridge.ts:182`).
- 한글 조합 — textarea 자체는 조합 안전 · 단축키 처리만 `isComposing` 거름(`B01_Dashboard_UI_Knowledge_Chat.ts:67` · `ui_template/ui_template_data_table.ts:521`) · 설계 화면 단축키는 textarea 를 건너뜀(`B05_Profile_UI_RouteEdit_Keys.ts:117`).
- 모달 흠 — 바탕 keydown Esc = 모달 닫기(`ui_template_modal.ts:58`) → textarea Esc 는 `stopPropagation` · 열린 고침이 있으면 `beforeClose` 물음(`:25` · `:41-43`).
- 저장 선례 — 판 = sha256 앞 16자(`M02_Template_Layers.py:123-127`) · 판 다르면 `StaleTemplate` → 409(`:43-49` · `:245-250`) · 원자 쓰기 = 임시 파일 → `os.replace`(`M02_MasterTemplete/DataFlow/M02_DF_Router.py:80-87` · `common_util/common_util_atomic.py:10-31` `atomic_write_bytes`) · 경로 탈출 막음 `_inside`(`M02_Template_Layers.py:59-63`) · 권한 `require_system_admin`(`common_util/common_util_auth.py:167-172`) · 묶음 예 `main.py:530`.
- 줄 바꿈 안전 — 판이 맞으면 파일이 그대로라 보낸 줄 범위가 맞음 · 판 확인 ~ 쓰기 사이 경합은 관리자 한 명이면 무시 가능(`ponytail:` 표시 · 필요하면 잠금 하나).
- 관리자 판정(화면) — `fetchDashboardMe().role`(`B01_Dashboard_Api_Fetch.ts:214-217` · 기억 선례 `ui_template_workflow_layout.ts:10-15`) · 더 가벼운 것 = 기억된 세션 `fetchSessionUser()`(`A06_Login/A06_Login_Api_Fetch.ts:91-93` · `role :14`) · 가장 작은 길 = GET 응답에 `admin` 칸(서버가 세션 role 로) · 요청 하나 덜.
### 4. 그림 바로 바꿈
- 올리기 선례 `B01_Dashboard_Router_Assets.py:52-80`(`UploadFile` · 확장자 `:66-68` · 크기 · 빈 파일 `:71-72`) · 내려주기 `:121-129`(`Response(content, media_type)`).
- 내려주기 자리 — Vite 정적 없음(`vite.config.ts:21`) · 서버 `/static` = 빌드 결과(`main.py:368-372`) · `/b07-cad` 따로(`:393-397`) → `/api/help/<페이지>/img/<이름>`(로그인 쿠키 같은 출처) 그대로.
- 캐시 — Starlette 0.27.0 `FileResponse` 는 304 처리 없음(StaticFiles 만) → 응답 `Cache-Control: no-cache` + 내가 바꾼 뒤 `img.src += ?t=` · 남의 화면은 다음 열 때 새 그림.
- 같은 이름 덮음 = 글 안 바뀜(가장 작음) · 다른 이름 = 그 그림 줄을 같은 PUT 으로 고침 · 옛 파일 남음(지울지 = 정할 거리).
- 누름 겹침 — 359 계획 「그림 누르면 새 탭 원본」과 더블클릭이 겹침 → 250 ms 가름(B08 선례) 또는 원본 보기 뺌.
- 손 바꾼 그림 표시 `_manual.json` — 바로 덮는 꼴에서도 필요(캡처를 다시 돌려도 관리자 그림을 안 덮음) · 올리기 때 서버가 이름을 더함.
### 5. 「따로 저장 없음」 = git 파일 바로 고침
- 자리 — 랩탑 메인 = `C:\Program_coding\…`(`main_laptop_1`) · 데스크탑 메인 = 임시 배포(`main_desktop_1` · `OWNERS.md:19-20` · `.claude/deploy_hold.txt`) · 시놀로지는 코드 폴더 안 옮김 → 고친 글은 그 서버 폴더에만 · 커밋 · push 해야 다른 데로 감.
- 랩탑 메인 — 미커밋이면 `git-sync.ps1` 받기 통째 건너뜀(`:240-242`) · `git-sync-all.ps1` 점검이 「미커밋」으로 멈춤(`:62-65` → `:116`) · 그 폴더 창의 autopush 가 쓸어 올림(커밋 글 섞임).
- 데스크탑 메인 — 보통 싱크는 임시 배포 건너뜀(`:95` 끝 칸 0 → `:106` `continue`) · 전역(`-Global`)이면 허용 목록(`:19` package 둘) 밖 미커밋 → DIRTY(`:106`) → 멈춤(`:116`) · 받기 단계는 랩탑 판과 같은 파일만 add(`:184`) · 모으기는 임시 배포 가지를 전역 때만(`git-sync.ps1:389-390`).
- 가장 작은 고침 — 두 자리에 「가이드 폴더만 add → 있으면 `chore(가이드): 사용자 편집` 커밋 → 제 가지 push」: 랩탑 메인 점검 고리(`:62` 앞 · 메인만) · 데스크탑 점검 몸(`:106` · 끝 칸 1 이고 `-Check` 아닐 때 · DIRTY 셈 앞). 그 뒤 모으기(`:169`)가 dev 로 옮김.
- 겹침 — 쓰는 창(서브)이 같은 파일을 고쳤으면 합치기 충돌 → 지금 규칙대로 abort · 보고(CLAUDE.md 6장) · 「같은 자리면 랩탑 쪽」 규칙과 반대로 가이드 폴더는 사용자 판 우선 → 지침 예외 한 줄(사용자 승인) · 겹침 줄이는 길 = 페이지 넘긴 뒤엔 쓰는 창이 그 페이지 안 만짐.
### 6. 캡처 · 가이드 프로젝트
- 도구 — `playwright==1.62.0` · `pillow==12.3.0`(`requirements.txt:31-32`) · venv 에서 import 됨 · Pillow WebP 됨 · Edge 있음(`Program Files (x86)/Microsoft/Edge`) · 채널 선례 `B08_Quantity_Milestone_Capture.py:38`.
- 359-B ⑤ · ⑥ 계획 그대로 — 가이드 전용 용화 복제 · E · D 가이드 프로젝트 새로 · PLAN `539-1~4`(`PLAN.md:116-122`).
- 한 가이드로 바뀌는 것 — 그림 폴더 = 글 폴더(옮기면) · 장면 이름 = 페이지 폴더 안 · 기능별 바로 열기는 필수 아님(페이지 자리로 감) · `_manual.json` 건너뜀 유지 · 쓰는 창이 그림 · 글을 같은 폴더에 써서 창끼리 페이지 나눔 그대로.
## ③ 권하는 구조
- 글 자리 — `A05_EduDetail/guide/<페이지>/` 한 폴더(md · webp · `_scenes.json` · `_manual.json`) · `resources/help` 는 git mv 로 옮김(이력 남음) · 쓰는 창이 일 잡기 전에.
- 파일 꼴 — 페이지 폴더 · 기능 파일(지금 그대로) · `00_설명서` = 화면 한눈에 · `01~09_<기능>` = 조작 · `10` · `20` · `30` = 있는 D · E 문서 그대로 · 닻 = `<페이지>/<파일 이름>` · 페이지 이름 = `00_설명서` 첫 제목 · 묶음 이름(임도 설계 · 예정노선 · 안정성평가)만 화면 상수.
- 읽기 — `GET /api/help` 한 번 = 모든 페이지 `[{page, title, items:[{key, title, text, version}]}]` + `admin` · 페이지 규칙 = `^[BDE]\d{2}$` 폴더만 · `_` 로 시작하는 파일 · 그림은 항목 아님.
- 링크 — [?] = 같은 모달 · `wide` · 왼쪽 차례(묶음 → 페이지 → 기능 · 지금 페이지 펼침) · 오른쪽 한 글(모든 페이지 이어 그림 · 그림 `loading="lazy"`) · 처음 = 보이는 주제 절 → 없으면 그 페이지 절로 `scrollIntoView` · 짝 처리 걷음.
- 고침 — 시스템 관리자만 · 블록 더블클릭 → 그 블록 원문 textarea · Ctrl+Enter(또는 바깥 누름) = 저장 · Esc = 취소(모달로 안 올림) · `PUT /api/help/{page}/{key}` `{version, start, end, text}` → 판 다르면 409 → 「먼저 바뀜 — 다시 불러옴」 · 저장 뒤 그 항목만 다시 그림 · 새 문단 · 새 절 = 이웃 블록 글 칸에 줄을 더 씀(따로 단추 없음).
- 그림 — `![설명](이름.webp)` 한 줄 → `<figure><img><figcaption>` · 없는 그림 = 「그림 없음 — 더블클릭해 지정」 자리(관리자) · 더블클릭 → 작은 창(자리 = `<페이지>/` + 이름 칸 · 파일 고르기) → `POST /api/help/{page}/img`(png · jpg · webp · 5 MB · 이름 규칙 · `_inside` · Pillow 로 그림인지 확인) → 같은 이름 덮음 · 다른 이름이면 그 줄 PUT · `_manual.json` 더함 · 내려주기 `GET /api/help/{page}/img/{name}` `no-cache`.
- 코드 자리 — 서버 `common_util_help_router.py`(34 줄 → 약 130) 한 파일 · 쓰기 길 둘만 `dependencies=[Depends(require_system_admin)]` · 화면 `ui_template_help.ts`(221 줄) + 새 `ui_template_help_edit.ts`(더블클릭 · 그림 창).
- 싱크 — `git-sync-all.ps1` 두 자리 「가이드 폴더만 커밋 · push」 · 충돌 = abort 보고 · 가이드 폴더 사용자 판 우선 예외(지침 한 줄 · 사용자 승인).
- 시험 — 지킴 시험 = 코드 동작만(읽기 · 줄 바꿈 · 409 · 403 · 이름 규칙 · 경로 탈출 · 올리기 크기) · 글 내용 검사(명사형 · 가리킨 그림 있음)는 쓰는 창 자체 점검(`tmp/`)으로 내림.
## ④ 계획 걸음 후보
한 줄 = 무엇 · 어디 · 무엇으로 확인.
1. 글 자리 옮김 · `git mv resources/help A05_EduDetail/guide` + 참조 다섯 · `test_54_2` 통과 · 옛 [?] 모달 그대로 열림(ORCA B05).
2. 한 가이드 읽기 · `GET /api/help`(모든 페이지 · 판 · `admin`) · 시험(차례 · 판 · `_` 파일 뺌 · 나쁜 폴더 뺌).
3. 모달 한 가이드 · `ui_template_help.ts` 차례 · 스크롤 · `wide` · 짝 걷음 · ORCA B05 · B06(구조물 배관) · E02 [?] 에서 보이는 첫 제목 수치.
4. 그림 그리기 · 내려주기 · renderer `figure` + `GET …/img/{name}`(이름 규칙 · `_inside` · `no-cache`) · 시험(변환 글 · 경로 탈출 404) + ORCA 그림 보임.
5. 블록 원문 자리 · `renderHelpMarkdown` `data-src`(페이지 안 넘기면 지금과 같은 출력 — B01 채팅) · 시험(변환 글).
6. 글 바로 고침 · `PUT` 줄 범위 · 판 · 409 · 403 · 원자 쓰기 + 더블클릭 textarea · Esc · 조합 · `beforeClose` · 시험 + ORCA 한글 고침 → 원래 글로 되돌림.
7. 그림 바로 바꿈 · `POST …/img` · `_manual.json` · 이름 바뀜 = 줄 고침 · 시험(확장자 · 크기 · 그림 아님 거절) + ORCA 바꿈 → 되돌림.
8. 싱크 · `.claude/git-sync-all.ps1` 두 자리 · `-Check` 실행 + 데스크탑 가이드 파일 하나 고친 채 점검 통과 확인(브레인).
9. 캡처 · 가이드 프로젝트 · PLAN `539-1~4` 그대로(출력 = 같은 페이지 폴더).
10. 글 + 그림 채움 · PLAN `540~542` 그대로 · 창마다 제 페이지 폴더만 · `data-help-topic` 새로 안 닮(선택).
## ⑤ 정할 거리
1. 글 자리 — A05 로 옮김(권함) vs `resources/help` 그대로(글 · 그림 뿌리 둘).
2. [?] 꼴 — 모달 한 가이드(권함) vs 가이드 페이지 새 탭 vs 모달 + [새 창으로 보기].
3. 저장 때 — Ctrl+Enter · 바깥 누름 모두 저장(권함 · 「바로 저장」) vs Ctrl+Enter 만.
4. 그림 이름 바꿈 때 옛 파일 — 남김(권함 · 되돌림 쉬움) vs 지움.
5. 그림 한 번 누름 = 원본 새 탭 — 250 ms 늦춰 살림 vs 뺌.
6. 글 내용 검사(명사형 · 그림 있음) — 지킴 시험에서 빼고 쓰는 창 자체 점검으로(권함 · 사용자 글이 시험을 빨갛게 안 함) vs 그대로.
7. 가이드 충돌 때 사용자 판 우선 — CLAUDE.md 「랩탑 쪽」 규칙의 예외 한 줄(사용자 승인 필요).
8. 데스크탑에서 고친 글 올림 때 — 전역 깃 싱크 때만(지금 구조 · 권함) vs 보통 싱크 때도 데스크탑 메인 커밋 · push 만.
9. A05 공개 「교육」 페이지에 가이드 입구 — 로그인 뒤 같은 모달 · 로그인 전 공개 안 함(그림에 프로젝트 자료).
10. 묶음 차례 — B → E → D vs 이름 순 B → D → E · B01 · B10 · B11 넣을지(359 표 4).
@@ -1,6 +1,6 @@
# 요구서 359 — 사용자 가이드(페이지 · 기능별 그림 + 설명)
원문 = `사용자요구_1025.md` 요구 359 · 근거 분석 = `_분석_359-A_외부조사.md`(Altair Flux · 라이브러리) · `_분석_359-B_코드현황.md`(지금 도움말 · 페이지 목록 · 용화 프로젝트) · 계획 = `PLAN.md` 538~542.
원문 = `사용자요구_1025.md` 요구 359 · 원문 고침 = 요구 360 · 근거 분석 = `_분석_359-A_외부조사.md`(Altair Flux · 라이브러리) · `_분석_359-B_코드현황.md`(지금 도움말 · 페이지 목록 · 용화 프로젝트) · `_분석_360-A_외부조사.md`(한 가이드 링크 · 더블클릭 고침) · `_분석_360-B_코드현황.md`(옮김 · 고침 · 싱크) · 계획 = `PLAN.md` 538~542.
## 1. 사전조사 결과 (요구 359-7)
@@ -19,38 +19,37 @@
- 주의 상자 = 「주의 · 참고」 둘만 · 그림 = 2배 해상도로 찍어 폭 900 안팎으로 보임 · 그림 이름은 주제별로 묶음.
- 버릴 것 = 6단 깊은 차례 · 내용 없는 목록 페이지 · 따로 떨어진 문서 사이트.
## 3. 만들 것
## 3. 만들 것 (요구 360 반영)
### 3-1. 가이드 글 (페이지마다)
### 3-1. 가이드 한 벌
- 자리 = `A05_EduDetail/guide/<페이지>/` — 글(md) · 그림(WebP) · 찍을 장면 목록(`_scenes.json`) · 손으로 바꾼 그림 목록(`_manual.json`)을 한 폴더에 · 지금 `resources/help` 56 문서를 이 자리로 옮김(이력 남음).
- 짜임 = 묶음(임도설계 → 안정성평가 → 예정노선) → 페이지 → 기능 — 페이지 폴더 하나 · 기능 파일 하나 · 파일 이름이 링크 자리(예 `B05/02_구조물`).
| 파일 | 내용 |
| --- | --- |
| `00_설명서.md` | 화면 한눈에 — 통째 그림(번호) + 번호 표 + 작업 순서 |
| `01~09_<기능>.md` | 기능별 조작 — 여는 길 → 단계 표 → 그림 → 주의 · 패널 카드 · 모달마다 하나 |
| `10_칸_뜻.md` · `20_쓰인_방법과_근거.md` · `30_사용자_확정_전_값.md` | 있는 페이지는 그대로 · 그림만 더함 |
| `10_칸_뜻.md` · `20_쓰인_방법과_근거.md` · `30_사용자_확정_전_값.md` | 있는 D · E 문서 그대로 · 그림만 더함 |
- 그림 최대한 많이 — 페이지마다 통째 1장 + 카드 · 모달 · 단계마다 부분 그림 · 모두 150장 안팎.
- 기능별 열기 — 패널 카드 · 모달에 주제 표시를 달아 [?] 가 그 기능 주제부터 엶(지금 B05 구조물에 쓰는 방식).
- 글 = 명사형 종결(지금 시험이 검사).
### 3-2. 그림 자리 (요구 359-1)
### 3-2. [?] = 그 페이지로 가는 링크 (요구 360-2)
- `A05_EduDetail/guide/<페이지>/` — 그림(WebP) · 찍을 장면 목록(`_scenes.json`) · 손으로 바꾼 그림 목록(`_manual.json`).
- 서버가 그 폴더에서만 내줌(`/api/help/<페이지>/img/<이름>` · 로그인 · 경로 탈출 막음) — 관리자가 바꾸면 새로고침 없이 바로 보임.
### 3-3. [?] 모달 (요구 359-2)
- 지금 모달 그대로 · 글에 그림 · 주의/참고 상자 · 다른 주제 링크를 그림 · 그림 누르면 새 탭에 원본.
- [?] → 넓은 모달에 가이드 통째 · 왼쪽 차례(묶음 → 페이지 → 기능 · 지금 페이지 펼침) · 오른쪽 글은 그 페이지 자리로 바로 이동 · 위아래로 넘기면 다른 페이지도 이어 봄.
- 페이지마다 따로 만들지 않음 — 링크 자리만 다름.
- [?] 가 없는 대시보드(B01)에 [?] 하나 더함(머리 자리).
### 3-4. 시스템 관리자 바로 고침 (요구 359-4 · 6)
### 3-3. 시스템 관리자 바로 고침 (요구 360-1 · 3)
- 모달 머리에 [고치기](시스템 관리자만) → 글 상자(마크다운) + 옆 미리보기 → [저장] · 남이 먼저 고쳤으면 「다시 불러오기」 안내 · 안 저장 닫기 = 물음.
- 그림마다 [그림 바꾸기](png · jpg · webp · 5 MB · 같은 이름에 덮음) · [그림 넣기](올리고 글 칸에 그림 줄 넣음).
- 손으로 바꾼 그림은 표시 → 자동 캡처를 다시 돌려도 안 덮음.
- 저장 = 그 서버 폴더의 git 파일에 바로 씀(M02 마스터 시스템 층과 같은 길) → 깃 싱크가 「사용자 편집」 커밋으로 올림.
- 글 — 문단 · 제목 · 목록 · 표를 더블클릭 → 그 자리가 글 상자로 바뀜 → 바깥을 누르거나 Ctrl+Enter = 바로 저장 · Esc = 취소 · [저장] 단추 없음.
- 그림 — 더블클릭 → 파일 고르기 창(내 PC 어느 폴더든) → 고른 그림으로 바로 바뀜(같은 이름에 덮음 · WebP 로 바꿔 저장 · 폭 1800 px 넘으면 줄임).
- 새 그림 — 글에 그림 줄을 써 넣으면 빈 그림 자리가 생김 → 더블클릭해 파일 지정.
- 따로 저장 · 사본 없음 — 고친 것이 곧 가이드 내용(그 서버 폴더의 파일을 바로 덮음) · 다른 관리자가 먼저 고쳤으면 「먼저 바뀜 — 다시 불러옴」 안내 · 손으로 바꾼 그림은 자동 캡처가 다시 덮지 않음.
- 일반 사용자 = 읽기만(더블클릭해도 아무 일 없음) · 서버도 시스템 관리자만 받음.
- 고친 파일은 깃 싱크가 「사용자 편집」 커밋으로 올림 — 데스크탑 임시 배포에서 고친 것은 전역 깃 싱크 때.
### 3-5. 그림 만들기 (요구 359-6)
### 3-4. 그림 만들기 (요구 359-6)
- 원본 = 용화 노선 — 가이드 전용 복제 「가이드_용화」(검증_sub6 복제 · B07~B09 완료분) · E = 그 복제로 E01 생성 · E02~E07 돌림 · D = 용화 둘레 지점으로 새 예정노선(3 연도).
- 자동 캡처 스크립트 — 헤드리스 Edge · 장면 목록대로 화면 열기 · 카드 펼치기 · 모달 열기 → 노란 테두리 + 번호 원을 덧씌워 찍음 → WebP · 화면이 바뀌면 다시 돌리면 끝.
@@ -60,23 +59,30 @@
| 번호 | 정할 거리 | 정함 | 다른 길 |
| --- | --- | --- | --- |
| 1 | 관리자가 고친 글 · 그림 저장 자리 | git 파일 직접(M02 시스템 층과 같음 · 이력 = git) · 데스크탑에서 고친 것은 전역 깃 싱크가 올림 · 겹치면 사용자 편집 우선 | DB · storage 덧층(어느 PC 든 바로 공유 · 이력 없음) |
| 2 | 편집기 | 글 상자 + 미리보기 | 위지윅(TipTap · 의존성 큼) |
| 3 | 번호 표시 | 캡처 때 그림에 박음 + 그림 아래 번호 표 | 화면에서 덧그림(관리자가 옮김) |
| 4 | 대상 페이지 | B01~B09 · E01~E07 먼저 → D01~D04 다음 · B10 · B11(빈 화면) · M(관리자) 뺌 | D 빼기 |
| 5 | 원본 프로젝트 | 「가이드_용화」 복제(약 3 GB · 시놀로지로 데스크탑에도 번짐) | 검증_브레인232 그대로 씀 |
| 6 | 그림 형식 | WebP · 2배 캡처 · 폭 900 표시 | PNG |
| 7 | 고침 이력 | 마지막 판만(되돌리기 = git) | 판마다 보관 |
| 8 | 언어 | 한국어만 | 다국어 틀 |
| 1 | 가이드 그릇 | 넓은 모달 · 가이드 통째 · 그 페이지로 이동 | 새 탭 가이드 페이지(설계 화면 떠남 물음 · 3D 다시 그림) |
| 2 | 글 고침 방식 | 더블클릭한 덩어리를 원문 글 상자로(한글 조합 · 붙여넣기 · Ctrl+Z 브라우저 기본) | 화면 글 위에서 바로(표 · 그림 · 굵게가 깨짐) |
| 3 | 저장 때 | 바깥 누름 · Ctrl+Enter · 안 바뀌었으면 저장 안 함 | Ctrl+Enter 만 |
| 4 | 그림 이름 | 지금 이름에 덮음(글 안 바뀜) | 고른 파일 이름으로 새로 |
| 5 | 그림 한 번 누름 | 아무 일 없음(더블클릭과 안 겹침) | 원본 새 탭 |
| 6 | 글 검사 | 명사형 · 그림 있음 검사는 Claude 가 쓸 때만 · 사용자 고친 글은 안 막음 | 시험이 늘 검사 |
| 7 | 대상 페이지 | B01~B09 → E01~E07 → D01~D04 · B10 · B11(빈 화면) · M(관리자) 뺌 | D 빼기 |
| 8 | 원본 프로젝트 | 「가이드_용화」 복제(약 3 GB · 시놀로지로 데스크탑에도 번짐) | 검증_브레인232 그대로 씀 |
| 9 | 그림 형식 | WebP · 2배 캡처 · 폭 900 표시 | PNG |
| 10 | 기능별 [?] | 안 만듦(페이지 링크만 · 요구 360-2) | 카드마다 [?] |
## 5. 이번에 안 넣는 것 (필요하면 뒤에)
## 5. 사용자 확정
- 안내 투어(Driver.js) · 모든 페이지 글 찾기 · [인쇄] · A05 교육 페이지(로그인 전 공개)에 가이드 목차.
- 가이드 파일이 겹칠 때(사용자 고침 ↔ Claude 고침) **사용자 판 우선** — 지금 지침은 「랩탑 쪽 우선」이라 가이드 폴더만 예외 한 줄 필요(승인 대기).
## 6. 쓰는 라이브러리 (상용 조건)
## 6. 이번에 안 넣는 것 (필요하면 뒤에)
- 안내 투어(Driver.js) · 모든 페이지 글 찾기 · [인쇄] · 저장 뒤 [되돌리기] 단추(되돌리기 = git) · A05 교육 페이지(로그인 전 공개)에 가이드 입구(그림에 프로젝트 자료).
## 7. 쓰는 라이브러리 (상용 조건)
| 라이브러리 | 쓰는 곳 | 라이센스 | 상태 |
| --- | --- | --- | --- |
| Playwright(파이썬) | 자동 캡처 | Apache-2.0 | 설치됨 |
| Pillow | WebP 저장 · 자르기 | MIT-CMU(HPND) | 설치됨 |
| Pillow | WebP 저장 · 자르기 · 올린 그림 확인 | MIT-CMU(HPND) | 설치됨 |
| python-multipart | 그림 올리기 받기 | Apache-2.0 | 설치됨 |
| 새 라이브러리 | — | — | 0 |