From 905e6d4eaaff88e838e1d4a223a507aeeb70de53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B5=9C=EC=A4=80=EC=98=81?= Date: Wed, 11 Nov 2026 11:09:05 +0900 Subject: [PATCH] chore: add Claude Code guidelines, rules and skills - CLAUDE.md: product principles, crate layering, common commands, commits. - .claude/rules: common, Rust, frontend, Tauri IPC, docs and security rules. - .claude/skills: check, add-tauri-command, project-model-change, change-record, msix-integration-test, backlog-status. Refs #16 Co-Authored-By: Claude Opus 5.5 --- .claude/rules/common.md | 47 ++++++++++++ .claude/rules/docs.md | 47 ++++++++++++ .claude/rules/frontend.md | 48 ++++++++++++ .claude/rules/rust.md | 60 +++++++++++++++ .claude/rules/security.md | 38 ++++++++++ .claude/rules/tauri-ipc.md | 35 +++++++++ .claude/skills/add-tauri-command/SKILL.md | 46 ++++++++++++ .claude/skills/backlog-status/SKILL.md | 37 +++++++++ .claude/skills/change-record/SKILL.md | 75 +++++++++++++++++++ .claude/skills/check/SKILL.md | 56 ++++++++++++++ .claude/skills/msix-integration-test/SKILL.md | 67 +++++++++++++++++ .claude/skills/project-model-change/SKILL.md | 42 +++++++++++ CLAUDE.md | 56 ++++++++++++++ 13 files changed, 654 insertions(+) create mode 100644 .claude/rules/common.md create mode 100644 .claude/rules/docs.md create mode 100644 .claude/rules/frontend.md create mode 100644 .claude/rules/rust.md create mode 100644 .claude/rules/security.md create mode 100644 .claude/rules/tauri-ipc.md create mode 100644 .claude/skills/add-tauri-command/SKILL.md create mode 100644 .claude/skills/backlog-status/SKILL.md create mode 100644 .claude/skills/change-record/SKILL.md create mode 100644 .claude/skills/check/SKILL.md create mode 100644 .claude/skills/msix-integration-test/SKILL.md create mode 100644 .claude/skills/project-model-change/SKILL.md create mode 100644 CLAUDE.md diff --git a/.claude/rules/common.md b/.claude/rules/common.md new file mode 100644 index 0000000..c8914b7 --- /dev/null +++ b/.claude/rules/common.md @@ -0,0 +1,47 @@ +# 공통 클린코드 규칙 + +모든 파일에 적용한다. 언어별 규칙은 `rust.md`, `frontend.md`, `tauri-ipc.md`, `docs.md`가 보충한다. + +## 범위와 변경 크기 + +- 요청한 범위만 바꾼다. 지나가는 코드의 스타일 정리·리네임·재배치를 섞지 않는다. +- 새 기능보다 기존 함수 재사용을 먼저 찾는다. `package-infra`에 이미 있는 `hash_file`, `atomic_json`, `reject_links`, `lock_project`, `appended_path` 같은 헬퍼를 다시 만들지 않는다. +- 한 함수는 한 가지 일을 한다. 분기가 3단계를 넘으면 이름 있는 함수로 뺀다. +- 파일 하나가 500줄을 넘기 시작하면 모듈 분리를 제안한다(현재 `main.ts`, `store.rs`가 경계선). + +## 이름 + +- 코드 식별자는 영어. 사용자에게 보이는 문자열(오류 메시지, UI 텍스트, 문서)은 한국어. +- 불리언은 상태를 그대로 읽히게 짓는다: `dirty`, `busy`, `available`, `trusted_people`. `is_`/`has_` 접두사는 Rust 메서드에서만. +- 약어를 새로 만들지 않는다. `doc`(ProjectDocument), `esc`(HTML escape)처럼 이미 쓰는 것만 유지한다. +- JSON 필드는 camelCase, Rust 필드는 snake_case, 변환은 serde `rename_all`에 맡기고 수동 매핑을 하지 않는다. + +## 오류 처리 + +- 오류 메시지 형식: `ErrorCode: 한국어 설명과 조치`. 코드는 PascalCase 한 단어(`RevisionConflict`, `MissingTool`, `InputChanged`). 기존 코드가 있으면 재사용하고, 새 코드는 README 또는 변경 기록에 적는다. +- 오류를 삼키지 않는다. 실패를 기본값으로 대체하는 fallback(미서명으로 자동 전환, 빈 설정으로 조용히 진행 등)을 만들지 않는다. 예외는 명시된 두 곳만: 최근 목록 저장 실패는 경고로 표시하고 프로젝트 열기를 막지 않는다, 이전 v2 프로젝트의 누락 `registry`/`signing` 필드는 기본값으로 연다. +- 조치 방법을 담는다. 사용자가 무엇을 고쳐야 하는지 한 문장으로. + +## 결정성 + +- 파일 목록·맵은 정렬된 자료구조(`BTreeMap`, `BTreeSet`, 정렬된 `Vec`)로 다룬다. 같은 입력은 같은 출력을 내야 한다. +- 시각은 UNIX 초(u64)로 저장한다. 표시 형식 변환은 UI에서만. +- 바이트 수처럼 JS `number` 정밀도를 넘을 수 있는 값은 IPC 경계에서 10진 문자열로 보낸다. + +## 주석과 문서화 + +- 주석은 "왜"만 쓴다. 코드가 말하는 "무엇"을 반복하지 않는다. 주석은 영어 한 문장. +- 공개 함수에 문서 주석을 달 때는 계약(입력 제약, 실패 조건, 부작용 없음)을 쓴다. +- TODO를 남기지 않는다. 미구현은 명시 오류로 거부하고 README의 "다음 작업"이나 백로그에 적는다. + +## 테스트 + +- 동작을 바꾸면 테스트를 함께 바꾼다. 실패 경로(거부, 충돌, 취소, 변조 탐지)를 성공 경로와 같은 비중으로 검사한다. +- 테스트 이름은 검증하는 규칙을 문장으로 쓴다: `json_and_duplicate_extensions_are_rejected_even_with_valid_contents`. +- 실제 SDK·네트워크·레지스트리·인증서 저장소를 건드리는 테스트는 `#[ignore]` 또는 환경 변수 게이트 뒤에 둔다. +- 테스트가 실패하면 그대로 보고한다. 테스트를 약화시켜 통과시키지 않는다. + +## 줄 끝과 인코딩 + +- UTF-8. `.gitattributes`에 따라 `*.md`, `*.json`, `*.html`은 LF. Rust/TS는 `text=auto`를 따른다. +- 파일 끝에 개행 하나. BOM 없음(현재 `style.css`의 BOM은 기존 상태이며 건드리지 않는다). diff --git a/.claude/rules/docs.md b/.claude/rules/docs.md new file mode 100644 index 0000000..68fa232 --- /dev/null +++ b/.claude/rules/docs.md @@ -0,0 +1,47 @@ +--- +paths: + - "docs/**/*.md" + - "README.md" + - "src/README.md" + - "src/tests/*.json" +--- + +# 문서 · 기록 규칙 + +문서는 한국어, 선언형 종결("~한다", "~이다"). 날짜는 `2026-10-23` 형식. 영어 식별자·명령·파일명은 백틱으로 감싼다. + +## 어떤 변경이 어떤 문서를 바꾸는가 + +| 변경 | 반드시 갱신 | +| --- | --- | +| 사용자 동작·CLI 옵션·종료 코드·오류 코드 | `src/README.md` 해당 절 | +| `.isproj`/local JSON 필드 | `docs/code-design/13-isproj-project-format.md`, `docs/code-design/examples/msix.isproj`, `src/fixtures/InstallerProject.isproj` | +| 기능 추가·정책 결정 | `docs/changes/YYYY-MM-DD-.md` 신규 작성, 루트 `README.md` 링크 | +| 실제 도구를 돌린 시험 | `src/tests/verification-YYYY-MM-DD-.json` | +| 백로그 항목 진척 | `docs/backlog/README.md` 상태 열 | +| 범위 변경(1차/후속 이동) | `docs/code-design/12-msix-first-builder.md`, 백로그, `docs/plan/10-development-schedule.md` | + +## 변경 기록(`docs/changes`) 구성 + +1. 제목과 첫 단락: 날짜, 무엇을 왜 바꿨는지, 범위 밖임을 명시할 것. +2. `## 사용` 또는 `## 결정`: 사용자 절차 또는 결정 목록. +3. `## 모델과 실행`: 프로젝트/로컬/계획/결과 필드와 실행 순서. +4. `## 확인 결과`: 실행한 검사와 **실행하지 않은 검사**를 모두 나열. 테스트 개수, 해시, 상태 문자열을 적는다. +5. `## 근거`: Microsoft Learn 등 외부 문서 링크. + +## 검증 JSON(`src/tests/verification-*.json`) + +- `date`, `checks`(불리언 맵), 실제 결과 객체(`buildId`, `sha256`, `status`, `signingReport` 등), `installationTest`, `notRun` 목록을 포함한다. +- 실행하지 않은 항목은 생략하지 않고 `"notRun"`으로 적는다. GUI 클릭 시험을 하지 않았으면 `"guiClickTest": "notRun"`. +- 로컬 경로가 들어가므로 공유 전에 검토한다. 토큰·개인 키·PFX 비밀번호는 절대 넣지 않는다. + +## 금지 표현 + +- 실행하지 않은 것을 "확인했다"로 쓰지 않는다. 시안·설계 작성은 구현 완료 증빙이 아니다. +- "배포 준비 완료", "설치 검증 완료", "지원 인증"은 Windows VM 설치·업데이트·제거 증빙이 있을 때만. +- 백로그 ID를 완료로 표시하려면 해당 행의 완료 기준 전체가 충족돼야 한다. 일부 구현은 README의 "일부 구현" 문장으로 남긴다. + +## 링크 + +- 저장소 내부 링크는 상대 경로. 깨진 링크를 만들지 않도록 대상 파일 존재를 확인한다. +- 루트 `README.md`는 색인 역할이다. 새 설계·매뉴얼·변경 문서를 만들면 한 줄로 추가한다. diff --git a/.claude/rules/frontend.md b/.claude/rules/frontend.md new file mode 100644 index 0000000..a3d978c --- /dev/null +++ b/.claude/rules/frontend.md @@ -0,0 +1,48 @@ +--- +paths: + - "src/apps/desktop/src/**" + - "src/apps/desktop/tests/**" + - "src/apps/desktop/index.html" + - "src/apps/desktop/package.json" + - "src/apps/desktop/tsconfig.json" +--- + +# 프런트엔드(TypeScript · CSS) 규칙 + +프레임워크 없는 TypeScript. 화면은 문자열 템플릿으로 만들고 `root.innerHTML`에 넣은 뒤 `data-action`/`data-field` 속성으로 이벤트를 연결한다. `tsc --noEmit` strict와 `node --test`를 통과해야 한다. + +## 모듈 구조 + +- `main.ts`는 상태와 조정(invoke 호출, render, action 분기)만 둔다. 화면 조각과 순수 로직은 별도 모듈로 뺀다: `start-screen.ts`, `registry-editor.ts`, `signing-editor.ts`, `project-transition.ts`, `window-chrome.ts`. +- 새 탭·편집기는 `render(data, disabled): string`을 export하는 모듈로 만들고, `main.ts`에서는 import와 action 분기만 추가한다. +- 테스트는 `tests/.test.mjs`에서 `.ts`를 직접 import한다. Node의 `--experimental-strip-types`로 실행되므로 **`enum`, `namespace`, 매개변수 프로퍼티, 데코레이터를 쓰지 않는다**. 타입은 `type` 별칭과 `import type`으로. +- 순수 함수(그룹화, 경로 표시, 전환 판단)는 DOM 없이 호출 가능해야 테스트할 수 있다. `document`를 쓰는 코드와 분리한다. + +## 보안 · 렌더링 + +- 템플릿에 들어가는 모든 동적 값은 `esc()`/`escape()`를 거친다. 프로젝트 이름, 경로, 오류 메시지, ID도 예외 없다. 테스트는 `` 같은 값이 이스케이프되는지 확인한다. +- `tauri.conf.json`의 CSP는 `'self'`만 허용한다. 인라인 `