# VERSION_HISTORY ## 0.2.0 (2026-10-28) - **작성자**: 개발 지시 — Neo(`Ariweb-Suitle_Dev-Order_v0.2.0.md`) · 구현 — Claude Fable 5.1(격리 작업 트리 `feature/visual-editor-v0.2.0`, 기준 main `4b3714e37c543fcfa8862dbc68c76f62a9b0bf97`). 커밋·push·병합·배포·운영 서버 접근은 하지 않았다 — Neo 가 검토 뒤 수행한다. - **이전 버전**: 0.1.1(2026-10-26, 첫 구현 릴리스 — 아래 절) · 0.1.4 개발 지시(2026-10-27, HAL AI 대시보드·다중 AI 공동 작업창 지시 문서만 추가, `4b3714e`). 0.2.0 은 **가운데 버전 번호를 올리는 기능 릴리스**다: 도입 모듈 Webmaker 에 사용자 기능(직접 편집)이 더해졌고 Webmaker 자체도 1.7.3 → **1.8.0** 으로 올랐다. 0.1.1 의 모든 기준·0.1.4 의 지시는 그대로 유효하다(이번 범위 밖의 0.1.4 항목은 구현하지 않았다). - **구성**: HAL · 고객 포털 · Node Agent 는 0.1.1 그대로. 도입 모듈 **Webmaker 1.8.0**(직접 편집 포함) · AriMail 1.0.11(변경 없음). 외부 npm 의존성 없음, Node 22.13+. ### 요구(사용자 요구 — 약화 없이 반영) Webmaker 가 초안을 만들어 보이는 페이지가 생긴 뒤 **직접 시각 편집 모드**를 더한다(Wix·아임웹 방식 끌어다 놓기). 변경은 Suite 의 `modules/webmaker` 와 기존 Webmaker 저장소 양쪽에 반영한다. 필수 동작·보안 규칙은 `Ariweb-Suitle_Dev-Order_v0.2.0.md` 에 계약으로 적었다. ### 재사용한 기존 기능(그대로 도입) - Webmaker 1.8.0 의 **직접 편집(시각 편집기)** 전부 — 미리보기 도구 줄 "직접 편집" 전환(사이트·HTML 페이지가 골라져 있을 때만), 캔버스 글 바로 고치기(두 번 클릭/Enter), 요소 선택·도구 막대(↑↓·복제·삭제·끌기 손잡이), 기존 블록 끌어 옮기기, 구성 요소 팔레트 7종(섹션/컨테이너·제목·문단·버튼(링크)·이미지·구분선·여백) 끌어다 놓기 + "추가" 버튼, 속성 창(상위 선택·이동·복제·삭제·글·링크 주소·이미지 주소/대체 글·정렬·글자색·배경색·안쪽/바깥 여백), 저장 상태(변경 없음/저장되지 않음/저장 중/저장됨/저장 실패 — aria-live), 저장(Ctrl/Cmd+S), 실행 취소/다시 실행, 버리고 다시 불러오기, 편집 끝내기, 페이지·사이트·화면 전환·새로고침·소스 보기 전환·창 닫기 전 저장하지 않은 변경 보호. 기존 소스 편집기·모바일 미리보기·버전/복원·배포·가져오기·다국어·모듈·SEO·Site Brief 는 그대로. - 재사용한 함수(Webmaker 기존 코드를 그대로 호출): `resolveTextFile`(경로 검증·링크 거부), `listFiles`, `gitRecord`/`lib/gitstore.recordChange`(버전 기록 — 새 종류 `visual-edit`), `publicView`, `broadcast`, `jobOf`(AI 작업·배포 중 판정), `readBody`, `sessionUser`·`fromTenantPage`·`auth.csrfOk`(출처·CSRF), `siteUrl`, `isSecureReq`, `MAX_TEXT_BYTES`(5MB 상한), `store.save`(Suite `rev` 증가). 화면: `discardOk`·`renderPreview`·`renderGit`·`loadFrame`·`setEditorOpen`·`logLine`·`pushMsg`·`api`(CSRF 헤더)·`T`. ### 수정한 기존 기능 - **Webmaker(`modules/webmaker`, 파일 머리·줄 주석 `v1.8.0`)**: `server.js` — `require('./lib/visual-editor')`, `veRuntime()`·`requestOrigin()`, `GET /files` 응답에 `hash`, 새 경로 `GET/PUT /api/sites//visual/<페이지>`(아래 "직접 편집·끌어다 놓기·저장·버전·보안"). `public/app.js` — `discardOk`(직접 편집 변경도 묻기), `VER_KIND` 에 `visual-edit`(기존 `manual-edit` 는 "소스 편집" 으로 표기), `renderPreview`(직접 편집 중이면 미리보기 덮어쓰지 않고 `VisualEditor.onSiteUpdated`), `btnToggleSource`(한 번에 하나), `beforeunload`, `resetToNew`, `btnReload`·`fileSelect.onchange`, `openSite` 끝(사이트 바뀌면 편집 종료). `public/index.html` — `#btnVisual`, `#veBar`, `.ve-stage`(`#vePalette`·`#frameWrap`·`#veInspector`), 스크립트 2개. `public/style.css` — `.ve-*`(900px 이하 세로 배치·접기). `public/admin.js` — 버전 종류 표기. `package.json` 1.8.0. - **Suite 최소 연결 변경(`[Ariweb Suite 변경]`, 0.1.1 의 8개 파일 변경은 그대로 유지)**: `modules/webmaker/server.js` 의 직접 편집 `PUT` 에도 저장본 `rev` 충돌 검사(`revConflict`, §9.3)를 소스 편집기·기본 사항 저장과 같이 적용 — 화면이 보낸 `rev` 가 다르면 409 와 양쪽 요약(`conflict.currentRev` 등). 화면(`visual-editor-ui.js`)은 `GET /visual` 의 `rev` 를 기억해 저장 때 보내고 응답의 `rev` 로 갱신한다(upstream Webmaker 는 `rev` 를 돌려주되 무시한다). 그 밖의 Suite 전용 변경(SSO·내부 API·배너·`lib/ariweb.js`·`store.rev`)은 바뀌지 않았다 — `diff` 로 upstream 과의 차이가 0.1.1 의 Suite 블록 + 1.8.0 공통 변경만임을 확인했다. - **Suite 도구**: `scripts/import-sources.mjs` 에 `--allow-dirty`(참조 저장소를 나란히 개발 중일 때 고정 커밋 위의 작업 트리 변경·추적되지 않은 새 파일을 가져오고 `upstream{version·branch·headCommit·workingTreeDirty·note}` 를 기록) 와 `--only` 때 다른 소스 기록 유지. `hal/modules/index.mjs`·`agent/jobs/module.mjs` 의 Webmaker 버전 주석, `portal/webmaker/REUSE.md` 갱신. Agent·포털 코드 동작은 바뀌지 않았다(릴리스 artifact 는 `package.json` 0.2.0 으로 `webmaker-0.2.0.tar.gz` 등으로 만들어진다). **`scripts/release.mjs` 와 `hal/core.mjs` 는 바뀌었다** — 도입 소스 출처 fail-closed(아래 ⑪)와 릴리스 승인 세 검사 필수(아래 종결 검토 ③). - 오류 수정: Webmaker 직접 편집 저장에서 JSON 파싱 실패가 500 으로 나오던 것을 400 한국어 안내로(TDD 중 발견, 직접 편집 경로에만 적용). - **검토 수정(Neo 독립 검토)** — ① 출시 차단: 직접 편집 PUT 이 본문을 읽기(await) 전에 파일 hash 를 잡아 두어 두 저장이 나란히 들어오면 둘째가 첫째를 조용히 덮어쓸 수 있었다 → 본문을 다 읽은 뒤 사이트 기록(`store.load`)·파일을 다시 읽어 hash(Suite 는 `rev` 도)를 비교하고 검증·쓰기까지 await 없이 이어 간다(둘째는 409 stale, 첫 저장 보존). 결정적 회귀 테스트(chunked PUT 두 개의 본문을 순서대로 완료). ② 안전 강화: 직접 편집 저장을 `lib/visual-editor.writeTextAtomic`(같은 폴더 임시 파일 0644 → rename, 실패 때 정리·오류 전달, 파일 시스템 주입 가능)로 바꿔 쓰기 실패·중단 때 마지막 정상 페이지가 잘리지 않는다(500 + "기존 페이지는 그대로 있습니다", 버전 미생성). 소스 편집기의 기존 쓰기는 바꾸지 않았다. ### 고객 화면 - 포털 사이트 상세 › 제작 탭 › "제작 화면 열기"(SSO) → Webmaker 빌더 오른쪽 미리보기 도구 줄의 **직접 편집**. 포털 자체 화면은 바뀌지 않았다. 직접 편집은 AI Wallet(캐시)을 쓰지 않으므로 포털 AI Wallet 카드에 영향이 없고, 직접 편집 저장본(버전 `visual-edit`)은 포털 배포 화면의 저장본 선택·Source 변경 이력에 그대로 보인다(내부 API `projects/` 의 `versionList`). - 포털 상단 배너(그룹·운영 사이트)는 직접 편집 중에도 그대로 보인다. ### 운영자 화면 - HAL 운영자 콘솔 변경 없음. Webmaker 관리자 콘솔의 버전·변경 종류 표기에 "직접 편집"(`visual-edit`)이 추가되고 기존 `manual-edit` 는 "소스 편집" 으로 보인다. 운영자 조치 항목 없음(설정값·보관소 변경 없음). ### 직접 편집 · 끌어다 놓기 · 저장 · 버전 · 보안 동작 - **캔버스**: `GET /api/sites//visual/<페이지>` 가 저장된 HTML 을 편집 캔버스 문서로 바꿔 준다(`lib/visual-editor.prepareCanvas`). 페이지 `