Skip to content

Commit e4be435

Browse files
committed
Merge remote-tracking branch 'origin/main' into feat/image-box-component-9
# Conflicts: # eslint.config.js # package.json # pnpm-lock.yaml
2 parents 96e618e + 7305c2c commit e4be435

41 files changed

Lines changed: 2037 additions & 192 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude/decisions/README.md

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,22 +19,24 @@
1919
- 기존 규칙을 그대로 따르는 CRUD 구현
2020
- 한 번 쓰고 끝나는 페이지 내부 구현 세부사항
2121

22-
## 파일명
22+
## 파일 위치와 이름
2323

24-
```text
25-
NNN-short-title.md
26-
```
24+
실제 decision 문서는 `.claude/decisions/records/``NNN-short-title.md` 형식으로 둡니다. `README.md``template.md``records/`에 넣지 않고 `.claude/decisions/` 최상위에 둡니다.
2725

2826
예시:
2927

3028
```text
31-
001-admin-api-reference.md
32-
002-query-key-policy.md
33-
003-page-folder-boundary.md
29+
.claude/decisions/
30+
├── README.md
31+
├── template.md
32+
└── records/
33+
├── 001-admin-api-reference.md
34+
├── 002-query-key-policy.md
35+
└── 003-page-folder-boundary.md
3436
```
3537

3638
## 작성 형식
3739

38-
새 decision은 `.claude/decisions/template.md`복사한 형식으로 작성합니다.
40+
새 decision은 `.claude/decisions/template.md`복사해 `.claude/decisions/records/` 작성합니다.
3941

4042
문서는 길게 쓰지 않습니다. 결정 이유, 버린 대안, 이후 수정자가 지켜야 할 점만 남깁니다.
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# 001. UI 컴포넌트 시각 검토는 Storybook + GitHub Pages 배포로 한다
2+
3+
## 상태
4+
5+
- Accepted
6+
7+
## 맥락
8+
9+
공통 컴포넌트(Sidebar, PageHeader, SegmentedControl, Button, Logo)와 도메인 카드 컴포넌트가 늘어나면서, 실제 라우팅 없이도 팀원이 UI를 눈으로 확인할 방법이 필요했다. 앱 내부에 임시 `playground` 라우트를 만드는 방법과 Storybook을 붙이는 방법을 검토했다.
10+
11+
## 결정
12+
13+
`storybook` + `@storybook/react-vite`(Vite 8 지원 확인됨)를 devDependency로 추가하고, `main` 브랜치 push 시 `.github/workflows/deploy-storybook.yml`이 GitHub Pages(`/makers-admin-fe/` 서브패스)에 정적 빌드를 배포한다.
14+
15+
## 근거
16+
17+
- 컴포넌트가 늘어나도 `ComponentName.stories.tsx`를 옆에 추가하는 것만으로 확장되고, 임시 라우트처럼 삭제를 깜빡할 위험이 없다.
18+
- 팀원이 앱을 로컬에서 띄우지 않고도 배포된 페이지에서 바로 확인 가능하다.
19+
- `storybook init`의 기본 `--features``test`(Vitest 브라우저 addon + Playwright 브라우저 바이너리)는 스코프 밖이라 제외하고 `docs`, `a11y`만 설치했다.
20+
21+
## 대안
22+
23+
- 앱 내부 `routes`/`playground` 라우트: 지금 당장은 더 빠르지만, 실제 라우팅에 임시 코드가 섞여 남을 위험이 있어 기각.
24+
- Storybook `test`/Chromatic 관련 addon: 컴포넌트 시각 확인이 목적이라 지금은 불필요, 필요해지면 별도로 추가.
25+
26+
## 영향
27+
28+
- 새 재사용 컴포넌트를 추가하면 `ComponentName.tsx` 옆에 `ComponentName.stories.tsx`를 함께 추가한다(테스트 파일과 동일한 co-location 관례).
29+
- `.storybook/main.ts``viteFinal``vite.config.ts`와 동일한 alias(`@`, `@api`, `@components`, `@hooks`, `@lib`, `@pages`)와 `@tailwindcss/vite` 플러그인을 그대로 반영한다 — `vite.config.ts`의 alias나 플러그인을 바꾸면 `.storybook/main.ts`도 함께 업데이트해야 한다.
30+
- `.storybook/preview.tsx``src/index.css`를 import하므로, 전역 스타일/토큰 변경은 Storybook에도 자동 반영된다.
31+
- GitHub Pages 배포는 `STORYBOOK_BASE_PATH` 환경변수로 서브패스(`/makers-admin-fe/`)를 처리한다 — 저장소 이름이 바뀌면 `deploy-storybook.yml`의 값도 함께 바꿔야 한다.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# 002. 재사용 컴포넌트는 컴포넌트별 폴더로 관리한다
2+
3+
## 상태
4+
5+
- Accepted
6+
7+
## 맥락
8+
9+
`src/components/common``Button.tsx`, `Button.test.tsx`, `Button.stories.tsx`처럼 컴포넌트당 파일이 3개씩 쌓이면서 평면 구조가 스캔하기 번거로워졌다.
10+
11+
## 결정
12+
13+
`src/components/{domain}/{ComponentName}/{ComponentName}.tsx` 형태로 컴포넌트별 폴더를 만들고, 같은 폴더에 `.test.tsx`/`.stories.tsx`를 co-locate한다. `scripts/gen-index.ts`를 재귀 구조로 바꿔 컴포넌트 폴더와 도메인 폴더 각각의 barrel `index.ts`를 자동 생성하게 했다.
14+
15+
## 근거
16+
17+
- 컴포넌트 하나당 관련 파일이 한 폴더에 모여 탐색이 쉬워진다.
18+
- `@components/common/Button` 같은 기존 alias 딥 임포트는 폴더+barrel 구조에서도 그대로 resolve되어, 외부에서 이 컴포넌트를 참조하던 코드는 수정할 필요가 없었다.
19+
- 같은 도메인 내 다른 컴포넌트를 참조할 때는 `../ComponentName` 상대 import를 쓴다(예: `PageHeader``Button`, `Sidebar``Logo`).
20+
21+
## 대안
22+
23+
- 평면 구조 유지: 파일 수가 적을 때는 문제 없지만, 컴포넌트마다 test/stories가 늘어나며 이미 스캔하기 어려워진 상태라 기각.
24+
25+
## 영향
26+
27+
- 새 재사용 컴포넌트를 추가할 때는 `common/Button/` 같은 컴포넌트 폴더부터 만든다. `.claude/rules/architecture.md`의 도메인 구조 예시 참고.
28+
- `src/components/common`, `introductions`, `projects` 전 도메인을 이 구조로 옮겼다. 새 도메인도 처음부터 이 구조로 만든다.
29+
- `pnpm gen:index` 실행 시 컴포넌트 폴더 depth와 무관하게 재귀적으로 barrel을 생성하므로, 이후 깊이가 더 깊어져도 스크립트 수정 없이 동작한다.

.claude/hooks/guard-rules.mjs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { readFileSync } from 'node:fs'
2+
3+
let payload
4+
5+
try {
6+
payload = JSON.parse(readFileSync(0, 'utf8'))
7+
} catch {
8+
process.exit(0)
9+
}
10+
11+
const toolInput = payload.tool_input ?? {}
12+
const filePath = toolInput.file_path ?? ''
13+
const content = toolInput.new_string ?? toolInput.content ?? toolInput.command ?? ''
14+
15+
const isCodeFile = /\.(ts|tsx|js|jsx)$/.test(filePath)
16+
17+
if (isCodeFile && content.includes('console.log')) {
18+
console.error('Avoid console.log. Use the project logging/debugging approach instead.')
19+
process.exit(1)
20+
}
21+
22+
if (isCodeFile && /:\s*any([^A-Za-z]|$)|<any>|as any/.test(content)) {
23+
console.error('Avoid explicit any. Use a specific type or unknown.')
24+
process.exit(1)
25+
}
26+
27+
if (/(^|\s)(npm|yarn|npx)\s/.test(content)) {
28+
console.error('Use pnpm (or pnpm exec/pnpm dlx) in this project.')
29+
process.exit(1)
30+
}
31+
32+
if (/tailwind\.config\./.test(filePath)) {
33+
console.error('This is a Tailwind CSS v4 project. Do not create tailwind.config unless explicitly requested.')
34+
process.exit(1)
35+
}

.claude/hooks/guard-rules.ps1

Lines changed: 0 additions & 36 deletions
This file was deleted.

.claude/hooks/lint-check.mjs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { readFileSync } from 'node:fs'
2+
import { execFileSync } from 'node:child_process'
3+
4+
let payload
5+
6+
try {
7+
payload = JSON.parse(readFileSync(0, 'utf8'))
8+
} catch {
9+
process.exit(0)
10+
}
11+
12+
const filePath = payload.tool_input?.file_path ?? ''
13+
14+
if (filePath && (filePath.endsWith('.ts') || filePath.endsWith('.tsx'))) {
15+
try {
16+
const output = execFileSync('pnpm', ['exec', 'eslint', '--quiet', filePath], {
17+
encoding: 'utf8',
18+
timeout: 30_000,
19+
})
20+
console.log(output.trimEnd().split('\n').slice(-5).join('\n'))
21+
} catch (error) {
22+
const output = `${error.stdout ?? ''}${error.stderr ?? ''}`
23+
console.log(output.trimEnd().split('\n').slice(-5).join('\n'))
24+
}
25+
}

.claude/hooks/lint-check.ps1

Lines changed: 0 additions & 15 deletions
This file was deleted.

.claude/hooks/skill-suggest.mjs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { readFileSync } from 'node:fs'
2+
3+
let payload
4+
5+
try {
6+
payload = JSON.parse(readFileSync(0, 'utf8'))
7+
} catch {
8+
process.exit(0)
9+
}
10+
11+
const prompt = payload.prompt ?? ''
12+
13+
if (!prompt) {
14+
process.exit(0)
15+
}
16+
17+
const lowerPrompt = prompt.toLowerCase()
18+
const suggestions = []
19+
20+
const rules = [
21+
[/commit|staged|push/, '/commit-kr - create a Korean commit message'],
22+
[/\bpr\b|pull request/, '/create-pr - create a PR title and body draft'],
23+
[/refactor|cleanup|dedupe|simplify/, '/refactor - analyze refactoring candidates'],
24+
[/test|vitest|tdd|coverage/, '/gen-test - generate tests'],
25+
[
26+
/swagger|openapi|api generate|api client|api scaffold|admin api/,
27+
'/scaffold-api - generate API functions and Query hooks',
28+
],
29+
[/figma|design|screen|layout|component/, '/figma-to-component - implement a Figma-based component'],
30+
[/review/, '/code-review - review changed code'],
31+
]
32+
33+
for (const [pattern, suggestion] of rules) {
34+
if (pattern.test(lowerPrompt)) {
35+
suggestions.push(suggestion)
36+
}
37+
}
38+
39+
if (suggestions.length > 0) {
40+
console.log('Suggested local skills:')
41+
for (const suggestion of suggestions) {
42+
console.log(` ${suggestion}`)
43+
}
44+
}

.claude/hooks/skill-suggest.ps1

Lines changed: 0 additions & 42 deletions
This file was deleted.

.claude/known-issues/README.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Known Issues
2+
3+
이 폴더는 우리가 지금 당장 고칠 수 없거나 우리 코드의 문제가 아닌, 외부 요인으로 발견된 이슈를 기록합니다.
4+
5+
## 기록 대상
6+
7+
- 디자인 시스템/외부 패키지의 값이 Figma나 스펙과 다른 경우
8+
- 서드파티 라이브러리 버그로 생긴 workaround
9+
- API 스펙과 실제 응답이 다른 경우
10+
- 우선순위가 낮아 지금은 미루는 알려진 성능/품질 이슈
11+
12+
## 기록하지 않는 것
13+
14+
- 우리 코드로 바로 고칠 수 있는 버그 (그냥 고친다)
15+
- 구조/라이브러리 선택 같은 결정 사항 (`.claude/decisions/`에 기록)
16+
17+
## 파일 위치와 이름
18+
19+
실제 이슈 문서는 `.claude/known-issues/records/``short-title.md` 형식으로 둡니다. `README.md``template.md``records/`에 넣지 않고 `.claude/known-issues/` 최상위에 둡니다.
20+
21+
## 작성 형식
22+
23+
새 이슈는 `.claude/known-issues/template.md`를 복사해 `.claude/known-issues/records/`에 작성합니다.

0 commit comments

Comments
 (0)