feat: integrate latest HMDesign design system updates
This commit is contained in:
1 parent
99faec189e
commit
1c4e0bb9a1
209 files changed
+8845
-552
No files matched your search
@@ -1,5 +1,7 @@
|
||||
# Accordion
|
||||
|
||||
> 2026-10-10 추가 수정 요청 기준: 펼침·접힘 모두 hover한 제목 Trigger에만 Black 5% 배경. 본문 배경은 유지. 과거 검증 기록은 당시 결과이며 현재 검증은 [추가 수정 보고서](../guidelines/publisher-additional-review-2026-10-10.md)를 따릅니다.
|
||||
|
||||
현재 HM 구현의 기준 문서. 공통 원칙은 `docs/guidelines/프로젝트-지침.md`(§6, §7), Token 구조 원칙은 `테마-토큰-가이드.md`를 따른다. 이 문서는 Accordion 고유의 API·Token·상태·결정만 기록한다. Collapsible(`collapsible.md`)과 값을 공유하지 않는다.
|
||||
|
||||
## 1. 상태
|
||||
@@ -38,7 +40,7 @@
|
||||
| 상태 | 값 |
|
||||
|---|---|
|
||||
| Closed / Open | Radix `data-state` |
|
||||
| Hover | Trigger background `transparent`, cursor pointer. 기존 underline/focus 정책 유지, disabled 제외 |
|
||||
| Hover | 펼침·접힘 모두 Trigger에 Black Alpha 5%, cursor pointer. 본문 유지, disabled 제외 |
|
||||
| Focus (`:focus-visible`) | shadcn ring (`ring-3 ring-ring/50`) 유지 |
|
||||
| Disabled | `opacity: 0.6`(이 컴포넌트 값, 전역 Disabled 규칙으로 승격 안 함), `cursor: not-allowed`, 키보드 이동에서 제외 |
|
||||
| Open / Close animation | shadcn `accordion-down` / `accordion-up` 0.2s ease-out (height). 첫 렌더에서는 Radix가 animation을 막는다 |
|
||||
@@ -83,7 +85,7 @@ Radix 구조·ARIA(`aria-expanded`, `aria-controls`, `role=region`)·키보드(A
|
||||
## 11. 미확정 / 보류
|
||||
|
||||
- 수치(48px, 16/24/500, padding, divider 색, Disabled opacity 0.6)는 현재 HM 규격이며 디자인 확정 시 재검토.
|
||||
- 현재 Hover는 `transparent`다. Focus Light 2 50% 3px ring과 Disabled opacity 0.6·cursor not-allowed는 유지.
|
||||
- 현재 Hover는 제목 영역 Black Alpha 5%다. Focus Light 2 50% 3px ring과 Disabled opacity 0.6·cursor not-allowed는 유지.
|
||||
- Indicator는 shadcn chevron 유지(Select의 HM glyph와 별개). 별도 Source glyph 없음.
|
||||
- Motion 규칙이 없어 shadcn animation 유지. `prefers-reduced-motion` 대응은 추가하지 않았다(기존 구현에도 없음).
|
||||
- Container 외곽 박스/Card형 variant는 만들지 않았다.
|
||||
@@ -101,7 +103,7 @@ src/components/accordion.stories.tsx
|
||||
|
||||
## 13. 검증 상태
|
||||
|
||||
> HISTORICAL_RECORD: 아래 날짜별 검증은 당시 구현의 기록이다. 과거 soft surface 측정은 보존하며, 현재 Hover 규격은 §4의 `transparent`를 따른다.
|
||||
> HISTORICAL_RECORD: 아래 날짜별 검증은 당시 구현의 기록이다. 과거 soft surface 측정은 보존하며, 현재 Hover 규격은 §4의 Black Alpha 5%를 따른다.
|
||||
|
||||
- 2026-10-06 Visual QA: 1280/1024/768/390px에서 Closed/Open Hover의 전체 soft surface·pointer, Focus 3px ring, Disabled opacity 0.6·not-allowed 및 가로 overflow 없음 확인. `typecheck`, `build`, `build-storybook` 통과.
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# Alert Dialog
|
||||
|
||||
> 2026-10-10 추가 수정 요청 기준: 취소 Gray Solid / 삭제 Red Solid, 기존 Radix focus·닫기 계약 유지. 과거 검증 기록은 당시 결과이며 현재 검증은 [추가 수정 보고서](../guidelines/publisher-additional-review-2026-10-10.md)를 따릅니다.
|
||||
|
||||
현재 HM 구현의 기준 문서. 공통 원칙은 `docs/guidelines/프로젝트-지침.md`(§6, §7), Token 구조 원칙은 `테마-토큰-가이드.md`를 따른다. 이 문서는 Alert Dialog 고유의 API·Token·상태·결정만 기록한다. Dialog(`dialog.md`)와 값을 공유하지 않는다.
|
||||
|
||||
## 1. 상태
|
||||
@@ -14,7 +16,7 @@
|
||||
|
||||
## 2. 적용 근거
|
||||
|
||||
- **참고 근거**: 외부 ui_viz Reference (ZIP 미포함)의 Dialog 문서가 Alert Dialog를 FOLLOW_UP(DIALOG-03)으로만 두고 규격은 없다. 의도(확인·취소를 명시적으로 요구하는 중요한 결정)를 참고했다. 현재 Button 조합은 사용자 확정 규칙에 따라 일반 확인은 취소 Gray Solid / 확인 Green Solid, 삭제 확인은 취소 Gray Outline / 삭제 Red Outline이며 같은 세트의 appearance·size를 통일한다.
|
||||
- **참고 근거**: 외부 ui_viz Reference (ZIP 미포함)의 Dialog 문서가 Alert Dialog를 FOLLOW_UP(DIALOG-03)으로만 두고 규격은 없다. 의도(확인·취소를 명시적으로 요구하는 중요한 결정)를 참고했다. 현재 Button 조합은 사용자 확정 규칙에 따라 일반 확인은 취소 Gray Solid / 확인 Green Solid, 삭제 확인은 취소 Gray Solid / 삭제 Red Solid이며 같은 세트의 appearance·size를 통일한다.
|
||||
- **현재 HM 규격**: 아래 §3~§4. Dialog의 접근성 원칙과 `asChild` 처리 규칙은 재사용하고 수치는 현재 HM Semantic으로 새로 정했다.
|
||||
- **구현 방식**: shadcn / Radix AlertDialog 구조 유지. Dialog + destructive 플래그로 합치지 않고 별도 컴포넌트로 둔다.
|
||||
- **Dialog와의 차이**: Close(X) 없음, 바깥 클릭으로 닫히지 않음, 초기 focus가 Cancel, Body·Header divider 없음, 폭 400px 고정 상한.
|
||||
@@ -48,9 +50,9 @@
|
||||
|
||||
Radix AlertDialog props 그대로. export: `AlertDialog`, `AlertDialogTrigger`, `AlertDialogPortal`, `AlertDialogOverlay`, `AlertDialogContent`, `AlertDialogHeader`, `AlertDialogFooter`, `AlertDialogTitle`, `AlertDialogDescription`, `AlertDialogAction`, `AlertDialogCancel`.
|
||||
|
||||
- `AlertDialogAction`: HM Button을 Radix Action 위에 `asChild`로 합성(`<Button asChild><AlertDialogPrimitive.Action/></Button>`). 기본 `variant="primary"` `appearance="solid"`, `size` 기본 `default`. 위험한 작업은 `variant="destructive" appearance="outline"`.
|
||||
- `AlertDialogAction`: HM Button을 Radix Action 위에 `asChild`로 합성(`<Button asChild><AlertDialogPrimitive.Action/></Button>`). 기본 `variant="primary"` `appearance="solid"`, `size` 기본 `default`. 위험한 작업은 `variant="destructive" appearance="solid"`.
|
||||
- `AlertDialogCancel`: 같은 방식, 기본 `variant="cancel"` `appearance="solid"`.
|
||||
- `AlertDialogAction variant="destructive"`만 지정하면 기본 `solid`가 적용되어 **미지원 Destructive Solid**가 된다. 삭제 확인은 Action과 Cancel 모두 `appearance="outline"`을 명시하고 같은 size를 사용한다. 자동 appearance 변경은 없다. [Button 허용 조합·기본값 주의](button.md#62-기본값별칭합성-주의)를 따른다.
|
||||
- `AlertDialogAction variant="destructive"`의 기본 `solid`는 지원된다. 삭제 확인은 Action과 Cancel 모두 Standard Solid와 같은 size를 사용한다. 자동 appearance 변경은 없다. [Button 허용 조합·기본값 주의](button.md#62-기본값별칭합성-주의)를 따른다.
|
||||
- 합성한 Radix 요소에는 `data-slot`을 붙이지 않는다. 붙이면 `asChild` Slot 병합에서 자식 값이 이겨 Button의 `data-slot="button"`이 사라지고 HM Button 스타일이 적용되지 않는다(Dialog에서 해결한 문제와 같은 원인). 출력 속성은 Button의 `data-slot="button"`, `data-variant`, `data-appearance`, `data-size`.
|
||||
- Alert Dialog 자체에는 Button 스타일을 정의하지 않는다. Button API(`variant`/`appearance`/`size`)만 전달한다.
|
||||
- `AlertDialogContent`에 Close(X)는 없다. 새 prop(`size`, `variant`, `destructive`)은 만들지 않았다.
|
||||
@@ -84,7 +86,7 @@ Radix AlertDialog 구조 전부: Portal·Overlay·modal·focus trap·초기 focu
|
||||
|
||||
- 수치(400px, 18px Title, 24px padding, 그림자)는 현재 HM 규격이며 디자인 확정 시 재검토.
|
||||
- Overlay 색·blur, Motion은 shadcn 기본 유지.
|
||||
- 파괴적 작업의 기본 강조(Red outline)는 Dialog 삭제 확인과 같은 조합이며 Alert Dialog 고유 규칙이 아니다.
|
||||
- 파괴적 작업의 기본 강조(Red Solid)는 Dialog 삭제 확인과 같은 조합이며 Alert Dialog 고유 규칙이 아니다.
|
||||
- 아이콘/Media slot, non-dismissible 정책 변경(예: Escape 막기)은 만들지 않았다.
|
||||
- 소비 화면의 공통 header/footer 높이 대응 없음.
|
||||
|
||||
|
||||
@@ -52,6 +52,8 @@ Badge:
|
||||
|
||||
`packages/ui/src/theme/badge.css` (`--hm-badge-*`): `radius`, `padding-x/y`, `border-width`, `font-size/line-height/font-weight`, variant별 `{default,secondary,destructive,outline}-{background,text,border-color}`. Semantic 참조. Primitive 신규 추가 없음.
|
||||
|
||||
Dashboard 업무 상태의 outline Badge는 [공식 상태 mapping](../patterns/dashboard-layout.md#dashboard-업무-상태-공통-계약)에서 기존 Token을 연결한다. 이 문서화된 소비 예제는 사용자별 디자인 의도 승인이나 Runtime Theme JSON key 확장이 아니다. Guard는 선언 확인·DOM 적용값·override 의도를 [별도 판정](../guidelines/ai-generation-guard.md#css-intent와-동적-token-검사-2026-10-10)하며 실제 Badge 스타일·API는 변경하지 않는다.
|
||||
|
||||
## 7. shadcn / Radix에서 유지한 항목
|
||||
|
||||
CVA 구조, `asChild`(Radix Slot), `data-slot`, `cn(..., className)`, 아이콘 크기 규칙(`[&>svg]:size-3`).
|
||||
|
||||
+15
-13
@@ -1,5 +1,7 @@
|
||||
# Button
|
||||
|
||||
> 2026-10-10 추가 수정 요청 기준: Gray Solid/Outline 기준 #767676, Red Solid 추가. 팝업 결정 버튼은 동일 Solid·size. 일반 화면의 여러 반복·보조 버튼은 Outline, 검색은 조회 Solid Green / 초기화 Outline Gray 예외. 과거 검증 기록은 당시 결과이며 현재 검증은 [추가 수정 보고서](../guidelines/publisher-additional-review-2026-10-10.md)를 따릅니다.
|
||||
|
||||
현재 HM 구현과 Runtime-neutral 사용 기준 문서. 공통 원칙은 `AGENTS.md`와 `docs/guidelines/runtime-portability.md`를 따른다. 이 문서는 Button API·Token·상태·사용 위치·조합 계약을 기록한다.
|
||||
|
||||
## 1. 상태
|
||||
@@ -15,7 +17,7 @@
|
||||
## 2. 적용 근거
|
||||
|
||||
- **ui_viz Confirmed**: size, padding-x, label size/line-height(button.md §26, D-087), Brand gradient·bevel(D-087), Standard Solid/Outline 색(§28, D-086, D-087), Hover/Pressed 동일 Black 20%(§12), Red Outline Hover/Pressed Red 8%.
|
||||
- **HM 사용자 확정 규칙**: 실제 화면 Brand 최대 1개·팝업 Brand 금지, 일반 확인/작성 Solid 세트, 삭제 확인·행/반복 작업 Outline 세트, 같은 세트의 appearance와 size 통일(§5). Disabled `0.6`은 ui_viz 규격 값이며, Input·Select의 2026-10-02 결정과는 별개다.
|
||||
- **HM 사용자 확정 규칙**: 실제 화면 Brand 최대 1개·팝업 Brand 금지, 일반 확인/작성 Solid 세트, 삭제 확인 Solid 세트·행/반복 작업 Outline, 같은 세트의 appearance와 size 통일(§5). Disabled `0.6`은 ui_viz 규격 값이며, Input·Select의 2026-10-02 결정과는 별개다.
|
||||
- **shadcn 유지**: 구조(CVA, `data-slot`, `cn(..., className)`), focus/invalid ring class, `ghost`·`link` variant와 기존 size 이름.
|
||||
- **미정의/TBD**: Focus 표현(ui_viz TBD → shadcn 기본 focus ring 유지), `aria-invalid` 표현(ui_viz에 없음 → shadcn class 유지), `ghost`·`link`의 규격(ui_viz 없음).
|
||||
|
||||
@@ -57,10 +59,10 @@
|
||||
- `outline`: 반복·보조 작업과 표/목록 행 작업에 사용한다.
|
||||
- 일반 작성·수정창: 취소 Solid + 등록/저장 Solid.
|
||||
- 일반 확인창: 취소 Solid + 확인 Solid.
|
||||
- 삭제 확인창: 취소 Outline + 삭제 Outline.
|
||||
- 삭제 확인창: 취소 Solid + 삭제 Solid.
|
||||
- 표/목록 행과 반복·보조 작업: 동일 `appearance`의 Outline 조합.
|
||||
- FilterBar 대표 Story의 초기화·조회: `cancel` + `primary`, 둘 다 Outline·`size="default"`. 목록의 반복 조회·보조 작업 세트다.
|
||||
- 하나의 세트는 `appearance`와 `size`를 통일한다. 역할 차이는 variant의 기존 역할색과 문구로 표현한다.
|
||||
- 검색은 조회 `primary/solid` + 초기화 `cancel/outline`·같은 size를 사용한다. 조회·초기화는 진행/취소 결정 세트가 아니므로 같은 appearance를 강제하지 않는다.
|
||||
- 취소·적용처럼 동일 작업의 결정 세트는 `appearance`와 `size`를 통일한다. 역할 차이는 variant의 기존 역할색과 문구로 표현한다.
|
||||
|
||||
사용 위치를 기준으로 appearance를 명시하며 버튼 문구만으로 판단하지 않는다. 컴포넌트는 appearance 생략 시 기본 `brand`를 출력하므로, 팝업·버튼 세트에서는 기본값에 의존하지 않는다.
|
||||
|
||||
@@ -89,7 +91,7 @@ asChild: shadcn 그대로
|
||||
- `secondary` (Brown): `brand`, `solid`, `outline`.
|
||||
- `modify` (Orange): `brand`, `solid`. **`outline` 미지원**.
|
||||
- `cancel` (Gray): `solid`, `outline`. **`brand` 미지원**.
|
||||
- `destructive` (Red): `outline`만 지원. **`brand`, `solid` 미지원**.
|
||||
- `destructive` (Red): `solid`, `outline` 지원. **`brand` 미지원**.
|
||||
|
||||
공개 Props는 `variant`와 `appearance`를 독립적으로 받는다. TypeScript 통과나 Storybook Controls에서 선택 가능하다는 사실은 해당 조합의 디자인 지원을 뜻하지 않는다. 미지원 조합에는 필요한 역할별 CSS Custom Property가 없으며 자동 보정·fallback도 없다. 기존 CSS 변수에 임의 fallback이나 새로운 역할색을 추가하지 않는다.
|
||||
|
||||
@@ -98,16 +100,16 @@ asChild: shadcn 그대로
|
||||
- `<Button>`은 Primary Brand다. `variant="destructive"`만 지정하면 미지원 Destructive Brand, `variant="cancel"`만 지정하면 미지원 Cancel Brand가 된다. 각각 허용 appearance를 명시한다.
|
||||
- `variant="default"`는 Primary 별칭이며 appearance 생략 시 Brand다. `variant="outline"`는 Primary Outline 별칭이며 전달한 appearance보다 우선한다. Red Outline은 `variant="destructive" appearance="outline"`로 작성한다.
|
||||
- `ghost`/`link`는 HM Role × Appearance 계약 밖의 shadcn 호환 variant다. `data-appearance`를 출력하지 않으며 appearance를 전달해도 HM treatment를 적용하지 않는다.
|
||||
- `AlertDialogAction`과 `AlertDialogCancel`의 기본 appearance는 Button과 달리 `solid`다. `<AlertDialogAction variant="destructive">`만 지정하면 미지원 Destructive Solid다. 삭제 확인은 Action과 Cancel **모두** `appearance="outline"`을 명시한다. 자세한 합성 API는 [Alert Dialog](alert-dialog.md#5-api)를 따른다.
|
||||
- `AlertDialogAction`과 `AlertDialogCancel`의 기본 appearance는 `solid`다. 삭제 확인도 Action(Red)과 Cancel(Gray) 모두 Standard Solid를 사용한다. 자세한 합성 API는 [Alert Dialog](alert-dialog.md#5-api)를 따른다.
|
||||
|
||||
```tsx
|
||||
// 삭제·취소: 같은 appearance와 size (DialogClose asChild로도 합성 가능)
|
||||
<Button variant="cancel" appearance="outline" size="default">취소</Button>
|
||||
<Button variant="destructive" appearance="outline" size="default">삭제</Button>
|
||||
<Button variant="cancel" appearance="solid" size="default">취소</Button>
|
||||
<Button variant="destructive" appearance="solid" size="default">삭제</Button>
|
||||
|
||||
// Alert Dialog 삭제 확인: 두 요소 모두 Outline을 명시
|
||||
<AlertDialogCancel appearance="outline" size="default">취소</AlertDialogCancel>
|
||||
<AlertDialogAction variant="destructive" appearance="outline" size="default">삭제</AlertDialogAction>
|
||||
// Alert Dialog 삭제 확인: 두 요소 모두 Standard Solid
|
||||
<AlertDialogCancel appearance="solid" size="default">취소</AlertDialogCancel>
|
||||
<AlertDialogAction variant="destructive" appearance="solid" size="default">삭제</AlertDialogAction>
|
||||
```
|
||||
|
||||
미지원 조합 추가, role별 자동 appearance 선택, 기본 appearance 변경은 사용자 결정이 필요한 별도 변경이다. 현재 계약과 공개 API를 유지한다.
|
||||
@@ -129,7 +131,7 @@ React가 아닌 Runtime도 배포된 `@hm-design/ui/theme.css` 또는 승인된
|
||||
- Role × Appearance는 §6.1의 허용 조합만 사용한다. 위 속성 vocabulary가 모든 곱집합을 허용하는 것은 아니다.
|
||||
- CSS는 `--hm-button-*` Component variable과 `--hm-sem-*`/기존 Theme variable을 소비한다. HEX와 임의 variable을 추가하지 않는다.
|
||||
- native `disabled`, `:hover`, `:active`, `:focus-visible`로 Disabled/Hover/Pressed/Focus 계약을 유지한다. `aria-disabled`만으로 native disabled를 대체하지 않는다.
|
||||
- 팝업의 취소/확인 조합은 같은 `size`를 사용하고, 삭제 확인은 취소·삭제 모두 Outline이어야 한다. Escape, Tab 순서, 초기 포커스와 닫힌 뒤 trigger 포커스 복귀는 modal primitive 또는 동등한 keyboard contract로 보존한다.
|
||||
- 팝업의 취소/확인 조합은 같은 `size`를 사용하고, 삭제 확인은 취소·삭제 모두 Standard Solid이어야 한다. Escape, Tab 순서, 초기 포커스와 닫힌 뒤 trigger 포커스 복귀는 modal primitive 또는 동등한 keyboard contract로 보존한다.
|
||||
|
||||
React의 `variant` prop을 그대로 복제할 필요는 없지만, 동일한 role/treatment attribute와 시각·상태·접근성 계약을 유지해야 한다.
|
||||
|
||||
@@ -148,7 +150,7 @@ CVA 구조, `data-slot`, `asChild`(Radix `Slot`), `className` 확장, focus-visi
|
||||
## 11. Storybook
|
||||
|
||||
- 대표 Story `All`("Button")이 기본 sidebar의 유일한 Button 항목이다 → 1뎁스.
|
||||
- `All`의 구역: Overview → Sizes → Variants → States. 기본 버튼·크기·허용 조합·Brand/Standard 상태를 보여준다. Red Outline은 Variants와 Standard States에도 포함되며, 삭제·취소 세트와 Long Label은 verification Story에서 따로 확인한다.
|
||||
- `All`의 구역: Overview → Sizes → Variants → States. 기본 버튼·크기·허용 조합·Brand/Standard 상태를 보여준다. Red Solid와 Outline은 Variants와 Standard States에도 포함되며, 삭제·취소 세트와 Long Label은 verification Story에서 따로 확인한다.
|
||||
- verification(`tags: ["verification"]`, 기본 sidebar 제외): `Roles`, `Sizes`, `States`("Brand States"), `StandardStates`, `LongLabel`, `KoreanLabels`, `IconTextNarrow`, `Destructive`, `Playground`(HM 전용), `Compatibility`(ghost/link, default/outline 별칭). Controls는 조합별 선택을 제한하지 않으므로 §6.1의 허용 조합을 직접 지킨다. Verification은 기술 점검용이며 운영 화면의 사용 위치·세트 규칙은 §5가 우선한다.
|
||||
- 대표 경로/ID: `Components/Form/Button → All` (`components-form-button--all`), `Components/Overlay/Dialog → All` (`components-overlay-dialog--all`), `Components/Overlay/Alert Dialog → All` (`components-overlay-alert-dialog--all`), `Patterns/Data/Filter Bar → Filter Bar` (`patterns-data-filter-bar--all`). 삭제 세트 점검 ID는 `components-form-button--destructive`(verification)다.
|
||||
- 운영 규칙은 `프로젝트-지침.md` §6.3, §7 참조.
|
||||
|
||||
+14
-3
@@ -72,11 +72,21 @@ CardHeader, CardTitle, CardDescription, CardAction, CardContent, CardFooter: sha
|
||||
|---|---|---|
|
||||
| `src/components/card.stories.tsx` `Compatibility` | shadcn 호환 확인 | verification 전용 |
|
||||
| `src/patterns/dashboard-layout.stories.tsx` | 업무 목록 건수(`role="status"`), KPI 라벨(Title 없이 Description만), 가로 스크롤 안내 | Pattern Story 안의 소비 예시. 별도 스타일 없음 |
|
||||
| `src/App.tsx` (Demo) | Panel 부제 | `.hm-panel-header`가 11px·`--hm-muted`로 덮어씀. Demo 전용(§8.1) |
|
||||
| 과거 UI Demo (`src/App.tsx`, 공식 이전 전 baseline) | Panel 부제 | `.hm-panel-header`가 11px·`--hm-muted`로 덮어씀. Demo 전용(§8.1) |
|
||||
|
||||
- Header에 Description이 있으면 shadcn의 `has-data-[slot=card-description]:grid-rows-[auto_auto]`로 2행 grid가 되고, `CardAction`은 `row-span-2`로 두 행에 걸친다. 이 동작은 shadcn 그대로다.
|
||||
- Description의 HM Token·크기·색은 미정의다. 필요해지면 이 문서에서 결정한 뒤 Token으로 추가한다(§11).
|
||||
|
||||
### 5.2 Tabs를 Card 안에 조합할 때
|
||||
|
||||
기본 White Card 안의 탭은 `TabsList panelSurface="surface"`를 사용하고, CardContent 안의 각 `TabsContent`는 `px-0 py-6`로 조합한다. Card의 배경·border·radius·기본 여백은 유지하며 내부 탭 패널의 중복 `border bg-background rounded-b p-6`만 제거한다. [Tabs 조합 예제](tabs.md#16-publisher--developer-조합-안내-2026-10-09)와 Tabs 대표 Story의 Usage를 기준으로 한다.
|
||||
|
||||
- CardContent는 기본 24px 좌우 여백을 소유한다. 내부 TabsContent에 24px 좌우 여백을 다시 더하지 않는다. `size="sm"`의 12px은 기존 호환 규격이며 이번 조합 때문에 24px로 강제하지 않는다.
|
||||
- `surface="content"` Card는 실제 배경에 맞춰 `panelSurface="content"`를 사용한다. `panelSurface`는 Card의 표면이나 패널 배경을 자동 변경하지 않는다.
|
||||
- 탭 콘텐츠 상하 24px은 조합 예시 값이며, Card의 Header→Content 24px이나 전체 화면 섹션 간격을 대체하는 공통 Token이 아니다. §11의 Tabs Meta 예외(0px 간격)를 새로 구현한 것도 아니다.
|
||||
- 내부 Input·Textarea의 border, Table의 행 배경·구분선, Alert 등의 역할별 스타일은 보존한다. CardDescription의 호환 범위는 §5.1을 유지하며 PageHeaderDescription의 8px/14·20 규격으로 바꾸지 않는다.
|
||||
- 좁은 화면에서는 flex/grid 자식인 Card 자체와 CardContent의 `min-w-0` 등 소비 Layout 수축 조건을 확인한다. Table이 있는 grid 조합에서 Card 자체의 자동 최소 폭을 유지하면 내부 스크롤 전에 페이지가 넓어질 수 있다. Tabs/Table 내부 스크롤을 함께 확인하며 Card의 새로운 Responsive Variant나 폭 Token은 추가하지 않는다.
|
||||
|
||||
## 6. Token
|
||||
|
||||
Component Mapping 위치: `packages/ui/src/theme/card.css` (`--hm-card-*`), `packages/ui/src/theme.css`에서 import.
|
||||
@@ -116,7 +126,7 @@ semantic HTML(`div`), React composition(Header/Title/Description/Action/Content/
|
||||
### 8.1 Demo `.hm-panel`과 운영 Card 구분
|
||||
|
||||
- **운영 Card**: `@hm-design/ui`의 `<Card />`와 `packages/ui/src/theme/card.css`. 이 문서 §3의 값(padding 24px, Title 20/28/600 등)과 대표 Story `All`이 기준이다. 소비 프로젝트는 `hm-panel*` class 없이 이 API만 쓴다.
|
||||
- **Demo Panel**: `src/App.tsx`의 4개 Card에 붙은 `hm-panel`, `hm-panel-header`, `hm-panel-icon`, `hm-panel-content` class와 `src/hm-theme.css` 규칙. 패키지(`packages/ui`)에 포함되지 않으며 Card 규격 Reference가 아니다.
|
||||
- **과거 Demo Panel**: 공식 이전 전 UI Demo의 `src/App.tsx`에 있던 4개 Card에 붙은 `hm-panel`, `hm-panel-header`, `hm-panel-icon`, `hm-panel-content` class와 `src/hm-theme.css` 규칙. 패키지(`packages/ui`)에 포함되지 않으며 Card 규격 Reference가 아니다.
|
||||
- `.hm-panel`은 Card 외형(border, radius, background, shadow)을 지정하지 않는다. 다만 Demo class 묶음은 운영 Card 값을 다음처럼 덮어쓴다.
|
||||
|
||||
| Demo class | 덮어쓰는 값 | 운영 Card 값 |
|
||||
@@ -129,6 +139,7 @@ semantic HTML(`div`), React composition(Header/Title/Description/Action/Content/
|
||||
| `.hm-panel-content` | `padding: 23px` | 좌우 24px |
|
||||
|
||||
- Demo 값은 HM Token이 아닌 hex 값을 포함한다. Card Token·Story의 근거로 쓰지 않으며, Demo 화면을 Card 디자인 Reference로 캡처·인용하지 않는다.
|
||||
- 현재 `src/App.tsx`는 `WorkDashboard`를 렌더한다. 현재 업무 앱에는 `hm-panel-header` 사용이 없지만 과거 CSS와 Git 이력은 보존한다. 기존 Demo override 기록을 현재 공개 Card 규격이나 신규 override 승인으로 해석하지 않는다. Guard의 Component 식별·진입점 범위 판정은 [STYLE-001 범위 계약](../guidelines/ai-generation-guard.md#style-001-component-식별과-진입점-범위-2026-10-11)을 따른다.
|
||||
|
||||
## 9. Storybook
|
||||
|
||||
@@ -166,7 +177,7 @@ packages/ui/src/theme.css (card.css import)
|
||||
src/components/card.stories.tsx
|
||||
src/components/story-board.tsx
|
||||
src/patterns/dashboard-layout.stories.tsx (CardDescription 소비 예시)
|
||||
src/App.tsx (Demo, hm-panel* class 사용)
|
||||
src/App.tsx (현재 WorkDashboard; 과거 hm-panel* Demo 기록은 §8.1)
|
||||
src/hm-theme.css (.hm-panel* Demo 전용 스타일, §8.1)
|
||||
```
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# Checkbox
|
||||
|
||||
> 2026-10-10 추가 수정 요청 기준: `asChild`는 단일 React DOM 호환 요소를 받으며 소비자 자식·ID·이벤트·ref를 보존하고 내부 Indicator를 추가한다. 커스텀 요소는 props/ref를 최종 DOM으로 전달해야 한다. 기존 기본 button·외부 form 유지. 과거 검증 기록은 당시 결과이며 현재 검증은 [추가 수정 보고서](../guidelines/publisher-additional-review-2026-10-10.md)를 따릅니다.
|
||||
|
||||
현재 HM 구현의 기준 문서. 공통 원칙은 `docs/guidelines/프로젝트-지침.md`(§6, §7), Token 구조 원칙은 `테마-토큰-가이드.md`를 따른다. 이 문서는 Checkbox 고유의 API·Token·상태·결정만 기록한다.
|
||||
|
||||
## 1. 상태
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# Combobox
|
||||
|
||||
> 현재 접근성 보완(2026-10-10): 흰 Trigger의 빈 값 안내는 기존 `--hm-sem-fg-secondary`를 사용한다. 기본 Theme에서 #6e6759/흰색이며 공통 placeholder Token과 Disabled opacity는 보존한다. 아래 과거 검증의 #999 실측은 당시 기록이다.
|
||||
|
||||
> 2026-10-10 추가 수정 요청 기준: 현재 구현의 연결형 Popup을 기준으로 문서를 통일. 팝업 dialog 이름은 aria-label → aria-labelledby → 고유 trigger ID 순으로 연결. Command 검색·listbox 이름과 인스턴스 ID는 독립. 과거 검증 기록은 당시 결과이며 현재 검증은 [추가 수정 보고서](../guidelines/publisher-additional-review-2026-10-10.md)를 따릅니다.
|
||||
|
||||
현재 HM 구현의 기준 문서. 공통 원칙은 `docs/guidelines/프로젝트-지침.md`(§6, §7), Token 구조 원칙은 `테마-토큰-가이드.md`를 따른다. 이 문서는 Combobox 고유의 API·Token·상태·결정만 기록한다.
|
||||
|
||||
## 1. 상태와 성격
|
||||
@@ -17,7 +21,7 @@
|
||||
|
||||
- **참고 근거**: 외부 ui_viz Reference (ZIP 미포함)의 기존 테스트 규격에는 Combobox가 없다(Select와 Search Field는 다른 컴포넌트). 참고할 수치가 없었다.
|
||||
- **Component로 만든 이유**: 검색 가능한 단일 선택은 서비스에서 반복되고(trigger 텍스트, 검색, 선택 표시, 닫힘, focus 복귀가 동일) 최소 API(`options`)로 충분해서 typed wrapper를 제공한다. 더 복잡한 항목(그룹, 아이콘 등)은 소비자가 `Command`를 직접 조합한다.
|
||||
- **구현 방식**: Popover(Portal, collision, Escape, focus 복귀)와 Command(검색, 필터링, 키보드, listbox ARIA)를 그대로 조합한다. Select의 구현이나 연결형 윤곽을 복제하지 않았다.
|
||||
- **구현 방식**: Popover(Portal, collision, Escape, focus 복귀)와 Command(검색, 필터링, 키보드, listbox ARIA)를 그대로 조합한다. Select 구현을 복제하지 않고 Popover + Command를 유지하며 현재 연결형 윤곽을 사용한다.
|
||||
- **보류**: §11.
|
||||
|
||||
## 3. Select와의 구분
|
||||
@@ -26,7 +30,7 @@
|
||||
|---|---|---|
|
||||
| 용도 | 정해진 짧은 목록에서 선택, 검색 불필요 | 검색/필터가 필요한 선택 |
|
||||
| 구현 | Radix Select | Popover + Command(cmdk) |
|
||||
| 목록 | trigger에 붙은 연결형 윤곽, 선택 항목은 면으로 표시 | 독립 floating 패널(검색 Input + 목록), 선택 항목은 Accent 45% 면 + check 아이콘 |
|
||||
| 목록 | trigger에 붙은 연결형 윤곽, 선택 항목은 면으로 표시 | trigger 연결형 패널(검색 Input + 목록), 선택 항목은 Accent 45% 면 + check 아이콘 |
|
||||
| 접근성 모델 | Radix Select(listbox) | `role=combobox` trigger + 패널 안 cmdk combobox/listbox |
|
||||
|
||||
## 4. 기본 규격 (현재 HM 규격)
|
||||
@@ -35,8 +39,8 @@
|
||||
|---|---|
|
||||
| Size | `large`(기본, 44px, 16 / 24), `medium`(34px, 14 / 20) — Select와 같은 두 크기 |
|
||||
| Trigger | 폭 100%(부모 폭), padding-x 12px, 1px `--hm-sem-stroke-input-default`, radius 4px, 흰 면, 오른쪽 chevron 18px |
|
||||
| 값 / placeholder | 선택된 option의 label, 없으면 placeholder("선택", `--hm-sem-fg-placeholder`), 길면 말줄임 |
|
||||
| Popup | padding 0, 폭 = trigger 폭(`--radix-popover-trigger-width`), 독립 4px gap. Focus Light 2 border, input radius 4px(네 모서리), shadow `0 2px 24px black 12%` |
|
||||
| 값 / placeholder | 선택된 option의 label, 없으면 placeholder("선택", `--hm-sem-fg-secondary`), 길면 말줄임 |
|
||||
| Popup | padding 0, 폭 = trigger 폭(`--radix-popover-trigger-width`), sideOffset=-1로 1px 연결 경계 공유. Focus border, 안쪽 두 모서리 radius는 기존 Input token, shadow `0 2px 24px black 12%` |
|
||||
| 검색 | Command Input(placeholder 기본 "검색...") |
|
||||
| 목록 | Command List(최대 280px), Item 높이 36px·padding-x 12px·radius 0·weight 400. Large 16/24, Medium 14/20. 선택 check 16px, 긴 label은 말줄임 |
|
||||
| Empty | "결과가 없습니다."(`emptyText`) |
|
||||
@@ -59,7 +63,7 @@ export: `Combobox`, types `ComboboxOption`(`{ value, label, disabled? }`), `Comb
|
||||
- `options`(필수), `value`/`defaultValue`/`onValueChange(value)`, `placeholder`, `searchPlaceholder`, `emptyText`, `size`, `disabled`, 그리고 `button` props(`id`, `aria-label`, `className`…).
|
||||
- 필터링: option의 `value`와 `label`(keywords)에 cmdk 기본 fuzzy 필터를 쓴다.
|
||||
- 이미 선택된 option을 다시 선택해도 값은 유지된다(해제 UI는 없다).
|
||||
- **접근성**: Trigger는 `role="combobox"`, `aria-haspopup="listbox"`, `aria-expanded`. 패널 안 Command Input이 `role=combobox`(`aria-controls` → `role=listbox`), option은 `role=option`. 이름은 `<label htmlFor=id>` 또는 `aria-label`을 소비자가 준다. 실제 ARIA combobox(편집 가능한 trigger input)가 아니라 **버튼 trigger + 패널 내 검색 combobox** 구조다(shadcn 공식 구조).
|
||||
- **접근성**: Trigger는 `role="combobox"`, `aria-haspopup="dialog"`, `aria-expanded`이며, 열린 동안 `aria-controls`가 Popover의 `role="dialog"`를 가리킨다. 패널 안 Command Input은 별도 `role="combobox"`로 cmdk listbox를 제어하고, 항목은 `role="option"`이다. 소비자는 공개 `Label`의 `htmlFor`와 trigger `id`, 또는 `aria-label`/`aria-labelledby`로 항목명을 연결한다. 버튼 trigger + dialog 내부 검색 combobox 구조이며, trigger를 `aria-haspopup="listbox"`로 덮어쓰지 않는다. Enter/Space로 열기, 검색·방향키·Enter로 선택, Escape로 닫기와 trigger focus 복귀를 유지한다.
|
||||
- generic data framework, 다중 선택, 비동기 로딩은 만들지 않았다.
|
||||
|
||||
### 값 소유권과 외부 초기화
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# Date Picker
|
||||
|
||||
> 현재 접근성 보완(2026-10-10): 흰 Trigger의 빈 값 안내는 기존 `--hm-sem-fg-secondary`를 사용한다. 기본 Theme에서 #6e6759/흰색이며 공통 placeholder Token과 Disabled opacity는 보존한다. 아래 과거 검증의 #999 실측은 당시 기록이다.
|
||||
|
||||
현재 HM 구현의 기준 문서. 공통 원칙은 `docs/guidelines/프로젝트-지침.md`(§6, §7), Token 구조 원칙은 `테마-토큰-가이드.md`를 따른다. 이 문서는 Date Picker 고유의 API·Token·상태·결정만 기록한다.
|
||||
|
||||
## 1. 상태와 성격
|
||||
@@ -27,7 +29,7 @@
|
||||
|---|---|
|
||||
| Size | `large`(기본, 안쪽 42px + 1px border = 44px, 16 / 24), `medium`(안쪽 32px = 34px, 14 / 20) — Select와 같은 두 크기 |
|
||||
| Trigger | 폭 100%(부모 폭), padding-x 12px, 1px `--hm-sem-stroke-input-default`, radius 4px, 흰 면, 오른쪽 달력 아이콘 18px `--hm-sem-fg-secondary` |
|
||||
| 값 / placeholder | 선택값은 `--hm-sem-fg-primary`, placeholder("날짜 선택")는 `--hm-sem-fg-placeholder`, 길면 말줄임 |
|
||||
| 값 / placeholder | 선택값은 `--hm-sem-fg-primary`, placeholder("날짜 선택")는 `--hm-sem-fg-secondary`, 길면 말줄임 |
|
||||
| 날짜 표시 | 로컬 `Date`의 연·월·일 → `YYYY.MM.DD` (예: `2026.01.09`, `2026.10.06`). `format` prop으로 교체 |
|
||||
| Popup | Popover 면(흰 면, 1px pale border, 4px radius, 그림자)에 Popover padding 0, 폭 `auto`로 Calendar에 맞춤 |
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# Dialog
|
||||
|
||||
> 2026-10-10 추가 수정 요청 기준: 일반 확인과 삭제 확인의 취소·실행은 모두 Standard Solid. 과거 검증 기록은 당시 결과이며 현재 검증은 [추가 수정 보고서](../guidelines/publisher-additional-review-2026-10-10.md)를 따릅니다.
|
||||
|
||||
현재 HM 구현의 기준 문서. 공통 원칙은 `docs/guidelines/프로젝트-지침.md`(§6, §7), Token 구조 원칙은 `테마-토큰-가이드.md`를 따른다. 이 문서는 Dialog 고유의 API·Token·상태·결정만 기록한다.
|
||||
|
||||
> 근거 문서: ui_viz `docs/components/dialog.md`(Dialog / Modal). 문서가 스스로 `NO_SOURCE_EVIDENCE`(Source Dashboard에 Dialog specimen 없음)라고 밝히며, 값의 상당수는 D-093(2026-09-29) Dialog-local Confirmed다. Foundation `elevation.*`, `z-index.*`, `motion.*`는 TBD이고 Dialog 범위 값을 Foundation token으로 올리지 않는다.
|
||||
@@ -58,7 +60,7 @@
|
||||
| Focus | 전역 focus ring은 ui_viz TBD. 조합한 Button이 각자의 focus를 가짐 | TBD |
|
||||
| Long Content | Header·Footer 고정, Body만 세로 scroll, 짧으면 scrollbar 없음 | Confirmed |
|
||||
| Wide Content | Body 안 가로 scroll, 페이지 가로 overflow 없음 | Confirmed |
|
||||
| Confirmation / Destructive | 컴포넌트 상태가 아니라 Button 조합: 일반 확인은 취소 `cancel`+`solid` / 확인 `primary`+`solid`, 삭제 확인은 취소 `cancel`+`outline` / 삭제 `destructive`+`outline`. 같은 세트의 appearance·size 통일, Brand 금지 | HM 사용자 확정 Button 세트 규칙 |
|
||||
| Confirmation / Destructive | 컴포넌트 상태가 아니라 Button 조합: 일반 확인은 취소 `cancel`+`solid` / 확인 `primary`+`solid`, 삭제 확인은 취소 `cancel`+`solid` / 삭제 `destructive`+`solid`. 같은 세트의 appearance·size 통일, Brand 금지 | HM 사용자 확정 Button 세트 규칙 |
|
||||
|
||||
Loading, Selected, Disabled 등 Dialog 자체의 다른 상태는 ui_viz에 없어 만들지 않았다.
|
||||
|
||||
@@ -82,7 +84,7 @@ DialogClose:
|
||||
- 새 prop(`size`, `variant`, `destructive`, `loading`, `placement`, `dismissible`)은 근거가 없어 만들지 않았다.
|
||||
- `DialogBody`를 추가한 이유: ui_viz가 Body를 필수 region이자 유일한 scroll owner로 정의하기 때문이다. Body 없이도 동작하지만(자식이 그대로 놓임) 이 경우 Body padding과 내부 scroll이 적용되지 않는다.
|
||||
- `DialogClose` 변경 이유: shadcn은 `DialogClose asChild`의 `data-slot="dialog-close"`가 자식 `<Button>`의 `data-slot="button"`을 덮어써 HM Button 스타일(`[data-slot="button"]`)이 사라진다. Dialog Actions는 Button 조합이 규격(§4)이라 Dialog 쪽에서 고쳤다.
|
||||
- Actions의 Button에는 appearance를 명시한다. Button 기본값은 Brand이며, Destructive는 Outline만 지원한다. [Button 허용 조합·기본값 주의](button.md#61-허용-role--appearance-ai-reference)를 따른다.
|
||||
- Actions의 Button에는 appearance를 명시한다. Button 기본값은 Brand이며, Destructive는 Solid와 Outline을 지원한다. [Button 허용 조합·기본값 주의](button.md#61-허용-role--appearance-ai-reference)를 따른다.
|
||||
|
||||
## 6. Token
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# Drawer
|
||||
|
||||
> 2026-10-10 추가 수정 요청 기준: 데스크톱 하단 우측 가로 취소 → 실행, 640px 이하 전체 폭 세로 실행 위 / 취소 아래. DOM은 취소 → 실행 순서이며 모바일 CSS column-reverse 적용. vaul 드래그 닫기 유지. 과거 검증 기록은 당시 결과이며 현재 검증은 [추가 수정 보고서](../guidelines/publisher-additional-review-2026-10-10.md)를 따릅니다.
|
||||
|
||||
현재 HM 구현의 기준 문서. 공통 원칙은 `docs/guidelines/프로젝트-지침.md`(§6, §7), Token 구조 원칙은 `테마-토큰-가이드.md`를 따른다. 이 문서는 Drawer 고유의 API·Token·상태·결정만 기록한다. Dialog·Sheet와 값을 공유하지 않는다.
|
||||
|
||||
## 1. 상태
|
||||
@@ -36,7 +38,7 @@
|
||||
| Title | 18 / 28 / 700 |
|
||||
| Description | 14 / 20 / 400, `--hm-sem-fg-secondary` |
|
||||
| Body | 14 / 20 / 400, 좌우 padding 24px, 유일한 scroll 영역 |
|
||||
| Footer | padding `16 24 24`, gap 8px, 세로 쌓임(주 action이 위, shadcn 기본) |
|
||||
| Footer | padding `16 24 24`, gap 8px. 데스크톱 우측 가로 취소 → 실행, 640px 이하 전체 폭 세로 실행 → 취소 |
|
||||
| Close(X) | 없음(handle drag, Overlay 클릭, Escape, `DrawerClose`) |
|
||||
| Overlay | shadcn 기본(`bg-black/10` + blur) |
|
||||
|
||||
|
||||
@@ -44,6 +44,32 @@ Radix `Label` props 그대로 (`htmlFor`, `asChild` 등). 출력 속성: `data-s
|
||||
|
||||
- Required 표시(`*`)를 위한 prop은 만들지 않았다(ui_viz `field-semantics.md` §1: Select/Checkbox/Radio 등에 required API·표시를 새로 추가하지 않는다). 소비자가 `aria-hidden` span으로 조합한다.
|
||||
|
||||
### 신규 업무 화면의 연결 예제
|
||||
|
||||
`Label`은 `@hm-design/ui`에 공개 export되어 있다. 지원하는 Field Label은 직접 스타일링한 native `<label>` 대신 실제 `Label`을 렌더한다. Input/Textarea는 `id`, Select는 **Root가 아닌 SelectTrigger**의 `id`, Combobox는 trigger로 전달되는 공개 `id`에 연결한다. `aria-labelledby`로 화면에 보이는 항목명을 접근성 이름으로 함께 사용한다.
|
||||
|
||||
```tsx
|
||||
import { useId } from "react"
|
||||
import { Label, Input, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, Combobox } from "@hm-design/ui"
|
||||
|
||||
export function Fields() {
|
||||
const id = useId()
|
||||
return <>
|
||||
<Label htmlFor={`${id}-name`}>이름</Label>
|
||||
<Input id={`${id}-name`} size="medium" />
|
||||
<Label id={`${id}-type-label`} htmlFor={`${id}-type`}>유형</Label>
|
||||
<Select>
|
||||
<SelectTrigger id={`${id}-type`} aria-labelledby={`${id}-type-label`} size="medium"><SelectValue placeholder="선택" /></SelectTrigger>
|
||||
<SelectContent><SelectItem value="work">업무</SelectItem></SelectContent>
|
||||
</Select>
|
||||
<Label id={`${id}-owner-label`} htmlFor={`${id}-owner`}>담당자</Label>
|
||||
<Combobox id={`${id}-owner`} aria-labelledby={`${id}-owner-label`} options={[{ value: "kim", label: "김한맥" }]} size="medium" />
|
||||
</>
|
||||
}
|
||||
```
|
||||
|
||||
Label/control 간격은 부모 조합이 소유한다. 반복 Field는 인스턴스별 ID를 사용하며, Label 클릭 focus와 팝업 키보드·접근성 이름은 실제 브라우저에서 확인한다. 위 예제는 기존 공개 props를 사용하며 새 `label`/`required` prop을 만들지 않는다. native Label 사용을 무조건 금지하지 않는다. 명시적인 비 React adapter 또는 기존 HM Label로 연결할 수 없는 사용처는 지원 제약·의미 있는 HTML 선택 이유·접근성 확인 결과를 기록한다. Story에 남은 native Label fixture만으로 신규 화면의 예외를 인정하지 않는다.
|
||||
|
||||
## 6. Token
|
||||
|
||||
Component Mapping 위치: `packages/ui/src/theme/label.css` (`--hm-label-*`).
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# Menubar
|
||||
|
||||
> 2026-10-10 추가 검증: 파일 메뉴 항목에서 ArrowRight를 누르면 편집 Trigger만 Focus되고 다음 popup이 닫히는 문제를 재현했다. 이전 popup의 exit animation 동안 남은 DismissableLayer가 다음 popup Focus를 외부로 처리했다. Main Content의 닫힘 애니메이션만 제거해 즉시 unmount하며 열림 애니메이션·Radix 키보드/API·Sub menu는 유지한다. 현재 결과는 [추가 수정 보고서](../guidelines/publisher-additional-review-2026-10-10.md)를 따른다.
|
||||
|
||||
현재 HM 구현의 기준 문서. 공통 원칙은 `docs/guidelines/프로젝트-지침.md`(§6, §7), Token 구조 원칙은 `테마-토큰-가이드.md`를 따른다. 이 문서는 Menubar 고유의 API·Token·상태·결정만 기록한다. Dropdown Menu(`dropdown-menu.md`), Navigation Menu(`navigation-menu.md`)와 값을 공유하지 않는다.
|
||||
|
||||
## 1. 상태
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# Progress
|
||||
|
||||
> 2026-10-10 추가 수정 요청 기준: `asChild` 단일 소비자 요소와 자식을 보존하고 Indicator를 추가한다. 채워진 막대 우측 끝에 기존 Progress radius를 적용하며 색·높이·진행률 API는 유지. 과거 검증 기록은 당시 결과이며 현재 검증은 [추가 수정 보고서](../guidelines/publisher-additional-review-2026-10-10.md)를 따릅니다.
|
||||
|
||||
현재 HM 구현의 기준 문서. 공통 원칙은 `docs/guidelines/프로젝트-지침.md`(§6, §7), Token 구조 원칙은 `테마-토큰-가이드.md`를 따른다. 이 문서는 Progress 고유의 API·Token·상태·결정만 기록한다.
|
||||
|
||||
## 1. 상태
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# Sheet
|
||||
|
||||
> 2026-10-10 추가 수정 요청 기준: 화면 가장자리 모서리는 직각, 안쪽 두 모서리만 기존 --hm-radius-control-md를 임시 재사용. 신규 확정 radius 수치가 아니며 GNB/LNB 모바일 Sheet도 같은 계약. 과거 검증 기록은 당시 결과이며 현재 검증은 [추가 수정 보고서](../guidelines/publisher-additional-review-2026-10-10.md)를 따릅니다.
|
||||
|
||||
현재 HM 구현의 기준 문서. 공통 원칙은 `docs/guidelines/프로젝트-지침.md`(§6, §7), Token 구조 원칙은 `테마-토큰-가이드.md`를 따른다. 이 문서는 Sheet 고유의 API·Token·상태·결정만 기록한다. Dialog 문서(`dialog.md`)와 값을 공유하지 않는다.
|
||||
|
||||
## 1. 상태
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# Table
|
||||
|
||||
> 2026-10-10 추가 수정 요청 기준: Hover·Selected·Selected+Hover는 #BDDFD4 20%. 공통 강조 토큰과 Checkbox 선택색은 유지. 과거 검증 기록은 당시 결과이며 현재 검증은 [추가 수정 보고서](../guidelines/publisher-additional-review-2026-10-10.md)를 따릅니다.
|
||||
|
||||
현재 HM 구현의 기준 문서. 공통 원칙은 `docs/guidelines/프로젝트-지침.md`(§6, §7), Token 구조 원칙은 `테마-토큰-가이드.md`를 따른다. 이 문서는 Table 고유의 API·Token·상태·결정만 기록한다.
|
||||
|
||||
## 1. 상태
|
||||
@@ -35,9 +37,9 @@
|
||||
|
||||
| 상태 | 값 |
|
||||
|---|---|
|
||||
| Row Hover | body 행 배경 `--accent` 45%(`color-mix`, 면만 변경, header 제외) |
|
||||
| Selected (`data-state="selected"`) | 행 배경 `--accent` 45%. 소비자가 속성을 붙인다 |
|
||||
| Selected + Hover | `--accent` 45% 유지(농도 변화 없음) |
|
||||
| Row Hover | body 행 배경 `--accent` 20%(`color-mix`, 면만 변경, header 제외) |
|
||||
| Selected (`data-state="selected"`) | 행 배경 `--accent` 20%. 소비자가 속성을 붙인다 |
|
||||
| Selected + Hover | `--accent` 20% 유지(농도 변화 없음) |
|
||||
| Focus / Disabled / Loading | Table 자체에는 없음(셀 안 content가 각자 가진다) |
|
||||
|
||||
## 5. API
|
||||
@@ -53,7 +55,7 @@ shadcn 구조 그대로. export: `Table`, `TableHeader`, `TableBody`, `TableFoot
|
||||
|
||||
Component Mapping 위치: `packages/ui/src/theme/table.css` (`--hm-table-*`).
|
||||
|
||||
`min-width`, `background`, `text`, `font-size|line-height|font-weight`, `cell-padding-y|x`, `divider-width|color`, `header-background|text|font-size|font-weight|border-top|border-bottom`, `row-hover-background`, `row-selected-background`, `footer-background|font-weight`, `caption-*`. Semantic과 Theme palette(`--hm-sem-palette-green-*`, `--hm-sem-stroke-input-default`, `--hm-sem-palette-white`)를 참조하고 다른 컴포넌트 Token을 쓰지 않는다. 신규 Primitive 없음(ui-viz의 `#EDF4F1`은 기존 Primitive의 `color-mix`로 표현). row hover / selected는 shadcn `--accent`의 `color-mix` 45%(Select·Menu·Pagination hover와 같은 Soft Surface 규칙, 공통 `--hm-sem-surface-highlight`를 Component Token이 참조).
|
||||
`min-width`, `background`, `text`, `font-size|line-height|font-weight`, `cell-padding-y|x`, `divider-width|color`, `header-background|text|font-size|font-weight|border-top|border-bottom`, `row-hover-background`, `row-selected-background`, `footer-background|font-weight`, `caption-*`. Semantic과 Theme palette(`--hm-sem-palette-green-*`, `--hm-sem-stroke-input-default`, `--hm-sem-palette-white`)를 참조하고 다른 컴포넌트 Token을 쓰지 않는다. 신규 Primitive 없음(ui-viz의 `#EDF4F1`은 기존 Primitive의 `color-mix`로 표현). row hover / selected는 shadcn `--accent`의 `color-mix` 20%(Select·Menu·Pagination hover와 같은 Soft Surface 규칙, 공통 `--hm-sem-surface-highlight`를 Component Token이 참조).
|
||||
|
||||
## 7. shadcn에서 유지한 항목
|
||||
|
||||
@@ -74,7 +76,7 @@ container(`overflow-x-auto`)와 table 구조, `caption-bottom`, Head/Cell의 che
|
||||
## 10. 사용자 확정 결정
|
||||
|
||||
- 2026-10-02: ui-viz는 참고 자료이며 최종 기준은 현재 HM 구현과 이 문서다(작업 지시). 개별 수치에 대한 별도 결정은 없다.
|
||||
- 2026-10-06 (컬러 역할 정리): 행은 넓은 Soft Surface이므로 Hover·Selected·Selected+Hover 모두 `--accent` 45%를 쓴다(이전 `--hm-green-tint` 18% / 40%). Active State Semantic(Light 2)은 쓰지 않는다. 선택 구분은 면 색이 아니라 행 안의 Checkbox(Active Semantic)가 담당한다. `--accent` 값 자체는 바꾸지 않았다. Table row highlight surface는 Select Highlight / Selected와 동일한 Accent 45% 정책을 사용한다.
|
||||
- 2026-10-06 (컬러 역할 정리): 행은 넓은 Soft Surface이므로 Hover·Selected·Selected+Hover 모두 `--accent` 20%를 쓴다(이전 `--hm-green-tint` 18% / 40%). Active State Semantic(Light 2)은 쓰지 않는다. 선택 구분은 면 색이 아니라 행 안의 Checkbox(Active Semantic)가 담당한다. `--accent` 값 자체는 바꾸지 않았다. Table row highlight surface는 Select Highlight / Selected와 동일한 Accent 20% 정책을 사용한다.
|
||||
|
||||
## 11. 미확정 / 보류
|
||||
|
||||
|
||||
+77
-9
@@ -2,7 +2,7 @@
|
||||
|
||||
현재 HM 구현의 기준 문서. 공통 원칙은 `docs/guidelines/프로젝트-지침.md`(§6, §7), Token 구조 원칙은 `테마-토큰-가이드.md`를 따른다. 이 문서는 Tabs 고유의 API·Token·상태·결정만 기록한다.
|
||||
|
||||
## 기본 사용: Primary (2026-10-08)
|
||||
## 기본 사용: Primary (2026-10-08 기본 API / 2026-10-09 조합 안내)
|
||||
|
||||
앱 진입점에서 `@hm-design/ui/theme.css`를 로드한다. `TabsList`의 기본값은 `fill=true`, `panelSurface="content"`이며 기본 API만으로 Primary가 적용된다.
|
||||
|
||||
@@ -14,23 +14,23 @@ import { Tabs, TabsList, TabsTrigger, TabsContent } from "@hm-design/ui"
|
||||
<TabsTrigger value="overview">개요</TabsTrigger>
|
||||
<TabsTrigger value="details">상세</TabsTrigger>
|
||||
</TabsList>
|
||||
<TabsContent value="overview" className="border bg-background rounded-b p-4">개요 콘텐츠</TabsContent>
|
||||
<TabsContent value="details" className="border bg-background rounded-b p-4">상세 콘텐츠</TabsContent>
|
||||
<TabsContent value="overview" className="px-0 py-6">개요 콘텐츠</TabsContent>
|
||||
<TabsContent value="details" className="px-0 py-6">상세 콘텐츠</TabsContent>
|
||||
</Tabs>
|
||||
```
|
||||
|
||||
- **Primary**: `<TabsList>`, `<TabsList fill>`, `<TabsList fill panelSurface="content">`는 같은 디자인이다. 선택 면은 White → `--hm-sem-bg-content` Gradient다.
|
||||
- **Secondary 명시적 사용**: 위 예제의 List를 `<TabsList fill panelSurface="surface" aria-label="업무 보기">`로 바꾸고 **각** `TabsContent`에 `border bg-card rounded-b p-4`를 사용한다. 선택 면은 기존 White surface다.
|
||||
- **Primary**: `<TabsList>`, `<TabsList fill>`, `<TabsList fill panelSurface="content">`는 같은 디자인이다. 실제 content 면 위에서 사용하며 선택 면은 White alpha **0.8** → `--hm-sem-bg-content` Gradient다. 탭 전체 opacity는 1이다.
|
||||
- **Secondary 명시적 사용**: 흰색 Card 안에서는 List를 `<TabsList fill panelSurface="surface" aria-label="업무 보기">`로 바꾸고 **각** `TabsContent`의 `px-0 py-6`를 유지한다. 바깥 Card가 White surface와 여백을 소유하므로 내부 패널에 별도 박스를 추가하지 않는다.
|
||||
- **Legacy non-fill 명시적 사용**: `<TabsList fill={false} aria-label="업무 보기">`와 **각** `TabsContent`의 `border bg-card rounded-b p-4` 조합으로 이전 스타일을 유지한다. `<TabsList fill={false} panelSurface="surface">`도 같은 시각이다. OLD_TEST_ONLY / REMOVE_CANDIDATE 이력은 유지하며 별도 승인 없이 삭제하지 않는다.
|
||||
|
||||
`TabsContent`는 패널 배경·테두리를 자동으로 지정하지 않는다. 소비자가 Primary에는 `bg-background`(content), Secondary / Legacy에는 `bg-card`(surface)를 연결한다. `panelSurface`는 List의 선택 면·연결 곡선에만 적용되며 콘텐츠 색을 바꾸지 않는다. Bar와 패널 사이에 gap이나 별도 구분선을 넣지 않는다. 상태·Variant는 §4.1, 외부 소비자 변경 안내는 §15를 따른다.
|
||||
`TabsContent`는 패널 배경·테두리를 자동으로 지정하지 않는다. Primary의 바탕은 페이지/Layout의 content 면(`bg-background`), Secondary는 상위 Card의 surface 면이다. `panelSurface`는 List의 선택 면·연결 곡선에만 적용되며 콘텐츠 색을 바꾸지 않는다. Bar와 패널 사이에 gap이나 별도 구분선을 넣지 않는다. 상태·Variant는 §4.1, 외부 소비자 변경 안내는 §15, 중첩 박스 없는 조합은 §16을 따른다. 2026-10-09 실제 구현 요청에 따라 Primary 상단 흰색 불투명도 80%를 해당 Tabs CSS Mapping에 반영했다(§16.3).
|
||||
|
||||
## 1. 상태
|
||||
|
||||
| 항목 | 내용 |
|
||||
|---|---|
|
||||
| 구현 상태 | 기본 Primary Fill + 명시적 Secondary Fill + Legacy non-fill + 넘침 이동 버튼(D-090) 구현 (`hm-tab` class 없음) |
|
||||
| 기준일 | 2026-10-08 (Primary 기본값 승인 반영) |
|
||||
| 기준일 | 2026-10-09 (D-01 조합·D-02 상단 White 80% 반영, API는 2026-10-08 기본값 유지) |
|
||||
| 기반 | shadcn/ui Tabs (Radix `Tabs`) |
|
||||
| 대표 Story | `Components/Navigation/Tabs` → `All` (이름 "Tabs"): Primary(Fill + content) / Secondary(Fill + surface) |
|
||||
| 보류 | 아래 §11 |
|
||||
@@ -77,7 +77,7 @@ import { Tabs, TabsList, TabsTrigger, TabsContent } from "@hm-design/ui"
|
||||
|
||||
### 4.1 현재 Fill 디자인: Primary / Secondary State · Variant
|
||||
|
||||
- **Primary (기본값)**: `fill=true`, `panelSurface="content"`. Selected는 White → bg-content Gradient, top / left / right는 Green Light 3(`--hm-tab-fill-line-color`), bottom은 content 패널색이다.
|
||||
- **Primary (기본값)**: `fill=true`, `panelSurface="content"`. Selected는 White alpha 0.8 → bg-content Gradient, top / left / right는 Green Light 3(`--hm-tab-fill-line-color`), bottom은 content 패널색이다. 전체 탭 opacity와 전경·경계는 변경하지 않는다.
|
||||
- **Secondary**: `fill=true`, `panelSurface="surface"`. Selected는 기존 White surface 면, 같은 Green Light 3 테두리, bottom은 surface 패널색이다.
|
||||
- **공통 Geometry**: 기존 높이 34px, Typography 16/24/700, 좌우 padding 16px, 상단 radius 4px, 선택 탭의 8px 곡선 연결을 유지한다. Overflow가 없으면 균등 폭, 모든 Fill 이웃은 1px left border와 `margin-left: -1px`로 경계를 공유한다. Overflow이면 라벨 필요 폭을 유지한다.
|
||||
- **Inactive**: 면·top / vertical border·전경은 §4의 기존 비선택 값, bottom line만 Green Light 3다.
|
||||
@@ -131,13 +131,15 @@ Radix Tabs 구조·ARIA(`role=tablist/tab/tabpanel`, `aria-selected`)·roving ta
|
||||
- `LongLabel`은 짧은 라벨, 긴 라벨 1개, 긴 라벨 여러 개, 260px 좁은 container를 함께 검증한다. 라벨은 `nowrap`·무말줄임이며 실제 필요 폭이 넘을 때 이동 버튼으로 전환한다.
|
||||
- non-fill Story(`Selected`, `SelectedMiddle`, `Fill`, `FillContent`, `FillOverflow`와 대표의 non-fill 구역)는 2026-10-06에 제거했다. API(`fill=false`, Legacy profile CSS)는 유지한다(§10).
|
||||
- 2026-10-08 숨김 `Compatibility`(`verification` 태그 + **VERIFICATION ONLY** 표시)는 Legacy `fill={false}` / `fill={false} panelSurface="surface"` 동일성과 `panelSurface="surface"`만 명시한 경우의 Secondary 전환을 확인한다. 일반 Story 메뉴를 추가하지 않는다.
|
||||
- Story의 콘텐츠 panel은 Primary `TabsContent` + `border bg-background`, Secondary / Legacy `TabsContent` + `border bg-card` 소비자 조합 예시다.
|
||||
- Overview / Default API / Variants / States 및 Fill verification 예제의 콘텐츠 panel은 `px-0 py-6`로 통일해 D-01을 실제로 반영한다. Primary는 상위 content 면, Secondary는 상위 surface 면에 연결하며 내부 패널의 별도 border·배경·radius를 제거한다. Compatibility의 Legacy non-fill 두 예제만 이전 `border bg-card rounded-b p-4`를 보존한다.
|
||||
- **Usage**(2026-10-09 추가)는 공개 Card / Input / Textarea / Table을 조합해 Card 내부 Secondary와 페이지 content 면 위 Primary를 보여준다. 두 예제 모두 `TabsContent`는 `px-0 py-6`이며 별도 배경·border·radius를 추가하지 않는다. 대표 Story ID·기존 구역·verification Story는 유지한다.
|
||||
|
||||
## 10. 사용자 확정 결정
|
||||
|
||||
- 2026-10-06: Tabs의 최종 디자인 언어는 **Primary = Fill + `panelSurface="content"`**(기본형), **Secondary = Fill + `panelSurface="surface"`**(서브형) 두 가지다. 이 결정이 ui_viz보다 우선한다. non-fill 기본 profile은 OLD_TEST_ONLY로 분류해 대표 Story에서 내렸다.
|
||||
- **2026-10-06 당시 범위**는 Storybook 대표형에 한정했다. 당시 Public API 기본값(`fill=false`, `panelSurface="surface"`)과 non-fill CSS branch는 유지하고 기본값 변경·branch 삭제를 별도 승인 대상으로 남겼다. 당시 저장소 내 소비처가 없다는 관찰은 외부 소비자의 무영향을 보장하지 않는다.
|
||||
- **2026-10-08 추가 개선 E 승인**: `TabsList` 기본값을 `fill=true`, `panelSurface="content"`로 변경한다. Primary / Secondary / Legacy의 기존 CSS 디자인 값·선택자·동작·Theme / Token을 유지한다. non-fill의 OLD_TEST_ONLY / REMOVE_CANDIDATE 이력과 명시적 사용 API는 유지하며 삭제 승인은 포함하지 않는다. `panelSurface`는 Fill일 때만 효과가 있는 List prop이다(`Tabs` Root prop이 아님).
|
||||
- **2026-10-09 실제 구현 요청**: 사전공유 D-01/D-02를 문서 외 실제 구현에도 적용한다. Fill Story의 중첩 패널 박스를 제거하고 PageHeader 대표 Pattern에 직접 Tabs를 조합한다. 기존 `tabs.css`의 `fill=true` + `panelSurface="content"` 내부 face gradient 상단만 80%로 바꾼다. Secondary·Legacy·공개 API·Theme JSON·공통 Palette 변경은 포함하지 않는다.
|
||||
|
||||
## 11. 미확정 / 보류
|
||||
|
||||
@@ -163,6 +165,7 @@ src/components/story-board.tsx
|
||||
|
||||
## 13. 검증 상태
|
||||
|
||||
- **2026-10-09 D-01/D-02 실제 반영**: 전체 typecheck·앱 build·Storybook build 통과. 1280×900 / 390×844의 Primary 선택 면 상단 `color(srgb 1 1 1 / 0.8)`·하단 불투명 content·전체 opacity 1, Secondary 불투명 White, Fill panel transparent/border 0/padding 24px 0을 확인했다. PageHeader Pattern의 8px·20px과 실제 조합, Legacy·Disabled·키보드·넘침 이동·긴 라벨·입력 초안 보존을 확인했다. 참고 원본/비대상 파일과 API는 보존했으며 상세 범위·수치는 §16의 통합 보고를 따른다. 아래 과거 검증 기록은 해당 날짜의 이력이다.
|
||||
- 2026-10-08 추가 개선 E: 기존 6024 Storybook 재사용. 대표 `All`에서 기본 Props / `fill`만 명시 / 두 Props 명시가 모두 Primary(`data-fill="true"`, `data-panel-surface="content"`)이며 같은 Gradient·Green Light 3 경계·34px·16/24/700·8px 곡선을 확인했다. Secondary의 White 면·패널과 Bar / panel 1px 겹침도 유지했다.
|
||||
- 숨김 `Compatibility`: `fill={false}`의 content / surface 조합은 같은 White 선택 면·Legacy 경계·라벨 필요 폭이고 곡선이 없다. `panelSurface="surface"`만 명시하면 Secondary다. CSS 주석을 제외한 모든 규칙·값과 Production의 기본값 두 개를 제외한 코드가 작업 시작 상태와 동일함을 비교했다.
|
||||
- 실제 포인터 / 키보드: 클릭·ArrowLeft / Right·Home / End 선택과 콘텐츠 전환, 비선택 Hover Black 20% / 선택 Gradient 유지, focus-visible 3px 링, Disabled opacity 0.5·pointer-events none·tabIndex -1·방향키 건너뛰기를 확인했다. 독립 Overflow Story는 260px frame / 192px list에서 다음 이동 `scrollLeft 0→33.33`, 이전 이동 `→0`, 끝 버튼 Disabled 전환과 선택 유지가 정상이다.
|
||||
@@ -216,3 +219,68 @@ src/components/story-board.tsx
|
||||
- **레이아웃 차이**: non-fill은 라벨 필요 폭, Fill은 Overflow가 없을 때 컨테이너 전체를 균등 분할한다. 높이 34px은 같으나 탭 폭·공유 경계·선택 연결 곡선·패널색이 달라질 수 있다. 좁은 폭에서는 기존 Overflow 이동 버튼이 나타날 수 있다.
|
||||
- **CSS Override 영향**: frame의 기본 attribute가 `data-fill="false"` / `data-panel-surface="surface"`에서 `"true"` / `"content"`로 바뀐다. non-fill 조건 selector, list width / flex, active background / border, 곡선 pseudo-element override를 사용하는 소비자는 검토가 필요하다. `className`과 ref는 계속 tablist에 전달된다.
|
||||
- **확인 범위**: 현재 저장소의 TabsList 사용은 Story만 확인했다. 외부 소비자 전체의 명시적 Props·패널색·레이아웃·CSS Override는 실제 확인하지 못했으므로 위 내용은 영향 가능성과 이행 안내이며 외부 호환성 전체 검증을 뜻하지 않는다.
|
||||
|
||||
## 16. Publisher / Developer 조합 안내 (2026-10-09)
|
||||
|
||||
사전공유 v0.2의 D-01(중첩 박스 제거)을 기존 공개 API로 표현한다. Component 자체에는 원래 패널 박스가 없으므로 소비 조합만 바꾸며 새 Variant·Token을 만들지 않는다.
|
||||
|
||||
### 16.1 표면 선택과 여백 소유권
|
||||
|
||||
| 상황 | List | 콘텐츠 배치 |
|
||||
|---|---|---|
|
||||
| 기본 흰색 Card 안 | `panelSurface="surface"` | Card / CardContent의 기본 여백을 유지. 각 TabsContent는 `px-0 py-6` |
|
||||
| Card 없이 content 페이지 위 | 기본 List 또는 `panelSurface="content"` | 기존 Layout의 content 배경·여백 사용. 탭 전체를 새 흰색 박스로 감싸지 않음 |
|
||||
| 기존 `Card surface="content"` 안 | `panelSurface="content"` | 실제 하단 표면에 맞춤. 흰색 Card 예제를 기계적으로 적용하지 않음 |
|
||||
| 내부 정보 구분 필요 | 실제 하단 표면에 맞춤 | 기존 Separator / Alert 등 역할이 있는 Component를 조합 |
|
||||
|
||||
```tsx
|
||||
import { Card, CardContent, CardHeader, CardTitle, Tabs, TabsContent, TabsList, TabsTrigger } from "@hm-design/ui"
|
||||
|
||||
<Card className="min-w-0">
|
||||
<CardHeader><CardTitle>프로젝트 정보</CardTitle></CardHeader>
|
||||
<CardContent className="min-w-0">
|
||||
<Tabs defaultValue="overview">
|
||||
<TabsList panelSurface="surface" aria-label="프로젝트 정보 보기">
|
||||
<TabsTrigger value="overview">기본 정보</TabsTrigger>
|
||||
<TabsTrigger value="schedule">일정·산출물</TabsTrigger>
|
||||
</TabsList>
|
||||
<TabsContent value="overview" className="px-0 py-6">기본 정보</TabsContent>
|
||||
<TabsContent value="schedule" className="px-0 py-6">일정·산출물</TabsContent>
|
||||
</Tabs>
|
||||
</CardContent>
|
||||
</Card>
|
||||
```
|
||||
|
||||
- **Do**: 바깥 Card의 배경·border·radius·24px 기본 여백을 유지하고 중복 `rounded-b border bg-background p-6`만 제거한다. 콘텐츠 내부 Input·Textarea·Table의 고유 스타일은 유지한다.
|
||||
- **Don't**: Input border, Table 행 배경, Alert 표면까지 일괄 제거하지 않는다. `panelSurface`만 바꾸고 실제 상위 배경은 다른 색으로 두지 않는다.
|
||||
- `py-6`(현재 24px) / `px-0`은 이 탭 조합의 예시 값이다. 모든 Component의 padding이나 제목→설명 간격으로 승격하지 않는다. [Card](card.md#3-기본-규격)의 Header→Content 24px과 [PageHeader](../patterns/page-header.md#3-token-packagesuisrcthemepage-headercss)의 제목→설명 8px·아래 콘텐츠 20px은 별개다.
|
||||
- CardDescription은 PageHeaderDescription과 동일 규격이 아니다. [CardDescription의 shadcn 호환 범위](card.md#51-carddescription-사용-범위)를 따른다.
|
||||
|
||||
### 16.2 Responsive / Accessibility / 상태 확인
|
||||
|
||||
- 소비 Layout의 flex/grid 자식인 **Card 자체**와 CardContent·Tabs는 필요 시 `min-w-0`으로 수축을 허용한다. CardContent에만 지정하면 grid 자식 Card의 min-content 폭(내부 Table 최소 폭 + 좌우 padding)이 페이지를 넓힐 수 있다. 긴 라벨은 말줄임으로 대체하지 않고 기존 Tabs 넘침 이동을 사용한다. Table의 기본 최소 폭 520px과 내부 스크롤은 [Table](table.md)을 유지한다.
|
||||
- `aria-label` 또는 `aria-labelledby`로 tablist를 식별하고 Trigger / Content의 `value`를 일치시킨다. Input·Textarea에는 연결된 Label을 둔다. 입력 상태를 탭 전환 후에도 유지해야 하면 소비자 상위 state로 관리한다(Usage 예제 참고).
|
||||
- 클릭, ArrowLeft/Right, Home/End, focus-visible, disabled 건너뛰기, 넘침 버튼과 선택 콘텐츠 전환을 확인한다. Disabled trigger 전체 opacity 0.5는 기존 상태 계약이며 아래 그라데이션 alpha와 별개다.
|
||||
- Empty / Loading / Error 표현이 필요하면 기존 Component / Pattern을 조합한다. 패널 박스 제거는 데이터 조회·오류 처리나 새로운 Tabs 상태 API를 제공하지 않는다.
|
||||
- desktop / mobile에서 문서 전체 가로 넘침과 내부 Tabs / Table 스크롤을 구분한다. utility 이름만 확인하지 말고 실제 패널 배경 transparent·border 0·padding 24px 0 및 자식 정렬을 브라우저에서 확인한다. 공통 검증은 [개발 적용 가이드](../guidelines/개발-적용-가이드.md#81-탭-조합과-역할별-간격)를 따른다.
|
||||
|
||||
### 16.3 D-02: 상단 흰색 80% 실제 반영
|
||||
|
||||
사전공유 폴더의 원문은 v0.2 상태를 유지하지만, 사용자가 2026-10-09 후속 요청에서 보류 항목을 실제 구현까지 반영하도록 명시했다. 이 요청에 따라 공통 Theme 전체가 아니라 **Tabs의 Primary content branch만** 아래와 같이 적용했다.
|
||||
|
||||
```css
|
||||
[data-slot="tabs-frame"][data-fill="true"][data-panel-surface="content"] {
|
||||
--hm-tab-fill-panel: var(--hm-sem-bg-content);
|
||||
--hm-tab-fill-face: linear-gradient(
|
||||
to bottom,
|
||||
color-mix(in srgb, var(--hm-sem-palette-white) 80%, transparent) 0%,
|
||||
var(--hm-sem-bg-content) 100%
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
실제 출력 대상은 Fill의 `[data-slot="tabs-trigger"][data-state="active"]`가 소비하는 `background-image`다. 면의 상단 흰색 alpha만 0.8이고 하단 content는 불투명이다. 방향·stop 위치·텍스트·아이콘·경계·Secondary·Legacy·비선택 Hover·Focus·Disabled 상태 규칙을 유지하며 탭 전체 `opacity`는 1이다(기존 Disabled opacity 0.5는 유지). 새 공개 Theme JSON alpha 입력이나 Component API를 추가하지 않았다.
|
||||
|
||||
현재 저장소의 TabsList 소비처는 Tabs 대표/verification Story와 PageHeader 대표 Pattern 조합이다. 이 content branch를 사용하는 외부 앱도 패키지 CSS 업데이트 시 새 면을 받지만 외부 코드와 override 전체는 제공되지 않아 별도 확인 대상이다. 같은 Default 흰색을 사용하는 Button·Card·Input·다른 Pattern에는 변경이 전파되지 않는다.
|
||||
|
||||
비교 분류·반영 범위와 이번 검증은 [사전공유 통합 보고](../guidelines/publisher-integration-2026-10-09.md)를 따른다. 외부 소비 화면과 참고 예시의 모바일 이슈는 소스가 제공되지 않아 추가 확인 대상이다.
|
||||
@@ -1,5 +1,7 @@
|
||||
# Toggle Group
|
||||
|
||||
> 2026-10-10 추가 수정 요청 기준: 소비자 style과 내부 --hm-toggle-group-gap을 병합. spacing은 4px 단위이며 명시적 동일 CSS 변수 override는 기존 확장 계약으로 유지. 과거 검증 기록은 당시 결과이며 현재 검증은 [추가 수정 보고서](../guidelines/publisher-additional-review-2026-10-10.md)를 따릅니다.
|
||||
|
||||
현재 HM 구현의 기준 문서. 공통 원칙은 `docs/guidelines/프로젝트-지침.md`(§6, §7), Token 구조 원칙은 `테마-토큰-가이드.md`를 따른다. 이 문서는 Toggle Group 고유의 API·Token·상태·결정만 기록한다. Toggle(`toggle.md`)과 역할 비교는 거기 §14.
|
||||
|
||||
## 1. 상태
|
||||
|
||||
@@ -1,5 +1,39 @@
|
||||
# AI Generation Guard — 경량 검증
|
||||
|
||||
## 별도 요구사항 액션 검사
|
||||
|
||||
`node scripts/guard-requirements.mjs <guard.json> <requirements-actions.json>`는 원본 Guard의 status/issues를 보존하고 별도 판정을 출력한다. 정책 입력 예시는 `{"schemaVersion":1,"actionPolicy":{"allowedLabels":["조회","초기화"]}}`다. 실제 요구사항에서 허용한 소비 화면의 Button/button/link 이름만 작성하며, Component 기본 동작을 검사하는 경우 그 이름도 명시한다. 허용하지 않은 정적 이름(예: 미요청 CSV 다운로드)은 REQ-003 FAIL, 동적/복합 이름·spread props·오래된 source/contract는 NOT VERIFIED다.
|
||||
|
||||
자유 형식 요구사항의 의미를 자동 추정하지 않는다. 범위는 FULL Guard가 확인한 파일의 literal 액션 이름이며 wrapper/namespace/동적 UI/API 호출과 전체 접근성은 별도 검토한다. 이 검사의 PASS로 원본 CSS intent·Runtime 미검증을 제거하지 않는다. 이전 실험에는 소급 적용해 원래 점수를 바꾸지 않는다.
|
||||
|
||||
## 정적 결과와 최종 화면 결과
|
||||
|
||||
JSON schemaVersion 2는 기존 `status`, exit code, 원본 `issues`를 유지하고 `staticStatus`, `runtimeStatus`, 그룹별 `basis/evidence`, Token 참조와 source/contract fingerprint를 추가한다. `staticStatus`는 RENDER 항목만 분리하며 CSS intent·native control·해석 불가 graph는 그대로 미검증이다. `runtimeStatus`는 Guard 자체에서 항상 NOT VERIFIED다. 따라서 RENDER-002만 남은 화면의 정적 PASS와 미해석 화면을 구분할 수 있다. 소비 graph는 변경하지 않는다.
|
||||
|
||||
## Theme Token 검사
|
||||
|
||||
현재 확장 규칙은 아래 [CSS Intent와 동적 Token 검사](#css-intent와-동적-token-검사-2026-10-10)를 함께 적용한다. 현재 suite는 Guard 75개·증거 연결 20개·요구사항 연결 5개다. 아래 63개/11개 및 51개/46개 테스트 수와 안정화 설명은 당시 기록이다.
|
||||
|
||||
`TOKEN-001`: CSS 선언 값, JSX style 문자열, Tailwind 임의 값·v4 shorthand의 `var(--hm-...)` 참조가 연결된 공개 Theme/Status CSS 또는 소비 CSS/inline custom property 선언에 없으면 FAIL. 사용되지 않은 파일이나 다른 lazy Story의 선언은 빌리지 않는다. fallback 색이 있어도 없는 HM token은 FAIL이다. 파싱 불가 public CSS 정의는 NOT VERIFIED. 계산된 HM 참조는 유한 후보 전체를 확인하고, 해석 불가 참조는 `TOKEN-002` NOT VERIFIED다. selector별 cascade·실제 computed value는 브라우저 확인 대상이다. HM 이외 변수도 수집하지만, 연결 선언이 없는 외부 host 변수는 HM 미정의 FAIL과 구분하여 NOT VERIFIED로 남긴다.
|
||||
|
||||
`tokenEvidence`는 entry별 연결 정의 수와 검사한 참조를 제공한다. 공개 Token의 정답은 실제 연결 CSS 및 [Runtime 계약표](runtime-theme-contract.md)다. Component mapping은 runtime JSON key와 같은 집계가 아니다. 별도 토큰·색상은 추가하지 않는다.
|
||||
|
||||
`node scripts/public-theme-tokens.mjs`로 연결된 공개 CSS의 선언 목록을 JSON으로 출력한다. 현재 1,170개 선언명이며 Runtime JSON 입력 key 수와 다르다. Native role widget은 `REUSE-006`으로 근거 검토를 요구하고 일반 콘텐츠 HTML은 허용한다.
|
||||
|
||||
## Runtime 증거 연결
|
||||
|
||||
원본 Guard JSON과 실제 브라우저 증거를 별도로 보존한다. Runtime JSON에 `sourceFingerprint`, `contractFingerprint`, 네 `viewports`(width/status), 이름 있는 핵심 `interactions`(name/status)를 기록한 뒤 실행한다.
|
||||
|
||||
```sh
|
||||
node scripts/guard-evidence.mjs guard.json runtime.json
|
||||
```
|
||||
|
||||
결합 결과는 정적 PASS + 일치하는 해시 + 네 viewport PASS + 핵심 동작 PASS일 때만 PASS다. 정적 FAIL, native/CSS intent의 미검증은 제거하지 않는다. 소스·공개 계약 변경 시 이전 증거는 NOT VERIFIED다. Runtime JSON은 제출된 검사 증거이며 도구가 독립 인증하거나 모든 상태를 보장하는 것은 아니다. `guard-evidence.test.mjs`가 오래된 증거, 누락 viewport/동작, 정적 FAIL/미검증 보존을 검사한다. 원본 `status`와 결합 결과를 혼용하지 않는다.
|
||||
|
||||
`--result`의 React bootstrap 증명이 없거나 RENDER-001이면 결합 PASS를 허용하지 않는다. 결합 결과도 원본 FULL_SCREEN/PARTIAL scope를 그대로 상속한다. 당시 확장은 Guard 51+12=63개, 증거 연결 5+6=11개였다. 이후 CSS Intent·동적 Token 확장으로 현재 Guard 75개·증거 연결 20개이며, 요구사항 연결 5개는 별도 suite다. 과거 결과는 당시 기록으로 보존한다.
|
||||
|
||||
재현 가능한 예제: `examples/ai-quality`의 10개 독립 bootstrap. `node scripts/verify-quality-runtime.mjs`는 각 실제 dist 화면을 검사하고 Guard·Runtime·결합 JSON과 캡처를 `_local/quality-20261010`에 각각 기록한다. Playwright 경로는 `HM_PLAYWRIGHT_DIR`, Chrome 실행 경로는 `HM_CHROME_PATH`, 서버 URL은 `HM_QUALITY_URL`로 명시한다. 실패 범위 재검사는 인자로 화면 ID를 전달한다.
|
||||
|
||||
`node scripts/ai-generation-guard.mjs --target <앱> --scope FULL_SCREEN|PARTIAL`
|
||||
|
||||
- 기존 Navigation·Storybook 격리·CSS entry·공개 Import 검사를 유지한다. Navigation 재사용 시 확정한 `--mode`를 전달한다.
|
||||
@@ -8,9 +42,178 @@
|
||||
- `REUSE-001` FAIL: 공개 이름에 대응하는 HM `data-slot`을 소비자의 기본 HTML에 부여함. 공식 여부가 불명확한 wrapper는 NOT VERIFIED다. slot은 컴포넌트 재사용 증거가 아니다.
|
||||
- `REUSE-002` FAIL: 공개 컴포넌트를 import한 뒤 참조하지 않음. re-export·type import·별칭·namespace·props 전달은 단순 미사용으로 판정하지 않는다.
|
||||
- `REUSE-003` NOT VERIFIED: HM slot/class를 겨냥한 CSS. 승인된 override와 복제 의도를 정적 코드만으로 구분할 수 없으므로 실제 사용을 확인한다.
|
||||
- `REUSE-004` NOT VERIFIED: 기본 select/input/textarea/button 사용. 합법적인 기본 HTML과 기존 컴포넌트 대체 구현을 구분하여 검토한다. 일반 div·레이아웃 CSS는 복제로 단정하지 않는다.
|
||||
- `REUSE-004` NOT VERIFIED: 기본 select/input/textarea/button/label 사용. 합법적인 기본 HTML과 기존 컴포넌트 대체 구현을 구분하여 검토한다. native Label은 공개 Label의 지원 사용처인지 control 연결과 예외 이유를 확인하며 무조건 FAIL로 판정하지 않는다. 일반 div·레이아웃 CSS는 복제로 단정하지 않는다.
|
||||
- 최종 제출물이 있으면 같은 실행에 `--result <HTML 또는 JS/TS bootstrap>`을 지정한다. 해당 artifact를 시작점으로 검사한다. React mount가 확인되지 않으면 `RENDER-001`, 확인되어도 실제 브라우저 결과는 `RENDER-002` NOT VERIFIED다. 경로 이름만으로 preview.html을 금지하지 않는다. 실제 React를 실행하는 HTML은 정상 entry다.
|
||||
|
||||
PASS는 정적 계약 통과만 의미한다. 실제 React 화면을 빌드하고 브라우저에서 utility 적용·레이아웃·핵심 동작을 최소 1회 확인한다. 별도 HTML 모방 화면이나 이미지로 이를 대체하지 않는다. 화면에서 실행되지 않는 코드, 조건부 렌더, CSS 복제 의도, 동적 binding은 정적 검사만으로 완전히 판별할 수 없다. 미확인은 NOT VERIFIED로 기록한다.
|
||||
|
||||
기존 exit code 계약은 FAIL=1, 설정/도구 오류=2, 그 외=0이다. 따라서 exit 0만으로 PASS를 기록하지 않는다. JSON의 `status`, `checkedGroups`, `issues`를 함께 확인한다. NOT VERIFIED는 FAIL이 없다는 사실과 전체 계약 검증 완료를 구분한다.
|
||||
|
||||
FAIL 수정 후 수정 파일만 PARTIAL 재검사한다. 성공한 검사는 반복하지 않는다. 최소 회귀 테스트: `node --test scripts/ai-generation-guard.test.mjs` (새 의존성 설치 없음).
|
||||
|
||||
AI 생성 개선 회귀는 기존 46개 본문을 보존하고 native Label 검토·공개 Label 별칭·외부 React FULL/PARTIAL·실제 Sidebar/Theme 누락·graph 밖 파일을 5개 추가하여 51개다. 아래 안정화 절의 46/46은 당시 기록이다. [개선 및 재실험 결과](ai-generation-improvement-2026-10-10.md)를 함께 확인한다.
|
||||
|
||||
## Production 분기 분석
|
||||
|
||||
### 독립 외부 React 앱
|
||||
|
||||
Production graph는 대상 앱의 bootstrap에서 시작한다. 본 저장소의 graph에 외부 화면이나 Story를 등록할 필요가 없다. 기존 CLI를 본 저장소에서 실행하여 계약은 현재 공개 API, 검사 대상은 외부 앱으로 분리한다.
|
||||
|
||||
```sh
|
||||
node scripts/ai-generation-guard.mjs --target <외부 앱> --scope FULL_SCREEN --mode GNB_ONLY --entry index.html --result index.html --json
|
||||
node scripts/ai-generation-guard.mjs --target <외부 앱> --scope PARTIAL --mode GNB_ONLY --files src/main.tsx --entry index.html --result index.html --json
|
||||
```
|
||||
|
||||
`--files`는 bootstrap을 대신하지 않는다. graph 밖 파일은 SCOPE-001, 누락 bootstrap은 ENTRY-001이며 미검증이다. `--result`를 전달하여 실제 React mount를 찾으면 RENDER-002가 남는다. 이것은 검사 대상 누락이 아니라 별도 브라우저 확인 요구다. 승인된 소비 CSS도 REUSE-003의 원본 판정을 유지하고 별도 증거로 검토한다. 브라우저 확인 또는 CSS 승인 기록으로 원본 JSON을 PASS로 덮어쓰지 않는다. 외부 앱의 package 버전이 이 저장소 계약과 다른지는 별도로 확인한다.
|
||||
|
||||
Pattern 선택 적합성·native Label 지원 경계·요구사항 밖 CSV 등 액션은 요구사항/선택 기록/실제 동작을 대조하는 수동 평가 대상이다. Guard 정적 PASS만으로 이를 확인했다고 보고하지 않는다. STORYBOOK profile은 기존 Reference 검사용이며 외부 업무 화면 검사 우회 경로가 아니다.
|
||||
|
||||
기본 `--profile PRODUCTION`은 HTML/JS bootstrap의 import graph를 검사한다. Navigation은 [분기 분석기](../../scripts/guard-navigation-analysis.mjs)가 직접 component 호출의 literal props, 기본 props, immutable local 값, JSX return/slot, ternary/logical 조건을 추적한다. 현재 entry에서 사용되지 않는 JSX 값은 실제 mount와 구분한다. 같은 컴포넌트의 호출이 여러 개이면 모든 호출의 결과를 합치며, 한 호출에서 위반이 확인되면 FAIL을 유지한다.
|
||||
|
||||
- 실제 도달하는 금지 Sidebar/혼합 Navigation: `NAV-001/002` FAIL.
|
||||
- literal로 배제된 분기·반환되지 않는 Reference JSX 값: Navigation violation으로 세지 않는다. import·공개 API·CSS 검사는 계속 수행한다.
|
||||
- 동적 props, spread, mutation, opaque callback, 지원하지 않는 제어 흐름: 가능한 위반은 `NOT VERIFIED`로 남는다. 미분석 JSX는 기존 검사를 유지하며 없다고 가정하지 않는다.
|
||||
- `DashboardLayout.sidebar`가 현재 props로 `undefined/null/false`임이 증명되면 빈 slot이다. 값이 불명확하면 `NAV-005`를 유지한다.
|
||||
|
||||
분석기는 JavaScript를 실행하지 않으며 일반적인 bundler/전체 CFG가 아니다. NOT VERIFIED는 실제 entry와 데이터 상태를 브라우저에서 확인하거나, literal props를 가진 직접 bootstrap fixture로 확인한다. `checkedFiles`는 import graph의 파일이며 실제 mount 목록이 아니다. `checkedHMElements`도 정적 참조 목록이고 화면 DOM 개수의 증거가 아니다.
|
||||
|
||||
## 독립 Storybook 검사
|
||||
|
||||
`STORYBOOK`은 `--profile` 값이며 scope가 아니다. 지원 scope는 `FULL_SCREEN | PARTIAL`이고, `--scope STORYBOOK`은 설정 오류다. Storybook profile에는 Production 전용 `--result`를 전달하지 않는다.
|
||||
|
||||
```sh
|
||||
node scripts/ai-generation-guard.mjs --target . --profile STORYBOOK --scope FULL_SCREEN --json
|
||||
node scripts/ai-generation-guard.mjs --target . --profile STORYBOOK --scope PARTIAL --files src/components/tabs.stories.tsx,src/patterns/page-header.stories.tsx --json
|
||||
```
|
||||
|
||||
`.storybook/main.ts/js/mjs`의 literal `stories` glob과 `.storybook/preview.tsx/ts/jsx/js`를 별도 root로 사용한다. 기존 workspace의 `fast-glob`을 사용하며 패키지 설치·설정 실행은 하지 않는다. computed discovery는 `SB-004` NOT VERIFIED이며 `--entry story-path,...`로 범위를 명시할 수 있다. 각 Story의 의존 graph에 공통 preview CSS/decorator를 연결하며, 다른 lazy Story의 CSS를 연결 증거로 빌리지 않는다. Production graph에 Story를 추가하지 않는다. `--result`는 Production 전용이다.
|
||||
|
||||
| 검사 | Production | Storybook |
|
||||
|---|---|---|
|
||||
| Story/helper/reference import, `.sb-*` CSS | 기존 격리 검사 FAIL | Reference의 정상 의존성 허용 |
|
||||
| 공개 import/export·private source import | 기존 검사 유지 | 같은 검사 유지 |
|
||||
| Theme/utility/status CSS entry | bootstrap 연결 | preview + Story graph 연결 |
|
||||
| Navigation | 전달한 mode에 맞춰 분기 검사 | mode 미지정 시 Reference API를 보존(NOT APPLICABLE); 명시 mode는 정적 위반 검사 |
|
||||
| native public component slot 위조 | FAIL | FAIL |
|
||||
| 공개 컴포넌트가 없는 내부 namespace wrapper slot | 기존 FAIL/NOT VERIFIED | 문서화된 Reference composition인지 NOT VERIFIED; 재사용 증거로 인정하지 않음 |
|
||||
|
||||
새 업무 화면을 Story로 등록하는 것은 여전히 금지된다. Storybook profile은 신규 Production Navigation을 허용하는 경로가 아니다. Story별 대표/verification 분류, 혼합 Navigation의 승인 의도와 모든 runtime 상태는 자동 확정하지 않는다. 페이지 단위 검사는 관련 Story를 `--entry`로 고르고 mode를 명시하여 수행한다. 기존 Component/Pattern 구현은 소비 화면 검사에서 제외하며 패키지 typecheck/build 및 별도 runtime 검증으로 확인한다. 선택한 package source가 graph 밖이면 SCOPE-001을 유지한다.
|
||||
|
||||
## CSS Intent 및 보존 범위
|
||||
|
||||
### CSS 측정과 Intent 검토 근거
|
||||
|
||||
Runtime JSON의 선택적 `cssEvidence`를 `guard-evidence.mjs`가 별도 결과로 연결한다. 원본 Guard issues/status와 `REUSE-003`는 변경하지 않는다. 기존 Runtime JSON도 호환된다. 측정이 없으면 `cssEvidence.status`는 NOT VERIFIED이며 기존 viewport/interaction Runtime 판정과 구분한다.
|
||||
|
||||
| 범위 | 근거 | 한계 |
|
||||
|---|---|---|
|
||||
| 정적 규칙 | Guard의 공개 Component import·Navigation·CSS entry·tokenEvidence | 실제 mount/cascade/스타일 생성은 별도 확인 |
|
||||
| 실제 스타일 | selector/property/width별 computed 값과 기대값의 비교 | 기록한 상태·속성만 확인; 디자인 의도 승인 아님 |
|
||||
| 사용자 디자인 의도 | issue 단위 rationale과 문서 recipe SHA/행 연결 | REUSE-003 NOT VERIFIED 유지; 자동 승인 없음 |
|
||||
| 동적 Token | 실제 상태에서 해석된 custom property 값 | 미실행 테마·상태와 동적 참조는 NOT VERIFIED |
|
||||
|
||||
```json
|
||||
{
|
||||
"cssEvidence": {
|
||||
"checks": [{
|
||||
"name": "완료 Badge ink", "kind": "COMPUTED_STYLE", "width": 390,
|
||||
"selector": ".dashboard-status [data-slot=\"badge\"][data-status=\"done\"]",
|
||||
"property": "color", "actual": "rgb(255, 255, 255)", "expected": "rgb(255, 255, 255)"
|
||||
}],
|
||||
"intentReviews": [{
|
||||
"issue": { "code": "REUSE-003", "file": "src/index.css", "line": 15 },
|
||||
"rationale": "공식 Dashboard Badge recipe와 소비 mapping을 비교함. 사용자 의도는 미확정.",
|
||||
"reference": { "file": "docs/patterns/dashboard-layout.md", "line": 69, "sha256": "실제 문서 파일의 SHA256" }
|
||||
}]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
위 값·행은 입력 형식 예시이며 해당 화면에서 실제 측정하고 현재 문서 행·해시를 기록한다. `CSS_VARIABLE` kind는 property가 `--`로 시작해야 하며 `getComputedStyle(element).getPropertyValue(property).trim()`으로 측정한다. `COMPUTED_STYLE`은 color/backgroundColor 등 실제 computed 속성을 기록한다. 기대값은 공개 CSS/공식 recipe에서 정하고 actual을 복사해 만들지 않는다. Theme import → 상태 CSS → 실제 변수 → Badge color/background/border를 각각 연결한다.
|
||||
|
||||
측정은 네 표준 폭 중 Runtime PASS가 있는 폭에만 연결하며 source/contract가 stale하면 사용하지 않는다. 비어 있는 값·지원하지 않는 kind/폭은 NOT VERIFIED다. 제공한 status 대신 actual/expected 일치로 판정하고 실제 mismatch는 Runtime/결합 FAIL을 유지한다. 누락·잘못된 검토 근거는 CSS 증거 NOT VERIFIED로 남긴다. 문서 참조는 Guard contractSource 안의 실제 파일과 해시가 일치하고 원본 issue의 code/file/line이 같아야 연결된다. 연결된 검토도 NOT VERIFIED로 표시한다. 측정 PASS와 결합 전체 PASS를 혼용하지 않는다.
|
||||
|
||||
원본 Guard의 contract 해시에 `guard-evidence.mjs`가 포함되므로 이 도구가 변경되면 이전 연결 Runtime을 새 계약의 PASS로 옮기지 않는다. 재사용 원본은 보존하고, 변경된 계약의 Guard와 실제 브라우저 측정을 별도 결과에 기록한다. 전체 Storybook·이미 성공한 화면 재생성은 필요하지 않다.
|
||||
|
||||
정상 Gradient·token·utility를 통과 목적으로 수정하지 않는다. 공식 package Theme CSS는 공개 entry로 연결하고 내부 구현은 소비자 replica 검사에서 제외한다. 소비자의 HM slot/class 스타일은 승인된 override인지 복제인지 정적 판정할 수 없으므로 REUSE-003 NOT VERIFIED를 유지한다. Tabs 내부 `tabs-*` slot도 이 검토 범위에 포함한다. 파싱 불가 CSS는 CSS-005 NOT VERIFIED이며 기본 HTML의 공개 slot 위조는 REUSE-001 FAIL이다.
|
||||
|
||||
CSS entry의 정적 PASS는 Tailwind source 검색 범위·utility 생성·computed style을 보장하지 않는다. `index.css → tailwind.css`, `hm-theme.css → @hm-design/ui/theme.css`, 필요 시 공개 status CSS, 공개 `@hm-design/ui/tailwind.css`의 source 경로를 실제 build/브라우저에서 확인한다. D-02 Primary 80% 상단 stop과 Secondary/Legacy 보존은 Theme source 해시·CSS 선언·실제 Tabs 렌더로 검증한다.
|
||||
|
||||
## CSS Intent와 동적 Token 검사 (2026-10-10)
|
||||
|
||||
기존 Production bootstrap graph, PARTIAL 선택/연관 의존성, Storybook entry별 격리는 유지한다. 추가 분석기는 소비 graph만 읽으며 Component/Theme 구현이나 대표 Story를 수정하지 않는다. 기존 `status`/`staticStatus`/`issues`를 지우지 않고 `styleEvidence`와 결합 결과의 `styleVerification`을 추가한다. 새 위반은 기존 exit 1 계약을 따른다.
|
||||
|
||||
검사 대상은 AI 생성 화면의 스타일 규칙 준수다. 외주 퍼블리셔의 Theme 편집 기능·편집 권한·Designer 기능을 추가하거나 확대하지 않는다. 기존 Theme 적용/전환·Token 값·공개 API·Component 스타일은 유지한다. 검사 예제나 문서 recipe는 새로운 CSS override 또는 Theme 편집 방식을 승인하지 않는다. Theme 기능 자체의 개선 필요성은 별도 검토 항목으로만 보고한다.
|
||||
|
||||
| 영역 | 확인하는 내용 | 결과와 한계 |
|
||||
|---|---|---|
|
||||
| A — STATIC | 공개 CSS entry/import, 연결 Token 선언, 유한 동적 후보, 명확한 Component 하드코드 | 기존 CSS-001/002/003, IMP-001, TOKEN-001 및 STYLE-001 FAIL은 다른 PASS로 덮지 않음 |
|
||||
| B — RUNTIME | 실제 custom property/computed 값, 우선순위가 반영된 결과, 지정 상태·폭 | 제출된 이름 있는 측정만 확인. 미실행 Theme·hover/focus/disabled·외부 입력 전체는 NOT VERIFIED |
|
||||
| C — DESIGN_INTENT | 요청 의미, override 승인, 불명확한 일반 콘텐츠 스타일 | 자동 승인 경로 없음. recipe/hash/행 검토도 NOT VERIFIED 유지 |
|
||||
|
||||
`STYLE-001`은 명시된 HM slot, 실제 공개 HM Component에 연결된 class 또는 공개 HM JSX Component를 대상으로 한 HEX/RGB/HSL 및 0이 아닌 px/rem/em padding/margin/gap/radius 하드코드 override를 FAIL로 판정한다. React 숫자 spacing/radius와 유한 조건부 값, `rounded-[13px]` 등 임의 utility도 포함한다. `var()` fallback 속 색상은 직접 하드코드 override와 구분하며, 없는 Token은 TOKEN-001로 계속 FAIL이다. `!important`, 일반 콘텐츠의 literal 색상·geometry와 Token 기반 Component override는 `STYLE-002` 검토 위치에 디자인 의도 NOT VERIFIED를 기록한다. 일반 콘텐츠 CSS를 Component 복제로 단정하거나 일괄 FAIL로 바꾸지 않는다. named color, %, calc(), 일반 Tailwind numeric utility 등 모든 CSS 문법을 금지 여부까지 자동 판별하는 것은 아니다. selector의 영향은 GLOBAL/COMPONENT_SCOPED inventory로 제공하며 selector cascade나 격리 보장은 Runtime 대상이다.
|
||||
|
||||
`tokenEvidence.references`는 file/line/name/fallback/origin/status를 기록한다. origin은 PUBLIC/CONSUMER/CONSUMER_INLINE/UNRESOLVED다. 연결된 소비 custom property는 공개 Theme Token과 구분한다. 소비 선언 존재 PASS는 selector별 실제 적용을 뜻하지 않는다. HM 이외 변수도 수집하며 연결 선언이 없는 외부 host 변수는 NOT VERIFIED다. `TOKEN-003`은 `var(--hm-name broken)`처럼 명확히 잘못된 참조를 FAIL로 판정한다. 전체 CSS 문법·variable cycle 검사는 별도 한계다.
|
||||
|
||||
동적 분석은 문자열/숫자 literal, 모듈 최상위 const, 괄호·TS assertion, 문자열 `+`, 조건부 분기의 모든 후보와 template 조합을 최대 32개까지 해석한다. shadowed/destructured/function-local binding은 접지 않고 코드를 실행하지 않는다. 후보 중 하나라도 미정의 HM Token이면 FAIL이며 후보 문자열 일부를 가짜 Token 이름으로 검사하지 않는다. 미해석 className/style props/style spread/style value와 동적 Token template은 `TOKEN-002` 및 `tokenEvidence.dynamic` 위치 ID로 남긴다. import된 상수·객체 props·외부 입력·상태 전체를 추측하지 않는다. 선언 목록은 동적 위치가 있는 entry에만 출력해 전체 Storybook JSON 크기 증가를 제한한다.
|
||||
|
||||
위치별 Runtime 증거는 기존 CSS 측정의 name/kind/selector/property/actual/expected/width와 함께 다음 필드를 요구한다. 실제 source site의 `id`, `file`, `ruleId`를 그대로 복사하고 browser/state/height/component를 실제 검사 환경에서 기록한다. 아래 값은 형식 예시다.
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "기본 Badge text", "kind": "COMPUTED_STYLE",
|
||||
"siteId": "Guard가 출력한 실제 위치 ID", "file": "src/App.tsx", "ruleId": "TOKEN-002",
|
||||
"component": "Badge", "selector": "[data-slot=\"badge\"]", "property": "color",
|
||||
"width": 390, "height": 900, "state": "default-theme:active",
|
||||
"browser": { "name": "Chrome", "version": "실제 버전" },
|
||||
"actualExpression": "var(--hm-sem-fg-primary)", "tokens": ["--hm-sem-fg-primary"],
|
||||
"actual": "실제 computed 값", "expected": "공개 계약에서 정한 computed 기대값"
|
||||
}
|
||||
```
|
||||
|
||||
동적 Token은 actualExpression에서 HM 참조를 추출해 해당 entry의 연결 선언과 tokens를 대조한다. fallback 덕분에 computed 값이 같아도 실제 참조가 미정의면 Runtime FAIL이다. 불완전 graph, 누락된 expression/Token/브라우저 정보, 다른 site/property의 측정은 NOT VERIFIED다. 네 폭에서 명명한 상태의 PASS가 있어야 그 위치의 RUNTIME PASS이며 추가 측정의 FAIL도 보존한다. 기존 형식의 64건 CSS 측정은 측정 PASS로 유지할 수 있지만 새 위치별 증거를 대신하지 않는다. 사용자 제출 증거의 실제 브라우저 실행을 이 도구가 독립 인증하는 것은 아니다.
|
||||
|
||||
CSS 선언 위치는 측정 selector가 원본 selector와 같아야 한다. 더 좁은 실제 DOM selector를 사용할 때는 `sourceSelector`에 원본 selector를 기록하고, 측정한 DOM의 `element.matches(sourceSelector)` 결과를 `matchesSourceSelector: true`로 함께 제출한다. Component 이름도 원본 대상과 일치해야 한다. 다른 DOM에서 같은 값이 나온 결과를 가져와 위치 검증으로 사용하지 않는다.
|
||||
|
||||
`styleVerification.checks`는 STATIC/RUNTIME/DESIGN_INTENT/FINAL에 해당하는 `staticStatus`/`runtimeStatus`/`designIntentStatus`/`finalStatus`, 관련 file/component/rule/DOM/token와 measurement/reason을 반환한다. 필수 결과 중 FAIL이 하나라도 있으면 FINAL FAIL, 미검증이 있으면 NOT VERIFIED다. 동적 위치의 RUNTIME PASS는 관측한 문자열과 스타일만 증명하므로 미확정 분기 전체의 STATIC/FINAL을 PASS로 올리지 않는다. T01의 정적 CSS 연결·Token 선언은 PASS, 세 Badge override의 실제 적용은 별도로 검증할 수 있지만 사용자 의도는 계속 NOT VERIFIED다. 원본 `staticStatus`의 REUSE-003 기록은 보존한다.
|
||||
|
||||
문서 근거는 contractSource 경계·실제 SHA·원본 issue·유효 행 범위를 확인한다. 측정 기대값은 actual 복사가 아니라 공개 recipe에서 정하고, `var()`가 치환된 브라우저 직렬화 형식으로 비교한다. 일반 CSS 문자열과 computed custom property의 직렬화 차이를 스타일 오류로 보고하지 않도록 측정 도구에서 기대 표현식을 해석한다. 실제 값 mismatch를 느슨한 비교로 숨기지 않는다.
|
||||
|
||||
```sh
|
||||
node scripts/ai-generation-guard.mjs --target <기존 앱> --scope FULL_SCREEN --mode DASHBOARD_ONLY --result index.html --json
|
||||
node scripts/ai-generation-guard.mjs --target <기존 앱> --scope PARTIAL --mode DASHBOARD_ONLY --files src/index.css --result index.html --json
|
||||
node scripts/guard-evidence.mjs <새 guard.json> <동일 source/contract의 새 runtime.json>
|
||||
node --test scripts/ai-generation-guard.test.mjs scripts/guard-evidence.test.mjs scripts/guard-requirements.test.mjs
|
||||
```
|
||||
|
||||
전체 292 Story 재렌더나 신규 AI 화면/모델 호출은 필요 없다. 기존 63/11개 본문은 보존하고 현재 Guard 75개·증거 연결 20개·요구사항 연결 5개를 함께 검사한다. 과거 원본 FAIL/NOT VERIFIED 증거는 보존하고 새로운 결과를 별도 위치에 저장한다.
|
||||
|
||||
## 2026-10-10 필수 스타일 누락 (R1)
|
||||
|
||||
완전히 해석한 bootstrap graph에서 필수 Theme(CSS-001), Tailwind utility(CSS-002), 필요한 Dashboard Status(CSS-003)가 없으면 FAIL이다. 해석 불가 import·CSS·bootstrap이 있으면 NOT VERIFIED를 유지한다. exit 0만으로 PASS를 기록하지 않는다. 기존 36개 테스트와 신규 누락 사례 4개를 유지한다.
|
||||
|
||||
## 잔여 판정 회귀 범위 (2026-10-10 안정화)
|
||||
|
||||
해당 안정화 당시 기존 40개 테스트 본문을 보존하고 6개를 추가해 46/46을 확인했다. 당시 Guard와 Navigation 분석기 정책·구현은 변경하지 않았다. 이후 확장된 현재 수량은 위 최신 검사 절을 따른다. [당시 실행 범위와 잔여 위험](publisher-stabilization-2026-10-10.md)을 함께 확인한다.
|
||||
|
||||
| 추가 테스트 | 확인하는 계약 |
|
||||
|---|---|
|
||||
| 41 | Storybook PARTIAL에서도 선택 Story의 preview 스타일 연결 누락은 FAIL이다. |
|
||||
| 42 | computed discovery 대신 명시한 `--entry`만 검사한다. 선택하지 않은 Story까지 검증했다고 보고하지 않는다. |
|
||||
| 43 | 현재 import가 해석돼도 상속 tsconfig 전체 해석은 ENTRY-003 NOT VERIFIED다. |
|
||||
| 44 | 내부 Reference wrapper의 NOT VERIFIED가 같은 Story의 공개 slot 위조 FAIL을 낮추지 않는다. |
|
||||
| 45 | compact Navigation 증명과 소비 CSS intent 승인은 별개다. 후자는 REUSE-003 NOT VERIFIED다. |
|
||||
| 46 | Production·Storybook 모두 독립 package 구현을 선택하면 소비 graph 밖 SCOPE-001 NOT VERIFIED다. |
|
||||
|
||||
이 테스트 통과는 미검증 판정의 회귀 보호이며 미검증 항목을 PASS로 전환하는 근거가 아니다. 실제 build·브라우저 결과도 원본 Guard JSON 상태를 덮어쓰지 않는다. Reference wrapper의 승인 의도, native control의 합법성, CSS intent, 상속 alias와 opaque 흐름, package 구현의 소비 검사 경계는 계속 구분하여 보고한다.
|
||||
|
||||
|
||||
## STYLE-001 Component 식별과 진입점 범위 (2026-10-11)
|
||||
|
||||
class의 `hm-` 접두사만으로 공개 Component를 확정하지 않는다. 기존 known HM slot 이름 범위의 class는 현재 import graph의 JSX/createElement에서 공개 HM Component에 실제 연결되었을 때 계속 검사하며, native 콘텐츠 class는 REUSE-003 및 STYLE-002의 의도 검토와 구분한다. 불명확한 동적 class는 기존 보수적 탐지를 유지한다.
|
||||
|
||||
단순 양의 선행 ancestor class와 명시된 descendant HM slot으로 구성된 selector는 현재 진입점의 JSX 및 HTML class 목록을 대조한다. 그 ancestor가 없고 graph/class 입력이 완전하며 공개 package 구현 텍스트에도 같은 이름이 없는 경우 `styleEvidence.checks[].applicability.status = NOT APPLICABLE`과 근거를 기록한다. 선언은 inventory에서 지우지 않고 RUNTIME/DESIGN_INTENT/FINAL의 NOT VERIFIED를 보존한다. 이는 CSS 승인이나 다른 진입점의 면제가 아니다. 일반 목록 composition class를 새 Component override 대상으로 확장하지 않으며 기존 REUSE-003/STYLE-002 의도 검토를 보존한다.
|
||||
|
||||
동적 class, spread, DOM class/HTML 변경(계산된 property 포함), 미해결 import/inline script, selector의 comma·pseudo·escape·nesting은 위 제외 근거로 사용하지 않는다. class가 현재 진입점 또는 HTML에 존재하면 기존 STYLE-001 탐지를 유지한다. Storybook은 기존 Reference 정책을 유지하고 새 일반 업무 화면의 우회 profile로 사용하지 않는다.
|
||||
|
||||
이 변경은 일반 콘텐츠 이름 오탐과 현재 사용되지 않는 ancestor 범위의 확정 FAIL만 교정한다. 실제 연결된 HM 하드코드 override·미정의 Token·복제 slot·Navigation 위반 정책은 유지한다. 과거 75/20/5 검사 결과는 당시 기록이다. Component 식별·범위 경계 회귀 11개(76~86)를 추가했으며 새로운 Guard 계약 해시는 이전 Runtime 연결 결과와 구분한다.
|
||||
@@ -0,0 +1,96 @@
|
||||
# HMDesign AI 화면 생성 지침 개선 및 재검증 — 2026-10-10
|
||||
|
||||
RESULT: PARTIAL. 기준 HEAD는 `48ca1d22de0a4eca5af2084676fd6739e7223912`, 시작 Working Tree는 clean, 범위는 지침·사용 설명·Guard다. Component/API/Theme/Token/운영 화면은 보존했다. GitHub main 일반 push 결과 SHA와 상세 증거는 독립 실험의 `REPORT.txt`에 기록한다. 공식 Gitea는 접근·수정하지 않았다.
|
||||
|
||||
## 자료 확인 및 비교 가능성
|
||||
|
||||
사용자가 확인한 원본은 `C:\Users\ㅅㅎ\.codex\visualizations\2026\10\10\01a12479-1eac-7691-8044-de2330b7bfef\HMDesign-AI-Generation-Test`다. REPORT, experiment/rubric/results/findings, 10개 requirements·React 소스·initial·generation log·Guard·스크린샷을 확인했다. 원본 증거·소스 570개 SHA256 변화는 0개다(node_modules와 baseline 저장소 스냅샷은 인벤토리에서 제외).
|
||||
|
||||
새 자료는 `D:\디자인시스템\HMDesign-AI-Generation-Test\retest-20261010`에 보존한다. requirements 10개와 rubric은 원본과 byte 일치, Seed는 실제 기록 `20261010`, 선택 알고리즘은 LCG(1664525,1013904223)+Fisher-Yates다. Viewport는 390/768/1280/1440 × 900이다. 동일 로컬 Windows/Node 20.20.1, React 19.3.0/Vite 8.3.0, 기존 의존성 복사와 같은 Chrome 실행 경로/Playwright 측정 함수를 사용했다. 원본의 정확한 브라우저 build ID는 NOT VERIFIED이며 서버 포트·새 파일 위치는 다르다.
|
||||
|
||||
**NON-COMPARABLE**: 원본의 정확한 serving model ID와 reasoning 설정이 노출되지 않았다. 주 실험은 상속한 Codex 모델로 실행했으나 동일 모델·추론 수준을 입증할 수 없다. Seed는 화면 선택 Seed이며 모델 생성의 난수 Seed가 아니다. 점수 차이는 관측값이며 지침만의 인과적 효과가 아니다. 원본 코드·점수는 새 생성 에이전트에 전달하지 않았고 각 작업은 `fork_turns=none`으로 독립 요구사항과 고정 reference만 받았다. 공유 파일시스템에서 접근 지시와 로그로 분리했으며 OS 수준 격리는 아니다. 평가자는 생성 소스를 수정하지 않았다.
|
||||
|
||||
## 원인 및 최소 변경
|
||||
|
||||
| 문제 | 실제 확인과 한계 | 반영 |
|
||||
|---|---|---|
|
||||
| 검색 Pattern | 원본 02는 인덱스를 읽었지만 FilterBar 대신 자체 search-layout/field/actions를 선택. HM Input/Label/Button은 실제 사용. Pattern을 못 찾았다는 근거는 없고 구체적인 미사용 제약 기록이 부족했다. | [AGENTS](../../AGENTS.md), [인덱스](component-pattern-reference.md), [FilterBar](../patterns/filter-bar.md)에 Table 유무와 무관한 우선 검토·부분 조합·구체적 미사용 이유를 명시. 부적합한 Pattern 강제 없음. |
|
||||
| native Label | 원본 07 main.tsx:132의 기간 Field는 공개 Label로 표현 가능했으나 native label을 콘텐츠로 분류. 접근성 연결 자체는 유효. Dialog:162/Sheet:69/Drawer:71 Story의 유사 fixture는 있으나 복사 인과관계는 미입증. | [Label](../components/label.md#5-api)에 실제 Input/Textarea id·SelectTrigger id·Combobox trigger id/aria-labelledby 예제. 반복 useId·비지원 예외 설명. 3개 Story는 설명 주석만 추가. |
|
||||
| CSV 범위 확장 | 원본 07 main.tsx:77,123,179의 목록/행 CSV는 요구사항에 없고 생성 로그가 보고서 유틸리티로 선택했다고 기록. Story를 필수로 오해했다는 인과관계는 미입증. | AGENTS와 [상세 지침](ai-implementation-details.md)에 미요청 CSV/다운로드/API/메뉴/Navigation은 제안만 허용. |
|
||||
| Guard | 원본 10개 모두 graph에 실제 main/CSS가 포함되고 4개 정적 그룹 PASS. RENDER-002는 전부 1개, 승인 소비 CSS REUSE-003은 01:3/03:6/04:2/07:6. 대상 누락이 원인이 아니다. | [Guard](ai-generation-guard.md)에 기존 외부 target/entry/result CLI를 설명. native label을 기존 REUSE-004 검토 대상에 추가하는 한 줄 변경. 범용 예외/JSON 덮어쓰기/Production graph 확대 없음. |
|
||||
|
||||
Label 예제는 기존 공개 타입으로 별도 TypeScript 검사 PASS다. Combobox의 실제 Label 클릭/스크린리더 발화는 이번 신규 예제 자체로 실행하지 않았으므로 NOT VERIFIED다. 주 실험의 Input/Select/Checkbox Label 연결과 overlay 이름/focus는 실제 브라우저에서 확인했다.
|
||||
|
||||
## 문서 충돌 3건
|
||||
|
||||
| 원래 위치·충돌 문장 | 현재 구현·대표 Story·API | 최신 확정 기준·최종 기준 | 수정 문서 |
|
||||
|---|---|---|---|
|
||||
| 프로젝트-지침.md:272, “GNB ONLY 내부 Sidebar에서 기존 LNB 메뉴 부품을 재사용…허용” | GNB/LNB/DashboardSidebar API와 Reference 조합은 호환성을 위해 존재. GNB All/Bar, LNB All, Dashboard Compact Header를 구분. API 존재가 신규 운영 허용을 뜻하지 않는다. | [추가 수정 요청](publisher-additional-review-2026-10-10.md)의 신규 GNB_ONLY+GNBMobileMenu, Sidebar 없음. Dashboard도 Sidebar 없음, 공식 LNB_ONLY 허용. | [프로젝트 지침](프로젝트-지침.md#612-navigation-single-mode-2026-10-07-사용자-확정): 이전 Sidebar 배경/조합 설명은 호환성 전용. |
|
||||
| page-header.md:90,92, “Dashboard 내부 Header/Menu/Sidebar와 합성”, “Sidebar 포함 1232px” | PageHeader는 콘텐츠 제목이며 자체 Navigation/min-width 없음. DashboardLayout/Content/Scroll 공개 API와 dashboard-layout All CompactHeader는 48px Header·960px 내부 스크롤. 기존 sidebar prop은 보존. | 추가 수정 기준과 현재 Dashboard 운영 계약: 48px Header+상태 필터+Content, Sidebar 없음, 최소 960px 내부 스크롤. 1232px은 legacy verification만. | [PageHeader](../patterns/page-header.md) 활성 운영 설명 두 문장. |
|
||||
| filter-bar.md:24–33,90–101,124, 검색→조건/초기화, 조회 Outline, “둘 다 outline…같은 appearance” | FilterBar/FilterBarSearch/FilterBarActions는 상태 없는 공개 조합. All/Full Story는 현재 조건→검색→조회 Solid→초기화 Outline. 공통 Pattern 기본 배치는 유지; src/list-screen.css는 승인된 소비 opt-in. | 추가 수정의 PageHeader 밖 흰 Card 하나, 8px, 조건→검색→조회→초기화, 조회 Solid Green·초기화 Outline Gray. 초안/적용값은 소비자가 소유. | [FilterBar](../patterns/filter-bar.md): 목록 계약·두 사용 예제·버튼 설명 정렬, 공통 구조/API 변경 없음. |
|
||||
|
||||
당시 검증 보고서와 D-01/D-02·퍼블리셔 기록은 수정하지 않았다. 3건의 활성 문서 충돌은 해결했으며 모든 문서 전체에서 충돌이 없다는 주장은 하지 않는다.
|
||||
|
||||
## 통합 검증
|
||||
|
||||
| 항목 | 실제 결과 |
|
||||
|---|---|
|
||||
| TYPECHECK / UI_BUILD | root/UI/CENTER typecheck PASS; pretypecheck의 기존 package build PASS, 중복 빌드 없음. |
|
||||
| PRODUCTION_BUILD | 업무 앱·Dashboard export+finalizer·Recruit export Vite build PASS. 운영 화면 자체의 새 브라우저 회귀 전수검사는 수행하지 않음. |
|
||||
| STORYBOOK_BUILD | 공식 npm build-storybook PASS. 최초 잘못 지정한 CLI 경로의 MODULE_NOT_FOUND 로그는 보존하고 올바른 명령으로 수정. |
|
||||
| COMPONENT_TEST | 기존 8개 본문 보존, 8/8 PASS. |
|
||||
| GUARD_TEST | 기존 46개 본문 보존+5개 추가, 51/51 PASS. 실제 Sidebar/Theme 누락 FAIL과 graph 밖 SCOPE-001을 계속 탐지. |
|
||||
| GUARD_FULL_SCREEN | 업무/GNB, Dashboard, Recruit: FAIL 0, NOT VERIFIED. result React mount/CSS 공개 연결 검사와 브라우저 품질을 구분. |
|
||||
| GUARD_PARTIAL | root CSS PARTIAL: FAIL 0, NOT VERIFIED. 외부 FULL/PARTIAL은 신규 49번 회귀에서 정적 그룹 PASS+RENDER-002 확인. |
|
||||
| GUARD_STORYBOOK | FULL/PARTIAL: FAIL 0, NOT VERIFIED. 보존된 native Label fixture/Reference/CSS intent를 허용 PASS로 바꾸지 않음. |
|
||||
| DOC_LINKS | 92개 Markdown/418개 내부 링크 검사 PASS, 누락 경로·heading 0. |
|
||||
| CSS_IMPORTS | tracked CSS 81개/69개 import 경로 확인, 누락 0. tw-animate-css는 Node 기본 조건 대신 실제 CSS style export 조건으로 확인. |
|
||||
| EXPORTS | 공개 artifact 존재 확인, UI 255/Theme 8/CENTER 25/Reference 10. CENTER는 CSS를 직접 읽지 못하는 Node 대신 compiled export AST+성공한 bundler build로 확인. |
|
||||
|
||||
## 주 실험 결과
|
||||
|
||||
| 화면 | 모드 | 점수 | 실제 대표 tuple 일치 | 상호작용 PASS |
|
||||
|---|---|---:|---:|---:|
|
||||
| 01 검색·필터·Data Table | GNB_ONLY | 100.00 | 15/15 | 7 |
|
||||
| 02 모바일 현장 업무 | GNB_ONLY | 100.00 | 14/14 | 5 |
|
||||
| 03 업무 Dashboard | DASHBOARD_ONLY | 99.38 | 7/8 | 4 |
|
||||
| 04 채용 공고 | GNB_ONLY | 100.00 | 15/15 | 5 |
|
||||
| 05 승인·결재 | LNB_ONLY | 99.17 | 5/6 | 5 |
|
||||
| 06 Form | GNB_ONLY | 100.00 | 12/12 | 5 |
|
||||
| 07 통계·보고서 | DASHBOARD_ONLY | 95.50 | 1/10 | 4 |
|
||||
| 08 설정·권한 | LNB_ONLY | 96.00 | 2/10 | 4 |
|
||||
| 09 중첩 LNB | LNB_ONLY | 100.00 | 8/8 | 5 |
|
||||
| 10 Sheet/Drawer/AlertDialog | GNB_ONLY | 100.00 | 7/7 | 6 |
|
||||
|
||||
기존 100점 rubric/세부 배점과 tuple/property 비교를 유지했다. 모르는 동일 tuple은 0점이고 동일 원인은 owning category 한 번만 감점했다. 03의 상태 ghost 버튼 배경 차이, 05의 outline small 동일 specimen 부재, 07/08의 font-family fallback stack 차이는 그대로 감점했다. Noto Sans KR 로딩은 성공했으나 07/08의 `"Noto Sans KR", sans-serif`가 기준 `"Noto Sans KR", "Malgun Gothic", sans-serif`와 다르다. 03은 99.44→99.38, 08은 100→96점으로 낮아졌으며 이 차이를 숨기지 않았다.
|
||||
|
||||
| 항목 | 원본 Baseline | 새 관측값(NON-COMPARABLE) |
|
||||
|---|---:|---:|
|
||||
| 생성 / Typecheck / Build / Runtime | 각각 10/10 | 각각 10/10 |
|
||||
| 평균 | 97.79 | 99.00 |
|
||||
| 공개 Component 재사용 | 99.81% | 100%, 실제 JSX 505/505 |
|
||||
| Guard PASS / FAIL / NOT VERIFIED | 0 / 0 / 10 | 0 / 0 / 10 |
|
||||
| 검색 Pattern 미활용 / 지원 native Label / CSV 범위 확장 | 각각 1건 | 각각 0건 |
|
||||
| 확인된 활성 문서 충돌 | 3건 | 해당 3건 해결 |
|
||||
| 페이지 가로 overflow / 핵심 접근성 문제 | 관측 0건 | 관측 0건 |
|
||||
| 상호작용 | 53 PASS | 50 PASS, 3 N/A |
|
||||
|
||||
표의 표시값 기준 차이는 +1.21점(정밀값 기준 +1.21723점), 재사용 +0.19%p다. 3 N/A는 원본 요구사항에 없는 열 표시·채용 정렬/페이지·설정 취소 복원이며, 요청되지 않은 기능을 점수에 맞추려고 추가하지 않았다. CSV 검사도 기존 다운로드 실행에서 새 미요청 액션 부재 확인으로 바뀌었다. 따라서 53개 시나리오가 전부 동일하다는 주장도 하지 않는다. 40 viewport 실제 dist 캡처와 50개 동작을 확인했으며 스크린리더 발화·실기기 터치·실제 backend·모든 상태 조합은 NOT VERIFIED다.
|
||||
|
||||
## 교차 모델과 남은 문제
|
||||
|
||||
추가 모델 `gpt-5.6-sol`, reasoning `low`를 명시해 독립 02/06/07을 생성했다(별도 3개, 주 실험에 합산하지 않음). Typecheck/Build/실제 Runtime 3/3, 12개 viewport 페이지 overflow 0, Guard 0 PASS/0 FAIL/3 NOT VERIFIED. 실제 동작 11개 중 9 PASS/2 FAIL이다.
|
||||
|
||||
| 화면 | 확인된 지침 준수와 남은 실패 |
|
||||
|---|---|
|
||||
| cross 02 | FilterBar 실제 재사용. HM CSS 연결/6개 업무/Sheet 완료 동작 성공. 미요청 오늘 일정·안전 공지 2개 메뉴 추가, 미정의 stroke-divider 토큰 2곳, Tabs aria-controls가 존재하지 않는 panel을 참조. |
|
||||
| cross 06 | HM Label/Input/Select/Checkbox 사용과 동의·오류 메시지·정상 제출 성공. 미요청 홈·처리 현황 2개 메뉴 추가, 미정의 bg/text/border 토큰 9곳. 오류 후 첫 필드 focus 이동 실패(오류 표시 자체는 성공). |
|
||||
| cross 07 | 48px/960px·기간 변경·CSV 부재 성공. HM Label 지원 기간명을 span으로 표현, 미정의 text 토큰 6곳, font stack 추가 차이. 공개 컴포넌트 없이 Chart를 임의 생성하지 않음. |
|
||||
|
||||
미정의 참조는 17곳/8개 고유 이름이며 해당 실제 computed variable은 빈 값이다. Guard CSS 그룹은 entry 연결을 검사하므로 이를 Token 유효성 승인으로 해석할 수 없다. 태그 span으로 Field Label을 대체하는 선택도 이번 native label 정적 탐지 밖이다. 모델 1종의 3개 사례는 일관된 재현성을 입증하지 못한다. 추가 토큰 존재 검사·범위/Label 검토 자동화·focus와 panel 계약은 후속 과제로 보고하며 Component·Token을 이번 범위에서 고치지 않는다.
|
||||
|
||||
## 보존과 이전 판단
|
||||
|
||||
시작 tracked source SHA256 비교에서 공개 구현·Theme/Token·D-01/D-02·운영 Dashboard/Recruit·퍼블리셔 확정 결과와 과거 보고서는 변경 없음. 3개 Story AST는 주석을 제외하고 동일, Story ID 292→292 동일. 생성 소스 initial/final TSX·CSS·HTML 변화 0이다. 평가기/브라우저 selector·CLI 경로·바이너리 폰트 읽기 오류의 최초 로그와 필요한 실패 항목 재확인 증거는 삭제하지 않았다.
|
||||
|
||||
필수 project 회귀는 통과했고 지침/Guard의 최소 변경은 GitHub 검토 대상으로 준비됐다. 주 실험에서 3개 기존 위반은 관측되지 않았으나 교차 모델 범위/Token/접근성 실패와 비교 불가능 조건이 남는다. 공식 Gitea 이전의 읽기·쓰기 작업은 수행하지 않았으며, 현재 결과를 전체 모델/접근성 인증으로 간주하지 않는다.
|
||||
@@ -0,0 +1,71 @@
|
||||
# HMDesign AI 화면 생성 오류 수정과 검증 근거
|
||||
|
||||
2026-10-10 기준 커밋 `8f50e3fb00e315501be043df6ff06928bf87961c`에서 AI 생성 지침과 Guard 증거 연결을 보강했다. Component·Pattern 구현, Theme·Typography·Spacing·대표 Story는 변경하지 않았다. 실제 실행기와 수정 화면은 `D:/디자인시스템/HMDesign-AI-CrossModel-Test/stabilization-20261010`에 별도로 관리한다. 실험 파일은 HMDesign GitHub 저장소에 포함하지 않는다.
|
||||
|
||||
요청한 수정과 로컬 검증은 통과했다. T01의 사용자 CSS Intent와 미실행 T03는 NOT VERIFIED를 유지한다. 새 AI 모델·Claude·하위 에이전트 호출은 0회이며 기존 10/12회 사용·잔여 2회와 STOP 기록을 보존했다.
|
||||
|
||||
## 수정과 영향 범위
|
||||
|
||||
| 문제 | 수정 | 영향 |
|
||||
|---|---|---|
|
||||
| High T02 | 공개 exports/types와 실제 파일 목록 우선 탐색을 명시. 실행기 STOP에 원본 명령·exit·DEPENDENCY_EXPLORATION 위치를 기록 | 의존성 탐색 오류를 생성/Build 실패와 구분. 과거 중단 화면은 재생성하지 않음 |
|
||||
| High T06 | 복합 검색 예외는 명령 전체가 literal 읽기 + 최종 rg인 경우로 제한. compiler는 실행 위치에서 탐지 | suffix만 보고 앞선 실패를 무시하는 문제 방지. vite.config.ts 읽기를 Build로 오분류하지 않음 |
|
||||
| Medium T06 | 수정 복제본의 `.page-content`에 position:relative 1줄 추가. LNB/AI 지침에 숨김 알림·스크롤 측정 Usage 추가 | 원본 화면 FAIL을 보존하며 main의 위치 기준만 수정 |
|
||||
| Medium T02 모바일 ID | 수정 복제본 ID cell span에 whitespace-nowrap. DataTable 문서에 size/minSize의 DOM 연결 한계와 가독성 예제 추가 | ID 전체 값과 기존 14px 글꼴 보존. 제목 wrapping과 표 내부 스크롤 유지 |
|
||||
| Medium T01 Guard | `guard-evidence.mjs`에 선택적 cssEvidence 측정·issue/문서 SHA 연결 추가 | 실제 스타일과 승인 의도 분리. REUSE-003를 자동 PASS로 바꾸지 않음 |
|
||||
|
||||
HMDesign 변경 파일은 AGENTS.md, ai-screen-contract.md, ai-generation-guard.md, LNB/DataTable/DashboardLayout 문서, guard-evidence.mjs와 그 테스트 및 이 보고서다. 기존 `ai-generation-guard.mjs`의 위반 규칙과 모든 기존 테스트 본문은 보존했다. 신규 UI API·Component·Story를 만들지 않았다.
|
||||
|
||||
## 실제 로컬 검증
|
||||
|
||||
| 검사 | 결과 |
|
||||
|---|---|
|
||||
| 실행기 기존 테스트 | 22/22 EXECUTED PASS; 원본 test/proof 파일 보존 |
|
||||
| 실행기 추가 검사 | 16/16 EXECUTED PASS; 실제 High T02/T06 사건 재생 포함 |
|
||||
| 설치된 실행기 | 테스트 후보와 SHA 일치. launcher syntax PASS; 로컬 VM에서 외부 spawn 전 차단 PASS |
|
||||
| Guard 기존 회귀 | 63/63 EXECUTED PASS; 위반 탐지·미검증 보존 |
|
||||
| Guard 증거 연결 | 기존 5 + 신규 6 = 11/11 EXECUTED PASS |
|
||||
| 수정 T02/T06 | 각각 Typecheck/Build exit 0; 독립 의존성 재설치 없음 |
|
||||
| HMDesign 원본 | npm run typecheck 및 npm run build exit 0 |
|
||||
| Build 경고 | 기존 앱 bundle 500kB 초과 및 bundler callback timing 안내. 오류 없음 |
|
||||
| T06 상태 검사 | 네 폭에서 초기·조회·무결과·초기화·완료/disabled/focus·내부 마지막 JOB-024 접근 PASS |
|
||||
| T02 ID 검사 | 네 폭에서 전체 ID 한 줄·ellipsis 없음·제목 wrapping·마지막 열 접근·조회/초기화 PASS |
|
||||
| T01 CSS | 네 폭 × 네 상태 × 변수/color/background/border = 64/64 PASS; 공식 문서 SHA와 issue 연결 |
|
||||
| Navigation | T06 LNB_ONLY, T02 GNB_ONLY, T01 DASHBOARD_ONLY. 모바일 메뉴 Enter/Escape/focus 복귀 4건 PASS |
|
||||
|
||||
새 CSS 근거는 실제 Guard source/contract 해시에 연결한다. 측정 status는 actual/expected 비교로 계산하며 mismatch는 FAIL이다. 문서 근거가 없거나 stale·범위 밖이면 NOT VERIFIED다. 실제 스타일 PASS는 사용자 의도 승인을 의미하지 않는다.
|
||||
|
||||
| 화면 | 새 Guard 원본 status | 새 정적 | 새 Runtime | 새 결합 |
|
||||
|---|---|---|---|---|
|
||||
| 수정 T06 복제본 | NOT VERIFIED | PASS | PASS | PASS |
|
||||
| 수정 T02 복제본 | NOT VERIFIED | PASS | PASS | PASS |
|
||||
| 원본 T01 새 증거 | NOT VERIFIED | NOT VERIFIED | PASS | NOT VERIFIED |
|
||||
|
||||
T01 원래 Guard/Runtime/결합 증거는 그대로 보존한다. 증거 연결 도구 변경으로 contract 해시가 달라져 새 Guard와 브라우저 측정을 별도로 생성했다. 기존 Runtime의 해시를 새 값으로 옮기지 않았다. T01의 새 cssEvidence만 PASS이며 원본 REUSE-003와 CSS Intent 검토는 NOT VERIFIED다.
|
||||
|
||||
## 화면 측정 전후
|
||||
|
||||
높이 900px의 동일 Chrome 로컬 환경에서 측정했다. T06 변경 후 아래 문서 높이는 다섯 검사 상태 모두 같고, absolute 숨김 알림의 offsetParent는 MAIN이며 크기는 1×1px이다. 실제 알림 문구와 완료 후 tab focus도 확인했다.
|
||||
|
||||
| 폭 | 기존 T06 문서 높이 | 수정 후 문서 높이 | 바깥 scrollY | 기존 T02 ID 줄 수 | 수정 후 ID 줄 수 | 수정 후 ID cell 폭 |
|
||||
|---:|---:|---:|---:|---:|---:|---:|
|
||||
| 390 | 6581 | 900 | 0 | 5 | 1 | 79.27px |
|
||||
| 768 | 3481 | 900 | 0 | 2 | 1 | 79.27px |
|
||||
| 1280 | 2417 | 900 | 0 | 1 | 1 | 112.20px |
|
||||
| 1440 | 2417 | 900 | 0 | 1 | 1 | 127.39px |
|
||||
|
||||
기존 측정은 이전 보고서/browser-probe.json의 원본 FAIL 및 ID 근거를 재사용했다. 변경 후 측정은 이번 실행이다. 수정 화면의 main 내부 스크롤은 보존하며 페이지 가로 overflow가 없다. 기존 T06 배경·높이 분배·간격과 T02 font-size 14px/line-height 20px/색/padding은 그대로다.
|
||||
|
||||
## 증거 보존과 검증 최적화
|
||||
|
||||
원본 T02/T06 app source, 기존 evaluation 파일 105개, authorization, STOP, session-launches와 기존 22개 test/proof의 해시 보존을 감사했다. 실제 resume-control의 controller와 launcher만 허용 범위에서 바꾸고 이전 두 파일을 revision4-preserved로 보존했다. 유지보수 manifest와 신규 로컬 proof는 별도 파일이다. launcher는 executionEnabled:false에서 외부 모델 spawn 전에 중단한다. 기존 승인 해시를 자동 갱신하거나 STOP을 해제하지 않았다.
|
||||
|
||||
과거 공통 80/80은 frozen f78cc206의 역사적 결과로만 재사용한다. 현재 HEAD 전체 회귀 인증으로 확장하지 않는다. 이번 변경에 Component/Theme/대표 Story 변경이 없어 전체 292 Story·전체 Component 테스트·기존 성공 화면 재생성을 반복하지 않았다. Guard 계약에 영향을 받은 세 화면의 증거는 새로 연결했다. npm의 pretypecheck/prebuild 공통 package build가 각각 실행된 것은 표준 hook 중복이며 별도 회귀 재검사로 집계하지 않는다.
|
||||
|
||||
브라우저 측정 도구의 최초 textbox/searchbox locator 오류와 favicon 404 진단은 별도 기록이다. 오류 URL이 기본 `/favicon.ico`임을 확인해 선택적 진단으로 보존했으며 JS·CSS·font·실제 앱 console 오류는 PASS 조건에서 계속 검사했다. 해당 도구 수정으로 실패한 측정을 재개했고 통과한 Guard는 source/contract freshness 확인 후 재사용했다.
|
||||
|
||||
## 남은 미검증과 다음 실험 조건
|
||||
|
||||
T01 사용자 CSS Intent, High T02 생성 코드 품질, High T06 화면, T03 Medium/High, 실제 스크린리더·물리 touch·Safe Area와 미실행 동적 테마 상태는 NOT VERIFIED다. 관련 원본 점수·FAIL을 변경하지 않았다. 현재 실험 자료와 로컬 실행기 검증은 준비돼 있으며 모델 실행은 계속 중단 상태다. 향후 T03 재개는 별도 사용자 지시와 새 실행기/proof 해시를 연결한 승인 기록이 필요하다.
|
||||
|
||||
D-01/D-02, 퍼블리셔 추가 확정 사항, 기존 Foundation/Theme/Component 스타일과 Story ID는 변경하지 않았다. 공식 Gitea에 접근하거나 수정하지 않았고 이전·GitHub 연결 해제·ZIP 배포는 수행하지 않았다. GitHub commit/push SHA와 KST 작업 시간은 독립 실험 경로의 FINAL_REPORT.md에 기록한다.
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
## AI 화면 구현 Quick Start
|
||||
|
||||
화면 구현 요청을 받으면 아래 순서를 그대로 따른다. 파일이나 API의 존재를 확인할 수 없으면 추측하지 말고 미확인으로 기록한다.
|
||||
신규 React 화면은 [선택·완료 계약](./ai-screen-contract.md)을 먼저 따른다. 아래는 Runtime adapter와 기존 소비 경로의 상세 참고다. 파일이나 API의 존재를 확인할 수 없으면 추측하지 말고 미확인으로 기록한다.
|
||||
|
||||
1. **프로젝트 구조와 Runtime 확인**: 제공된 파일 범위를 살펴보고 `REACT_VITE | STATIC_HTML | VANILLA_WEB | OTHER_RUNTIME` 중 대상을 정한다. Component·Pattern 파일이 실제 범위에 있는지 확인한다.
|
||||
2. **Component 검색**: `packages/ui/src/components/ui/`와 `packages/ui/src/index.ts`에서 공개 Component·Props를 찾고, `docs/components/<component>.md`를 확인한다. 기존 공개 Component를 우선 사용한다.
|
||||
@@ -27,6 +27,10 @@
|
||||
|
||||
**Story 구분**: 운영 기준은 대표 `All` Story이고 `verification`·Compatibility·Fixture Story는 운영 예제가 아니다. Storybook 문서 화면은 `StoryPage` 공통 Inner를 사용하며, 이는 Storybook 표현용으로 `@hm-design/ui` 공개 API가 아니다.
|
||||
|
||||
**선택·범위 계약**: 구현 전에 요구사항·필수 동작·완료 조건을 기록하고 기능별 Pattern 후보와 실제 선택/미사용 이유를 남긴다. 목록 검색은 Table 유무와 관계없이 [FilterBar](../patterns/filter-bar.md)를 먼저 검토한다. Field Label은 [공개 Label](../components/label.md#5-api)과 control ID/접근성 이름을 연결한다. 레이아웃·콘텐츠 HTML과 HM 미지원 사용처는 허용하며 native 위젯/label 예외의 구체적인 이유를 기록한다. 기존 공개 Component·Pattern으로 해결되지 않는 기능은 지원 한계와 최소 대안을 보고하고, 요청 없는 Component/API/Token 확장은 하지 않는다. CSV·다운로드·외부 API·추가 메뉴·Navigation 등 요청 밖 기능은 구현하지 않고 제안으로만 보고한다. Story의 fixture·부가 액션은 필수 구현 목록이 아니다.
|
||||
|
||||
**최종 확인**: 390/768/1280/1440px에서 페이지 overflow·줄바꿈·Navigation 및 Dashboard 960px 내부 스크롤을 확인한다. 접근성 이름·Label 연결, 키보드 순서·focus 복귀, disabled/readOnly, 요구된 상호작용과 실제 액션 목록을 대조한다. Guard 정적 결과와 브라우저 증거를 구분하며 실행하지 않은 검사·실제 스크린리더 발화 등은 `NOT VERIFIED`로 보고한다.
|
||||
|
||||
**화면 생성 시 필수 확인**: Navigation을 지정받으면 아래 모드별 정책에 따라 기존 공식 Component를 적용하고, 미지정이면 기존 모드 선택 규칙을 따르며 그 근거를 기록한다([선택 기준](./navigation-single-mode.md#선택-근거)). LNB ONLY의 정상적인 공식 LNB 생성은 Sidebar 금지 대상에서 명시적으로 제외한다. GNB ONLY의 Sidebar·GNB Sidebar Composition 또는 DASHBOARD ONLY의 Sidebar/LNB가 요청되면 금지 규칙을 안내하고 해당 기능을 구현하지 않으며, 대체 Navigation을 임의로 추가하지 않는다. GNB는 Desktop 메뉴와 `GNBMobileMenu`를 함께 구성한다([GNB 모바일](../patterns/gnb.md#8-desktop--mobile)). Dashboard 운영 화면에는 Sidebar를 생성하지 않는다. `DashboardSidebar` 공개 Export와 선택적 `sidebar` slot은 기존 호환성·검증용이며 운영 허용을 뜻하지 않는다. Dashboard 상태는 Theme 다음에 공개 Status CSS를 로드하고 기존 Badge mapping을 소비한다([상태 예제](../patterns/dashboard-layout.md#dashboard-업무-상태-공통-계약)). FilterBar의 입력 조건과 조회 적용 조건·초기화 책임을 구분한다([조회 예제](../patterns/filter-bar.md#61-조회-버튼으로-적용하는-소비-예제)). `REACT_VITE` 독립 화면은 bootstrap에서 기존 앱 CSS entry(`@/index.css` → `@/hm-theme.css` → 필요 시 공개 상태 CSS)를 로드하며, `@hm-design/ui/tailwind.css`만 단독 import하지 않는다. 빌드 후 `.flex`, `.grid` 등 대표 utility의 생성·실제 적용과 캡처 레이아웃을 확인하고, 빌드 성공만으로 화면 검증을 PASS 처리하지 않는다. React 소비자는 Tailwind 검색 범위와 HM package source를 확인하고([Tailwind](./runtime-portability.md#21-tailwind-v4-소비자-검색-범위)), 폰트·Asset 경로는 실행 위치별로 확인한다([Asset](./runtime-portability.md#4-asset과-실행-위치)).
|
||||
|
||||
## AI Implementation Defaults
|
||||
@@ -35,7 +39,7 @@
|
||||
|
||||
- 구현 전에 `STORYBOOK_ONLY | PRODUCTION_UI | BOTH` 중 변경 범위를 정한다.
|
||||
- 기존 Component와 유사 대표 Story를 먼저 검색한다. `packages/ui`, `src/components`, `src/patterns`, `src/center`, 기존 Storybook stories와 shared helpers를 확인하고 도메인에 맞는 구현을 재사용한다.
|
||||
- 재사용 순서: 기존 HM Component → 기존 Variant / Prop → 기존 Composition → shadcn → Radix Primitive → 최소 Custom. 새 Component는 기존 Component·Composition으로 표현 불가능하고 Variant 확장이 부적절하며 shadcn/Radix 조합도 어려운 경우에만 만든다. 재사용 불가 사유와 최소 추가 범위를 설명한다.
|
||||
- 재사용 순서: 기존 HM Pattern → 기존 HM Component → 기존 Variant / Prop → 기존 Composition. 공개 API가 지원하지 않는 경우에만 근거를 기록하고 shadcn → Radix Primitive → 최소 Custom을 검토한다. 새 Component는 기존 Component·Composition으로 표현 불가능하고 Variant 확장이 부적절하며 shadcn/Radix 조합도 어려운 경우에만 만든다. 재사용 불가 사유와 최소 추가 범위를 설명한다.
|
||||
- Storybook은 구현 Reference Catalog다. 대표/PRIMARY Story의 시각 언어와 공통 상태 mapping을 재사용하고 검증 전용 Story를 운영 예제로 삼지 않는다. 신규 업무 화면의 등록 대상이 아니며, 생성 결과는 별도 React 화면·독립 미리보기로 제공한다.
|
||||
- Theme은 구현 시작부터 적용한다. 기존 Semantic Token → 해당 Component Token → 기존 CSS Variable을 먼저 확인하고, 없을 때만 필요한 최소 Semantic 확장을 검토한다. 기존 Token이 있는 색상·spacing·값을 하드코딩하거나 같은 Token을 여러 파일에 중복 정의하지 않는다.
|
||||
- Theme 사용은 별도 승인 없이 기본 적용한다. Theme Source/값 수정은 명시적 필요성과 영향 범위를 확인한다. `themes/*.json` → Runtime Loader → CSS Custom Properties → Semantic → Component Mapping과 Primary / On Accent의 독립 fallback을 유지한다.
|
||||
@@ -44,7 +48,7 @@
|
||||
- package exports, public props/types, package entry, Story ID, `meta.title`을 불필요하게 변경하지 않는다. 필요한 변경은 소비처·호환성 영향을 먼저 확인한다. Storybook 표현 문제와 Production 동작 문제는 해당 범위에서 해결한다.
|
||||
- Badge/Button/FilterBar를 재사용하더라도 동일한 상태 ID·라벨·필터 매칭이 반복되면 화면별 helper로 남기지 말고 Runtime-neutral 상태 계약을 먼저 검토한다. 계약은 React 구현과 분리하고 `data-status`, 독립 flag attribute, `aria-pressed` 등 다른 Runtime이 재현할 수 있는 상태 vocabulary를 정의한다.
|
||||
- 명시적 실험·Theme 미적용 prototype·외부 디자인 완전 재현·독립 POC만 별도 격리 범위에서 예외를 검토한다. Navigation 혼합은 아래 단일 모드 정책의 별도 기준을 따른다.
|
||||
- Button은 `brand | solid | outline`의 사용 위치와 세트 규칙을 `docs/components/button.md` 기준으로 따른다: 실제 화면 Brand 최대 1개·팝업 Brand 금지, 일반 확인/작성은 Solid 세트, 삭제 확인·행/반복 작업은 Outline 세트이며 세트의 appearance와 size를 통일한다. Runtime 변환은 `docs/guidelines/runtime-portability.md`의 DOM/Theme/keyboard 계약을 함께 보존한다.
|
||||
- Button은 `brand | solid | outline`의 사용 위치와 세트 규칙을 `docs/components/button.md` 기준으로 따른다: 실제 화면 Brand 최대 1개·팝업 Brand 금지, 일반 확인/작성은 Solid 세트, 삭제 확인은 Solid 세트, 일반 화면의 행/반복·보조 작업은 Outline을 사용한다. 결정 세트의 appearance·size를 통일하며 검색은 조회 Solid Green / 초기화 Outline Gray 예외다. Runtime 변환은 `docs/guidelines/runtime-portability.md`의 DOM/Theme/keyboard 계약을 함께 보존한다.
|
||||
- Dashboard 운영 화면은 전용 Header(48px)·업무 상태 필터와 Content로 구성하며 Sidebar 사용을 금지한다. Dashboard 대표 `Patterns/Layout/Dashboard → Dashboard` Story와 `docs/patterns/dashboard-layout.md`를 기준으로 하며, Header를 GNB로 대체하거나 일반 LNB/GNB를 함께 넣지 않는다. Sidebar verification Story는 신규 운영 화면의 Reference가 아니다.
|
||||
- Dashboard 및 DataTable은 기존 Pattern 구조를 우선한다. `Data Table` 대표 Story를 기준으로 하고 숨김 `With Filter Bar`는 verification 용도다.
|
||||
- Story의 fixture나 장식은 Component API나 Production 규칙과 구분한다. 대표 Story와 공개 API·사용 문서를 함께 확인한다.
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
# AI 화면 선택·완료 계약
|
||||
|
||||
읽는 순서는 `AGENTS.md` → 아래 해당 기능 행 → [공개 인덱스](component-pattern-reference.md)의 선택 문서와 대표 All Story다. 과거 보고서·verification Story의 기능을 새 요구사항으로 복사하지 않는다.
|
||||
|
||||
## 구현 전 기록
|
||||
|
||||
요구사항마다 필수 액션·상태·완료 조건을 기록한다. 요청된 메뉴 이름만 Navigation에 넣는다. 미지정이면 [선택 근거](navigation-single-mode.md#선택-근거)를 기록한다. 범위는 `STORYBOOK_ONLY | PRODUCTION_UI | BOTH`, 신규 화면 Runtime은 React다.
|
||||
|
||||
| 요구 기능 | 먼저 선택할 Pattern | Component·소비 책임 |
|
||||
|---|---|---|
|
||||
| 목록 검색·필터 | FilterBar, 표가 필요하면 DataTable | 조건 → 검색 → 조회 → 초기화. draft/applied 분리. PageHeader 밖 Card 하나. `layout="list-basic"` 가운데, 추가 조건은 `list-extended` 왼쪽. |
|
||||
| 업무 Dashboard | DashboardLayout·Header·Main·Content | Header 48px, 최소 960px 내부 스크롤. Sidebar 없음. 상태는 Dashboard Status 계약. |
|
||||
| Form | 별도 공개 Form Pattern 없음 | Label + Input/Textarea/Select/Checkbox를 Card 안에 조합. useId, htmlFor, 오류 메시지, 첫 오류 focus. 중복 Form Component 불필요. |
|
||||
| 서비스 상단 메뉴 | GNB + GNBMobileMenu | 요청된 경로만 Desktop/Mobile에 동일하게 구성. Sidebar 없음. |
|
||||
| 계층별 좌측 메뉴 | LNB + LNBMobileHeader/Menu | 공식 독립 LNB 허용. 모바일에도 LNB 모드 유지. |
|
||||
| 작업 확인 | Dialog 또는 AlertDialog | Title/Description, 취소/진행, Escape와 trigger focus 복귀. 취소·삭제는 Solid. |
|
||||
| 측면 상세 | Sheet | 방향·안쪽 모서리·키보드 focus는 기존 API. 메뉴 대체로 추가하지 않음. |
|
||||
| 하단 작업·드래그 | Drawer | desktop 취소→실행, mobile 실행 위·취소 아래. 실기기 drag 별도 검증. |
|
||||
| 초기/부분 로딩 | LoadingScreen 또는 Skeleton | 기존 콘텐츠 유지 여부를 요구사항으로 결정. |
|
||||
| 빈 목록·오류 | DataTable emptyMessage / 콘텐츠 HTML / Alert | 임의 Empty Component 불필요. 재시도는 요청된 경우만. |
|
||||
|
||||
Pattern → Component → Variant/Prop → Composition 순으로 선택한다. 부적합한 Pattern은 구체적인 API·구조 제약을 기록한다. React composition용 로컬 함수는 허용하지만 HM 위젯과 동일 기능의 중복 구현은 만들지 않는다.
|
||||
|
||||
### 의존성 탐색과 명령 결과
|
||||
|
||||
패키지의 공개 API와 설치된 `package.json`의 `exports`/`types`를 먼저 확인한다. 내부 선언이 필요한 경우 `rg --files <실제 패키지> -g '*.d.ts'`나 `Test-Path -LiteralPath`로 존재를 확인한 파일만 읽는다. 배포 패키지에 `src/features`가 있다고 추측하거나 없는 경로를 만들어 복구하지 않는다. CWD와 실제 node_modules 연결 위치를 기록한다.
|
||||
|
||||
독립 실험 사본에는 `.storybook` 설정이나 브라우저 도구가 제공되지 않을 수 있다. 실제 폴더 목록을 먼저 확인하고 검색 root에는 존재하는 경로만 넣는다. 대표 Story 소스는 Component/Pattern 참조에 사용하지만, Storybook 실행을 요청하지 않은 독립 React 생성에서는 `.storybook` 설정은 선택 참조다. 필수 문서·공개 패키지·bootstrap의 누락은 별도 실패이며, 선택 참조의 부재와 혼용하지 않는다. 도구 목록 검색 무결과는 도구가 다른 환경에도 없다는 증거가 아니다.
|
||||
|
||||
`rg`의 exit 1은 오류 진단이 없는 검색 무결과일 때만 정상 검색 결과다. exit 2, 읽기/접근 오류와 Typecheck/Build의 nonzero exit는 별도 실패다. 복합 명령의 마지막 exit 0이 앞선 읽기·컴파일 실패를 가릴 수 있으므로 검증 명령별 종료 코드와 진단을 보존한다. `vite.config.ts`를 읽는 명령은 Build 실행이 아니다. 중단 실험의 CLI 완료를 화면 생성 PASS로 기록하지 않는다.
|
||||
|
||||
실행기가 개별 명령 결과를 제공하지 않으면 파일 읽기와 각 검색을 별도 호출한다. 복합 명령의 마지막 exit 1만으로 전체 명령을 정상 무결과로 확정하지 않는다. 명령별 결과가 있으면 모든 단계의 원문·exit·stdout/stderr를 확인하고, 앞선 실제 실패를 보존한다.
|
||||
|
||||
## Theme와 접근성
|
||||
|
||||
- bootstrap은 `index.css`에서 Tailwind와 공개 HM Tailwind 설정, `hm-theme.css`에서 공개 Theme를 연결한다. 상태 사용 시 공개 Status CSS를 추가한다. [Runtime 계약](runtime-portability.md)을 적용한다.
|
||||
- 자주 쓰는 변수: `--hm-sem-bg-content`, `--hm-sem-bg-surface`, `--hm-sem-fg-primary`, `--hm-sem-fg-secondary`, `--hm-sem-stroke-default`, `--hm-sem-stroke-input-default`, `--hm-sem-action-primary`. 이름을 유추하지 말고 연결된 CSS의 선언을 확인한다. 공개 `text-primary`, `text-muted-foreground`, `bg-card` utility도 사용 가능하다.
|
||||
- `--hm-sem-text-*`, `--hm-sem-border-*`, `--hm-sem-stroke-divider`는 선언 확인 없이 쓰지 않는다. 없는 HM token을 임의 fallback 색으로 감추지 않는다. [Token 검사](ai-generation-guard.md#theme-token-검사)를 참고한다.
|
||||
- Component style/className은 기존 Prop·Token 계약을 먼저 사용한다. 동적 Token 후보와 fallback의 선언 여부를 확인하고, 외부 값·Props·동적 문자열은 실제 DOM·상태·브라우저·폭을 연결한 근거를 남긴다. HM Component의 임의 HEX/RGB/HSL·Spacing/Radius override는 Guard STYLE-001 대상이다. 일반 콘텐츠 레이아웃과 승인 여부가 불명확한 override는 [CSS Intent 검사](ai-generation-guard.md#css-intent와-동적-token-검사-2026-10-10)에서 구분하며, 미실행 Theme·상태와 사용자 디자인 의도는 NOT VERIFIED다.
|
||||
- 항목명은 공개 Label과 control ID를 연결한다. SelectTrigger/Combobox도 id 또는 aria-labelledby를 연결한다. 반복 조합은 useId를 사용한다. placeholder는 항목명 대체가 아니다.
|
||||
- Popup의 `aria-haspopup`은 `aria-controls`가 가리키는 실제 role과 일치해야 한다. HM Combobox는 dialog를 열고 내부 검색 입력이 listbox를 제어한다. 기존 Component의 연결 속성을 임의로 덮어쓰지 않는다. GNBUser/LNBProfile의 명시적 접근성 이름도 화면에 보이는 이름·설명을 포함한다.
|
||||
- 레이아웃·콘텐츠 HTML 허용. 미지원 native 위젯은 구체적인 이유와 이름 연결을 기록한다. 숨겨진 focus 대상, 존재하지 않는 active panel, disabled/readOnly 값 변경을 확인한다.
|
||||
- 내부 스크롤 화면의 숨김 absolute live region도 위치 기준이 필요하다. [LNB 콘텐츠 연결](../patterns/lnb.md#6-lnb-mode-콘텐츠-연결)의 positioned ancestor와 높이 분배를 따르고, 초기·조회·초기화·완료 상태에서 문서와 main의 scrollHeight/clientHeight를 따로 측정한다. 숨김 1px/clip 스타일만으로 외부 스크롤 방지를 보장하지 않는다. 전역 overflow:hidden으로 가리지 않는다.
|
||||
- 표의 ID처럼 분절되면 의미가 흐려지는 값은 [DataTable 식별자 소비 예제](../patterns/data-table.md#111-식별자-줄바꿈과-열-폭)를 따른다. 표 내부 가로 스크롤과 실제 전체 ID 식별을 함께 확인하며 Typography/Color를 축소해 해결하지 않는다.
|
||||
|
||||
## 완료와 보고
|
||||
|
||||
1. 화면 typecheck/build를 수행한다.
|
||||
2. 실제 entry에 Guard를 한 번 실행한다. 외부 앱도 동일 CLI로 검사한다. Production graph에 Story나 전체 저장소를 넣지 않는다. PARTIAL은 변경 파일을 명시한다.
|
||||
3. 실제 빌드 결과를 390/768/1280/1440px에서 확인한다. Dashboard는 내부 스크롤, 나머지는 페이지 가로 넘침 없이 구성한다. utility, Label, 키보드·focus 복귀, 보호 상태, 필수 액션을 확인한다.
|
||||
4. `staticStatus`, 원본 `status`, 브라우저 결과와 결합 결과를 따로 기록한다. source/contract 해시가 일치하는 Runtime 증거만 연결한다. 승인 CSS/native 예외의 미검증은 Runtime PASS로 지우지 않는다.
|
||||
5. 실제 렌더된 Component·Pattern, 선택/미사용 이유, Navigation, 액션 범위, 실행한 검사와 `NOT VERIFIED`를 보고한다. 미요청 CSV·다운로드·API·추가 메뉴는 구현하지 않는다.
|
||||
|
||||
신규 화면은 Story로 등록하지 않는다. Storybook Reference 개선은 사용자 요청 범위에서 별도로 수행한다. Guard PASS는 디자인 점수·스크린리더 인증·backend 성공을 의미하지 않는다.
|
||||
@@ -1,6 +1,6 @@
|
||||
# Component / Pattern Reference Index
|
||||
|
||||
AI 화면 구현 Quick Start의 Component·Pattern 검색에 사용하는 파일 인덱스다. 오전 `HMDesignTest.zip`과 현재 개발 저장소는 별도 스냅샷이다. 현재 검증된 최신 테스트 배포 기준 `HMDesignTest-Portable-Test-r3.zip`에는 아래 44개 Component와 8개 Pattern 모듈, Dashboard Status 소스/export/CSS/문서/정적 예제와 사전 빌드된 Storybook을 모두 포함한다. `HMDesignTest-Portable-Test-r2.zip`, 기존 `HMDesignTest-Portable-Test.zip` 및 오전 ZIP은 이전 스냅샷이며, 아래 오전 ZIP 수량은 역사적 비교로 표시한다. 공개 심볼의 Source of Truth는 [`packages/ui/src/index.ts`](../../packages/ui/src/index.ts)이며, Props와 상태는 각 연결 문서 및 구현을 확인한다. 파일 수, 공개 API 심볼 수, Story 그룹 수는 서로 다른 집계 단위다.
|
||||
AI 화면 구현 Quick Start의 Component·Pattern 검색에 사용하는 파일 인덱스다. 현재 테스트 공유 기준은 [README의 Git Clone 안내](../../README.md#git-clone-설치실행-현재-테스트-공유-기준)와 해당 checkout의 소스다. `HMDesignTest.zip`과 포터블 r1/r2/r3는 과거 스냅샷이며 현재 Git 소스와 별도로 취급한다. 당시 r3에는 44개 Component와 8개 Pattern 모듈, Dashboard Status 소스/export/CSS/문서/정적 예제와 사전 빌드된 Storybook을 포함했다. Git Clone에는 생성 dist·사전 빌드 Storybook·포터블 Node가 포함되지 않으므로 안내대로 설치·빌드한다. 아래 ZIP 수량은 역사적 비교다. 공개 심볼의 Source of Truth는 [`packages/ui/src/index.ts`](../../packages/ui/src/index.ts)이며, Props와 상태는 각 연결 문서 및 구현을 확인한다. 파일 수, 공개 API 심볼 수, Story 그룹 수는 서로 다른 집계 단위다.
|
||||
|
||||
## Component
|
||||
|
||||
@@ -57,7 +57,9 @@ AI 화면 구현 Quick Start의 Component·Pattern 검색에 사용하는 파일
|
||||
|
||||
## Pattern
|
||||
|
||||
현재 개발 저장소와 포터블 r3의 `packages/ui/src/patterns/`에는 8개 디렉터리와 62개 named export(값과 type 포함)가 있다. 역사적 오전 배포 기준 `HMDesignTest.zip`에는 7개 Pattern 모듈과 50개 named export가 있었다. Pattern 소스 디렉터리, Story 파일, Story 그룹 수는 별도 집계다.
|
||||
화면 요구 기능별 첫 선택은 [선택·완료 계약](ai-screen-contract.md#구현-전-기록)을 따른다. 공개 Form/Empty/Error Pattern은 현재 없으며 기존 Component composition으로 구성한다. FilterBar의 목록형 opt-in은 `layout="list-basic" | "list-extended"`다. Story의 추가 조건·액션은 사용자 요구사항이 아니다.
|
||||
|
||||
현재 개발 저장소의 `packages/ui/src/patterns/`에는 8개 디렉터리와 63개 named export(값과 type 포함, FilterBarProps 추가)가 있다. 기존 포터블 r3 스냅샷은 62개이며 이번 작업에서 ZIP을 갱신하지 않는다. 역사적 오전 배포 기준 `HMDesignTest.zip`에는 7개 Pattern 모듈과 50개 named export가 있었다. Pattern 소스 디렉터리, Story 파일, Story 그룹 수는 별도 집계다.
|
||||
|
||||
| Pattern (문서) | Import 경로 | 주요 용도 | 대표 Story |
|
||||
|---|---|---|---|
|
||||
@@ -72,18 +74,20 @@ AI 화면 구현 Quick Start의 Component·Pattern 검색에 사용하는 파일
|
||||
|
||||
Data Table은 기존 Table·Pagination·Checkbox·Select·Dropdown Menu 등을 조합한다. 연동 예제가 필요하면 Data Table Story 안의 `With Filter Bar`를 참고하되 숨김 `verification` Story이므로 일반 화면의 단독 기본 Reference로 삼지 않는다. Filter Bar는 단독으로도 사용 가능하며 검색·Select·Combobox·Date Picker 등 조회 조건의 layout이다. Dashboard 빠른 상태 필터는 Filter Bar API가 아니라 Dashboard Status 계약을 따른다.
|
||||
|
||||
오전 소스 ZIP을 받은 AI는 Dashboard Status 행의 현재 개발 경로를 사용할 수 있다고 가정하지 않는다. 최신 포터블 ZIP에서는 해당 상대경로와 공개 API를 사용할 수 있다. ZIP에 실제 포함된 Dashboard 구현·Story와 해당 ZIP 안의 Dashboard 문서를 확인하고, Status 공개 API가 없으면 없다고 보고한다.
|
||||
과거 소스/포터블 ZIP을 받은 AI는 Dashboard Status 행의 현재 개발 경로를 사용할 수 있다고 가정하지 않는다. 해당 ZIP에 실제 포함된 Dashboard 구현·Story·문서와 공개 API를 확인하고, Status 공개 API가 없으면 없다고 보고한다. 현재 Git checkout에서는 실제 파일 목록과 공개 exports를 확인한 뒤 사용한다.
|
||||
|
||||
## Reference 읽는 순서
|
||||
|
||||
### 화면 생성 시 놓치기 쉬운 소비 계약
|
||||
|
||||
- 검색·필터: Table이 없어도 [FilterBar](../patterns/filter-bar.md)를 먼저 확인한다. 공개 Pattern 미사용 시 요구사항과 맞지 않는 제약을 기록한다. 대표 Story의 fixture·추가 액션은 요구사항이 아니다.
|
||||
- Field Label: [공개 Label의 control 연결 예제](../components/label.md#5-api)를 확인한다. 기본 HTML은 레이아웃·콘텐츠나 미지원 사용처에 허용하며 기존 HM 위젯 대체는 이유 없이 만들지 않는다.
|
||||
- Navigation 미지정: [선택 근거](navigation-single-mode.md#선택-근거)를 기록한다. GNB/LNB의 목적과 대표 화면 구조로 판단하며 일반 목록의 기본 모드를 임의 확정하지 않는다.
|
||||
- GNB ONLY: [Desktop·Mobile 구성](../patterns/gnb.md#8-desktop--mobile)을 함께 구현한다. 대표 `patterns-layout-gnb--all`의 Overview·Usage를 확인한다. 신규 AI Production 화면에는 GNB Sidebar를 적용하지 않는다.
|
||||
- LNB ONLY: 기존 독립 LNB 구조와 [LNB Mobile Header/Menu](../patterns/lnb.md#3b-lnb-mobile-header-2026-10-07)를 유지한다.
|
||||
- DASHBOARD ONLY: Sidebar를 생성하지 않는다. 대표 `patterns-layout-dashboard-layout--all`의 전용 Header(48px)·업무 상태 필터 + Content, 최소 폭 960px·내부 가로 스크롤을 따른다. `DashboardSidebar`와 `sidebar` slot은 호환성·검증용이며 과거 Sidebar verification Story는 신규 운영 화면 구현 기준이 아니다.
|
||||
- Dashboard Status: 공개 `@hm-design/ui/dashboard-status.css`는 변수만 제공한다. [Theme → Status CSS → 기존 Outline Badge mapping·React 소비 예제](../patterns/dashboard-layout.md#dashboard-업무-상태-공통-계약)를 사용한다. `issue`는 독립 flag다. [Static HTML Reference](../patterns/dashboard-status-static.html)도 같은 계약을 소비한다.
|
||||
- FilterBar: [입력 draft / 조회 applied·초기화 예제](../patterns/filter-bar.md#61-조회-버튼으로-적용하는-소비-예제)를 확인한다. 대표 `patterns-data-filter-bar--all`은 조회 callback 없는 조합 예시이며 DataTable의 `patterns-data-data-table--with-filter-bar-story`는 즉시 적용 verification이다.
|
||||
- FilterBar: [입력 draft / 조회 applied·초기화 예제](../patterns/filter-bar.md#61-조회-버튼으로-적용하는-소비-예제)를 확인한다. 대표 `patterns-data-filter-bar--all`은 입력/조회 적용 상태와 초기화 callback을 구분하는 조합 예시이며 DataTable의 `patterns-data-data-table--with-filter-bar-story`는 즉시 적용 verification이다.
|
||||
- React 소비 CSS: [Tailwind v4 검색 범위와 HM source 유지](runtime-portability.md#21-tailwind-v4-소비자-검색-범위), [Runtime Theme 연결](runtime-theme.md)을 확인한다.
|
||||
- 실행 위치별 Asset: [Noto Sans KR·폰트 URL·단일 HTML 내장](runtime-portability.md#41-noto-sans-kr-경로-실행-환경별-확인)을 확인한다.
|
||||
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
# 디자인팀 컬러 Theme 사용 방법
|
||||
|
||||
Storybook에서 **Theme → Designer Playground → Editor**를 엽니다.
|
||||
로컬 기본 주소: http://localhost:6007/?path=/story/theme-designer-playground--editor
|
||||
Designer Playground는 내부 개발용 `internal` 태그로 기본 검수 메뉴에서 제외됩니다. 개발 서버 또는 배포 서버가 출력한 주소에 `?path=/story/theme-designer-playground--editor`를 붙여 직접 엽니다. 검수 화면은 HM Default를 사용합니다.
|
||||
|
||||
1. 처음 열면 `themes/default.json` 기반 HM Default 컬러가 표시됩니다. **Load Default JSON**, **Load Service Example JSON**으로 repository JSON을 URL에서 불러오거나 **Theme JSON URL**에 CDN URL을 입력한 뒤 **Load URL**을 누릅니다. 같은 탭에 저장값이 있다면 마지막 유효 Theme를 다시 표시합니다. **Reset to HM Default**로 기본값을 다시 불러옵니다.
|
||||
1. 처음 열면 `themes/default.json` 기반 HM Default 컬러가 표시됩니다. **Load Default JSON**, **Load Service Example JSON**으로 repository JSON을 URL에서 불러오거나 **Theme JSON URL**에 CDN URL을 입력한 뒤 **Load URL**을 누릅니다. 같은 탭에 저장값이 있다면 마지막 유효 Theme를 다시 표시합니다. 다른 Story로 이동해도 편집 데이터는 세션에 보관되지만 해당 Story의 색상은 HM Default이며, 편집기로 돌아오면 보관된 편집값을 다시 적용합니다. **Reset to HM Default**로 기본값을 다시 불러옵니다.
|
||||
2. Primary / Active / Focus / Accent / Destructive 등 역할의 컬러 피커 또는 HEX 입력을 수정합니다. 불투명 6자리 HEX(`#123abc`)를 사용합니다. 유효한 값은 입력 즉시 적용되며 별도의 Apply 버튼이 필요 없습니다. 미완성 입력은 마지막 유효 색을 유지합니다.
|
||||
3. 오른쪽 Live Preview에서 여러 컴포넌트를 함께 확인합니다. 화면이 좁으면 편집기 아래에 Preview가 이어집니다. Focus 확인은 Tab 키로 Checkbox/Input 등에 이동합니다. Select, Date Picker, Combobox 및 메뉴를 열면 Global Theme가 팝업에도 적용됩니다.
|
||||
4. 다른 Component / Pattern Story로 이동해도 같은 Theme를 확인할 수 있습니다. 값 변경 자체에는 reload, 파일 저장, Vite HMR, build, Storybook 재시작이 필요 없습니다. 기존 Runtime Contract 검증 Story는 독립 검증을 위해 편집 Theme를 적용하지 않습니다.
|
||||
4. 임시 Theme는 Designer Playground 내부에만 적용됩니다. 다른 Component / Pattern Story로 이동하면 override를 해제하고 HM Default로 검수합니다. 편집기 내부 값 변경에는 reload, 파일 저장, Vite HMR, build, Storybook 재시작이 필요 없습니다.
|
||||
5. **Reset to HM Default**는 현재 override를 해제하고 기본값을 즉시 복원합니다. 컴포넌트 API와 레이아웃은 바꾸지 않습니다.
|
||||
6. **Show JSON**으로 현재 데이터를 표시하고 **Copy JSON**으로 복사하거나 **Export JSON**으로 `hm-color-theme.json`을 내려받습니다. 클립보드 접근이 막히면 JSON 입력란에서 직접 복사합니다. 수정한 키만 저장하므로 나머지는 HM Default입니다.
|
||||
7. JSON을 입력란에 붙여 넣고 **Import JSON**을 누르거나 파일 입력으로 JSON을 선택하면 바로 적용됩니다. 이전 Theme와 병합하지 않고 새 Theme로 교체합니다. 잘못된 JSON/키/값/불완전한 gradient 그룹은 거부하고 마지막 유효 Theme를 유지합니다. 이 편집기는 컬러 전용이므로 radius 입력을 거부합니다.
|
||||
@@ -29,12 +28,13 @@ resetRuntimeTheme(document.documentElement)
|
||||
- Primary는 Badge default, Pagination current, Button outline 및 내비게이션 강조 글자에 적용합니다. Brand Button/GNB의 gradient와 일부 palette 장식은 별도 기존 계약을 유지합니다. Primary 하나로 모든 gradient stop을 재설계하지 않습니다.
|
||||
- Active는 Checkbox, Radio, Switch, Slider, Progress 및 Calendar/Date Picker의 선택 면을 바꿉니다. Focus와 독립적입니다. On Active는 그 위 아이콘/텍스트입니다.
|
||||
- Focus는 일반 입력 테두리와 Checkbox/Calendar 등의 ring, Slider Keyboard Focus의 Focus Semantic 20% halo입니다. Slider Hover/Drag halo는 Primary 20%이며 GNB/LNB는 contextual navigation focus 예외를 유지합니다.
|
||||
- Accent 45%는 Select/메뉴 Item/Calendar range middle·hover/Pagination hover/Table hover·selected의 Soft Highlight 면입니다. Combobox는 Command를 조합하므로 같은 강조 역할을 사용합니다. Toggle/Toggle Group Selected, Menubar 상위 Highlighted/Open 및 Navigation Menu Trigger/Open은 Accent 100% + On Accent를 사용합니다. Navigation Current는 Primary + contextual surface로 Control Active와 구분합니다.
|
||||
- Accent는 Select/메뉴 Item/Calendar range middle·hover/Pagination hover에 45%, Table 행 hover·selected에만 20%로 사용합니다. Combobox는 Command를 조합하므로 메뉴의 강조 역할을 사용합니다. Toggle/Toggle Group Selected, Menubar 상위 Highlighted/Open 및 Navigation Menu Trigger/Open은 Accent 100% + On Accent를 사용합니다. Navigation Current는 Primary + contextual surface로 Control Active와 구분합니다.
|
||||
- Destructive는 오류, invalid 및 destructive 표현입니다. Primary/Active/Focus와 독립적입니다.
|
||||
- 각 입력란은 Default JSON + partial override의 실제 계산된 역할 값을 표시합니다. Export는 표시값 전체가 아니라 명시적으로 수정·Import한 데이터를 저장합니다. Primary와 On Accent는 sibling Semantic이며 Default JSON과 CSS-only package fallback 모두 독립값을 유지합니다. 기본값이 같아도 Primary override가 On Accent를 함께 바꾸지는 않습니다.
|
||||
|
||||
## 저장과 알려진 제한
|
||||
|
||||
- 일반 새 탭은 독립 세션입니다. 탭 복제 또는 opener로 연 탭은 브라우저가 초기 sessionStorage를 복사할 수 있으며 이후 편집은 탭별로 독립적입니다.
|
||||
- 서버/DB/Publish 기능은 없습니다. 같은 브라우저 탭의 Storybook preview origin에 `sessionStorage`로 보관하며, 세션 저장을 사용할 수 없는 환경에서도 현재 화면의 편집/Export는 동작합니다. 장기 보관은 JSON Export를 사용하세요.
|
||||
- Global Theme는 `document.documentElement`에 적용하며 body Portal도 같은 Theme를 사용합니다. wrapper 밖으로 Portal된 popup은 Scoped Theme를 자동 전달받지 않습니다. 이 제한은 기존 FOLLOW_UP입니다.
|
||||
- 전체 Runtime Contract는 73개 입력을 유지합니다. 배포하는 Default JSON은 71개 컬러이며 radius/geometry는 package에서 관리합니다. 편집 화면은 상위 컬러 역할 17개만 노출하며 Component Token, radius, palette/gradient 개별 입력 UI를 만들지 않습니다. 기존 컬러 계약의 palette/gradient는 유효 JSON으로 Import할 수 있으며 gradient는 세트 전체를 제공해야 합니다.
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
# 월요일 공식 Gitea 소스 반영 준비
|
||||
|
||||
이번 작업은 준비 문서만 작성했다. 공식 Gitea는 NOT ACCESSED / NOT MODIFIED. GitHub 원격을 유지하며 ZIP을 만들지 않았다. 월요일 작업은 별도 지시에 따라 실행한다.
|
||||
|
||||
GitHub 임시 이력을 공식 Gitea에 merge/cherry-pick/import하지 않는다. 공식 저장소의 현재 main과 이력을 보존한 상태에서 승인된 최신 소스 파일을 비교·반영하고 공식 저장소에 별도 commit한다. 삭제/충돌/기존 사용자 변경은 자동 덮어쓰기하지 말고 별도 확인할 대상이다.
|
||||
|
||||
## 필수 파일
|
||||
|
||||
현재 기준은 BASE `0b2bc376aa8b6af9d2492b5620d8ae776391508d`부터 GitHub 최종 main까지다. 월요일 최신 SHA를 새로 확인해야 한다. 정확한 경로 목록은 다음 명령으로 생성한다.
|
||||
|
||||
```sh
|
||||
git diff --name-status 0b2bc376aa8b6af9d2492b5620d8ae776391508d HEAD
|
||||
```
|
||||
|
||||
이번 변경 묶음은 아래와 같다. 이전 시 변경 묶음만 복사하면 기존 의존 파일이 누락될 수 있으므로 전체 최신 추적 소스를 기준으로 공식 소스와 비교한다.
|
||||
|
||||
- `AGENTS.md`, `docs/guidelines/ai-generation-guard.md`, `ai-implementation-details.md`, `ai-screen-contract.md`, `component-pattern-reference.md`
|
||||
- `docs/patterns/filter-bar.md`, 이번 결과/준비 문서·요약 JSON
|
||||
- `packages/ui/src/index.ts`, `packages/ui/src/patterns/filter-bar/filter-bar.tsx`, `packages/ui/src/theme/filter-bar.css`, `dashboard-layout.css`
|
||||
- `src/patterns/filter-bar.stories.tsx`
|
||||
- `scripts/ai-generation-guard.mjs`, `ai-generation-guard.test.mjs`, `guard-theme-analysis.mjs`, `guard-evidence.mjs`, `guard-evidence.test.mjs`, `public-theme-tokens.mjs`, `publisher-components.test.mjs`
|
||||
- `scripts/prepare-quality-experiments.mjs`, `verify-quality-runtime.mjs`, `verify-quality-reference.mjs`, `verify-quality-regression.mjs`, `serve-quality-reference.mjs`, `audit-quality-contracts.mjs`, `summarize-quality-evidence.mjs`
|
||||
- `examples/ai-quality/01..10`의 `index.html/main.tsx/requirements.json`, `shared/**`, `README.md`, `tsconfig.json`, `vite.config.ts`
|
||||
|
||||
필수 기반 파일은 기존 `package.json`, `package-lock.json`, workspace packages, `.storybook`, Vite/TS 설정, scripts, public/theme/font assets다. 이번 작업은 dependency manifest/lock을 변경하지 않았다. `.git`, `node_modules`, `_local`, 생성 dist/Storybook output은 소스 이전 대상이 아니다. 이전 실험의 원본 증거는 소스와 별도로 보존한다.
|
||||
|
||||
## 의존성·검증 환경
|
||||
|
||||
실제 실행: Node 20.20.1, React/ReactDOM 19.3.0, TypeScript 7.0.2, Vite 8.3.0, Tailwind/@tailwindcss/vite 4.3.3, Storybook 10.6.1. 설치 버전의 단일 기준은 lockfile이며 공식 환경의 Node/npm 가용성은 월요일 확인해야 한다.
|
||||
|
||||
`@hm-design/ui`, `@hm-design/center-graphic`은 npm workspace build가 필요하다. public Theme CSS는 HM source/vendor CSS/font/status asset 연결을 유지한다. 소비 앱은 public export를 사용한다. 패키지 단독 소비는 npm pack 후 별도 앱에 설치해 typecheck/build/runtime를 확인했다.
|
||||
|
||||
브라우저 검증에는 Playwright 모듈·Chrome 실행 파일이 별도로 필요하다. 이번 환경에서는 Codex bundled Playwright와 설치된 Chrome을 사용했고 이를 root 의존성에 추가하지 않았다. `HM_PLAYWRIGHT_DIR`, `HM_CHROME_PATH`를 해당 환경 경로로 지정한다. 제품 소스에 로컬 절대 경로를 넣지 않는다.
|
||||
|
||||
## 검증 명령
|
||||
|
||||
```sh
|
||||
npm ci --ignore-scripts --no-audit --no-fund
|
||||
npm run check:theme-defaults
|
||||
npm run build:packages
|
||||
npm run typecheck
|
||||
npm run test:guard
|
||||
npm run test:components
|
||||
node --test scripts/guard-evidence.test.mjs scripts/theme-verification.test.mjs
|
||||
npm run build
|
||||
npm run build-storybook
|
||||
npm run build:publisher-example
|
||||
npm run build:dashboard-export
|
||||
node node_modules/vite/bin/vite.js build --config vite.recruit-export.config.ts
|
||||
node scripts/check-doc-links.mjs
|
||||
node scripts/public-theme-tokens.mjs
|
||||
node node_modules/typescript/bin/tsc -p examples/ai-quality/tsconfig.json
|
||||
node node_modules/vite/bin/vite.js build --config examples/ai-quality/vite.config.ts
|
||||
```
|
||||
|
||||
`verify-quality-regression.mjs`는 작업 완료 뒤 관련 build/typecheck/test/Guard를 묶어 실행하는 대안이다. 이미 실행한 같은 검사를 별도로 중복하지 않는다. UI build 산출물이 먼저 준비되어야 한다.
|
||||
|
||||
브라우저: preview 6321에서 `verify-quality-runtime.mjs`, reference server 6322에서 `verify-quality-reference.mjs`. 실제 배포와 다른 localhost 경로이므로 공식 경로/assets도 월요일 확인한다. 각 화면 `--result index.html` FULL_SCREEN·Navigation 모드와 PARTIAL/Storybook Profile을 확인하고 static/runtime 상태를 구분한다. 생성 화면 증거 집계는 `node scripts/summarize-quality-evidence.mjs`다.
|
||||
|
||||
`audit-quality-contracts.mjs`는 이전 로컬 Storybook/실험 증거의 절대 경로와 BASE commit이 필요하다. 공식 Git 이력에 임시 BASE를 가져오지 않는다. 월요일에는 보존된 baseline JSON·소스 hash를 별도 입력으로 비교하거나 공식 baseline으로 수정한 뒤 사용한다. 동일 경로의 이전 증거가 없으면 그 부분을 NOT VERIFIED로 남긴다.
|
||||
|
||||
## 남은 위험
|
||||
|
||||
- 기존 공식 저장소와 GitHub의 차이·충돌·추가 파일은 아직 확인하지 않았다. 소스 이전 준비 PASS는 공식 이전 완료를 뜻하지 않는다.
|
||||
- 모든 source가 이전되어도 ignored build/package dist와 외부 evidence는 다시 생성/별도 보존해야 한다.
|
||||
- native/CSS intent/computed Token의 기존 Guard NOT VERIFIED와 과거 contrast 잔여 문제는 그대로 남는다. 근거 없는 예외 등록·Theme 변경을 하지 않는다.
|
||||
- cross-model/낮은 추론 재생성·디자인 점수·스크린리더/실기기는 NOT VERIFIED다.
|
||||
- source 또는 public Component/Guard 계약이 변경되면 기존 Runtime hash 증거는 stale이다. 변경 화면만 새 증거로 검사한다.
|
||||
|
||||
필수 실패가 있으면 공식 push를 보류한다. GitHub 연결 해제는 공식 소스 반영·검증·commit/push·연결 확인 후 별도 지시에 따라 수행한다.
|
||||
@@ -0,0 +1,144 @@
|
||||
# HMDesign 공식 Gitea 소스 이전 준비
|
||||
|
||||
2026-10-12 월요일에는 검증된 GitHub 최신 **추적 소스 전체**를 공식 Gitea의 기존 이력 위에 반영한다. 이번 작업은 소스 정합성과 준비 자료만 정리했으며 공식 Gitea 접근·Clone·Commit·Push·연결 전환은 실행하지 않았다. [최종 정합성 보고](../reports/pre-gitea-finalization-2026-10-11.md)와 [전체 소스 목록](../reports/gitea-source-inventory-2026-10-11.json)을 함께 사용한다. [10월 10일 준비 기록](gitea-source-transfer-preparation-2026-10-10.md)은 당시 기록으로 보존한다.
|
||||
|
||||
## 기준 소스와 전달 자료
|
||||
|
||||
현재 소스 기준은 GitHub `shkim25027/HMDesignSystemTest`의 main이다. 이번 작업 시작 Local/GitHub HEAD는 모두 `4fe549da01683c363b0715aedeb82a089717f685`, 작업 트리는 CLEAN이었다. 이 기준에서 실행 코드·CSS·Theme·의존성·Story는 바꾸지 않고 문서만 보완한다. 문서를 포함한 최종 commit SHA는 자기 커밋 파일에 넣을 수 없으므로 작업 종료 보고와 로컬 `_local/finalization-20261011/release-manifest.json`에 기록한다. 월요일에는 전달받은 **최종 전체 SHA**와 아래 실제 GitHub main 조회 결과를 비교해 대상 소스를 고정한다.
|
||||
|
||||
```powershell
|
||||
git rev-parse HEAD
|
||||
git branch --show-current
|
||||
git status --porcelain=v1
|
||||
git ls-remote https://github.com/shkim25027/HMDesignSystemTest.git HEAD refs/heads/main
|
||||
git ls-files
|
||||
```
|
||||
|
||||
최종 소스 목록은 595개 경로다(기존 592개 + 이번 준비/보고/목록 3개). JSON의 `paths`와 실제 `git ls-files`를 비교한다. 이후 새 commit이 생기면 SHA·목록·변경 영향 판정을 새로 확인한다. GitHub에서 일부 최근 변경 파일만 복사하면 기존 기반 파일을 누락할 수 있다.
|
||||
|
||||
Git 소스와 별도로 보관할 로컬 증거는 다음과 같다. 이 경로는 Clone에서 열 수 있는 문서 링크가 아니다.
|
||||
|
||||
- HMDesign: `_local/finalization-20261011/`의 최종 보고, release manifest, tracked-files.txt, 재사용/보존 근거, 검증 로그.
|
||||
- 독립 실험: `D:/디자인시스템/HMDesign-AI-CrossModel-Test/finalization-20261011/`의 실행기 V3 후보와 21개 모의검사 근거.
|
||||
- 과거 실험·접근성·보안 증거: 기존 폴더를 그대로 보관하며 소스 이전 commit에 추가하지 않는다.
|
||||
|
||||
## 프로젝트 진입점
|
||||
|
||||
| 영역 | 실제 경로와 역할 |
|
||||
|---|---|
|
||||
| workspace | `package.json`, `package-lock.json`, `packages/*` |
|
||||
| UI 공개 API | `packages/ui/src/index.ts`, `packages/ui/package.json` |
|
||||
| UI 구현과 Pattern | `packages/ui/src/components/ui/`, `packages/ui/src/patterns/` |
|
||||
| Theme | `themes/default.json`, `packages/ui/src/theme/`, `packages/ui/src/theme.css`, `packages/ui/src/tailwind.css` |
|
||||
| CENTER | `packages/center-graphic/src/index.ts`, `packages/center-graphic/package.json` |
|
||||
| 기본 React 앱 | `index.html` → `src/main.tsx` → `src/App.tsx`, `src/index.css` → `src/hm-theme.css` |
|
||||
| Storybook | `.storybook/main.ts`, `.storybook/preview.tsx`, `.storybook/manager.css`, `src/**/*.stories.tsx` |
|
||||
| 새 목록 제작 예제 | `examples/publisher-list/README.md`, `main.tsx`, `vite.config.ts` |
|
||||
| AI 규칙과 검사 | `AGENTS.md`, `docs/guidelines/ai-screen-contract.md`, `scripts/ai-generation-guard.mjs` |
|
||||
| Windows 실행기 | `start-storybook.bat`, `scripts/start-storybook.mjs` |
|
||||
|
||||
Storybook manager 스타일은 `main.ts`의 `managerHead`에서 CSS를 연결한다. 별도 `manager.ts/tsx` 파일은 필수 파일이 아니다. 생성 package dist·앱 dist·storybook-static·theme-dist는 Git에 없으며 설치 후 재빌드한다. Noto Sans KR는 `public/fonts/`의 추적 asset과 라이선스를 유지한다.
|
||||
|
||||
## 의존성과 실행 조건
|
||||
|
||||
Node.js 조건은 lockfile/Vite 기준 `^20.19.0 || >=22.12.0`이며 Node 21은 제외한다. 검증 환경은 Node **20.20.1**, npm **10.8.2**, Windows, React/ReactDOM 19.3.0, TypeScript 7.0.2, Vite 8.3.0, Storybook 10.6.1, Tailwind/@tailwindcss/vite 4.3.3이다. 공식 회사 환경의 버전·프록시·인증·레지스트리 접근은 NOT VERIFIED다.
|
||||
|
||||
정확한 전체 의존성은 `package-lock.json`으로 고정한다. root의 UI/CENTER workspace, UI의 Radix·cmdk·TanStack Table·lucide-react 등과 React/Tailwind peer 계약을 유지한다. `@tanstack/react-table`과 `@tanstack/table-core`는 모두 9.2.4다. 개발 `shadcn`과 CSS 복사 계약도 유지하며 이번에 업데이트하지 않았다.
|
||||
|
||||
최초 설치와 실행:
|
||||
|
||||
```powershell
|
||||
node --version
|
||||
npm --version
|
||||
npm ci --no-audit --no-fund
|
||||
npm run build:packages
|
||||
npm run storybook
|
||||
# http://localhost:6024/
|
||||
# 별도 터미널의 실제 React 목록 예제:
|
||||
npm run dev:publisher-example
|
||||
```
|
||||
|
||||
Windows의 `start-storybook.bat`은 의존성/산출물이 없으면 준비하고 6024의 index/preview 응답을 확인한다. Node/npm/Git은 별도 설치 대상이며 포터블 Node나 ZIP을 제공하지 않는다. 공식 사내 실행 환경의 설치·호스팅 결과는 월요일 확인한다.
|
||||
|
||||
## 검증 명령과 선택 기준
|
||||
|
||||
소스 이전 후 package를 빌드하고 최종 타입과 build를 확인한다. `typecheck`의 prehook가 Theme defaults 확인과 package build를 수행한다. 같은 source/dependency 조건에서 이미 성공한 hook는 `--ignore-scripts`로 중복을 줄일 수 있다.
|
||||
|
||||
```powershell
|
||||
npm run typecheck
|
||||
npm run build --ignore-scripts
|
||||
npm run build-storybook --ignore-scripts
|
||||
node scripts/check-doc-links.mjs
|
||||
node scripts/public-theme-tokens.mjs
|
||||
```
|
||||
|
||||
변경 영향에 따라 아래 검사 중 필요한 것만 선택한다. 소스와 의존성·환경이 같은 기존 PASS를 재사용하고, 전체 292 Story 렌더를 무조건 반복하지 않는다. 회사 환경에서 새로운 설치/빌드 실패가 생기면 해당 실패를 해결·재검사한 뒤 진행한다.
|
||||
|
||||
```powershell
|
||||
# Guard 또는 증거 계약이 달라졌을 때: 현재 75 + 20 + 5
|
||||
node --test scripts/ai-generation-guard.test.mjs scripts/guard-evidence.test.mjs scripts/guard-requirements.test.mjs
|
||||
# Component / 접근성 / Theme 영향이 있을 때:
|
||||
npm run test:components
|
||||
node --test scripts/accessibility-regression.test.mjs
|
||||
node --test scripts/theme-verification.test.mjs
|
||||
# 소비 예제 영향이 있을 때:
|
||||
npm run build:publisher-example
|
||||
npm run build:dashboard-export
|
||||
node node_modules/vite/bin/vite.js build --config vite.recruit-export.config.ts
|
||||
```
|
||||
|
||||
브라우저 QA는 별도 설치된 Playwright·Chrome을 `HM_PLAYWRIGHT_DIR`·`HM_CHROME_PATH`로 연결한다. `scripts/verify-accessibility-runtime.mjs`는 `HM_A11Y_URL`과 별도 `HM_A11Y_OUTPUT`에 명명된 선택 검사를 기록한다. 실제 SR 발화·실터치는 이 스크립트의 PASS로 대체하지 않는다.
|
||||
|
||||
`audit-quality-contracts.mjs`는 과거 GitHub BASE와 로컬 절대 증거 경로 2개에 의존하는 **역사 비교 도구**다. 공식 Gitea 이력에 BASE commit을 가져와 실행하지 않는다. 공식 환경에서 그대로 실행하는 검증 목록에서 제외하고, 필요 시 별도 승인 범위에서 baseline 입력을 연결한다. 제품 앱·package manifest의 로컬 절대경로 의존성은 발견되지 않았다. CSS의 외부 Reference 경로 주석과 과거 QA 안내는 실행 의존성이 아니다.
|
||||
|
||||
## AI Guard 명령
|
||||
|
||||
현재 scope는 FULL_SCREEN/PARTIAL이고, STORYBOOK은 profile이다. Production `--result`는 실제 React bootstrap에 연결한다.
|
||||
|
||||
```powershell
|
||||
node scripts/ai-generation-guard.mjs --target <앱> --scope FULL_SCREEN --mode GNB_ONLY --result index.html --json
|
||||
node scripts/ai-generation-guard.mjs --target <앱> --scope PARTIAL --mode LNB_ONLY --files src/main.tsx --result index.html --json
|
||||
node scripts/ai-generation-guard.mjs --target . --profile STORYBOOK --scope PARTIAL --files src/components/combobox.stories.tsx,src/patterns/gnb.stories.tsx,src/patterns/lnb.stories.tsx --json
|
||||
node scripts/guard-evidence.mjs <guard.json> <runtime.json>
|
||||
```
|
||||
|
||||
`--scope STORYBOOK`과 STORYBOOK profile의 `--result`는 설정 오류다. exit 0만으로 PASS로 판단하지 않는다. 원본 `status`, `staticStatus` 및 CSS의 STATIC/RUNTIME/DESIGN_INTENT/FINAL을 별도로 보고한다. 오래된 source/contract 해시를 새 값으로 덮어쓰지 않는다. STYLE-001 FAIL, 동적 Token 유한 후보 선언, 외부 입력 미검증과 recipe가 디자인 승인 근거가 아니라는 계약을 유지한다. 비신뢰 Storybook 설정·glob 입력은 개발 의존성 위험 때문에 제한한다.
|
||||
|
||||
## 보존할 디자인과 정책
|
||||
|
||||
- D-01 중첩 Panel 제거·`padding: 24px 0`, D-02 Primary 상단 White alpha 0.8, Secondary·Legacy 유지.
|
||||
- 확정 목록 구성·조회 Solid Green/초기화 Outline Gray, Button Gray/Solid Red, Table 강조 20%, Progress 우측 radius, Accordion 제목 hover 5%, Sheet 안쪽 모서리, Drawer 모바일 버튼 순서.
|
||||
- Green LNB 펼친 2Depth와 Storybook 왼쪽 목차 배경 Black 8%. 선택·Hover·Focus와 전체 opacity 유지.
|
||||
- Theme 값의 원본은 `themes/default.json`. 공통 Color/Typography/Spacing/Token·Component API·대표 Story ID를 임의 변경하지 않는다. Sheet 최종 radius 등 미확정 값은 확정하지 않는다.
|
||||
- 실제 HM React 공개 Component/Pattern을 사용한다. ONE PAGE = ONE NAVIGATION MODE, GNB mobile 동반, 공식 LNB ONLY 허용, 신규 GNB/Dashboard Sidebar 금지, Dashboard Header 48px·최소 960px 내부 스크롤.
|
||||
- Storybook은 Reference다. 신규 업무 화면을 Story로 추가하지 않고 소비 bootstrap의 공개 Theme/Tailwind/status와 package font asset 연결을 유지한다.
|
||||
|
||||
## 남은 문제
|
||||
|
||||
| 분류 | 보존할 상태 |
|
||||
|---|---|
|
||||
| T03 Medium/High | 화면 생성 전 중단. 생성·품질·반응형·접근성 모두 NOT VERIFIED. 승인 12/12 사용, 추가 모델 호출 0 |
|
||||
| T03 실행기 | V3 후보 로컬 21/21 PASS. 기존 실행기·launcher·승인·STOP 보존. 실제 모델 세션에서의 통합은 NOT VERIFIED; 별도 승인 후 새 manifest로 사용 |
|
||||
| CSS Intent | T01 디자인 의도·미실행 동적 Theme/상태 NOT VERIFIED. 이전 contract는 역사적 결과만 재사용 |
|
||||
| 보안 | 과거 감사 기준 개발 High 7·Critical 0, 운영 0. braces 전파 경로, 안전한 patch 미확인. 새 audit/업데이트 없음 |
|
||||
| 접근성 | 활성 placeholder·일부 버튼/오류 대비 FAIL/DEFERRED. SR·실터치·Drawer drag·확대·모든 Theme/브라우저 NOT VERIFIED |
|
||||
| 빌드 | 기존 500kB chunk와 Storybook bundler 성능 경고 보존 |
|
||||
| 공식 환경 | Gitea 전용 파일·기존 소스 차이·분기/보호 정책·사내 Node/npm·호스팅·인증 NOT VERIFIED |
|
||||
|
||||
## 월요일 공식 이력을 유지하는 반영 순서
|
||||
|
||||
아래는 월요일 별도 승인된 작업의 절차이며 이번에는 실행하지 않았다.
|
||||
|
||||
1. 공식 Gitea checkout의 실제 branch/HEAD/working tree를 기록한다. 공식 저장소에만 있는 파일과 사용자 변경을 보존한다. 기존 이력 위에서 작업용 branch를 만들고 GitHub 소스와의 경로별 차이를 확인한다.
|
||||
2. 고정한 최종 GitHub SHA의 **추적 파일만** 별도 소스 디렉터리에서 비교·복사한다. `.git`을 복사하거나 GitHub main을 공식 main에 merge/cherry-pick하지 않는다. ZIP을 배포 수단으로 만들지 않는다.
|
||||
3. `.gitignore`, package/lock, `.storybook`, Component/Pattern/Theme, fonts/assets, scripts, examples/docs를 빠짐없이 반영한다. `node_modules`·dist·storybook-static·`_local`·실험 자료·개인 환경/비밀정보를 넣지 않는다.
|
||||
4. GitHub에 없는 공식 파일은 삭제 대상으로 간주하지 않는다. 양쪽에서 같은 경로를 변경했거나 삭제 후보가 있으면 소스/회사 설정의 용도를 확인해 결정한다. 일괄 미러링 삭제나 사용자 변경 덮어쓰기는 하지 않는다.
|
||||
5. 공식 작업 branch에서 설치·타입·build·Storybook과 변경 영향 검증을 수행한다. 실제 공식 assets/경로, 문서 링크와 staged diff를 확인한다. 필수 실패가 있으면 공식 반영을 보류한다.
|
||||
6. 회사의 review/branch 정책에 따라 공식 저장소에서 별도 commit하고 공식 기존 이력에 반영한다. GitHub 임시 이력을 가져오거나 force push/reset/clean으로 맞추지 않는다. 공식 Local/Remote SHA와 working tree를 확인한다.
|
||||
7. 공식 이전·검증·원격 확인이 모두 끝난 다음 **별도 지시**로 GitHub 원격 연결을 해제한다. 먼저 `git remote -v`로 실제 이름/URL을 기록하고 공식 remote를 확인한다. 공식 clone의 origin이 Gitea라면 origin을 제거하지 않는다. GitHub URL을 가리키는 정확한 remote만 `git remote remove <확인한 GitHub remote 이름>`으로 제거하고 `git remote -v`를 다시 확인한다. GitHub 저장소·이력 자체는 삭제하지 않는다.
|
||||
|
||||
## 작업 환경
|
||||
|
||||
- 1순위 추천: 공식 Gitea에 접근 가능한 로컬 Git·Node.js 개발 환경.
|
||||
- 추천 이유: 공식 이력과 회사 전용 파일을 비교하고 설치·명령 실행·검증·staged diff 검토까지 같은 checkout에서 수행할 수 있다.
|
||||
- 사용 방식: 별도 이전 지시와 함께 이 문서, 최종 전체 SHA, 소스 목록, 로컬 release manifest를 전달한다. 실제 회사 네트워크·권한·도구 가용성은 월요일 확인한다.
|
||||
@@ -0,0 +1,139 @@
|
||||
# HMDesign Guard 정확도 수정 결과 — 2026-10-10
|
||||
|
||||
RESULT: PARTIAL
|
||||
|
||||
TARGET: `D:\디자인시스템\hmdesign`
|
||||
|
||||
범위: Guard 검증 로직·테스트·설명 문서. Runtime: React/Vite. Production과 기존 Storybook Reference를 독립 검사한다. Component/Pattern/Theme/Token/D-01/D-02/대표 Story와 이전 퍼블리셔 통합 보고서는 수정하지 않았다. Git 명령을 실행하지 않았다.
|
||||
|
||||
## Guard 문제 분석
|
||||
|
||||
| 항목 | 원인·판정·수정 |
|
||||
|---|---|
|
||||
| Dashboard Sidebar | 이전 Guard는 import graph의 모든 JSX를 실제 render처럼 취급했다. export entry의 `DashboardScreen mode="compact"` → `compact=true` → `sidebar=undefined`와, 사용되지 않는 Reference JSX initializer를 구분하지 못해 NAV-001 FAIL 및 NAV-005를 냈다. 직접 component 호출·기본/literal props·immutable local 값·반환 JSX/slot을 분석하여 현재 entry에서 배제되는 분기만 제외했다. 실제 Chrome DOM의 Sidebar는 0개다. |
|
||||
| Storybook Scope | 기존 Guard는 Production 전용이므로 Story 변경의 SCOPE-001은 검사 범위 불일치였다. 독립 `--profile STORYBOOK`을 추가했다. 설정의 literal stories glob으로 63개 Story module을 발견하고, 각 Story graph에 공통 preview를 연결한다. 다른 lazy Story의 CSS를 연결 증거로 사용하지 않는다. |
|
||||
| CSS Intent | 기존 REUSE-003은 위반 확정 FAIL이 아닌 검토용 NOT VERIFIED였다. Primary 80%·Secondary·Legacy·Dashboard Gradient를 바꿀 근거가 없다. 해당 판정을 유지하고, 누락됐던 내부 `tabs-*` slot도 검토 대상으로 포함했다. package 내부 Theme CSS는 기존 소비자 replica 검사에서 제외한다. |
|
||||
| Navigation Policy | GNB_ONLY/DASHBOARD_ONLY의 Sidebar 금지와 혼합 Navigation 금지는 유지한다. LNB_ONLY 정상 사용도 유지한다. 실제 선택되는 Reference Sidebar branch는 FAIL, 동적 조건/spread/mutation/opaque callback은 가능한 위반을 NOT VERIFIED로 남긴다. 여러 호출 중 하나라도 확정 위반이면 FAIL이다. 공식 Sidebar를 component prop으로 전달해 렌더하는 경우도 탐지한다. |
|
||||
| Production Graph | bootstrap import graph와 공개 package API 경계는 보존한다. Story/helper/reference 소비는 계속 FAIL이다. package Component/Pattern/Theme source는 소비 graph로 강제 포함하지 않는다. 직접 선택한 package CSS는 SCOPE-001 NOT VERIFIED이며 패키지 build/typecheck 및 별도 CSS/실제 렌더 확인으로 구분한다. |
|
||||
|
||||
### 실제 렌더·조건·Reference 구분
|
||||
|
||||
- 실제 `<DashboardSidebar>` 또는 금지 `sidebar` slot을 반환하는 literal 경로: FAIL.
|
||||
- 조건이 미확정인 Sidebar: NOT VERIFIED. PASS로 숨기지 않는다.
|
||||
- 현재 compact literal props로 배제된 분기·반환되지 않는 Reference JSX 값: 현재 Navigation 위반에서만 제외한다. import/export/CSS 검사는 유지한다.
|
||||
- Reference라는 주석·파일명·Sidebar 문자열만으로 Production 사용을 허용하지 않는다. 같은 보존 분기를 선택하면 FAIL이다.
|
||||
- Storybook Reference의 Navigation API는 mode 미지정 시 NOT APPLICABLE이다. 명시 mode를 주면 기존 정적 금지 규칙을 검사한다. Story별 대표/verification 분류·모든 상태의 혼합 Navigation 의도를 자동 승인하지 않는다. 신규 업무 화면의 Story 등록 금지는 그대로다.
|
||||
|
||||
## 원인 분류
|
||||
|
||||
**실제 위반:** 이번 제공된 Production entry에서 확정한 신규 디자인 시스템 위반은 없다. 회귀 fixture의 실제 Sidebar·혼합 Navigation·비공개 import·위조 public slot·Production의 Story 의존은 FAIL을 유지한다.
|
||||
|
||||
**오탐:** Dashboard compact에서 mount되지 않는 legacy Sidebar branch의 NAV-001. 현재 mode로 빈 slot을 증명할 수 있는데 NAV-005를 내던 분석 한계. Story 변경의 SCOPE-001은 기존 전용 범위 불일치이며 독립 Storybook 검사로 해결했다.
|
||||
|
||||
**검증 불가:** CSS override의 승인/복제 의도, native control의 합법적 사용 의도, opaque/dynamic render flow, 독립 package source를 소비 Guard로 검사하는 범위, 전 Story/모든 browser/state의 runtime 회귀.
|
||||
|
||||
전체 Storybook의 `src/patterns/gnb.stories.tsx:406`은 공개 컴포넌트가 없는 내부 `lnb-mobile-nav` wrapper를 사용한다. 기존 [GNB Composition 계약](../patterns/gnb.md#15-gnb-only-sidebar-composition-2026-10-08)에도 있는 Reference이며 소비자 복제로 확정할 수 없다. Storybook에서만 이 종류를 REUSE-001 NOT VERIFIED로 분류한다. 같은 코드의 Production 사용은 FAIL이며, Storybook에서도 공개 component slot을 기본 HTML로 위조하면 FAIL이다. 파일별 허용 목록·무조건 PASS는 추가하지 않았다.
|
||||
|
||||
## 수정 파일
|
||||
|
||||
| 파일 | 변경 내용·이유 |
|
||||
|---|---|
|
||||
| [Guard](../../scripts/ai-generation-guard.mjs) | 독립 Storybook profile/preview 연결·진단 범위, Navigation 분석 연결, 내부 Reference wrapper의 검토 판정, tabs slot intent 인식, 검사 파일 목록. Production 규칙을 삭제하지 않고 근거의 확실성을 구분한다. |
|
||||
| [Navigation 분석기](../../scripts/guard-navigation-analysis.mjs) (신규) | 소비 코드를 실행하지 않는 제한된 render-value 분석. immutable literal props/locals만 absent를 증명한다. 미지원 흐름·callback·spread·mutation·alias·비원시 identity에는 불확실성을 유지한다. |
|
||||
| [회귀 테스트](../../scripts/ai-generation-guard.test.mjs) | 기존 14개 본문을 그대로 보존하고 22개 test를 추가한다. |
|
||||
| [Guard 정책 문서](ai-generation-guard.md) | 두 profile과 Component/Pattern 경계, 조건부 Navigation, Reference wrapper, CSS intent/utility 제한, exit 0 ≠ PASS 설명. |
|
||||
| 이 보고서 (신규) | 분석·명령·결과·보존·미검증 근거 기록. 이전 보고서를 덮어쓰지 않는다. |
|
||||
|
||||
## 추가 테스트
|
||||
|
||||
- 기존 테스트: 14개, 기존 본문 byte 내용(개행 정규화 대조) 유지, 14/14 PASS.
|
||||
- 신규 테스트: 22개. compact/default/literal/alias/barrel props, 실제 Reference 선택, 미확정 조건, 다중 호출, literal ternary/logical, spread·mutation·callback·destructuring·객체 alias, 혼합 Navigation 및 PARTIAL, Storybook discovery·공개 export·CSS entry·lazy CSS 격리, Reference wrapper, 정상 Gradient 파싱, malformed CSS·위조 slot, raw CSS import, package scope, component prop Sidebar 전달을 포함한다.
|
||||
- 전체 테스트: 36/36 PASS.
|
||||
- 실패 테스트: 0. 개발 중 테스트가 드러낸 누락은 최종 코드에서 수정했다. 성공한 최종 검증은 추가 변경이 없으면 반복하지 않았다.
|
||||
|
||||
## 최종 검증
|
||||
|
||||
| 항목 | 결과·실제 실행 근거 |
|
||||
|---|---|
|
||||
| GUARD_TEST | PASS — `node --test scripts/ai-generation-guard.test.mjs`, 36/36. |
|
||||
| GUARD_FULL_SCREEN | NOT VERIFIED — 운영 GNB_ONLY, Dashboard/Recruit DASHBOARD_ONLY 모두 FAIL 0. 각 Navigation·Production 격리·CSS entry·공개 import 그룹은 PASS. 각 11건의 잔여는 REUSE-003 10건 + RENDER-002 1건이다. |
|
||||
| GUARD_PARTIAL | NOT VERIFIED — 운영 CSS와 Dashboard composition 각각 RENDER-002 1건. Publisher 두 Story는 독립 profile에서 PASS. package Tabs CSS는 SCOPE-001 1건으로 독립 소비 검사가 아님을 명시한다. |
|
||||
| GUARD_STORYBOOK | NOT VERIFIED — 전체 63개 Story module의 graph 검사, FAIL 0. 공개 import·격리 profile·CSS entry 그룹 PASS, Navigation NOT APPLICABLE. 내부 Reference wrapper 1건, CSS intent 16건, native control 19건을 유지한다. Publisher 두 Story PARTIAL은 PASS. |
|
||||
| TYPECHECK | PASS — `npm run typecheck`, 사전 Theme/package 검사 및 루트·workspace TypeScript 검사 exit 0. |
|
||||
| UI_BUILD | PASS — 위 pretypecheck의 `npm run build:packages`가 UI/Center Graphic build를 수행했다. 동일 package build를 다시 실행하지 않았다. |
|
||||
| PRODUCTION_BUILD | PASS — `npm run build --ignore-scripts`; Dashboard 기존 Vite config build + `node scripts/finalize-dashboard-export.mjs`; Recruit 기존 Vite config build. 모두 exit 0. 이미 끝난 사전 package/Theme 검사는 중복하지 않았다. |
|
||||
| STORYBOOK_BUILD | PASS — `npm run build-storybook --ignore-scripts`, exit 0, 291개 Story ID 산출물. |
|
||||
| TEST | NOT VERIFIED — 일반 `test` script/Component unit runner가 없다. 지원되는 Guard suite는 GUARD_TEST에 별도로 기록한다. |
|
||||
| CSS_IMPORTS | PASS — source CSS 78개·import 63건, 미해결 0. `index.css → tailwind.css`, 공개 UI Tailwind/Theme/status entry, compiled UI `@source "./index.js"` 존재, flex/grid/min-w-0/px-0/py-6 생성 및 관련 React 계산값 확인. |
|
||||
| EXPORTS | PASS — runtime 공개 import 688건, 누락 0; 공개 export 산출물 16개 모두 존재. source barrel/API는 미변경. |
|
||||
|
||||
지원되지 않는 전용 Component/Pattern Guard profile, 전체 Story별 runtime/state/포인터 검사와 과거 pixel diff는 NOT VERIFIED다. 존재하지 않는 명령을 통과로 기록하지 않는다. 기존 Tailwind `bg-[var(...)]` 최적화 경고와 production 500kB 초과 chunk 경고는 그대로이며 build 실패가 아니다.
|
||||
|
||||
### 실제 Guard 명령
|
||||
|
||||
```sh
|
||||
node scripts/ai-generation-guard.mjs --target . --scope FULL_SCREEN --mode GNB_ONLY --result index.html --json
|
||||
node scripts/ai-generation-guard.mjs --target . --scope FULL_SCREEN --mode DASHBOARD_ONLY --result src/exports/dashboard/index.html --json
|
||||
node scripts/ai-generation-guard.mjs --target . --scope FULL_SCREEN --mode DASHBOARD_ONLY --result src/exports/recruit/index.html --json
|
||||
node scripts/ai-generation-guard.mjs --target . --scope PARTIAL --mode GNB_ONLY --files src/index.css,tailwind.css --result index.html --json
|
||||
node scripts/ai-generation-guard.mjs --target . --scope PARTIAL --mode DASHBOARD_ONLY --files src/patterns/dashboard-composition.tsx --result src/exports/dashboard/index.html --json
|
||||
node scripts/ai-generation-guard.mjs --target . --profile STORYBOOK --scope FULL_SCREEN --json
|
||||
node scripts/ai-generation-guard.mjs --target . --profile STORYBOOK --scope PARTIAL --files src/components/tabs.stories.tsx,src/patterns/page-header.stories.tsx --json
|
||||
node scripts/ai-generation-guard.mjs --target . --scope PARTIAL --files packages/ui/src/theme/tabs.css --json
|
||||
```
|
||||
|
||||
### 실제 React 확인
|
||||
|
||||
로컬 Chrome에서 실제 build 산출물을 확인했다. Dashboard/Tabs/PageHeader의 대표 확인 범위이며 전체 291개 Story를 다시 렌더했다는 주장이 아니다.
|
||||
|
||||
- Dashboard: Sidebar 0개, Header 48px, layout min-width 960px, body flex. Token 기반 20/50/80% gradient 유지. 완료 필터 클릭으로 `완료 업무 12건`과 선택 상태·Table 갱신 확인. 390px에서 document 390px, frame client 390/scroll 960, overflow-x auto. Console error/warn 0.
|
||||
- Tabs 1280/390px: Primary `color(srgb 1 1 1 / 0.8) → rgb(245,240,229)`, opacity 1. Secondary White→White. Fill active panel 7개 모두 24px 0 / transparent / border 0 / radius 0. Card 탭 전환 후 입력 초안 보존. document width 1265/375px(세로 scrollbar 제외), 가로 넘침 없음. Console error/warn 0.
|
||||
- Legacy Compatibility: 기존 non-fill 2개가 gradient none / White / panel border 1px / padding 16px. surface-only Secondary Fill은 평면 패널 유지.
|
||||
- PageHeader 1280/390px: 설명 margin-top 8px, Header margin-bottom 20px, panel 24px 0, Primary alpha .8. `완료 업무` 클릭 시 완료 Table로 전환, 문서 폭 1280/390px.
|
||||
- 브라우저 임시 viewport를 복원하고 검증 탭과 loopback 서버를 종료했다. source 화면/API를 바꾸지 않았다.
|
||||
|
||||
## 보존 확인
|
||||
|
||||
| 항목 | 결과 |
|
||||
|---|---|
|
||||
| D-01/D-02 | PASS — Tabs CSS/Story·PageHeader Story source hash 동일. 공식 Tabs source/dist CSS 동일. 실제 위 패널·Gradient·Legacy 렌더 보존. |
|
||||
| Component/API | PASS — 기존 Component/Pattern TSX·공개 barrel·package.json·lockfile hash 동일. |
|
||||
| Theme/Token | PASS — Theme JSON/계약/CSS source hash 동일, 기존 check:theme-defaults의 71색/73 defaults 일치. |
|
||||
| Storybook ID | PASS — Story source/export 미변경, 291개 현재 ID 산출물 및 기존 inventory 288개 ID 모두 보존. |
|
||||
| 참고 원본 | PASS — 3개 파일 SHA-256 동일, 읽기 전용 유지. |
|
||||
| 기존 파일 | PASS — 시작 source 504개 중 Guard·테스트·Guard 문서 3개만 변경, 나머지 501개 동일. 분석기·이 보고서는 신규다. 이전 통합 보고서/기존 작업을 보존했다. |
|
||||
|
||||
파일 목록·SHA-256·수정 전 사본은 `_local/guard-accuracy-2026-10-10/`: `_local/guard-accuracy-2026-10-10/` (당시 로컬 보관 증거, Git Clone 미포함)에 보존했다. node_modules·빌드 산출물·tsbuildinfo·기존 _local·Git metadata는 source baseline에서 제외했다. 빌드 산출물은 지원되는 기존 명령으로 재생성했고 source 보존과 구분한다. 해당 경로의 `baseline.json`, `reference-baseline.json`, `before/`, `tests-final.log`, `guard-summary.json`, `guard-*.json`, 각 build log, `static-audit.json`, `browser-evidence.json`, `preservation-final.json`이 이번 증거다. 이전 `_local/publisher-*` 로그/사본은 덮어쓰지 않았다.
|
||||
|
||||
## 남은 문제
|
||||
|
||||
- REUSE-003/004와 내부 Reference wrapper는 의도를 정적 코드만으로 확정할 수 없다. 실제 fixture·문서·사용 화면별 검토가 필요하다. 전체 Guard PASS로 표기하지 않았다.
|
||||
- RENDER-002는 tool의 브라우저 확인 요구를 나타낸다. 이번 대표 실제 렌더 증거와 원본 JSON 상태를 따로 기록한다. 브라우저 증거를 근거로 JSON을 임의 PASS로 덮어쓰지 않는다.
|
||||
- package source의 독립 Guard 범위는 지원하지 않는다. 패키지 typecheck/build/CSS declaration/hash/관련 렌더 검증은 별도 수행했다.
|
||||
- 일반 Component unit runner, 전 Story/Props/브라우저/state 회귀, 외부 소비 앱·배포·역사적 pixel diff는 NOT VERIFIED.
|
||||
- `.git`이 없는 폴더다. Git status/diff/HEAD 및 미커밋 구분은 NOT VERIFIED이며 파일 baseline으로 기존 작업을 보존했다.
|
||||
|
||||
## Git
|
||||
|
||||
```text
|
||||
Git Init: NOT EXECUTED
|
||||
Git Clone: NOT EXECUTED
|
||||
Local Commit: NOT EXECUTED
|
||||
Remote Push: NOT EXECUTED
|
||||
Git commands / remote changes: NOT EXECUTED
|
||||
```
|
||||
|
||||
## 최종 판단
|
||||
|
||||
- 기존 Dashboard Guard FAIL은 해결했다. 금지 Sidebar를 실제 선택하는 fixture는 계속 FAIL이다.
|
||||
- 실제 위반 탐지 능력은 기존 14개+신규 22개로 검증했다. 미확정 경로를 PASS로 숨기지 않는다.
|
||||
- 정상 D-01/D-02·Component/Pattern/Theme/Storybook source를 수정하지 않았고 지원되는 build/typecheck 및 대표 실제 렌더에서 회귀를 발견하지 않았다. 전수 runtime 회귀는 NOT VERIFIED다.
|
||||
- 로컬 Git 커밋은 보류한다. Git metadata 부재와 잔여 NOT VERIFIED 검토를 다음 단계에서 별도로 판단해야 한다. 이번에는 Git 작업을 수행하지 않았다.
|
||||
|
||||
## 작업 시간 (Asia/Seoul)
|
||||
|
||||
- Started At: 2026-10-10 00:14:14 KST
|
||||
- Completed At: 2026-10-10 00:48:42 KST
|
||||
- Actual Duration: 34분 28초
|
||||
- Estimated Duration: 45–65분
|
||||
- Variance: 예상보다 10분 32초–30분 32초 단축
|
||||
@@ -1,9 +1,13 @@
|
||||
# Navigation Single Mode Policy
|
||||
|
||||
> 기준 우선순위: 2026-10-10 추가 수정 요청의 확정 사항 → 충돌하지 않는 D-01/D-02 → 현재 HM Component/Pattern/Theme → 현재 Storybook/구현 → 과거 문서. [현재 추가 수정 기준](publisher-additional-review-2026-10-10.md). 미확정 값은 임의 확정하지 않으며 과거 검증 기록은 보존합니다.
|
||||
|
||||
2026-10-07 사용자 확정 정책. 이전 GNB/LNB/Dashboard 조합 기준을 대체한다. 2026-10-08 AI 신규 Production 업무 화면에서 LNB ONLY의 공식 LNB 생성을 허용하고 GNB ONLY·DASHBOARD ONLY의 Sidebar를 금지하는 최종 정책으로 정정했다. 기존 Component·Pattern·Storybook의 Sidebar/LNB 계약과 DASHBOARD ONLY의 기존 운영 계약은 유지한다.
|
||||
|
||||
**ONE PAGE = ONE NAVIGATION SYSTEM = ONE HEADER/NAVIGATION EXPERIENCE**
|
||||
|
||||
정책 충돌 테스트(T04)의 정상 응답 예: “요청한 GNB+LNB 혼합 구조는 단일 Navigation 정책과 충돌하므로 생성하지 않습니다. [모드 선택](#모드-선택)에 따라 GNB_ONLY 또는 LNB_ONLY 중 하나를 선택할 수 있습니다.” 충돌 인식·혼합 미생성·근거·대안·불필요 Component 미생성을 별도로 평가한다. 정상적인 구현 거부는 정책 준수 PASS이며 운영 화면 생성 성공률과 평균 디자인 점수의 분모에서는 제외한다. 단순 app 부재나 quota 오류는 정책 이해의 증거가 아니므로 NOT VERIFIED다.
|
||||
|
||||
## 적용 범위
|
||||
|
||||
AI 기반 코드 생성과 제안, 신규 페이지 구현, 기존 화면 수정, 프로토타입, Storybook 대표/PRIMARY Story, 실제 Production 구현 전체에 동일하게 적용한다. AI는 별도 요청이 없는 한 Navigation 조합을 생성하거나 제안하지 않는다. 별도 요청도 혼합 운영 구조를 자동 허용하지 않으며 정책 변경 또는 기술 검증의 목적을 먼저 구분한다.
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
# 퍼블리셔 추가 수정 반영 보고서 — 2026-10-10
|
||||
|
||||
작업 기준은 읽기 전용 `D:\디자인시스템\HMDesign-퍼블리셔-사전공유\HMDesign-퍼블리셔-추가수정요청.md`와 시작 HEAD `034e410efef0fdb5173d7a41aee65658b9068351`이다. 범위 BOTH, Runtime React. 이번 확정 요청 → 충돌하지 않는 D-01/D-02 → 공식 Component/Pattern/Theme → 현재 Storybook → 과거 문서 순으로 적용한다.
|
||||
|
||||
RESULT: PARTIAL. 확정된 구현 요청은 반영했으며 아래 실제 실행 검증은 통과했다. 스크린리더·실기기 터치와 정적 Guard의 확인 불가능 항목은 NOT VERIFIED로 남긴다. 과거 날짜별 증거는 보존한다. [배포 실행 안내](publisher-distribution-guide.md), [신규 실제 React 화면](../../examples/publisher-list/main.tsx), [Guard 정책](ai-generation-guard.md).
|
||||
|
||||
## 추가 요청 반영
|
||||
|
||||
| 영역 | 반영 결과 |
|
||||
|---|---|
|
||||
| 1. 목록형 검색 | 업무 목록, 채용 목록, Data Table/Filter Bar 예제에 PageHeader 밖·흰 Card 하나·조건→검색어→조회→초기화·8px 간격을 적용. 기본 구성 중앙, 추가 조건 구성 왼쪽. 구성 기준 class로 결정하며 공통 FilterBar 기본 배치는 유지. 조회 Solid Green·초기화 Outline Gray, 모바일 줄바꿈·버튼 행 우측 정렬. 입력 초안과 조회 적용값 분리. |
|
||||
| 2. Button | Gray 기준 #767676, Outline의 ink/border/hover 통일. 기존 destructive Red token으로 Standard Solid Red 표시. Dialog/Alert Dialog 취소·삭제 Solid. Hover/Focus/Disabled와 기존 Variant/API 유지. 명시적 Runtime 취소색 override도 유지하고 Reset 검증. |
|
||||
| 3. Storybook 스타일 | Typography의 기본·fallback·전체 stack 설명 분리. Color는 기존 Green/Brown/Orange 단계·HEX로 가로 배치, 기본색 강조. Label Input/Select 조합, Toggle 단독/단일·다중 그룹 비교. Tabs States 896px·20개 탭·이동 버튼. PageHeader 기본/Breadcrumb 비교. 기존 ID 유지. |
|
||||
| 4. Component 스타일 | Table Hover/Selected/Selected+Hover만 #BDDFD4 20%, Checkbox 및 다른 공유 강조색 유지. Progress 내부 막대 우측 radius, consumer text가 막대를 밀지 않도록 내부 indicator 위치 고정. Accordion 제목 Hover Black 5%, 본문 유지. 제목+설명 뒤 Separator 하나, 공통 Separator API 유지. |
|
||||
| 5. Sheet/Drawer | 네 방향 모두 안쪽 모서리만 기존 control radius token 재사용(현재 4px), 최종 수치로 확정하지 않음. 모바일 GNB/LNB는 기존 Sheet 사용. Drawer 데스크톱 우측 취소→실행, 모바일 전체 폭 실행 위·취소 아래. 기존 Vaul drag 계약 유지. |
|
||||
| 6. Navigation | Reference GNB+콘텐츠 LNB의 기본 icon 제외·선택 icon 허용, 같은 body 배경·세로선 하나·해당 Green/Brown 계열 선택/hover. 화살표 보존. 기존 Green LNB 펼친 그룹만 Black 8%, 전체 opacity 유지. 새 화면은 GNB_ONLY 및 GNBMobileMenu, Sidebar 없음. |
|
||||
| 7. Storybook 환경 | Create a new story 액션만 숨김, 검색/필터/설정/도움말 유지. Designer Playground internal 태그로 일반 메뉴 제외, decorator를 해당 Story로 제한하여 임시 Theme 유출 방지. 메뉴 키보드 전환 문제는 실제 재현 후 outgoing Content exit animation만 최소 수정. |
|
||||
| 8. React 기능 | C2~C5, PT1~PT2, R1~R3의 수정·재현·회귀 근거는 아래 표 참조. |
|
||||
| 9. 문서/배포 | 관련 계약·설명·링크·수량·실행 주소 정리. 독립 React GNB 사용자 목록 추가. 실제 CSS 진입점의 Tailwind source 연결 보완. 소스+compiled packages+Storybook+업무 화면+실행 안내를 ZIP으로 묶고 별도 압축 해제본에서 설치·열람·새 화면 제작/실행 확인. |
|
||||
|
||||
## 기능 수정과 재현
|
||||
|
||||
| ID | 재현 및 최소 수정 | 검증 |
|
||||
|---|---|---|
|
||||
| C2 | 기존 Checkbox/Progress asChild의 소비자 content 소실 재현. 단일 consumer element에 content와 내부 indicator를 합성. 기본 모드와 form 사용 유지. | 실제 TSX 렌더 테스트, hidden 회귀 Story, 브라우저 consumer text/indicator 확인 PASS |
|
||||
| C3 | 소비자 style이 내부 gap 변수를 덮는 문제 재현. 내부 변수→consumer style 병합, consumer 우선 계약 유지. | 소비자 색/style과 spacing 동시 유지 PASS |
|
||||
| C4 | CENTER railway existing 분기의 style/ID/ARIA 유실 재현. 최종 요소에 나머지 DOM props 한 번 전달. | 실제 React 렌더 테스트·타입 검사 PASS |
|
||||
| C5 | 반복 Combobox/Date Picker 이름 연결/ID 경계 확인. useId로 기본 trigger/popup ID, controls/label 연결, consumer label/id 우선 유지. cmdk list의 label prop 사용. | 반복 인스턴스 중복 ID 0, 팝업 접근성 이름/검색 영역 연결 PASS. 실제 SR 발화 NOT VERIFIED |
|
||||
| PT1 | 두 표의 페이지 크기 label ID 중복 재현. useId로 인스턴스별 label 연결. | 다중 표 렌더 테스트 PASS |
|
||||
| PT2 | readOnly·disabled 검색 값이 clear로 변경되는 문제 재현. 해당 상태에서는 clear 미제공. | 보호 상태/일반 editable clear 렌더 테스트와 브라우저 PASS |
|
||||
| R1 | 필수 Theme/Tailwind/status CSS 누락 검출 보완. 실제 경로가 확정된 누락은 FAIL, 그래프 해석 불가는 NOT VERIFIED. | 기존 36개 테스트 보존(정책 변경에 맞춘 누락 기대값 수정), 4개 추가 = 40/40 PASS |
|
||||
| R2 | 배포 선언이 참조하는 table-core를 직접 의존성으로 제공. 소비자 설치에서 react-table/core 버전 차이로 발생한 타입 실패도 재현, 두 의존성을 같은 9.2.4로 고정. | 재빌드·npm pack·독립 소비자 설치·skipLibCheck:false 엄격한 타입 검사 PASS |
|
||||
| R3 | 포인터/자동 실행과 키보드 focus 조건 차이 재현. parity 검사 중 specimen의 inert를 적용하고 실제 키보드 focus 검사 때 해제. 시작 방법을 판별해 자동·포인터는 focus NOT VERIFIED. | 자동 136개 검사 PASS + focus NOT VERIFIED, Tab/Enter 실행 138개 검사·58개 parts PASS |
|
||||
|
||||
컴포넌트 테스트는 동일한 실제 TSX를 Vite로 변환한 뒤 React로 렌더한다. 수정 전 6개 실패를 보존하고 수정 후 8/8 통과를 확인했다. Menubar는 ArrowRight/ArrowLeft 전환에서 새 메뉴가 즉시 닫히는 문제를 브라우저에서 재현했다. 기존 공개 API를 유지하며 닫히는 popup의 exit animation만 제거했고 양방향 키보드·포인터 전환을 확인했다.
|
||||
|
||||
## 최종 통합 검증
|
||||
|
||||
| 항목 | 결과 및 범위 |
|
||||
|---|---|
|
||||
| TYPECHECK | root/UI/CENTER 및 신규 예제 PASS |
|
||||
| UI_BUILD | 공개 UI/CENTER 패키지 빌드 PASS |
|
||||
| PRODUCTION_BUILD | 업무 앱, Dashboard export, 채용 export, 신규 사용자 목록 PASS |
|
||||
| STORYBOOK_BUILD | 최종 static Storybook PASS. 65개 PRIMARY 대표 Story 실제 React 렌더 확인. |
|
||||
| GUARD_TEST | 40/40 PASS, 기존 36개 케이스 보존 |
|
||||
| COMPONENT_TEST | 8/8 PASS |
|
||||
| ACCESSIBILITY | Label 연결, 반복 popup/페이지 label ID, 메뉴 키보드, 모바일 GNB Escape/focus 복귀, Theme 실제 키보드 Focus PASS. 실제 스크린리더·실기기 터치 NOT VERIFIED. |
|
||||
| VISUAL_CHECK | 업무 목록/채용/사용자 예제 390·768·1280·1440px, 변경 Story의 desktop/mobile, Tabs 내부 넘침, Sheet 4방향, Drawer 두 배치, Table/Accordion/Progress/Navigation 계산 스타일 확인 PASS. 모든 viewport·모든 Story 조합을 검사했다는 의미는 아님. |
|
||||
| PACKAGE_CONSUMER_TEST | npm pack된 공개 패키지 독립 설치 및 엄격한 타입 검사 PASS |
|
||||
| PORTABLE_STORYBOOK | ZIP 압축 해제본의 실제 start-preview.bat, Node 20.20.1, Component/Pattern/Theme 열람 PASS |
|
||||
| AI_SCREEN_GENERATION | 기존 공개 HM 컴포넌트로 새 GNB_ONLY React 화면 생성·실행·조회·초기화·390px 줄바꿈/표 내부 스크롤 PASS. ZIP에서 새 폴더에 복사 후 typecheck/build/run도 PASS. |
|
||||
| 생성 Guard | 새 화면 FULL_SCREEN GNB_ONLY, 업무/Story 소비 조합 PARTIAL: FAIL 0, 일부 NOT VERIFIED. 상속 tsconfig 해석·승인된 slot 소비 스타일·React 렌더는 Guard 정적 판정 한계로 남김. 소스/브라우저 추가 확인을 PASS로 대체 기재하지 않음. 최종 실제 CSS 진입점 PARTIAL 검사도 FAIL 0·NOT VERIFIED. |
|
||||
| 정적 감사 | 내부 MD 링크/heading, CSS import, 공개 import/export artifact 확인. 누락 없음. 최신 수량은 최종 로컬 증거를 기준으로 함. |
|
||||
|
||||
Tailwind는 실제 `src/index.css`의 `source("./")` 및 공개 HM CSS의 자체 compiled 폴더 검색을 사용한다. Windows에서 source(none)+파일 glob 및 compiled index.js 단일 경로가 utility를 누락하는 상태를 재현했다. package build의 배포 source를 `./`로 바꾼 뒤 display:flex, flex-wrap:wrap, 표 overflow:auto, 페이지 390px 폭과 실제 Focus ring을 확인했다. 이 소비 환경 수정은 공통 Component CSS로 넘침을 감춘 것이 아니다. [Tailwind 공식 소스 검색 계약](https://tailwindcss.com/docs/detecting-classes-in-source-files).
|
||||
|
||||
## 보존 확인
|
||||
|
||||
- 시작 HEAD와 비교해 D-01/D-02의 Tabs 소스/CSS, Carousel 소스, default.json, Primitive/default Theme CSS 및 생성 default 값은 변경 없음. 신규 semantic/primitive token 없음. 확정 요청에 필요한 Component mapping만 수정.
|
||||
- 기존 공개 export 계약 유지. 실제 artifact export 수 UI 255 / Theme 8 / CENTER 25 / CENTER Reference 10.
|
||||
- 기존 291개 Story ID 삭제 없음. 현행 292개 중 추가 1개는 internal verification 회귀 Story. 인벤토리 65 PRIMARY / 227 HIDE. 신규 업무 화면은 Story 등록 없이 독립 React 앱.
|
||||
- 참고 원본에 쓰기 작업 없음. 참고 폴더 SHA256 감사 비교 변화 없음. 이전 D-01/D-02·과거 검증 로그와 증거는 당시 기록으로 보존.
|
||||
- 공식 Gitea: NOT ACCESSED / NOT MODIFIED. GitHub main 일반 commit/push만 사용하며 결과 SHA와 로컬·원격 일치 정보는 최종 응답/로컬 보고서에 기록.
|
||||
|
||||
## 남은 문제와 배포 판단
|
||||
|
||||
확정 구현 요청은 완료. 미반영된 확정 사항 없음. 최종 Sheet radius 수치·Color의 상징적 의미·설정/도움말 숨김 범위는 요청대로 확정하지 않았다. 기존 drag 구현은 보존했으나 실제 손가락 drag 닫기와 SR 발화, Node가 없는 PC의 설치 절차는 NOT VERIFIED.
|
||||
|
||||
ZIP npm 설치에서 기존 shadcn 개발 도구 의존성에 High 7건이 보고됐다. 운영 의존성 `npm audit --omit=dev`는 0건이며 해당 개발 그래프 버전을 이번 변경에서 바꾸지 않았다. 강제 audit fix는 수행하지 않았다. 개발 도구 보안 정리는 별도 확인이 필요하다. 빌드의 500kB chunk/일부 bundler 성능 경고와 Storybook 내부 provider 안내는 남아 있다. 검증한 최종 화면에서 지속적인 앱 console error는 관찰하지 않았다.
|
||||
|
||||
정적 Storybook/예제 열람과 검증된 Node 환경의 소스 제작 배포는 가능하다. 기능·빌드·회귀 필수 검사 실패는 없으며 Guard/SR/실기기 미검증을 제품 인증이나 완전한 접근성 승인으로 해석하지 않는다. 이 제한을 포함해 RESULT는 PARTIAL로 보고한다.
|
||||
@@ -0,0 +1,60 @@
|
||||
# 퍼블리셔 Git 테스트 공유·실행 안내
|
||||
|
||||
현재 공유 기준은 [GitHub HMDesignSystemTest](https://github.com/shkim25027/HMDesignSystemTest)의 Git Clone입니다. 먼저 [AGENTS.md](../../AGENTS.md)를 확인합니다. 과거 ZIP 제작·압축 해제 검증은 [추가 수정 보고서](publisher-additional-review-2026-10-10.md)의 당시 기록이며 현재 설치 방법을 대체하지 않습니다. 이번 공유에는 신규 ZIP·포터블 패키지를 만들지 않습니다.
|
||||
|
||||
## 설치 조건과 Storybook 열람
|
||||
|
||||
lockfile의 Node 조건은 `^20.19.0 || >=22.12.0`이며 Node 21은 제외합니다. 검증 환경은 Windows, Node 20.20.1 / npm 10.8.2입니다. Git, Node/npm의 PATH와 버전을 확인합니다. 최초 설치에는 GitHub·npm 레지스트리 접속이 필요합니다. HM Registry 설치·publish는 필요하지 않습니다.
|
||||
|
||||
```powershell
|
||||
git clone https://github.com/shkim25027/HMDesignSystemTest.git
|
||||
cd HMDesignSystemTest
|
||||
node --version
|
||||
npm --version
|
||||
npm ci
|
||||
npm run build:packages
|
||||
npm run storybook
|
||||
```
|
||||
|
||||
브라우저에서 **http://localhost:6024/** 를 엽니다. Components에서 기존 UI, Patterns에서 업무/Layout 조합, Foundation에서 Color/Typography를 확인합니다. 내부 Theme 비교는 `?path=/story/theme-runtime-contract--comparison`, JSON Loader 검증은 `?path=/story/theme-runtime-contract-loader--cdn-verification`입니다. Runtime Focus는 `?path=/story/theme-runtime-contract--verification`의 Run verification 버튼에 Tab으로 이동한 뒤 Enter/Space로 검사합니다. 자동·포인터 실행의 Focus는 `NOT VERIFIED`입니다.
|
||||
|
||||
기존 `start-storybook.bat`도 사용할 수 있습니다. 의존성·패키지 산출물이 없으면 기존 설치·빌드 명령을 실행하고 HM Story index/preview 준비 후 6024 주소를 엽니다. 포트 충돌 시 오류를 표시합니다. 종료는 실행 터미널의 Ctrl+C입니다. Git Clone에는 `node_modules`, 사전 빌드 Storybook, ZIP 실행기, 로컬 증거가 포함되지 않습니다.
|
||||
|
||||
## 새 React 화면 제작과 실행
|
||||
|
||||
위 설치·package build 후 별도 터미널에서 실행합니다.
|
||||
|
||||
```powershell
|
||||
npm run dev:publisher-example
|
||||
```
|
||||
|
||||
출력된 Vite 주소(기본 5173)를 엽니다. [실제 예제](../../examples/publisher-list/main.tsx)는 공개 `@hm-design/ui`의 GNB/GNBMobileMenu, PageHeader, Card, FilterBar, Select, Button, DataTable을 렌더링합니다. GNB_ONLY이며 Sidebar를 추가하지 않습니다. 예제 폴더를 새 경로에 복사한 뒤 제목·data·columns와 필요한 조합을 수정합니다. 임시 검증 화면은 공식 Story로 등록하지 않습니다.
|
||||
|
||||
검색 조건 → 검색어 → 조회 → 초기화 순서, 8px 간격, 기본 구성 중앙 정렬을 사용합니다. 기간·담당자 등 추가 조건을 제공하는 구성은 `hm-list-search-extended`를 사용합니다. 입력값으로 정렬을 바꾸지 않습니다. 모바일은 줄바꿈·버튼 우측 정렬·표 내부 가로 스크롤을 유지합니다.
|
||||
|
||||
예제 CSS는 `index.css → hm-theme.css`를 연결하며 `source("./")`로 실제 예제 폴더를 검색합니다. 공개 `@hm-design/ui/tailwind.css`는 자체 compiled 폴더를 검색합니다. 폴더·bootstrap을 옮기면 CSS 상대 경로와 Vite/tsconfig 경로도 함께 확인합니다. 공통 Component 스타일을 변경해 가로 넘침을 감추지 않습니다. 루트에서 예제 검증 명령은 다음과 같습니다.
|
||||
|
||||
```powershell
|
||||
npm run build:publisher-example
|
||||
node node_modules/typescript/bin/tsc -p examples/publisher-list/tsconfig.json
|
||||
node scripts/ai-generation-guard.mjs --target examples/publisher-list --scope FULL_SCREEN --mode GNB_ONLY --result index.html
|
||||
```
|
||||
|
||||
복사한 화면은 해당 Vite config로 build/dev를 실행하고 Guard의 `--target`을 새 경로로 지정합니다. Guard는 정적 계약만 확인합니다. `NOT VERIFIED`는 소스 검토와 실제 React 브라우저의 utility·레이아웃·조회/초기화·모바일 메뉴 동작으로 별도 확인합니다. [Guard 정책](ai-generation-guard.md), [Component 인덱스](component-pattern-reference.md), [예제 사용법](../../examples/publisher-list/README.md)을 따릅니다.
|
||||
|
||||
전체 소스 타입은 `npm run typecheck`, UI package는 `npm run build:ui`, 앱은 `npm run build`, 정적 Storybook은 `npm run build-storybook`으로 확인합니다. MD 내부 링크는 `node scripts/check-doc-links.mjs`로 검사합니다.
|
||||
|
||||
## Designer와 확정 Theme
|
||||
|
||||
Designer는 일반 검수 메뉴에서 제외된 내부 환경입니다. `http://localhost:6024/?path=/story/theme-designer-playground--editor`로 엽니다. 확정 컬러의 원본은 `themes/default.json`이며 임시 편집은 Designer와 같은 document의 Live Preview/Portal에만 적용됩니다. 다른 Story로 이동하면 override가 해제되어 HM Default로 검수합니다.
|
||||
|
||||
편집 데이터는 같은 탭의 sessionStorage에 보관됩니다. 편집기로 돌아오거나 새로고침하면 보관값을 다시 적용합니다. 일반 새 탭은 독립 세션이고 탭 복제/opener는 브라우저가 초기 세션을 복사할 수 있습니다. 이후 각 탭의 편집은 독립적입니다. 유효한 6자리 HEX는 즉시 적용되며 Apply 버튼은 없습니다. Reset to HM Default는 override와 저장 편집값을 비웁니다. JSON Import는 이전 값을 병합하지 않고 교체하며 잘못된 입력은 마지막 유효값을 유지합니다. 서버 저장·공식 Token 변경·CDN publish는 수행하지 않습니다. [상세 사용법](designer-theme-guide.md).
|
||||
|
||||
## 알려진 제한과 과거 기록
|
||||
|
||||
- 실제 데이터 연동·서버 저장은 예제 범위 밖입니다. 업무 화면은 예시 데이터와 브라우저 저장소를 사용합니다.
|
||||
- Dashboard는 최소 폭 960px과 내부 스크롤 계약을 유지합니다.
|
||||
- Sheet의 최종 radius 수치, 컬러 상세 의미, 설정·도움말 숨김 범위는 미확정입니다.
|
||||
- 스크린리더 발화·실기기 touch/drag·Node 미설치 PC 설치는 별도 검증 대상입니다.
|
||||
- 2026-10-10 npm 감사에서 개발 의존성 High 7건, 운영 의존성 0건을 확인했습니다. 직접 개발 의존성 shadcn의 간접 braces 경로이며 [공식 보안 권고](https://github.com/advisories/GHSA-vfj7-8cjw-p6xm)는 패치 버전이 없다고 명시합니다. 안전한 패치로 해결할 수 없어 package/lockfile을 유지했습니다. 강제 major 변경은 보류합니다.
|
||||
- 과거 로컬 증거는 `_local/`에 보관되고 Git Clone에 포함되지 않습니다. 당시 기록을 새 PASS 근거로 재사용하지 않습니다. [과거 포터블 안내](portable-test-distribution.md)는 역사적 자료입니다.
|
||||
@@ -0,0 +1,336 @@
|
||||
# 퍼블리셔 사전공유 통합 보고 — 2026-10-09
|
||||
|
||||
> 최신 실제 구현 결과는 [후속 실제 구현 결과](#후속-실제-구현-결과)를 따른다. 아래 최초 기록의 보류·100% 유지·검증 수치는 21:57:22 이전 문서 통합 작업의 이력이며, 후속 요청 이후 현재 구현을 대신하지 않는다.
|
||||
|
||||
## 최초 문서 통합 결과 (이력)
|
||||
|
||||
RESULT: PARTIAL
|
||||
|
||||
REFERENCE: `D:\디자인시스템\HMDesign-퍼블리셔-사전공유` (읽기 전용)
|
||||
|
||||
TARGET: `D:\디자인시스템\hmdesign`
|
||||
|
||||
범위: `STORYBOOK_ONLY` / React. 문서와 기존 Storybook Reference에 실무 조합 지식을 통합한다. Production Component·Pattern 구현, 공개 API, Theme·Token 값과 기존 대표 디자인은 유지한다. PARTIAL은 D-02의 공통 Theme 적용 및 외부 소비 화면 검증을 보류한 결과이며, 이번 문서·Usage 보강의 실패를 뜻하지 않는다.
|
||||
|
||||
## 분석 결과
|
||||
|
||||
참고 폴더 전체는 `디자인변경-사전공유.md` v0.2와 `images/01-panel-before-after.png`, `images/02-gradient-before-after.png` 3개 파일이다. 문서 전체와 두 이미지를 확인했다. 별도 Component·Pattern·Story 소스나 원본 예시 앱은 제공되지 않았다. 이미지의 탭 개수·배치·임시 간격을 새로운 규칙으로 추정하지 않는다.
|
||||
|
||||
현재 대상의 AGENTS·README·주요 guideline, Component/Pattern 인덱스, Foundation/Theme/Storybook 구조와 공개 export·CSS entry를 확인하고, 참고 문서가 지정한 Tabs·Card·Table·PageHeader의 실제 API/CSS/대표 Story를 집중 대조했다. 관련 없는 모든 Component의 전수 동작 검증을 수행했다는 의미는 아니다. 참고 자료가 없는 나머지 규격은 기존 공식 문서를 유지한다.
|
||||
|
||||
| 사전공유 항목 | 수정 전 분류 | 근거 / 처리 |
|
||||
|---|---|---|
|
||||
| D-01: 불필요한 탭 패널 박스 제거 | 부분 반영됨 | TabsContent 자체는 이미 무배경·무border. 기본 문서와 상태 specimen은 별도 박스를 사용. 문서·Usage에 평면 조합 추가 |
|
||||
| White Card 안은 surface, 페이지 content 면은 content | 부분 반영됨 | 기존 `panelSurface` API와 CSS 존재. 상황별 선택·상위 표면 책임·content Card 예외 안내 보강 |
|
||||
| 각 패널 padding 24px 0 | 미반영 | 기존 기본 예제 `p-4` / bordered panel. 새 Usage와 권장 기본 예제 `px-0 py-6`; 전역 spacing 규칙으로 승격하지 않음 |
|
||||
| 바깥 Card 유지 / Input·Table·Alert 고유 스타일 보존 | 부분 반영됨 | 기존 Component 스타일은 존재. 패널 제거 적용 범위와 Do / Don't를 명시 |
|
||||
| D-02: Primary 상단 White 80% | 현재 구현과 충돌 | 공통 `tabs.css`는 100%. 원본은 방향 승인·국소 예시 적용·최종 요청서 대기. 공통 변경 보류 및 현재 값·목표 범위 구분 |
|
||||
| D-02의 방향·하단색·전체 opacity·Secondary·상태 보존 | 부분 반영됨 | 현재 CSS/동작 존재. alpha와 전체 opacity의 차이 및 향후 변경 제외 범위를 문서화 |
|
||||
| PageHeader 제목→설명 8px / 아래 콘텐츠 20px | 이미 반영됨 | `page-header.css`와 문서 일치. Tabs를 첫 콘텐츠로 배치하는 안내 보강 |
|
||||
| 기본 Card padding·Header→Content 24px | 이미 반영됨 | `card.css` / Card TSX와 문서 일치. `size="sm"` 12px 호환 범위 유지 |
|
||||
| CardDescription ≠ PageHeaderDescription | 이미 반영됨 | CardDescription shadcn 호환 범위가 이미 문서화. 조합 안내에서 연결, 신규 규격 미추가 |
|
||||
| 비교 예시의 48px·Card Token을 전역 gap으로 사용 | 현재 HMDesign 구조상 불필요 | 원본도 공통 변경에서 제외. Foundation의 전역 spacing scale 미정의와 일치 |
|
||||
| Radix 선택·키보드·focus·disabled·넘침 유지 | 이미 반영됨 | 기존 Tabs TSX / CSS / verification Story 유지. 새 Usage에도 접근 가능한 이름과 입력 Label 사용 |
|
||||
| utility 실적용 / desktop·mobile 넘침 확인 | 부분 반영됨 | 기존 검증 원칙 존재. 조합별 계산값과 확인 기준 연결 |
|
||||
| 참고 예시의 모바일 넘침·제목·Token 이슈 | 추가 확인 필요 | 예시 소스 미제공. 공통 Component 결함으로 단정하거나 무관한 구현을 수정하지 않음 |
|
||||
| Dashboard·Form·Search·Filter·Navigation·Empty/Loading/Error 새 규격 | 현재 HMDesign 구조상 불필요 | 원본에 새로운 계약 없음. 기존 Component/Pattern 선택 경로와 소비자 데이터 상태 책임만 안내 |
|
||||
| 원본 공통 Theme 및 모든 소비 화면 적용 | 추가 확인 필요 | 참고 문서도 미적용 / 전체 영향 미검증. 외부 화면의 파일·범위가 제공되지 않음 |
|
||||
|
||||
이미 반영된 내용은 기존 API·상태·Geometry·색상 연결·Typography·역할별 간격이다. 새로 반영한 내용은 상황별 조합, 패널 여백 소유권, 보존할 고유 스타일, 접근성·Responsive 실무 점검과 디자인 방향/출하 값의 구분이다.
|
||||
|
||||
## 수정 파일
|
||||
|
||||
| 파일 | 변경 이유 / 내용 |
|
||||
|---|---|
|
||||
| [README](../../README.md) | 실무 조합·보고서 진입 링크 추가. 존재하지 않는 AGENTS Quick Start anchor를 실제 필수 규칙 링크로 정정 |
|
||||
| [개발 적용 가이드](개발-적용-가이드.md) | Publisher/Developer 점검표, 역할별 간격·Theme·State·Responsive·Accessibility·AI 참조 연결. 현재 Story import 이름 명확화 |
|
||||
| [Tabs](../components/tabs.md) | 권장 기본 예제의 중첩 박스 제거, Card 조합·surface 선택·Do/Don't·입력 보존·D-02 보류 상태 추가 |
|
||||
| [Card](../components/card.md) | Tabs 안쪽 좌우 중복 여백 방지, surface별 연결과 small/Description/Meta 예외 구분 |
|
||||
| [PageHeader](../patterns/page-header.md) | 제목 아래 Tabs 조합 시 8px·20px 유지, 24px·48px 오용 방지와 Typography 역할 구분 |
|
||||
| [Tabs Story](../../src/components/tabs.stories.tsx) | 기존 All 안에 Card/page Usage와 Do/Don't 추가. 공개 Component 조합·입력 상위 state·고유 Label ID·Table 내부 스크롤 |
|
||||
| 이 보고서 | 참고 자료 전체의 비교 분류·보류·변경·검증 이력. 과거 2026-10-06 감사 기록을 덮어쓰지 않도록 날짜별 보고서 1개 추가 |
|
||||
|
||||
## MD / Component / Pattern / Storybook 보강
|
||||
|
||||
- MD: 기존 Tabs·Card·PageHeader·개발 가이드로 통합하고 공통 내용은 링크로 연결했다. 기존 Foundation·Theme·Navigation 문서를 복제하지 않았다.
|
||||
- Component: 새 Component/Variant/Props 불필요. 실제 `Card`, `CardHeader`, `CardTitle`, `CardContent`, `Tabs`, `TabsList`, `TabsTrigger`, `TabsContent`, `Input`, `Label`, `Textarea`, `Table` 계열을 공개 API에서 사용했다. Component 소스는 변경하지 않았다.
|
||||
- Pattern: PageHeader의 기존 margin과 역할별 Typography를 Tabs 조합에 연결했다. Pattern Runtime·Navigation 정책·Dashboard 최소 폭/내부 스크롤은 변경하지 않았다. Usage는 컴포넌트 조합 Reference로 새 업무 페이지가 아니다.
|
||||
- Storybook: 기존 `components-navigation-tabs--all`에 Usage / Do / Don't를 추가했다. 기존 Overview / Default API / Variants / States, 숨김 verification ID·대표 페이지 스타일·메뉴 구조는 유지했다. 원본 이미지를 복사하거나 새로운 독립 디자인을 만들지 않았다.
|
||||
|
||||
## 정합성 확인
|
||||
|
||||
- MD ↔ Component: TabsContent 무배경·무border, List 기본 fill/content와 실제 surface 선택, Card의 24px/default 및 12px/sm, PageHeader의 8px·20px을 코드와 대조했다.
|
||||
- Component ↔ Storybook: 기존 API·대표/verification Story 유지. 새 예제는 모두 공개 export로 렌더하며 폼 상태는 소비 조합에서 관리한다.
|
||||
- Component ↔ Theme/Token: 기본 Primary 상단 White 100%를 현재 값으로 안내한다. D-02 80%는 보류로 구분하며 Semantic·Mapping·Theme JSON·Token 값은 수정하지 않았다.
|
||||
- Pattern ↔ Storybook: PageHeader/Navigation/Dashboard 기존 계약을 유지한다. PageHeader 대표 Story의 8px·20px과 Tabs Usage의 표면·padding, Table 고유 스타일·내부 스크롤 범위를 실제 렌더에서 확인했다.
|
||||
|
||||
## 검증
|
||||
|
||||
아래는 이번 최종 통합 확인 결과다. 과거 문서의 PASS를 이번 결과로 재사용하지 않았다.
|
||||
|
||||
| 항목 | 이번 결과 |
|
||||
|---|---|
|
||||
| TYPECHECK | PASS — `npm run typecheck`의 사전 Theme/package 검증 후 workspace 연결 복구, `npm run typecheck --ignore-scripts` 통과. 최종 Story의 수축 클래스 보강 후 앱 TypeScript 검사 추가 확인 |
|
||||
| BUILD | PASS — `npm run build --ignore-scripts` (기존 사전 검증을 중복하지 않음). 최종 Production 소스는 이 빌드 이후 변경 없음 |
|
||||
| STORYBOOK_BUILD | PASS — `npm run build-storybook --ignore-scripts`. 모바일 Card 수축 수정 후 영향받는 Storybook 빌드만 다시 수행 |
|
||||
| TEST | PASS — `node --test scripts/ai-generation-guard.test.mjs`, 기존 14개 테스트 통과. 별도 일반 test script는 없음 |
|
||||
| LINT | NOT VERIFIED — 프로젝트에 lint script/config가 없음 |
|
||||
| DOC_LINKS | PASS — 수정 문서·신규 보고서의 로컬 경로/heading 링크 73개 확인 (외부 URL은 네트워크 검증 범위 밖) |
|
||||
| EXPORTS | PASS — 새 예제의 공개 UI import 18개 실제 package export 확인. 기존 Story export/ID 유지 |
|
||||
| CSS / THEME | PASS — `check:theme-defaults`의 JSON 71색/계약 73개 기본값 일치. Theme/Token/CSS source SHA-256 유지, 실제 panel utility 계산값 확인 |
|
||||
| GUARD | NOT VERIFIED — `node scripts/ai-generation-guard.mjs --target . --scope PARTIAL --files src/components/tabs.stories.tsx --json` 1회 실행. `SCOPE-001`: Story가 Production graph 밖. 신규 Production 화면 검사가 아니므로 Storybook을 억지로 Production entry로 지정하지 않음 |
|
||||
| VISUAL_CHECK | PASS (관련 범위) — 빌드된 Tabs / Card / PageHeader의 실제 Edge React 렌더, Tabs 1280×900·390×844, PageHeader 두 폭 확인. 전체 Component·브라우저 전수 검증은 NOT VERIFIED |
|
||||
| GIT_DIFF / 미커밋 상태 | NOT VERIFIED — 대상 및 상위 경로에 Git 저장소가 없음 |
|
||||
|
||||
### 실행 환경 복구와 경고
|
||||
|
||||
- 최초 타입 검사는 `node_modules/@hm-design/{ui,center-graphic}`의 Junction이 존재하지 않는 `D:\디자인시스템\HMDesign-main\hmdesign\packages\...`를 참조해 실패했다. 이전 링크를 각 `*.publisher-original-junction` 이름으로 보존하고 현재 대상의 `packages`로 연결했다. 로컬 소켓도 sandbox에서 차단되어 실제 검증 서버만 제한 밖의 **127.0.0.1:6025**로 실행했다. Source·Dependency 버전·lockfile은 변경하지 않았다.
|
||||
- Build/Storybook Build에는 기존 문서에서도 기록된 Tailwind `bg-[var(...)]` 최적화 경고와 500kB 초과 chunk 경고가 있다. 빌드는 exit 0이며 이번 작업에서 전체 CSS/번들 구조를 재설계하지 않았다.
|
||||
- Browser Console: Tabs 및 PageHeader 확인에서 error/warn 0건. 시각/계산값 확인은 정적 Guard와 별개로 수행했다.
|
||||
|
||||
### 실제 렌더 확인
|
||||
|
||||
- Tabs Usage의 두 패널: `background: transparent`, `border: 0px`, `padding: 24px 0px`, radius 0. Input 시작점은 패널 시작점과 일치하고 Input의 기존 1px border를 유지한다.
|
||||
- White Card: Card border 1px, 위/아래 padding 24px, CardContent 좌우 24px. Secondary 선택 면 White. 페이지 직접 배치: 기존 content 면 위 Primary, 상단 White 100% → content, 전체 opacity 1. Tab 높이 34px·16/24/700 유지.
|
||||
- 최초 새 Card Usage에서 Table 패널을 열었을 때 grid 자식 Card의 자동 최소 폭으로 모바일 문서 폭이 586px이 됐다. **새 조합의 Card 자체에 `min-w-0`**를 추가해 해결하고 문서에 같은 수축 조건을 안내했다. 공통 Card/Table을 수정하거나 Table 최소 폭을 낮추지 않았다.
|
||||
- 최종 모바일: viewport 390px / 문서 client=scroll=375px(브라우저 세로 scrollbar 제외), Card width 343px / 패널 293px, 페이지 패널 343px. Table min-width 520px / 내부 overflow-x auto / scrollWidth 520px. 문서 전체 가로 넘침 없음. Table의 가로 스크롤 가능 범위는 계산값으로 확인했으며 수동 scrollbar 이동은 NOT VERIFIED.
|
||||
- Desktop: viewport 1280px / 문서 client=scroll=1265px. 실제 클릭·ArrowRight·Home·End의 탭 전환, 상위 state의 입력 초안 보존, 3px focus-visible 링을 확인했다. 기존 넘침 버튼은 list 폭 192px / scrollWidth 605px에서 scrollLeft 0→36으로 이동하며 선택을 유지한다.
|
||||
- Card 대표 Story: surface/content, padding·gap 24px, Title 20/28/600. PageHeader 대표 Story: 설명 margin-top 8px / Header margin-bottom 20px / Title 28/36/700, desktop/mobile 문서 가로 넘침 없음.
|
||||
- 검증 화면: Desktop Usage: `_local/publisher-integration/desktop-usage.jpg` (당시 로컬 보관 증거, Git Clone 미포함), Mobile Table: `_local/publisher-integration/mobile-table.jpg` (당시 로컬 보관 증거, Git Clone 미포함). 로컬 스크린샷·baseline·검증 로그는 gitignore의 `_local/`에 둔다(소스 배포물에는 미포함).
|
||||
|
||||
## 기존 미커밋 파일 보존
|
||||
|
||||
시작 시 `git status --short`는 `not a git repository`로 실패했고 루트 `.git`이 없는 것을 확인했다. 커밋/미커밋 구분은 불가능하다. 기존 작업 삭제·reset·checkout·restore·clean은 실행하지 않았다.
|
||||
|
||||
수정 전 대상 파일 502개의 SHA-256 목록과 파일 사본을 `_local/publisher-integration/`에 보존했다. node_modules·빌드 결과·tsbuildinfo·기존 `_local` 등은 제외했다. 참고 원본 3개 파일은 별도 해시로 읽기 전용 보존을 확인한다. 새 빌드 산출물은 기존 gitignore 범위이며 Git 추가/커밋은 수행하지 않는다.
|
||||
|
||||
최종 해시 대조에서 기존 파일 중 변경은 위 6개 파일뿐이며 보고서 1개를 추가했다. 그 외 대상 기존 파일과 참고 원본 3개는 byte 단위로 동일하다. 기존 Tabs의 Overview / Default API / Variants / States 및 Compatibility 구역은 소스 비교로 동일함을 확인했다. Component·Pattern·Foundation·Theme·Storybook 설정·package/lockfile은 보존했다. 이는 Git diff를 실행했다는 의미가 아니다. 검증용 로컬 서버는 종료했다.
|
||||
|
||||
## 추가 검토 필요
|
||||
|
||||
- D-02 최종 적용 파일·범위·Theme 영향과 외부 소비 화면의 override/호환성. 요청서 확정 후 기존 content branch의 상단 stop만 검토한다.
|
||||
- 참고 예시 앱 소스의 모바일 넘침·제목·Token 조합. 현재 자료만으로 결함 위치를 확정할 수 없다.
|
||||
- 외부 프로젝트·전체 Component의 브라우저별 회귀·접근성/대비 전수 감사. 이번 관련 조합 확인 범위와 구분한다.
|
||||
|
||||
## 신규 Component / API가 필요하지만 보류한 항목
|
||||
|
||||
없음. D-01은 기존 Composition, D-02는 기존 CSS Mapping 범위로 해결 가능하다. 새 공개 opacity 입력·Theme Token·Responsive Variant를 만들 근거가 없다.
|
||||
|
||||
## 최종 판단
|
||||
|
||||
사전공유의 실무 지식은 기존 문서와 대표 Tabs Usage에 선별 통합했다. 공통 Theme의 80% 전환이나 모든 외부 소비 화면 적용은 완료로 표시하지 않는다. 현재 공식 구현이 가진 API·Theme·상태 규칙을 유지하면서, 소비자가 중첩 박스와 중복 여백을 피할 수 있는 확인 가능한 조합을 제공한다.
|
||||
|
||||
## 작업 시간 (Asia/Seoul)
|
||||
|
||||
- Started At: 2026-10-09 21:36:48 KST
|
||||
- Completed At: 2026-10-09 21:57:22 KST
|
||||
- Actual Duration: 20분 34초
|
||||
- Estimated Duration: 40–60분 (분석 15–20 / 보강 15–25 / 검증 10–15)
|
||||
- Variance: 예상보다 19분 26초–39분 26초 단축
|
||||
|
||||
## 후속 실제 구현 결과
|
||||
|
||||
RESULT: PASS (현재 대상의 명시적 D-01/D-02 구현 범위)
|
||||
|
||||
### 적용 근거와 영향 분석
|
||||
|
||||
- 참고 원본은 여전히 v0.2 문서와 이미지 2개이며 별도 ‘최종 요청본’ 파일은 없다. 사용자의 후속 요청이 이전 보류를 해제하고 D-01/D-02의 실제 구현을 명시하므로, 원문의 방향 승인/국소 적용 표기를 이유로 구현을 제외하지 않았다. 참고 파일은 수정하지 않았다.
|
||||
- 범위 `BOTH` / React: 공개 패키지의 Tabs CSS Mapping, 대표 Component/Pattern Story, 현행 문서. 새 Component·Pattern API·업무 페이지·Navigation을 만들지 않는다.
|
||||
- D-02의 적용 대상은 `[data-slot="tabs-frame"][data-fill="true"][data-panel-surface="content"]`가 설정하는 `--hm-tab-fill-face`이며, 실제 사용 CSS 속성은 Fill active trigger의 **background-image**다. 상단 `--hm-sem-palette-white`만 alpha 0.8로 합성한다. Gradient 방향/stop 0%·100%, 하단 content, 경계·전경·아이콘·전체 opacity는 유지한다.
|
||||
- 공통 흰색 Palette·Semantic·Theme JSON·다른 Component Mapping을 변경하지 않는다. Secondary(surface)는 불투명 White, Legacy non-fill은 기존 selected background·경계·조합을 유지한다. Hover·Focus·Disabled 상태 CSS와 Radix API/동작은 유지한다.
|
||||
- 수정 전 실제 TabsList 소비처는 `src/components/tabs.stories.tsx` 하나다. 신규 연결은 기존 PageHeader 대표 Story 내부이다. Production App·Dashboard·GNB·LNB에는 Tabs 소비처가 없으므로 불필요하게 이 화면을 수정하지 않는다. 외부 패키지 소비자는 같은 content branch 사용 시 새 face를 받으며 외부 override·코드 전수 확인은 자료 부족으로 ‘확인 필요’다.
|
||||
|
||||
### 모든 요청 재분류
|
||||
|
||||
| 요청 / 이전 분류 | 최종 분류 | 실제 반영 / 확인 범위 |
|
||||
|---|---|---|
|
||||
| D-01 중첩 박스 제거 / 부분 반영 | 반영 완료 | 모든 Fill 대표·verification panel의 border/background/radius 제거. Card Usage는 기존 바깥 Card 유지 |
|
||||
| 상황별 panelSurface / 부분 반영 | 반영 완료 | content 페이지는 Primary, White Card는 Secondary. 각 실제 부모 표면 연결 |
|
||||
| TabsContent 24px 0 / 미반영 | 반영 완료 | Fill 예제와 PageHeader Pattern 실제 panel에 px-0 py-6. 전역 Token으로 승격하지 않음 |
|
||||
| 바깥 Card·Input·Table·Alert 고유 스타일 / 부분 반영 | 반영 완료 | Component 고유 CSS·바깥 Card 유지. Tabs 패널 box만 제거 |
|
||||
| D-02 Primary 상단 White 80% / 충돌·보류 | 반영 완료 | 해당 Tabs content branch의 gradient 상단 stop만 alpha 0.8. 현재 문서·Story 설명도 80%로 갱신 |
|
||||
| D-02 하단/전체 opacity/Secondary/상태 보존 / 부분 반영 | 반영 완료 | 하단 content 불투명·전체 opacity 1, Secondary/Legacy와 상태 규칙 유지 |
|
||||
| PageHeader 8px·20px / 이미 반영 | 반영 완료 | 기존 Pattern + Tabs를 직접 합성. 제목/설명·Header/Tabs 실제 간격 확인 |
|
||||
| Card 여백·Header/Content 24px / 이미 반영 | 반영 완료 | Card Usage의 기존 기본 여백 유지, size=sm 호환 규격 미변경 |
|
||||
| CardDescription과 PageHeaderDescription 구분 / 이미 반영 | 반영 완료 | Description API·Typography 유지, 동일 규격 강제 없음 |
|
||||
| 비교용 48px·Card Token 전역 재사용 제외 / 불필요 | 반영 완료 | 원문의 제외 지침 준수. 새 전역 spacing 규칙 미추가 |
|
||||
| 선택·키보드·focus·disabled·넘침 / 이미 반영 | 반영 완료 | Component TSX·API·상태 CSS 보존 및 관련 브라우저 검증 |
|
||||
| utility 실적용·desktop/mobile 확인 / 부분 반영 | 반영 완료 | 최종 빌드의 1280px·390px 계산값·화면·동작 확인 완료 |
|
||||
| 참고 예시 원본 모바일·제목·Token 이슈 / 추가 확인 | 확인 필요 | 예시 소스 미제공. 현재 대상의 관련 조합은 직접 검증하지만 외부 원본 앱 수정 완료로 표시하지 않음 |
|
||||
| Dashboard/Search/Filter/Navigation/Empty 등 신규 규격 / 불필요 | 반영 완료 | 원본에 변경 요청 없음. 기존 Component/Pattern 규칙을 유지하라는 범위 제한 준수 |
|
||||
| 모든 외부 소비 화면 반영·전체 영향 / 추가 확인 | 확인 필요 | 외부 앱 소스/override/배포 범위 미제공. 현재 공개 패키지와 저장소 내 Tabs 소비처는 적용 |
|
||||
|
||||
**명시적 수정 요청의 미반영 항목: 없음.** 확인 필요는 제공되지 않은 외부 자료·전수 검증 범위이며 D-01/D-02의 구현을 보류한 것이 아니다. Legacy Compatibility는 원문이 보존하도록 한 기존 동작/예외이며 새 Fill 디자인 적용을 제외한 이유가 명시돼 있다.
|
||||
|
||||
### 실제 수정 파일
|
||||
|
||||
| 파일 | 수정 내용 |
|
||||
|---|---|
|
||||
| [Tabs CSS](../../packages/ui/src/theme/tabs.css) | content branch face 상단 alpha 1→0.8의 단일 CSS 선언 변경 |
|
||||
| [Tabs Story](../../src/components/tabs.stories.tsx) | Fill 전체 panel 평면 조합·상위 표면 연결. Legacy만 기존 조합 유지, 기존 Usage/state/ID 보존 |
|
||||
| [PageHeader Story](../../src/patterns/page-header.stories.tsx) | 기존 PageHeader 바로 아래 Tabs / Table 실제 합성, 새로운 Story 메뉴/API 없음 |
|
||||
| [Tabs 문서](../components/tabs.md) | 현재 80% 구현·영향·예외·Fill 예제 안내, 보류 해제 |
|
||||
| [PageHeader 문서](../patterns/page-header.md) | 실제 Pattern 조합·80%·20px 연결 명시 |
|
||||
| [개발 적용 가이드](개발-적용-가이드.md) | 현재 출하 값·대표/verification의 동일 기준·제한된 Theme 변경 범위 안내 |
|
||||
| 이 보고서 | 기존 작업 이력 보존, 후속 구현 결과·전체 요청 재분류·검증 기록 추가 |
|
||||
|
||||
패키지 dist와 앱/Storybook 산출물은 기존 build로 재생성하며 source 변경 목록과 구분한다. Dependency·lockfile·공개 export·Component TSX·Card/PageHeader/Table CSS는 변경하지 않는다.
|
||||
|
||||
### 후속 검증
|
||||
|
||||
| 항목 | 결과 |
|
||||
|---|---|
|
||||
| TYPECHECK | PASS — `npm run typecheck`의 Theme/package 사전 검사 후 Story 내부 Props 타입 오류 수정, `npm run typecheck --ignore-scripts`의 루트/workspace 검사 통과 |
|
||||
| BUILD | PASS — `npm run build --ignore-scripts`, 사전 package/Theme 검사는 중복하지 않음 |
|
||||
| STORYBOOK_BUILD | PASS — `npm run build-storybook --ignore-scripts`, 최종 실제 Storybook 빌드 |
|
||||
| TEST | PASS — `node --test scripts/ai-generation-guard.test.mjs`, 기존 14개 통과 |
|
||||
| DOC_LINKS / EXPORTS | PASS — 변경 문서의 로컬 path/heading 링크 56개. 두 Story 공개 import 각 18개/23개 확인, 기존 Story ID 유지 |
|
||||
| CSS 영향 / API 보존 | PASS — PostCSS 선언 대조에서 target branch의 face 1개 선언만 변경. compiled package CSS도 source와 일치. Component TSX·export·Theme JSON·비대상 CSS는 hash 동일 |
|
||||
| VISUAL_CHECK 1280 / 390 | PASS — 실제 Edge React 렌더, Tabs 대표 및 PageHeader Pattern 두 폭. Legacy·Disabled·Overflow·LongLabel 회귀와 실제 Table scrollbar 이동 확인 |
|
||||
| GUARD | NOT VERIFIED — PARTIAL 1회 실행. 수정 package CSS/Stories가 Production bootstrap graph 밖인 SCOPE-001 3건, FAIL 없음. 정적 Guard PASS로 오기하지 않음 |
|
||||
| LINT | NOT VERIFIED — 별도 lint script/config 없음 |
|
||||
| GIT_DIFF | NOT VERIFIED — .git 없는 폴더, 미커밋 상태 판정 불가 |
|
||||
|
||||
### 실제 브라우저 결과와 제한
|
||||
|
||||
- Primary: 실제 `background-image = linear-gradient(color(srgb 1 1 1 / 0.8) 0%, rgb(245, 240, 229) 100%)`, 전체 `opacity=1`. Secondary는 기존 불투명 White gradient. 높이 34px·16/24/700·Green Light 3 경계를 유지한다.
|
||||
- 대표 Tabs의 Fill 패널 7개는 background transparent / border 0 / radius 0 / padding 24px 0. Card Usage의 외곽 border·배경·24px 여백과 Input 1px border, Table White 행·520px 최소 폭은 유지한다.
|
||||
- Tabs 문서 client=scroll: 1280px viewport에서 1265px, 390px viewport에서 375px(세로 scrollbar 제외). Card/Table 가용 폭 293px, 페이지 Table 가용 폭 343px, 둘 다 scrollWidth 520px이며 문서 전체 가로 넘침 없음. Card Table의 실제 scrollbar drag는 scrollLeft **0→227px**으로 이동했다.
|
||||
- PageHeader Pattern: 제목→설명 margin 8px, Header→Tabs 실제 거리 **20px**, panel 24px 0·무배경·무border, Primary alpha 0.8 / opacity 1. desktop 문서 폭 1280px, mobile 390px로 가로 넘침 없음. mobile Table container는 client 358px / scrollWidth 520px. ‘완료 업무’ 실제 클릭 시 완료 Table로 전환한다.
|
||||
- 클릭·ArrowRight·Home·End 전환, 입력 초안 `후속 구현 검증` 보존, 3px focus-visible ring 유지. Disabled는 opacity 0.5·pointer-events none·tabIndex -1이며 메뉴 1에서 ArrowRight가 disabled 메뉴 2를 건너뛰어 메뉴 3을 선택한다.
|
||||
- Legacy non-fill 두 예제는 선택 White / gradient none / panel border 1px·padding 16px로 기존과 동일. Compatibility의 surface-only Fill은 Secondary White / flat panel로 새 조합을 따른다.
|
||||
- 기존 Overflow는 list client 192px / scrollWidth 605px에서 다음 버튼 scrollLeft **0→36px**·선택 유지. 390px LongLabel 문서 폭 390px이며 frame 358px/260px 내 기존 넘침 버튼으로 수용한다.
|
||||
- Tabs와 PageHeader Pattern Console error/warn 0건. Build/Storybook Build의 기존 Tailwind `bg-[var(...)]` 최적화 경고·500kB chunk 경고는 남아 있지만 두 명령 exit 0이다. 전체 브라우저/외부 소비 앱 회귀·외부 URL 링크·Hover 포인터 전수 감사는 NOT VERIFIED이며 상태 CSS 보존과 이번 관련 렌더 확인 범위를 구분한다.
|
||||
- 화면 기록: Tabs 1280: `_local/publisher-implementation/tabs-desktop.jpg` (당시 로컬 보관 증거, Git Clone 미포함), Tabs 390: `_local/publisher-implementation/tabs-mobile.jpg` (당시 로컬 보관 증거, Git Clone 미포함), Pattern 1280: `_local/publisher-implementation/pattern-desktop.jpg` (당시 로컬 보관 증거, Git Clone 미포함), Pattern 390: `_local/publisher-implementation/pattern-mobile.jpg` (당시 로컬 보관 증거, Git Clone 미포함). `_local/`의 증거·사본·로그는 기존 gitignore 범위로 source 배포와 구분한다.
|
||||
|
||||
### 기존 작업 보존
|
||||
|
||||
이번 시작 상태의 기존 source 503개와 참고 원본 3개의 SHA-256 목록·수정 전 사본을 `_local/publisher-implementation/`에 별도로 확보했다. 최초 `_local/publisher-integration/` 기록은 덮어쓰지 않는다. 초기화·삭제 명령이나 Git 추가/커밋을 수행하지 않는다.
|
||||
|
||||
최종 대조에서 수정은 위 7개 파일로 한정됐고, 나머지 기존 파일 496개와 참고 원본 3개는 byte 동일하다. 기존 첫 단계 문서·Usage는 필요한 부분만 이어서 수정했고, 그 외 이전 작업 파일·이력·백업은 보존했다. 브라우저 viewport를 복원하고 검증용 로컬 서버를 종료했다.
|
||||
|
||||
### 후속 작업 시간 (Asia/Seoul)
|
||||
|
||||
- Started At: 2026-10-09 22:00:35 KST
|
||||
- Completed At: 2026-10-09 22:17:11 KST
|
||||
- Actual Duration: 16분 36초
|
||||
- Estimated Duration: 25–40분
|
||||
- Variance: 예상보다 8분 24초–23분 24초 단축
|
||||
|
||||
## 프로젝트 전체 회귀 검증 및 로컬 커밋 판단
|
||||
|
||||
후속 회귀 검증은 현재 저장소 전체의 Component / Pattern / Foundation / Theme / Storybook / 문서를 대상으로 수행했다. Runtime은 REACT_VITE이며 실제 운영 앱과 기존 Storybook을 함께 검사했다. 앞 절의 구현 이력은 보존하며, 이 절이 전체 회귀 범위의 최신 판정이다.
|
||||
|
||||
```yaml
|
||||
RESULT: PARTIAL
|
||||
TARGET: D:\디자인시스템\hmdesign
|
||||
|
||||
[전체 영향 검증]
|
||||
Component: PASS — 전체 Story 렌더링, 공개 import/export, 대표 크기·상태 조합 확인
|
||||
Pattern: PASS — PageHeader, Dashboard, Data Table, Filter Bar, GNB/LNB와 기존 업무·채용 화면 확인
|
||||
Foundation: PASS — Color/Typography/Layout 대표 화면 및 기존 source hash 대조
|
||||
Theme: PASS — Theme JSON·계약·기존 CSS 값 보존, 기존 Runtime verification 결과 확인
|
||||
Storybook: PASS — 62개 source의 291개 Story 렌더 오류·Console error/warn 없음, 기존 ID 제거 없음
|
||||
MD: PASS — 전체 85개 MD의 내부 경로·heading 링크 검사, 기존 오류 2곳 수정
|
||||
Responsive: PASS — 대표 66개 Story와 React 화면 3개, 각각 390/768/1280/1440px
|
||||
Interactions: PARTIAL — 명시된 Tabs 동작 및 대표 폼·표·Navigation 동작 확인, 전 Component의 모든 포인터/Props 조합은 NOT VERIFIED
|
||||
|
||||
[D-01/D-02 검증]
|
||||
D-01: PASS — Fill panel 24px 0, 배경/border/radius 0, 바깥 Card 보존, PageHeader/Tabs/Table 합성 및 간격 유지
|
||||
D-02: PASS — Primary 선택 탭 상단 gradient stop alpha 0.8, 하단 content 불투명, 전체 opacity 1, Secondary/Legacy/API 보존
|
||||
|
||||
[검증 결과]
|
||||
TYPECHECK: PASS
|
||||
UI_BUILD: PASS
|
||||
PRODUCTION_BUILD: PASS
|
||||
STORYBOOK_BUILD: PASS
|
||||
TEST: PASS — 기존 Guard 테스트 14/14
|
||||
GUARD: PARTIAL — Dashboard FAIL, 운영/Recruit/수정 CSS 및 Publisher Story는 NOT VERIFIED 사유를 아래에 기록
|
||||
DOC_LINKS: PASS — 저장소 내부 링크; 외부 URL의 응답 상태는 NOT VERIFIED
|
||||
EXPORTS: PASS — runtime import 688건, 공개 export artifact 16개
|
||||
CSS_IMPORTS: PASS — source CSS 78개, import 63건, utility 생성 및 실제 적용 확인
|
||||
VISUAL_CHECK: PASS — 검사한 대표 화면/너비의 실제 React 렌더와 viewport 캡처; 전 화면 역사적 pixel diff는 NOT VERIFIED
|
||||
GIT_DIFF: NOT VERIFIED — Git 메타데이터 없음. 파일 hash·CSS 생성 결과·변경 파일 whitespace로 보존 범위 확인
|
||||
|
||||
[Git]
|
||||
Repository: ABSENT — 대상 및 D:\디자인시스템, D:\의 .git 확인, rev-parse 실패
|
||||
Branch: UNAVAILABLE
|
||||
Previous HEAD: UNAVAILABLE
|
||||
New HEAD: UNAVAILABLE
|
||||
Commit SHA: UNAVAILABLE
|
||||
Commit Message: NOT EXECUTED
|
||||
Commit Files: []
|
||||
Local Commit: NOT EXECUTED — 정상 저장소 없음 및 필수 Guard PASS 조건 미충족
|
||||
Remote Push: NOT EXECUTED
|
||||
|
||||
[보존 확인]
|
||||
기존 미커밋 변경: Git 기준 판정 불가; 회귀 시작 파일 hash와 이전 통합 baseline으로 이번 수정 범위 구분
|
||||
참고 원본: 읽기 전용 유지, 원본 3개 SHA-256 동일
|
||||
기존 Component/API: source TSX·공개 export·package.json·lockfile 미변경
|
||||
Theme/Token: Theme JSON·Runtime 계약·비대상 CSS 값 미변경
|
||||
|
||||
[최종 판단]
|
||||
- 검사한 전체 Story 및 대표 반응형 화면에서 D-01/D-02로 인한 회귀 문제 없음
|
||||
- 기존 export utility 누락과 문서 링크 오류를 최소 수정
|
||||
- Guard 잔여 실패/미검증을 PASS로 처리하지 않음
|
||||
- 로컬 커밋 보류, Git 초기화·Clone·원격 연결·Stage·Push 없음
|
||||
```
|
||||
|
||||
### 발견된 문제와 이번 실제 수정 파일
|
||||
|
||||
| 파일 | 원인 / 영향 범위 | 수정 및 검증 |
|
||||
|---|---|---|
|
||||
| [src/index.css](../../src/index.css), [tailwind.css](../../tailwind.css) | 기존 하위 Vite export root에서 앱·UI utility 검색 누락. Dashboard/Recruit의 `.flex`/`.grid`가 block으로 렌더됨. 상대 prefix source 검색도 이 환경에서 UI 클래스를 누락시킴 | 루트 Tailwind 입력 2줄과 기존 index의 상대 import 1줄로 검색 base를 명시. Component/API/Token 변경 없음. 기존 루트 방식과 최종 방식의 생성 CSS SHA-256이 동일하며, export의 실제 flex/grid와 3px Focus 링 복구 |
|
||||
| [shadcn 구현 원칙](shadcn-기반-구현-원칙.md) | 기존 AGENTS Quick Start heading 삭제로 링크가 끊어짐 | 현재 필수 규칙 heading으로 링크 교정, 전체 MD 링크 재검사 |
|
||||
| [Runtime Theme 과거 보고서](runtime-theme-report.md) | 과거 캡처 파일을 참조하지만 현재 폴더에 해당 이미지 없음 | 없는 이미지를 증거로 제시하지 않고 NOT VERIFIED 표시. 현재 Runtime 계약 링크로 연결 |
|
||||
| 이 보고서 | 전체 검증과 기존 구현 검증 범위 구분 필요 | 이전 이력 보존, 최신 결과·수정 범위·커밋 보류 사유 추가 |
|
||||
|
||||
회귀 검증에서 수정한 기존 source는 위 **index와 MD 3개**, 신규 source는 **루트 tailwind.css 1개**다. 회귀 시작 baseline의 기존 503개 중 나머지 **499개**는 byte 동일하다. `_local/`의 보조 검사 코드·로그·캡처와 dist는 커밋 대상이 아니다.
|
||||
|
||||
이전 퍼블리셔 구현 변경은 README, Card/Tabs 문서, 개발 적용 가이드, PageHeader 문서, Tabs CSS, Tabs Story, PageHeader Story 및 이 통합 보고서다. 이번 회귀 단계에서 이전 Component·Pattern 구현을 덮어쓰거나 다시 설계하지 않았다.
|
||||
|
||||
### 실제 검증 명령과 영향 추적
|
||||
|
||||
- `npm run typecheck`: Theme 기본값 검사, UI/Center Graphic package build 및 전체 workspace TypeScript 검사 통과.
|
||||
- `npm run build --ignore-scripts`: 실제 운영 앱 production build 통과. 사전 package 검사는 앞 명령에 포함됐다.
|
||||
- `npm run build-storybook --ignore-scripts`: 최종 Storybook build 통과.
|
||||
- `npm run build:dashboard-export`: 지원되는 기존 export build/finalize 명령 통과. 최종 CSS 입력 변경 후 해당 Vite build와 finalize를 다시 수행했다.
|
||||
- `node node_modules/vite/bin/vite.js build --config vite.recruit-export.config.ts`: 기존 Recruit config로 production export build 통과. 별도 npm script 없음.
|
||||
- `node --test scripts/ai-generation-guard.test.mjs`: 14개 통과. 별도 Component unit runner / lint script는 없으므로 존재하지 않는 검증을 통과로 표기하지 않는다.
|
||||
- 기존 Tailwind `bg-[var(...)]` 최적화 및 root bundle 500kB 경고는 exit 0의 경고이며 미수정했다.
|
||||
|
||||
`tabs.css`는 공개 UI `theme.css` → `theme/tabs.css`로 연결되고 package build에서 dist로 복사된다. 앱과 Storybook은 `index.css → tailwind.css` 및 `hm-theme.css → @hm-design/ui/theme.css`를 소비하므로 공통 CSS 자체는 전체 화면에 로드된다. 그러나 D-02 선언은 `[data-slot="tabs-frame"][data-fill="true"][data-panel-surface="content"]`의 `--hm-tab-fill-face` 한 곳으로 한정된다. active trigger의 background-image에만 사용되며 전역 opacity / white token / background token을 변경하지 않는다. 현재 실제 Tabs 소비처는 Tabs Story와 PageHeader Story이며, 기존 업무·Dashboard·Recruit 화면에는 Tabs DOM이 없다. 향후 동일 Primary 조합도 같은 요청된 gradient를 소비한다.
|
||||
|
||||
### 브라우저 증거와 확인 범위
|
||||
|
||||
전체 Story 291개의 실제 root 콘텐츠·오류 화면·Console을 검사했고 대표 66개 화면을 각 너비에서 재확인했다. 대표 범위는 Foundation 3개, 기존 Component/Pattern Overview·All, Center Graphic 및 Theme Designer다. 현재 Storybook index의 기존 288개 ID는 모두 유지되며 추가 3개 ID는 회귀 시작 전에 이미 존재했다. 이번 단계의 Story ID 변경은 없다.
|
||||
|
||||
Fill panel은 padding 24px 0 / transparent / border 0 / radius 0이다. PageHeader 설명 간격 8px, Header→Tabs 간격 20px와 Table 조합을 유지한다. 네 너비의 Primary 선택 gradient는 `color(srgb 1 1 1 / 0.8) → rgb(245, 240, 229)`이며 opacity 1이다. Secondary White gradient와 Legacy non-fill White 면·1px panel border·16px panel padding을 유지한다.
|
||||
|
||||
Tabs의 ArrowRight/Home/End, Disabled 건너뛰기, 다음 보기 내부 스크롤, 선택 유지, Card/페이지 초안 보존을 확인했다. Focus-visible은 기존 3px 링을 유지한다. Input 크기 28/34/42와 disabled/readonly, Select 키보드 선택, Checkbox/Switch Space, Accordion Enter, Dialog 입력·Escape·Focus 복원, LNB 펼침/접힘/하위 선택, GNB 모바일 메뉴·Escape도 대표 화면에서 확인했다. 기존 업무 화면의 검색·폼 취소(기존 12건 보존), Recruit 검색·상태 필터·정렬·전체 행 선택을 확인했다. 저장/삭제/원격 전송은 수행하지 않았다.
|
||||
|
||||
운영 앱은 GNB 56px(390/768), 70px(1280/1440)을 유지한다. Dashboard/Recruit는 네 너비 모두 48px Header, Sidebar 0개, 960px 최소 콘텐츠 및 390/768px의 내부 스크롤을 유지한다. 대표 264개 + 운영 화면 12개에서 문서 자체의 가로 넘침과 렌더 오류는 없었다. Table·Dashboard 내부 스크롤, ComboBox·Center Graphic의 명시적 ellipsis, Avatar Don't 예시의 의도적 잘림은 기존 계약으로 구분했다. 모든 페이지의 아래쪽까지 역사적 기준 이미지와 자동 pixel 비교한 것은 아니다.
|
||||
|
||||
최종 기록은 `_local/publisher-regression/`의 `static-audit.json`, `utility-parity.json`, `story-render-final.json`, `responsive-final.json`, `production-final.json`, `interactions.json`, `tabs-interactions-final.json`, `theme-results.json` 및 각 build/Guard log다. 최종 화면은 `screenshots/final-*.jpg`와 `contacts/`에 보관한다. 초기 spinner·표시 배율이 맞지 않은 캡처는 최종 증거로 사용하지 않는다. 캡처는 실제 viewport를 직접 지정한 최종 이미지 기준이다.
|
||||
|
||||
### Guard 원본 판정 및 미검증
|
||||
|
||||
| 검사 | 원본 결과 / 원인 | 실제 화면 증거와 잔여 |
|
||||
|---|---|---|
|
||||
| 운영 GNB_ONLY FULL_SCREEN | NOT VERIFIED — 정적 4개 그룹 PASS, RENDER-002와 기존 CSS intent REUSE-003 | 실제 앱 네 너비 확인 완료. 정적 도구의 원본 결과는 그대로 보존 |
|
||||
| Dashboard DASHBOARD_ONLY FULL_SCREEN | FAIL — NAV-001: 공통 composition의 기존 legacy Sidebar branch. NAV-005: 조건부 sidebar prop 정적 입증 불가 | export는 compact mode로 실제 Sidebar 0개. 도구가 실행되지 않는 분기까지 검사하며 control-flow를 구분하지 못함. 기존 legacy 화면 제거/Guard 완화로 우회하지 않음 |
|
||||
| Recruit DASHBOARD_ONLY FULL_SCREEN | NOT VERIFIED — 정적 4개 그룹 PASS, RENDER-002 및 기존 CSS intent | 실제 네 너비의 48px/960px 계약·utility·동작 확인 |
|
||||
| 변경 CSS PARTIAL | NOT VERIFIED — RENDER-002 | 실제 bootstrap·utility·레이아웃을 별도로 확인. 자동 결과를 PASS로 덮어쓰지 않음 |
|
||||
| 기존 Publisher CSS/Story PARTIAL | NOT VERIFIED — SCOPE-001 3건, Production Graph 밖 | 전체 Story build·CSF/public export/ID 대조·291개 실제 React 렌더로 별도 검사. Production Guard의 Story 검사 PASS로 대체하지 않음 |
|
||||
|
||||
남은 미검증은 Git status/diff/staging/HEAD, 외부 소비 앱·배포, 외부 URL 응답 상태, 전 Component의 모든 Props·포인터 조합/다른 브라우저, 모든 화면의 과거 pixel 비교, standalone `file://` 실행이다. Dashboard Guard의 분기 분석 한계와 기존 CSS intent 판정도 잔여 항목이다. **필수 검증 전체 PASS를 주장하지 않으며 커밋하지 않는다.** 공식 Gitea는 확인용 요청 URL만 알고 있고 현재 폴더의 remote 설정은 Git 메타데이터가 없어 확인 불가다. 이 작업에서 원격 쓰기는 없다.
|
||||
|
||||
### 회귀 작업 시간 및 종료 확인 (Asia/Seoul)
|
||||
|
||||
- Started At: 2026-10-09 22:31:29 KST
|
||||
- Completed At: 2026-10-10 00:09:52 KST
|
||||
- Actual Duration: 98분 23초
|
||||
- Estimated Duration: 60–90분
|
||||
- Variance: 예상보다 8분 23초–38분 23초 초과
|
||||
- 기존 baseline source 503개 중 수정 4개, 나머지 499개 동일. 신규 root Tailwind CSS 1개, 참고 원본 3개 동일.
|
||||
- 최종 viewport 복원, 검증용 브라우저 탭 종료, 로컬 서버 6025/6026/6027/6028 종료 및 Listen 없음 확인.
|
||||
@@ -0,0 +1,127 @@
|
||||
# HMDesign 잔여 이슈 최종 안정화 — 2026-10-10
|
||||
|
||||
RESULT: PARTIAL. 숨김 Select 비교 Story의 넘침을 수정했고 기존 Guard 40개와 추가 6개 테스트, 아래 빌드·브라우저·독립 설치 검증은 통과했다. 승인 후 최신 npm audit도 완료했으며 운영 취약점 0건·개발 High 7건·Critical 0건이다. 개발 도구 취약점, 기존 색상 대비 문제, 정적 Guard 한계, 실제 스크린리더·터치 미검증은 남긴다. 이전 보고서의 결과는 소급 변경하지 않는다.
|
||||
|
||||
TARGET: `D:\디자인시스템\hmdesign` / BOTH / React·Vite.
|
||||
|
||||
BASE_SHA: `cb1d2050d552a5442357b9dc2d181c20e74e7010`. 작업 전 로컬 main과 지정 GitHub main HEAD가 일치했고 Working Tree는 clean이었다. 최종 Git 상태는 로컬 실행 보고서와 최종 응답에 기록한다. 공식 Gitea: NOT ACCESSED / NOT MODIFIED. ZIP 생성·포터블 배포는 수행하지 않았다.
|
||||
|
||||
## 수정 파일과 영향 범위
|
||||
|
||||
| 파일 | 원인·변경·영향 |
|
||||
|---|---|
|
||||
| `src/components/select.stories.tsx` | 숨김 ListSizeComparison만 수정. 기존 Grid의 최소 열 폭 280px과 실제 고정 폭 384px가 불일치했다. 최대 specimen 폭 384px를 기준으로 열 수를 결정하고, 좁으면 `min(100%,384px)` 및 specimen `maxWidth:100%`·`min-w-0`로 줄인다. 라벨에 최대 폭임을 표시한다. 공통 Select·대표 All·API·Variant·Theme는 변경하지 않는다. |
|
||||
| `scripts/ai-generation-guard.test.mjs` | 기존 40개 본문을 보존하고 6개 경계 테스트 추가. Guard 정책·분석기는 변경하지 않는다. |
|
||||
| `docs/guidelines/ai-generation-guard.md` | 추가 테스트의 범위와 미검증 판정 유지 이유를 설명한다. |
|
||||
| `README.md` 및 이 보고서 | 후속 검증 결과·보류 보안 항목·접근성 한계·수동 절차를 연결한다. 과거 기록은 보존한다. |
|
||||
|
||||
## Select 넘침 분석과 전후 측정
|
||||
|
||||
실제 Chromium의 documentElement clientWidth/scrollWidth, 부모 Grid track과 specimen·Trigger·Popup rect를 측정했다. Popup 네 개를 모두 닫아도 수정 전 넘침 수치가 같았다. Trigger 텍스트와 아이콘은 기존 말줄임이 정상이며 공통 Select 자체의 문제를 확인하지 않았다. 비교 Grid가 자식의 고정 폭보다 작은 열을 만들면서 발생한 페이지 전체 넘침이며, 의도된 내부 스크롤이 아니다.
|
||||
|
||||
| Viewport | 수정 전 scrollWidth (열림/닫힘) | 수정 후 scrollWidth (열림/닫힘) | 수정 후 Grid track | specimen 폭 |
|
||||
|---|---|---|---|---|
|
||||
| 390 | 400 / 400 | 390 / 390 | 358px × 1 | 280, 280, 358, 358px |
|
||||
| 768 | 784 / 784 | 768 / 768 | 384px × 1 | 280, 280, 384, 384px |
|
||||
| 1280 | 1352 / 1352 | 1280 / 1280 | 384px × 3 | 280, 280, 384, 384px |
|
||||
| 1440 | 1440 / 1440 | 1440 / 1440 | 384px × 3 | 280, 280, 384, 384px |
|
||||
|
||||
전역 overflow 숨김을 추가하지 않았다. 4개 인스턴스 × 4개 viewport에서 Enter로 열기, Home으로 첫 옵션 이동, Enter 선택, Escape 닫기와 Trigger focus 복귀를 확인했다. opening animation과 Radix의 비동기 option focus가 끝난 실제 상태로 판정했다. Popup은 Trigger 폭과 일치하고 viewport의 좌우 경계를 넘지 않았다. 대표 Select·Combobox·DatePicker의 네 viewport 렌더와 Combobox 검색·선택도 별도로 확인했다. 모든 props/모든 브라우저의 전수 검증을 의미하지 않는다.
|
||||
|
||||
## 개발 의존성 분석
|
||||
|
||||
로컬 `npm ls`와 lockfile의 설치 버전, 공개 npm 레지스트리의 최신 버전 및 [GitHub 공식 보안 권고](https://github.com/advisories/GHSA-vfj7-8cjw-p6xm)를 새로 확인했다. 권고의 영향 범위는 braces ≤3.0.3이며 패치 버전은 없다. npm 조회 결과 braces 3.0.3 / micromatch 4.0.8 / fast-glob 3.3.3 / shadcn 4.21.4다.
|
||||
|
||||
| 패키지 | 설치 버전 | 직접/간접·경로 |
|
||||
|---|---|---|
|
||||
| shadcn | 4.21.1 | UI workspace 직접 devDependency |
|
||||
| @shadcn/registry | 0.1.0 | shadcn → registry |
|
||||
| ts-morph | 26.0.0 | shadcn 또는 registry → ts-morph |
|
||||
| @ts-morph/common | 0.27.0 | ts-morph → common |
|
||||
| fast-glob | 3.3.3 | shadcn/registry 또는 common → fast-glob |
|
||||
| micromatch | 4.0.8 | fast-glob → micromatch |
|
||||
| braces | 3.0.3 | micromatch → braces |
|
||||
|
||||
기존 High 7건은 독립된 근본 취약점 7개가 아니라 같은 braces 문제의 상위 의존성 전파를 포함한다. 깊게 중첩된 brace pattern이 Node stack을 소진해 프로세스를 종료시키는 문제다.
|
||||
|
||||
영향 경로는 CLI뿐이 아니다. `scripts/ai-generation-guard.mjs`의 Storybook discovery는 fast-glob에 로컬 설정의 literal glob을 전달한다. 현재 관리하는 glob으로 검사했을 때 정상 종료했지만 비신뢰 설정·극단적으로 중첩된 pattern을 처리하면 위험이 남는다. Production profile은 이 discovery 경로를 실행하지 않는다. `scripts/build-package.mjs`는 shadcn CSS와 라이선스를 복사할 뿐 CLI/registry glob을 실행하지 않는다. npm scripts도 shadcn CLI를 호출하지 않는다. 공개 UI pack에는 CSS asset만 동봉하고 CLI의 개발 의존성 그래프를 소비 앱에 배포하지 않는다.
|
||||
|
||||
안전한 patch로 근본 문제가 해소되는 근거가 없어 shadcn 4.21.4 업데이트만으로 High가 사라진다고 판단하지 않았다. 이번 최신 audit도 shadcn 1.0.0을 `isSemVerMajor:true`로 제안했다. 4.x에서 major 역행이며 build의 `shadcn/dist/tailwind.css` 계약에도 영향을 줄 수 있어 채택하지 않았다. force fix/override/major 변경은 하지 않았다. package.json·lockfile은 byte 동일하며, Storybook 10.6.1 / Vite 8.3.0 / React 19.3.0을 보존하고 새 설치·타입 검사·빌드로 현재 조합을 확인했다.
|
||||
|
||||
완화 방법: 신뢰하는 로컬 glob만 사용하고 비신뢰 registry/pattern을 shadcn CLI·Guard에 전달하지 않는다. 개발 도구를 외부 공개하지 않고 패치가 나오면 별도 호환성 검증을 수행한다. CLI 삭제·다른 라이브러리로의 교체는 이번 최소 수정에 포함하지 않는다.
|
||||
|
||||
NPM_AUDIT: PARTIAL — 2026-10-10 14:38 KST에 이번 감사로 한정한 사용자의 전송 승인 후 전체·운영 의존성을 각각 실제 검사했다. `npm audit --json` 결과는 High 7 / Critical 0 / 다른 등급 0, `npm audit --omit=dev --json` 결과는 모든 등급 0이다. 전체 명령 exit 1은 확인된 High 7건 때문이며 검사 실패나 취약점 0으로 처리하지 않았다. 운영 감사 exit 0이다. 근본 권고는 GHSA-vfj7-8cjw-p6xm 하나이며 위 7개 개발 패키지로 전파된다. 이전 기록 7건과 이번 fresh 결과 7건이 같고, 의존성 변경은 없다.
|
||||
|
||||
최초 자동 승인 거부 기록과 승인 전 미검증 보고서는 로컬에 보존했다. 승인 후에는 registry를 `https://registry.npmjs.org`로 명시하고 빈 user/global npm 설정 및 npm 인증 환경변수 제외 상태로 audit 명령만 실행했다. 소스코드·환경변수 덤프·인증정보를 전송하는 작업은 수행하지 않았다. raw 결과는 로컬의 `audit-total-current.json`, `audit-production-current.json`으로 보관하고 Git에 추가하지 않는다. 새 Clone/consumer 설치는 기존처럼 `--no-audit`로 완료한 결과를 유지한다.
|
||||
|
||||
## Guard 판정
|
||||
|
||||
| 실행 | 결과·실제 범위 |
|
||||
|---|---|
|
||||
| GUARD_TEST | PASS — 46/46, 기존 40개 본문 유지. |
|
||||
| GUARD_FULL_SCREEN | NOT VERIFIED — 공개 HM 목록 예제/GNB_ONLY/React index.html, FAIL 0. ENTRY-003 1, RENDER-002 1, REUSE-003 3. |
|
||||
| Production app FULL_SCREEN | NOT VERIFIED — GNB_ONLY/index.html, FAIL 0. RENDER-002 1, REUSE-003 13. |
|
||||
| Dashboard/Recruit FULL_SCREEN | NOT VERIFIED — 각각 bootstrap/DASHBOARD_ONLY, FAIL 0. CSS intent 각각 10/13. compact 분기의 Sidebar는 실제 DOM에서도 0개 확인. |
|
||||
| GUARD_PARTIAL | NOT VERIFIED — 변경 Select Story의 STORYBOOK profile, FAIL 0. native Story 예제 REUSE-004 2. |
|
||||
| GUARD_STORYBOOK | NOT VERIFIED — 63 Story module, FAIL 0. 내부 Reference wrapper 1, CSS intent 19, native controls 20. mode 미지정 Reference 범위의 Navigation은 NOT APPLICABLE. |
|
||||
|
||||
추가 테스트 41~46은 preview CSS 단절, 명시 entry 범위, 상속 tsconfig, Reference/public slot 경계, literal Navigation과 CSS intent의 독립성, package 구현의 범위를 확인한다. [Guard 정책](ai-generation-guard.md#잔여-판정-회귀-범위-2026-10-10-안정화)을 참조한다. NOT VERIFIED 판정의 회귀 테스트 통과를 해당 미검증 사항의 PASS로 전환하지 않는다.
|
||||
|
||||
CSS intent·Reference 승인 의도, 상속 alias 전체 해석, opaque render, package 구현 자체는 정적 소비 Guard의 한계다. 실제 브라우저·SR·실기기 시험의 미실시는 실행 검증의 미검증이며 이와 구분한다. 공개 slot 위조·필수 CSS의 확정 누락·도달하는 금지 Navigation·Production의 Story 의존은 기존대로 FAIL이다. 허용 목록이나 무조건 PASS는 추가하지 않았다.
|
||||
|
||||
## 접근성
|
||||
|
||||
자동 axe-core의 WCAG 2 A/AA·2.1 A/AA와 Chromium 실제 키보드 조작을 각각 실행했다. 자동 검사는 대표 Story 9개 및 열린 Combobox/DatePicker popup을 대상으로 하며 모든 Story/state의 전수 검사는 아니다.
|
||||
|
||||
- Keyboard: PASS (확인 범위). Checkbox Tab/Shift+Tab/Space, Radio ArrowRight, Toggle Space, Select Enter/Home/Escape, Combobox 검색→ArrowDown→Enter→focus 복귀, DatePicker Enter/Escape→focus 복귀, Tabs 방향키·내부 overflow 이동 버튼, Dialog focus trap, Sheet Escape/focus 복귀, Drawer 취소를 확인했다.
|
||||
- Focus Visible: PASS (확인 범위). Checkbox `:focus-visible`, Theme Runtime의 실제 Tab/Shift+Tab/Enter를 확인했다. Runtime은 138 checks / 58 parts / KEYBOARD_FOCUS: PASS. 정적 CSS entry 판정으로 대신하지 않았다.
|
||||
- Label·ID: PASS (확인 범위). Label 클릭의 Input focus, 대표 9개 Story의 중복 ID 없음, 반복 popup·pagination label React 테스트, Combobox listbox·DatePicker popup 이름 연결을 확인했다.
|
||||
- Disabled/readOnly: PASS (확인 범위). 입력값 보호·disabled 상태와 clear 미제공의 실제 React 테스트를 확인했다.
|
||||
- AUTO_ACCESSIBILITY: PARTIAL. Checkbox/Radio/Toggle의 대상 scan은 위반이 없었다. 기존 Select/Combobox/DatePicker placeholder는 `#999999`/White 대비 2.84:1, Input 오류 문구는 `#d32f2f`/`#f5f0e5` 대비 4.38:1로 axe serious color-contrast를 보고했다. 확정 Token과 기존 Theme mapping이므로 임의 수정하지 않았다. 이 대비 항목은 실행해 확인한 FAIL이며 접근성 전체를 PASS로 보고하지 않는다.
|
||||
- DatePicker 일자 label-content-name-mismatch: NOT VERIFIED. 실제 DOM은 표시 `1`, 이름 `2026년 10월 1일…`처럼 숫자를 포함한다. axe의 word token 연속 일치 판정은 한국어 일자 단위와의 결합을 불일치로 볼 가능성이 있다. 원본 위반 로그를 보존하고 [WCAG Label in Name](https://www.w3.org/WAI/WCAG22/Understanding/label-in-name.html)에 따른 수동 확인 대상으로 남긴다. SR·음성 조작을 실행하지 않고 자동 PASS로 바꾸지 않았다.
|
||||
- axe incomplete: NOT VERIFIED. Tabs gradient의 대비, 열린 popup의 ARIA 값 등 도구가 확정하지 못한 node는 수동 검사 대상으로 남겼다.
|
||||
- Select 열린 popup 추가 scan에서 aria-hidden-focus가 보고됐다. 기존 Radix modal의 숨긴 배경 Trigger와 관련된 관찰로, 실제 focus trap·지원 보조기술을 추가 확인해야 한다. 원본 경고를 제거하거나 이름 없는 Select listbox를 접근성 인증 완료로 처리하지 않는다.
|
||||
- SCREEN_READER / TOUCH_DEVICE / Drawer 실제 손가락 drag close: NOT VERIFIED.
|
||||
|
||||
기존 확정색 변경은 별도로 접근성 요구사항과 Token 영향 범위를 확인해 다룬다. Component/Theme source가 시작 시점과 같으므로 이번 변경이 대비 문제를 만들었다고 판단하지 않는다. 실제 SR 발화 인증이나 완전한 WCAG 적합성을 주장하지 않는다.
|
||||
|
||||
### 미실시 검증 절차
|
||||
|
||||
1. Windows NVDA + Chrome/Edge로 이름·role·상태를 읽는다. Label이 있는 Input, Checkbox/Radio/Toggle을 Tab으로 이동하고 Space·방향키의 상태 변화와 disabled/readOnly 보호를 확인한다.
|
||||
2. Select/Combobox/DatePicker를 2개 이상 같은 화면에 둔다. 키보드로 popup을 열고 이름·expanded·선택 option/date·검색 결과를 읽는다. Escape 후 원래 Trigger로 복귀하며 다른 인스턴스의 ID·이름·값과 혼동되지 않는지 확인한다. Select listbox의 독립 이름도 확인한다.
|
||||
3. Calendar의 숫자와 년월일 이름을 NVDA·음성 입력으로 확인한다. axe의 한국어 token 판정만으로 합격·불합격을 결정하지 않는다.
|
||||
4. Dialog/Sheet/Drawer를 열어 Title/Description 발화·focus trap·Escape/취소 후 Trigger 복귀를 확인한다. 숨긴 배경으로 focus가 이동하는지도 검사한다.
|
||||
5. iOS Safari + VoiceOver, Android Chrome + TalkBack 실기기로 390px 상당 화면을 확인한다. 터치 선택·Tabs 스크롤·GNB/LNB 메뉴·Calendar 선택을 검사한다. Drawer를 실제 손가락으로 drag해서 닫고 스크롤 충돌·focus/발화 복귀를 확인한다. pointer 에뮬레이션을 실기기 PASS로 보지 않는다.
|
||||
6. 기존 대비 부족은 확정 Theme에서 실측하고 WCAG AA 적용 범위·승인한 수정 방침을 기록한다. Tabs gradient 등 axe incomplete도 실제 배경에서 수동 측정한다.
|
||||
|
||||
## 전체 회귀와 Git 공유
|
||||
|
||||
| 항목 | 결과·실행 내용 |
|
||||
|---|---|
|
||||
| TYPECHECK | PASS — root/UI/CENTER, 예제·임시 신규 화면 tsconfig. |
|
||||
| UI_BUILD | PASS — UI/CENTER workspace, Theme defaults 71색/73항목 일치. |
|
||||
| PRODUCTION_BUILD | PASS — root, 목록 예제, Dashboard/Recruit export. |
|
||||
| STORYBOOK_BUILD | PASS — 최종 static build, 292 Story ID 유지·추가/삭제 0. |
|
||||
| COMPONENT_TEST | PASS — 기존 8/8, 본문 byte 동일. |
|
||||
| GUARD_TEST | PASS — 46/46. |
|
||||
| DOC_LINKS | PASS — 최종 MD 91개·내부 링크 400개, 경로/heading 오류 0. |
|
||||
| CSS_IMPORTS | PASS — 69 import 누락 0. |
|
||||
| EXPORTS | PASS — 공개 import 736개 누락 0, export artifact 16개 존재. UI 255 / Theme 8 / CENTER 25 / CENTER Reference 10. |
|
||||
| THEME_JSON_LOADER | PASS — 최종 static 네 viewport 각각 119 checks, 새 Clone dev에서도 119. |
|
||||
| THEME_DESIGNER | PASS — 최종 static 네 viewport 각각 96 checks, 새 Clone dev에서도 96. 같은 preview 문서의 임시 색 격리·세션 복원·Reset 확인. |
|
||||
| PACKAGE_CONSUMER | PASS — 최종 pack의 독립 설치, strict:true / skipLibCheck:false 타입 검사. |
|
||||
| NPM_AUDIT | PARTIAL — 최신 전체 High 7 / Critical 0, 운영 0. 개발 취약점은 major 변경 보류와 영향 경로·완화 방법을 위에 기록. |
|
||||
| RESPONSIVE | PASS (확인 범위) — 대표 Story 18개 × 4폭, 목록/root/Dashboard/Recruit/신규 예제, Select 비교 4폭, Sheet 4방향 × 4폭, Drawer 4폭. |
|
||||
| RUNTIME | PASS (확인 범위) — 292 Story의 1280px 실제 React 렌더와 대상 interaction. 모든 props/state/mobile의 전수 시험은 아니다. |
|
||||
|
||||
Console의 broken-avatar-image·missing-verification-theme 404는 의도한 fallback/실패계 시험이며 원본 로그를 보존했다. 실행한 화면에서 예상하지 않은 pageerror는 관찰하지 않았다. 500kB chunk·Storybook bundler 성능 경고는 남겼으며 기능 실패나 braces 취약점 해결로 혼동하지 않는다.
|
||||
|
||||
GitHub baseline main을 별도 폴더로 Clone하고 후보 변경만 반영했다. node_modules/dist를 복사하지 않고 `npm ci --no-audit`로 526 packages를 새로 설치했다. UI/CENTER build·typecheck·Storybook build/dev를 실행했다. README의 npm scripts로 실행했으며 시험 포트는 충돌을 피한 6045다. 공개 HM Component/Pattern/Theme 렌더를 확인하고 새 목록 React 화면을 Clone의 `_local/new-screen`에만 만들어 typecheck/build/dev와 네 폭의 조회/Reset/모바일 메뉴를 확인했다. 공식 프로젝트에 새 화면이나 Story를 추가하지 않았다.
|
||||
|
||||
## 기존 구현 보존과 최종 판단
|
||||
|
||||
D-01/D-02, Primary Alpha 0.8/Secondary/Legacy, Component/Pattern/Theme/Token/공개 API, C2~R3, 추가 수정된 Button/Table/Progress/Accordion/Sheet/Drawer/Navigation, Theme Loader/Designer와 대표 Story는 변경하지 않았다. 이번 브라우저 검사에서 Tabs padding 24px 0·border 없음, Progress 우측 radius, Accordion hover 5%, Sheet 안쪽 radius, Drawer 반응형 footer, Dashboard 48px header·960px 내부 스크롤·Sidebar 없음도 확인했다. 모든 역사적 화면의 pixel diff나 전 상태 재시험을 수행했다고 주장하지 않는다.
|
||||
|
||||
시작 때 기록한 추적 파일 521개의 SHA-256을 현재와 비교하고 읽기 전용 요청 원본의 SHA도 비교한다. Guard 구현·Navigation 분석기·기존 컴포넌트 테스트·package/lockfile·Theme와 정상 영역을 보존한다. 추가 Guard 테스트는 기존 40개 본문의 원본 prefix 보존을 검사한다. 로컬 시험 코드·로그·캡처·Clone·신규 시험 화면은 `_local/stabilization-20261010/`에 보관하며 Git에 포함하지 않는다.
|
||||
|
||||
Select 비교 문제는 해결했고 Guard의 기존 판정을 유지하는 테스트를 추가했다. Git 테스트 공유의 주요 빌드·실행 검증과 최신 감사 실행은 완료했다. 운영 취약점·Critical은 0이며 새 Critical/High 기능 회귀는 확인되지 않았다. 기존 개발 High 7건은 안전한 patch가 없어 보류한 항목이며, 기존 대비 부족·정적 한계·실제 SR/touch도 남긴다. PARTIAL은 완전한 접근성 승인이나 Gitea 이전 승인을 의미하지 않는다. 검증된 보류 파일만 지정 GitHub main에 일반 Commit/Push하는 조건을 충족한다. Force Push·reset/clean·Gitea 접근·ZIP 작업은 수행하지 않았다.
|
||||
@@ -0,0 +1,98 @@
|
||||
# 퍼블리셔 잔여 이슈 수정·회귀 검증 (2026-10-10)
|
||||
|
||||
RESULT: PARTIAL — 아래 필수 기능·빌드·테스트 검증은 통과했다. 개발 의존성 High 7건, 과거 실패 당시 브라우저 조건의 미확정, 기존 숨김 비교 Story의 넘침과 실기기/SR 미검증을 보존한다.
|
||||
|
||||
TARGET: `D:\디자인시스템\hmdesign` / BOTH / React.
|
||||
|
||||
BASE_SHA: `581a130883db921696cadda872ab0887e2b0e797`. 시작 working tree는 clean이며 GitHub main과 같았다. 공식 Gitea는 접근·변경하지 않았다. 이 문서는 이전 보고서를 대체·소급 수정하지 않는다.
|
||||
|
||||
## Theme 자동 검사
|
||||
|
||||
수정 전 정상 Chromium Context와 기존 Edge에서는 JSON Loader 119개·Designer 96개가 통과했다. 검사 중 CSS animation clock을 멈추는 **통제된 렌더 지연 재현**에서는 Loader가 80개 후 `HTTP JSON reaches rendered Checkbox`, Designer가 53개 후 `Checkbox fill uses Active`에서 실패했다. 이때 `data-state=checked`, `aria-checked=true`, Active Runtime Key `#007f73`는 정상인데 계산된 Checkbox 색상은 이전 Default/보간 색상이고 CSS transition은 paused 상태였다.
|
||||
|
||||
이 증거는 고정 250ms 대기가 최종 계산 색상을 보장하지 못하는 검사 문제를 확인한다. 이전 독립 검증 당시 브라우저가 같은 조건이었는지는 확인하지 못했다. 일반 실행에서 그 간헐적 실패가 자연 재발했다고 주장하거나 원래 환경 원인을 완전히 확정하지 않는다.
|
||||
|
||||
변경은 verification Story에 한정한다. 최종 CSS target 비교 범위에 transition duration/delay 0을 적용하며 일반 Editor·Component·Production timing은 그대로다. Designer의 시험용 input/click dispatch는 React `flushSync`로 commit 경계를 보장하고, 실제 변수/checked/ARIA/계산 색상 조건을 최대 5초 동안 확인한다. 고정 Sleep을 늘리지 않았고 Checkbox assertion과 119/96개 기존 검사를 보존했다. 조건이 끝내 만족되지 않으면 진단과 함께 실패한다. Controlled/Uncontrolled API, focus/keyboard, session store, Runtime Apply/Reset/Loader는 변경하지 않았다.
|
||||
|
||||
최종 정적 빌드에서도 정상·지연 조건 각각 Loader 119개 / Designer 96개가 통과했다. 새 Context·기존 Context/탭·새 탭·반복·역순·Reset 후·다른 Story 방문 후의 7가지 조건을 3라운드 검사했다(반복 조건은 라운드마다 2회): **각 Story 24회 통과, 실패 0**. 별도로 390/768/1280/1440px 각 1회와 독립 Clone 각 1회도 통과했다. 기존 Edge Designer와 새 Edge 탭 Loader에서도 각각 96/119개를 확인했다. 이 유한 반복 결과가 모든 브라우저의 간헐적 실패 부재를 보증하지는 않는다.
|
||||
|
||||
실제 Tab/Shift+Tab/Enter로 Runtime 검증을 실행해 **138 checks / 58 rendered parts / KEYBOARD_FOCUS: PASS**를 확인했다. 같은 preview document에서 Designer Active를 변경하고 Color Story로 전환했을 때 `performance.timeOrigin`이 같고 Default `#266651`로 복원되며 inline override가 제거됐다. 편집기로 돌아오면 세션 편집값이 복원되고 Reset으로 비워졌다. [Designer 안내](designer-theme-guide.md)는 이 동작과 일치한다.
|
||||
|
||||
## 문서와 Git 공유
|
||||
|
||||
- Git Clone에 없는 과거 증거 링크 7개를 당시 `_local/` 경로의 텍스트 보관 기록으로 전환했다. 파일을 새로 만들거나 과거 PASS/PARTIAL 결과를 바꾸지 않았다.
|
||||
- Runtime portability의 중복 `3.2 Button`을 `3.4 Button`으로 정정했다.
|
||||
- README·개발 적용·예제·공유 안내에 GitHub Clone, Node 조건 `^20.19.0 || >=22.12.0`, 검증 npm 10.8.2, `npm ci`, workspace build, Storybook 6024와 신규 React 화면 제작 절차를 반영했다. 과거 ZIP 기록은 분리 보존했다.
|
||||
- Designer의 “다른 Story에도 반영”이라는 오래된 화면 문구를 실제 격리 동작에 맞게 수정했다. 임시 데이터는 sessionStorage에 보관되며 검수 Story에 적용되지 않는다.
|
||||
- `node scripts/check-doc-links.mjs`는 Git 공유 MD의 경로·heading과 Clone 제외 로컬 증거 링크를 검사한다. 무시되지 않은 신규 MD도 검사한다. 최종 전체 검사에 오류가 없어야 한다.
|
||||
- 기존 Git 실행 BAT, package.json, lockfile은 변경하지 않았다. ZIP 생성·포터블 패키징·Gitea 접근은 수행하지 않았다. [현재 실행 안내](publisher-distribution-guide.md).
|
||||
|
||||
## 검증 결과와 범위
|
||||
|
||||
| 항목 | 실제 결과 |
|
||||
|---|---|
|
||||
| THEME_DEFAULTS | 71색 / 73 defaults 일치 |
|
||||
| UI_BUILD / PACKAGE_BUILD | UI·CENTER workspace build 통과 |
|
||||
| TYPECHECK | root/UI/CENTER 및 예제 통과 |
|
||||
| PRODUCTION_BUILD | root 앱·Dashboard export·공개 HM 목록 예제 통과 |
|
||||
| STORYBOOK_BUILD | 통과, 292개 ID 보존·삭제/추가 없음 |
|
||||
| COMPONENT_TEST | 기존 8/8 통과, 테스트 원본 byte 보존 |
|
||||
| GUARD_TEST | 기존 40/40 통과, 테스트·Guard 규칙 byte 보존 |
|
||||
| THEME_STATE_TEST | 신규 3/3 통과: 비동기 실제 상태 대기·미충족 timeout·검증 CSS 범위 |
|
||||
| GUARD_FULL_SCREEN | 예제 GNB_ONLY / React index.html, FAIL 0 |
|
||||
| GUARD_PARTIAL | 변경 Theme Story/helper만 Storybook profile로 확인, FAIL 0 |
|
||||
| GUARD_STORYBOOK | 전체 Storybook profile, FAIL 0 |
|
||||
| CSS_IMPORTS | CSS import 69개, 누락 0 |
|
||||
| EXPORTS | 공개 import 736개·export artifact 16개, 누락 0 |
|
||||
| DOC_LINKS | 전체 MD 경로/heading 및 로컬 증거 링크 검사 오류 0 |
|
||||
| THEME_JSON_LOADER / DESIGNER | 위 반복·지연·viewport·Clone 검사 통과 |
|
||||
| PACKAGE_CONSUMER | 최종 UI/CENTER pack 독립 설치, strict:true / skipLibCheck:false 타입 검사 통과 |
|
||||
| GIT_CLONE_RUNTIME | GitHub Clone의 fresh npm ci·typecheck·UI/CENTER/Storybook build·6024 dev 실행 통과 |
|
||||
| NEW_REACT_SCREEN | Clone의 `_local/new-screen`에서 공개 HM 실제 React bootstrap·typecheck/build/dev·조회/초기화/모바일 메뉴 통과 |
|
||||
| RESPONSIVE | 대표 Story 18개 × 4폭, 운영 앱·목록·신규 화면 4폭, Sheet 4방향 × 4폭·Drawer 4폭 확인 |
|
||||
|
||||
필수 Guard FAIL은 없지만 정적 Guard의 최종 상태는 `NOT VERIFIED`다. Native 검증 도구 UI/소비 스타일 의도와 React 실제 렌더 판정 한계를 의미한다. 원본 JSON을 PASS로 바꾸지 않았다. UI source·실제 렌더 증거와 구분한다.
|
||||
|
||||
패키지 소비 프로젝트는 `@tanstack/react-table`과 직접 `@tanstack/table-core` 9.2.4 경계를 확인했다. API export 수량은 UI 255 / Theme 8 / CENTER 25 / CENTER Reference 10이다.
|
||||
|
||||
전체 **292개 Story는 1280px에서 렌더 확인**했다. 전체 Story의 모든 Props/interaction/모바일을 전수 검사했다는 의미는 아니다. 상세 동작은 조회/초기화/Enter, 메뉴/Escape, Sheet 안쪽 모서리·focus 복귀, Drawer 버튼 위치, Dialog Solid 세트·focus 유지, Input readOnly/disabled, Label focus, Tabs ArrowRight·flat panel, Progress radius, Accordion 제목 Hover 5%, Theme Focus/격리로 한정한다.
|
||||
|
||||
예상하지 않은 앱 Runtime/Console error는 관찰하지 않았다. Loader의 의도적 missing JSON 404와 Avatar fallback의 의도적 broken image 404는 원본 로그에 보존한다. 전체 렌더 탐색에서 숨김 `components-form-select--list-size-comparison`만 1280px에서 scrollWidth 1352였다. 수정 전 정적 빌드도 동일 1352여서 기존 비교 canvas 제한으로 남기고 공통 Select/대표 Story를 수정하지 않았다. 대표 18개 Story와 앱/목록/신규 화면의 4폭에서는 페이지 가로 넘침이 없었다.
|
||||
|
||||
Clone은 기존 node_modules/dist/환경 설정을 복사하지 않고 GitHub에서 받았다. Push 전 후보 source 변경만 적용하여 독립 설치·빌드했으며 최종 commit의 tree와 대조한다. 임시 화면·검사 코드·산출물은 `_local/`에 두고 Git에 포함하지 않는다. 소스의 로컬 절대경로 의존성도 별도 검사한다. npm ci의 선택적 WASM dependency cleanup EPERM 경고는 남았으나 설치 exit 0·실제 타입/빌드/실행은 통과했다.
|
||||
|
||||
## 기존 요청 보존
|
||||
|
||||
시작 추적 source 517개의 SHA-256을 기록했다. 변경된 기존 파일은 문서 8개와 Theme 검사 Story 2개뿐이다. Component/Pattern 구현·CSS·대표 Story(Theme 내부 설명 제외)·공개 barrel/API·Default JSON/Primitive/Semantic/생성값·기존 Component/Guard 테스트·실행 BAT·package/lockfile은 byte 동일이다.
|
||||
|
||||
D-01/D-02, Secondary/Legacy, 목록 Card/Filter/Table, 버튼·Table 강조 20%·Progress·Accordion·Separator·Sheet/Drawer·Navigation 및 C2~R3 구현을 다시 변경하지 않았다. 필요한 대표 실제 동작을 위와 같이 재검증했으며 모든 상태의 역사적 pixel diff를 수행했다는 뜻은 아니다.
|
||||
|
||||
## 개발 의존성 보안
|
||||
|
||||
현재 `npm audit --json`은 High 7 / Critical 0, `npm audit --omit=dev --json`은 0이다. 7개는 개별 독립 취약점 7개가 아니라 다음 직접 개발 도구와 간접 전파 그래프다.
|
||||
|
||||
| 패키지 | 설치 버전 | 경계 |
|
||||
|---|---|---|
|
||||
| shadcn | 4.21.1 | UI workspace 직접 devDependency |
|
||||
| @shadcn/registry | 0.1.0 | 간접 개발 도구 |
|
||||
| ts-morph | 26.0.0 | 간접 코드 생성/분석 도구 |
|
||||
| @ts-morph/common | 0.27.0 | 간접 개발 도구 |
|
||||
| fast-glob | 3.3.3 | 간접 glob 탐색 |
|
||||
| micromatch | 4.0.8 | 간접 glob matching |
|
||||
| braces | 3.0.3 | 깊게 중첩된 pattern의 stack exhaustion 원인 |
|
||||
|
||||
실행 경로는 shadcn CLI의 registry/파일 glob 처리다. 현재 app/package/Storybook build scripts는 shadcn CLI를 실행하지 않는다. 운영 dependency 감사는 0이며 소비 앱에 shadcn devDependency를 배포하지 않는다. 외부의 비신뢰 glob/registry 입력으로 해당 CLI를 호출할 때 위험은 남는다.
|
||||
|
||||
[GitHub 공식 권고 GHSA-vfj7-8cjw-p6xm](https://github.com/advisories/GHSA-vfj7-8cjw-p6xm)는 braces <=3.0.3에 패치 버전이 없음을 명시한다. npm 레지스트리 최신 braces는 3.0.3, shadcn은 4.21.4이지만 audit의 영향을 받는 상위 범위에 속해 이 patch만으로 해소되지 않는다. audit가 제안하는 shadcn 1.0.0은 현재 4.x의 major 역행이므로 보류했다. 강제 fix/override/major 교체나 lockfile 변경을 하지 않았다. Storybook 10.6.1 / Vite 8.3.0 / React 19.3.0의 현재 호환 구성을 유지했다.
|
||||
|
||||
500kB chunk·Storybook bundler 성능 안내는 번들 크기/성능 경고이며 이 braces 입력 처리 취약점과 다른 원인이다. 불필요한 대규모 upgrade로 해결했다고 표시하지 않는다.
|
||||
|
||||
## 잔여 제한과 판단
|
||||
|
||||
- 이전 간헐적 실패 당시의 정확한 브라우저 lifecycle/visibility 조건은 미확정이다. 확인한 검사 clock 의존성은 수정했고 반복 실행에서 재발하지 않았다.
|
||||
- 개발 도구 High 7건과 숨김 Select 비교 canvas의 기존 넘침은 남는다.
|
||||
- 실제 SR 발화·실기기 touch/drag·Node 미설치 PC·지원되는 모든 Node/npm/브라우저 조합은 미검증이다.
|
||||
- 미확정 컬러 의미·최종 Sheet radius·설정/도움말 숨김은 확정하지 않았다.
|
||||
- 필수 빌드·테스트·독립 설치/실행·대표 UI 검증을 통과하고 Critical/High 기능 회귀가 없어 GitHub main 일반 Push 대상이다. 위 제한을 포함하는 PARTIAL 테스트 공유이며 공식 Gitea 이전·운영 승인 완료를 뜻하지 않는다.
|
||||
|
||||
증거: `_local/publisher-validation-20261010/`의 baseline·transition-before/final·checks·browser matrix/responsive/all-stories·interactions·focus-isolation·clone·consumer·audit·preservation 로그/JSON/캡처와 최종 보고. 이 경로는 로컬 보관 자료이며 Git Clone에 포함되지 않는다. 과거 `_local/publisher-*` 검증 결과는 덮어쓰지 않았다.
|
||||
@@ -61,7 +61,7 @@ Tailwind는 기본적으로 실행 cwd를 기준으로 자동 검색하고 `node
|
||||
|
||||
CSS entry가 루트에 있으면 같은 `source("./")`는 루트 전체를 뜻하므로 제한 효과가 다르다. `src/` 밖 공유 UI가 있다면 그 실제 경로를 `@source`로 추가한다. 명시 목록으로 제한할 때는 `source(none)` + 필요한 `@source`도 지원하지만, 앱·공유 UI·HM source를 빠짐없이 지정해야 한다. [공식 Tailwind 소스 검색 문서](https://tailwindcss.com/docs/detecting-classes-in-source-files).
|
||||
|
||||
**HM Component 클래스 보존**: 공개 `@hm-design/ui/tailwind.css`를 생략하지 않는다. [패키지 소스](../../packages/ui/src/tailwind.css)는 `./components / ./patterns`를 검색하고, [기존 package build](../../scripts/build-package.mjs)는 배포 CSS에서 이를 `@source "./index.js"`로 바꾼다. 따라서 앱 자동 검색을 `src/`로 좁혀도 HM compiled 클래스는 해당 CSS의 명시 source를 통해 검색한다. 소비자가 소스 alias로 직접 연결한다면 배포 CSS와 경로가 같다고 가정하지 말고 실제 source 파일 존재를 확인한다. HM package 전체나 외부 `node_modules` 전체를 추가 검색 대상으로 삼지 않는다.
|
||||
**HM Component 클래스 보존**: 공개 `@hm-design/ui/tailwind.css`를 생략하지 않는다. [패키지 소스](../../packages/ui/src/tailwind.css)는 `./components / ./patterns`를 검색하고, [package build](../../scripts/build-package.mjs)는 배포 CSS에서 이를 `@source "./"`로 바꾼다. 검색 범위는 해당 compiled HM 폴더다. Windows에서 파일 단위 `./index.js` 경로가 utility를 누락하는 상태를 재현해 폴더 검색으로 보완했다. 앱 자동 검색을 `src/`로 좁혀도 HM compiled 클래스는 공개 CSS의 source를 통해 검색한다. 소비자가 소스 alias로 직접 연결한다면 배포 CSS와 경로가 같다고 가정하지 말고 실제 source 파일 존재를 확인한다. 외부 `node_modules` 전체를 검색 대상으로 삼지 않는다.
|
||||
|
||||
완료 시 앱 CSS import 순서, HM `@source` 대상 존재, 필요한 utility 생성 여부(예: GNB 모바일 trigger의 `lg:hidden`, Badge의 flex·크기 class)를 실제 소비 빌드에서 확인한다. 이 문서 작업에서는 버전·설정·구문 지원·source 연결만 대조했다. junction 지연 재현과 외부 앱 utility 생성은 미검증이며, 새 설정 파일·의존성·빌드는 추가하지 않았다.
|
||||
|
||||
@@ -105,9 +105,9 @@ React는 이 계약을 `Badge`와 `Button`/기존 `FilterBar` 조합으로 표
|
||||
|
||||
이전 대화 없이도 다음 파일만으로 재현 가능해야 한다: `AGENTS.md`, `packages/ui/src/patterns/dashboard-status/contract.ts`, `src/patterns/dashboard-status-contract.css`, `src/patterns/dashboard-layout.stories.tsx`, `docs/patterns/dashboard-status-static.html`, `packages/ui/dist/theme.css`, `docs/guidelines/runtime-theme-contract.md`. 구현 후 상태 ID/label, matching/count, DOM attributes, Theme artifact 상대 경로, React/Static HTML 차이, `file://` 검증 결과를 각각 보고한다.
|
||||
|
||||
### 3.2 Button 사용 계약
|
||||
### 3.4 Button 사용 계약
|
||||
|
||||
Button의 공통 기준은 [Button 문서](../components/button.md)의 역할·조합 규칙을 따른다. `brand`는 실제 화면당 최대 1개이고 팝업에는 사용하지 않으며, 일반 확인/작성은 같은 `size`의 Solid 세트, 삭제 확인과 반복·보조 작업은 같은 `size`의 Outline 세트를 사용한다. Static HTML과 다른 프레임워크는 React API를 복제하지 않아도 되지만, semantic button, `data-slot`/`data-variant`/`data-appearance`/`data-size` 계약, 기존 Theme CSS variable, native disabled 및 keyboard/modal 동작을 보존해야 한다.
|
||||
Button의 공통 기준은 [Button 문서](../components/button.md)의 역할·조합 규칙을 따른다. `brand`는 실제 화면당 최대 1개이고 팝업에는 사용하지 않으며, 일반 확인/작성은 같은 `size`의 Solid 세트, 삭제 확인은 같은 `size`의 Solid 세트, 일반 화면의 반복·보조 작업은 Outline을 사용한다. 조회·초기화는 Solid Green / Outline Gray이며 결정 세트로 강제하지 않는다. Static HTML과 다른 프레임워크는 React API를 복제하지 않아도 되지만, semantic button, `data-slot`/`data-variant`/`data-appearance`/`data-size` 계약, 기존 Theme CSS variable, native disabled 및 keyboard/modal 동작을 보존해야 한다.
|
||||
|
||||
## 4. Asset과 실행 위치
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
| `color.on.state.active` | `--hm-sem-on-state-active` | `#ffffff` | Active 위 텍스트/indicator | Yes | checkbox, calendar |
|
||||
| `color.fg.inverse` | `--hm-sem-on-action-primary` | `#ffffff` | 반전 텍스트 | Yes | pagination, badge, button, gnb, lnb |
|
||||
| `color.bg.subtle` | `--hm-sem-bg-subtle` | `#f4f1ea` | 은은한 면 | Yes | calendar, badge, table |
|
||||
| `color.accent` | `--hm-sem-accent` | `#bddfd4` | Soft Highlight 45% / Selected·Open surface 100% 원색 | Yes | select, combobox, menu item, table, calendar, pagination hover / toggle, menubar, navigation-menu trigger |
|
||||
| `color.accent` | `--hm-sem-accent` | `#bddfd4` | Soft Highlight 45%, Table 행 20% / Selected·Open surface 100% 원색 | Yes | select, combobox, menu item, table, calendar, pagination hover / toggle, menubar, navigation-menu trigger |
|
||||
| `color.on.accent` | `--hm-sem-on-accent` | `#123328` | Accent 위 텍스트; Primary와 독립 sibling | Yes | select, combobox, menu item, calendar, pagination hover, toggle, menubar, navigation-menu |
|
||||
| `color.palette.green-light-4` | `--hm-sem-palette-green-light-4` | `#34daaa` | 선택적 Theme 팔레트: green-light-4 | Yes | button |
|
||||
| `color.palette.green-light-3` | `--hm-sem-palette-green-light-3` | `#249473` | 선택적 Theme 팔레트: green-light-3 | Yes | data-table Sort Direction Accent, tabs 장식, lnb gradient |
|
||||
@@ -80,7 +80,7 @@
|
||||
|
||||
총 73개. 기존 25개 + 핵심 역할 6개 + 선택적 팔레트 42개. 팔레트는 컴포넌트별 계약이 아니며 Primary / Active / Focus를 개별 지정하면 팔레트 alias보다 우선한다. Focus와 Active, Primary와 On Accent는 각각 sibling이며 서로 alias하지 않는다.
|
||||
|
||||
`color.action.cancel`은 Button의 `variant="cancel"` Outline ink를 위한 Public Runtime role로 사용한다. Solid 취소는 기존 gray Component mapping을 유지하고, Outline 취소는 이 semantic role을 소비한다. 외부 소비 가능성이 있으므로 deprecated로 간주하지 않는다. 적용·병합·fallback·scope 정책은 [Runtime Theme](runtime-theme.md)를 따른다.
|
||||
`color.action.cancel`의 공개 key·기본값은 보존한다. 2026-10-10 Gray 통일 요청에 따라 기본 Outline 취소 ink는 기존 Gray palette `#767676`을 사용한다. 기본값과 다른 명시적 취소 컬러 override는 내부 Button mapping에 전달하고 Reset 시 복원한다. 전체 Default preset을 주입해도 기본 Gray와 동일하다. Solid 취소는 기존 Gray mapping을 유지한다. [Runtime Theme](runtime-theme.md).
|
||||
# 디자인팀 Runtime 운영 추가 결정 — 2026-10-06
|
||||
|
||||
기존 v1 입력 73개와 CSS property/type 계약을 유지한다. 공개 API `isRuntimeTheme(unknown): value is RuntimeTheme`를 제공한다. 이 사전 검증은 DOM을 변경하지 않는다. 기존 `applyRuntimeTheme`의 invalid 입력 시 reset 정책은 유지한다. 편집기는 사전 검증으로 invalid Import를 차단해 마지막 유효 Theme를 보존한다.
|
||||
|
||||
@@ -176,7 +176,7 @@ Global A 아래 Scoped B는 독립 HM preset에서 시작한다. B가 지정하
|
||||
|
||||
## 검증 화면
|
||||
|
||||
Global External에서 실제 Select Portal을 연 화면: [runtime-theme-global-select.jpg](../../_local/runtime-theme-global-select.jpg). Primary/Active/Focus/Accent/Destructive는 각각 다른 값이다.
|
||||
Global External에서 실제 Select Portal을 연 과거 검증 화면은 `_local/runtime-theme-global-select.jpg`로 기록되었으나 현재 작업 폴더에는 파일이 없다. 해당 과거 이미지 근거는 NOT VERIFIED다. Primary/Active/Focus/Accent/Destructive의 서로 다른 값 적용 계약은 [Runtime Theme 계약](runtime-theme-contract.md)에서 확인한다.
|
||||
|
||||
|
||||
## 작업 시간 (Asia/Seoul)
|
||||
|
||||
@@ -92,7 +92,7 @@ applyRuntimeTheme(panel, {
|
||||
- Active: Checkbox checked, Radio selected, Switch on, Slider range/thumb border, Progress fill, Calendar single / range edge, Date Picker의 Calendar selected.
|
||||
- Focus: `color.stroke.input.focus` → `--hm-sem-stroke-input-focus` → `--ring`. Checkbox/Calendar/Input/Select 등의 Focus와 Active는 독립적이다. Default에서는 둘 다 Light 2지만 Verification에서는 다른 값이다.
|
||||
- Primary: Badge default, Pagination current, Button outline, GNB/LNB current/strong ink. Active와 alias하지 않는다.
|
||||
- Accent 45%: Select/Menu Item/Calendar hover·range middle/Pagination hover/Table row hover·selected 등의 Soft Highlight. 내부 `--hm-sem-surface-highlight`를 사용한다. Accent 100% + On Accent: Toggle/Toggle Group의 Persistent Selected Surface, Menubar 상위 Highlighted/Open, Navigation Menu Trigger/Open. Navigation Current는 Primary + contextual surface로 Control Active와 구분한다.
|
||||
- Accent 45%: Select/Menu Item/Calendar hover·range middle/Pagination hover의 Soft Highlight. 내부 `--hm-sem-surface-highlight`를 사용한다. Table row hover·selected만 동일 Accent를 20%로 계산한다. Accent 100% + On Accent: Toggle/Toggle Group의 Persistent Selected Surface, Menubar 상위 Highlighted/Open, Navigation Menu Trigger/Open. Navigation Current는 Primary + contextual surface로 Control Active와 구분한다.
|
||||
- On Accent: Primary와 sibling Semantic이다. `color.on.accent`와 CSS-only package fallback은 독립 기본값을 가지며 Primary를 override해도 On Accent는 함께 바뀌지 않는다.
|
||||
- Destructive: Input 오류, Badge/Button/Menu 오류 표현. Primary/Active/Focus와 독립적이다.
|
||||
- Slider Hover/Drag halo는 Primary 20%, Keyboard Focus halo는 Focus Semantic 20%다. Focus와 Hover/Drag가 겹치면 Focus 색이 우선한다. GNB/LNB는 contextual navigation focus 예외(초록 면의 inverse outline, Current/Open 면의 contextual outline)를 유지한다. 팔레트 기반 Table header/Tab/navigation 장식은 Control Active 의미가 아니다. Data Table Sort Indicator는 별도 Green Light 3 palette 기반이며 [Pattern 문서](../patterns/data-table.md)를 따른다.
|
||||
|
||||
@@ -170,7 +170,7 @@ Custom 구현은 필요한 동작과 API에 한해 최소 범위로 제한한다
|
||||
|
||||
## 9. AI 신규 화면 구현 순서
|
||||
|
||||
AI 화면 구현의 단일 실행 순서는 저장소 루트의 [AGENTS.md Quick Start](../../AGENTS.md#ai-화면-구현-quick-start)를 따른다. 후보 Component·Pattern의 실제 export, 사용 문서, 대표 Story는 [통합 Reference Index](component-pattern-reference.md)에서 찾는다. 일반 업무 화면은 Storybook에 등록하지 않고 별도 React 화면으로 생성하며, 화면별 빌드·필요한 검증·독립 미리보기를 결과로 제공한다. 상세 재사용·Theme·Navigation 조건은 이 문서와 연결된 Source of Truth를 유지한다.
|
||||
AI 화면 구현의 단일 실행 순서는 저장소 루트의 [AGENTS.md 필수 규칙](../../AGENTS.md#hmdesign-ai-화면-구현--필수-규칙)을 따른다. 후보 Component·Pattern의 실제 export, 사용 문서, 대표 Story는 [통합 Reference Index](component-pattern-reference.md)에서 찾는다. 일반 업무 화면은 Storybook에 등록하지 않고 별도 React 화면으로 생성하며, 화면별 빌드·필요한 검증·독립 미리보기를 결과로 제공한다. 상세 재사용·Theme·Navigation 조건은 이 문서와 연결된 Source of Truth를 유지한다.
|
||||
|
||||
구현 중에는 다음 단계에 필요한 최소 확인만 하고, 완료 후 diff / 요구사항 / 관련 Story / 필요한 프로젝트 검증을 한 번에 수행한다. 같은 조건으로 성공한 검증을 형식적으로 반복하지 않는다.
|
||||
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
# 개발 적용 가이드 (검토용 개정안)
|
||||
|
||||
> 기준 우선순위: 2026-10-10 추가 수정 요청의 확정 사항 → 충돌하지 않는 D-01/D-02 → 현재 HM Component/Pattern/Theme → 현재 Storybook/구현 → 과거 문서. [현재 추가 수정 기준](publisher-additional-review-2026-10-10.md). 미확정 값은 임의 확정하지 않으며 과거 검증 기록은 보존합니다.
|
||||
|
||||
페이지 구현 전에 [Navigation Single Mode Policy](navigation-single-mode.md)를 적용한다. AI 코드 생성·제안, 신규/기존 화면, 프로토타입, Production 모두 GNB / LNB / DASHBOARD 중 정확히 하나만 선택한다. 모바일도 같은 체계의 Responsive Variant를 사용하며 별도 요청 없이 Navigation 조합을 생성하거나 제안하지 않는다.
|
||||
|
||||
> 대상: 디자인팀과 서비스 개발팀. 현재 UI/CENTER compiled dist build/export, JSON Default/서비스 partial, 공개 Runtime 검증·Global/Scoped Apply와 URL Loader, Storybook JSON Preview, Theme-only artifact 산출이 구현되었다. Registry publish 이력은 테스트 ZIP 검증 범위 밖이며 실제 CDN infrastructure/publish pipeline은 다음 단계다. 테스트 ZIP은 로컬 workspace와 포함 dist를 사용하므로 Registry 접근·publish가 필요하지 않다. 아래 장기 운영 예시의 `@company/ui`는 목표명이며 현재 import는 `@hm-design/ui`다. 현재 실제 API/독립 배포 절차는 [Theme delivery](theme-delivery.md), 디자인팀 workflow는 [Theme guide](designer-theme-guide.md)를 따른다.
|
||||
> 대상: 디자인팀과 서비스 개발팀. 현재 UI/CENTER compiled dist build/export, JSON Default/서비스 partial, 공개 Runtime 검증·Global/Scoped Apply와 URL Loader, Storybook JSON Preview, Theme-only artifact 산출이 구현되었다. 현재 테스트 공유는 Git Clone → npm ci → npm run build:packages → npm run storybook(6024)이다. [현재 Git 설치·실행 안내](../../README.md#git-clone-설치실행-현재-테스트-공유-기준)를 먼저 따른다. Registry publish 이력은 Git 테스트 공유 검증 범위 밖이며 실제 CDN infrastructure/publish pipeline은 다음 단계다. Git Clone은 로컬 workspace를 빌드하므로 HM Registry 접근·publish가 필요하지 않다. 아래 장기 운영 예시의 `@company/ui`는 목표명이며 현재 import는 `@hm-design/ui`다. 현재 실제 API/독립 배포 절차는 [Theme delivery](theme-delivery.md), 디자인팀 workflow는 [Theme guide](designer-theme-guide.md)를 따른다.
|
||||
|
||||
## 1. 착수 순서
|
||||
|
||||
@@ -101,7 +103,7 @@ MVP의 Theme 문서 예시는 다음과 같다. `tokens`는 **선택적 override
|
||||
|
||||
## 6. Storybook 작성·검수 기준
|
||||
|
||||
- Story import는 `@company/ui`의 공개 진입점과 기본 CSS를 사용한다. 로컬 내부 파일을 직접 가리켜 패키지 배포 결과와 달라지는 구성을 피한다.
|
||||
- 현재 Story import는 `@hm-design/ui`의 공개 진입점과 기본 CSS를 사용한다(`@company/ui`는 장기 운영 목표명). 로컬 내부 파일을 직접 가리켜 패키지 배포 결과와 달라지는 구성을 피한다.
|
||||
- 컴포넌트별 공개 props, variant/state, 오류·비활성·로딩, 키보드/포커스 동작을 지원 범위에 맞게 기록한다.
|
||||
- 현재 Theme verification Story에서 Default/External과 Runtime 계약을 비교한다. Theme selector toolbar는 없다. Preview는 운영 Publish를 수행하지 않고 패키지 Runtime API를 사용한다.
|
||||
- 값 검수는 실제 컴포넌트의 기본/hover/focus/disabled/error 상태, 대비·가독성, 잘림·넘침을 포함한다. Theme 변경이 닿는 Story에 집중한다.
|
||||
@@ -117,3 +119,29 @@ MVP의 Theme 문서 예시는 다음과 같다. `tokens`는 **선택적 override
|
||||
- 컴포넌트 API 변경은 Theme Publish만으로 처리하지 않고 패키지 릴리스와 앱 업데이트로 전달한다.
|
||||
|
||||
운영 절차는 [운영/배포 가이드](운영-배포-가이드.md)를 따른다.
|
||||
|
||||
## 8. Publisher / Developer 화면 조합 확인
|
||||
|
||||
사용 요소는 [Component / Pattern 인덱스](component-pattern-reference.md)에서 선택하고 기존 Component → Variant / Props → Pattern / Composition 순으로 해결한다. 실무 예시의 숫자를 새 공통 규칙으로 만들지 않는다. 이번 사전공유는 Tabs 조합과 디자인 방향에 관한 자료이며 Dashboard·GNB·LNB·Filter·Loading의 새 규격을 제공하지 않는다.
|
||||
|
||||
### 8.1 탭 조합과 역할별 간격
|
||||
|
||||
| 확인 항목 | 현재 기준 / 실무 주의 |
|
||||
|---|---|
|
||||
| 탭 콘텐츠의 중첩 박스 | [Tabs §16](../components/tabs.md#16-publisher--developer-조합-안내-2026-10-09). Card 안은 surface, content 페이지 위는 content. TabsContent의 중복 배경·border·좌우 padding 제거 |
|
||||
| 역할별 간격 | [PageHeader](../patterns/page-header.md): 제목→설명 8px, 아래 콘텐츠 20px. [기본 Card](../components/card.md): 여백·Header→Content 24px. TabsContent `py-6`는 조합 예시로만 사용 |
|
||||
| Typography / Color | [Typography Reference](../../src/foundation/typography.stories.tsx), [Color Reference](../../src/foundation/color.stories.tsx)와 각 Component 문서. CardTitle·PageHeaderTitle·Tab label을 같은 크기로 통일하지 않음 |
|
||||
| Spacing / Layout | [Layout Reference](../../src/foundation/layout.stories.tsx). 전역 spacing scale은 미정의. Card 전용 Token·비교 이미지의 48px을 화면 전체 gap으로 재사용하지 않음 |
|
||||
| Theme 연결 | 기존 앱 CSS entry의 Tailwind / 공개 HM CSS를 재사용. [소비자 검색 범위](runtime-portability.md#21-tailwind-v4-소비자-검색-범위)를 확인하고 새 utility가 실제 생성되는지 검증 |
|
||||
| State | Selected·Inactive·Hover·Focus·Disabled는 기존 Tabs 계약. Empty / Loading / Error는 기존 [Component / Pattern](component-pattern-reference.md)을 조합하고 소비자가 데이터 상태를 관리 |
|
||||
| Responsive | 실제 부모의 수축(`min-w-0`)과 문서 넘침 확인. Tabs는 기존 넘침 버튼, [Table](../components/table.md)은 기본 최소 폭 520px·내부 스크롤 유지. 페이지 Navigation은 기존 단일 모드 유지 |
|
||||
| Accessibility | tablist 접근 가능한 이름, Trigger / Content value 일치, 연결된 입력 Label, 방향키·Home/End·focus-visible·disabled 건너뛰기 확인. 입력 초안 유지가 필요하면 소비자 상위 state 사용 |
|
||||
|
||||
### 8.2 디자인 방향과 실제 반영 상태 구분
|
||||
|
||||
- 사전공유 v0.2의 중첩 박스 제거(D-01)는 기존 API만으로 가능하다. TabsContent는 원래 배경·border를 자동 추가하지 않으므로 소비 코드를 조정한다. 고유 Input·Table·Alert 스타일은 제거하지 않는다.
|
||||
- 상단 White 80%(D-02)는 사용자의 2026-10-09 실제 구현 요청에 따라 Tabs의 Primary content branch에 반영했다. `background-image` 상단 stop의 alpha만 0.8이며 전체 탭 opacity는 1, Secondary·Legacy·Disabled 상태 규칙은 유지한다. 공통 Palette·Theme JSON을 80%로 바꾸지 않는다. [Theme 사용과 Source 수정](테마-토큰-가이드.md#theme-사용과-theme-source-수정) 및 [Tabs 실제 반영 범위](../components/tabs.md#163-d-02-상단-흰색-80-실제-반영)를 따른다.
|
||||
- 대표 Story와 Fill verification 예제 모두 중첩 박스 없는 패널을 사용한다. Legacy Compatibility는 이전 조합 보존 목적이며 신규 운영 디자인 기준으로 사용하지 않는다. AI 화면은 [AGENTS.md](../../AGENTS.md)에 따라 실제 HM React Component를 렌더하며 별도 HTML 모방 화면을 제출하지 않는다.
|
||||
- 검증은 최종 통합 단계에서 필요한 빌드·정적 Guard·실제 브라우저 확인을 수행한다. 배경 transparent·border 0·padding 24px 0, 자식 정렬과 고유 스타일, 실제 gradient alpha·전체 opacity, desktop / mobile 넘침과 핵심 동작을 구분해 기록한다. 정적 PASS로 브라우저 확인을 대체하지 않으며 미실행은 `NOT VERIFIED`로 표시한다.
|
||||
|
||||
이번 비교 분류·변경 파일·검증 범위는 [사전공유 통합 보고](publisher-integration-2026-10-09.md)를 따른다.
|
||||
@@ -269,7 +269,7 @@ Layout / Pattern → 현재 HM 대표 Story / Pattern 문서와 단일
|
||||
|
||||
### 6.12 Navigation Single Mode (2026-10-07 사용자 확정)
|
||||
|
||||
**ONE PAGE = ONE NAVIGATION MODE.** GNB ONLY / LNB ONLY / DASHBOARD ONLY 중 정확히 하나를 선택한다. 독립 모드를 결합하는 GNB + LNB, GNB + Dashboard, LNB + Dashboard, 세 가지 중첩은 금지한다. GNB ONLY 내부 Sidebar에서 기존 LNB 메뉴 부품을 재사용하는 것은 독립 LNB Mode 추가가 아니며 허용한다. Sidebar 외곽 배경만 Green Light 2로 적용하고 메뉴 디자인·구조·동작은 유지한다.
|
||||
**ONE PAGE = ONE NAVIGATION MODE.** GNB ONLY / LNB ONLY / DASHBOARD ONLY 중 정확히 하나를 선택한다. 독립 모드를 결합하는 GNB + LNB, GNB + Dashboard, LNB + Dashboard, 세 가지 중첩은 금지한다. 신규 AI Production 화면의 GNB ONLY·DASHBOARD ONLY에는 Sidebar를 생성하지 않는다. LNB ONLY의 공식 좌측 Navigation은 허용한다. GNB 내부 LNB 부품 Sidebar와 Green Light 2 배경 계약은 기존 Component·Pattern·Reference의 호환성 보존용이며 신규 운영 화면 허용 기준이 아니다.
|
||||
|
||||
- AI 기반 코드 생성·제안, 신규 페이지 구현, 기존 화면 수정, 프로토타입, Storybook, 실제 Production 구현 전체에 동일하게 적용한다. AI는 별도 요청이 없는 한 Navigation 조합을 생성하거나 제안하지 않는다.
|
||||
- 모바일에서도 선택한 체계를 유지한다. LNB Desktop(≥1024px) → LNB Mobile Header(≤1023px)는 같은 LNB Mode다.
|
||||
|
||||
@@ -59,6 +59,8 @@ Dashboard 운영 화면은 전용 Header/Menu·업무 상태 필터와 Content
|
||||
|
||||
상태 CSS는 변수 정의만 제공한다. 기존 `Badge variant="outline"`에는 화면의 wrapper에서 아래 mapping을 적용한다. 완료의 흰색 ink가 유지되므로 기존 어두운 Badge 배경도 함께 유지한다. `issue` Badge는 실제 상태 Badge와 별도로 렌더링한다.
|
||||
|
||||
이 recipe와 일치하더라도 소비자의 HM slot CSS는 Guard `REUSE-003 NOT VERIFIED`를 유지한다. [CSS Intent 근거 연결](../guidelines/ai-generation-guard.md#css-측정과-intent-검토-근거)은 정확한 issue·문서 SHA·실측 변수를 연결하며 스타일 적용 확인과 사용자 디자인 의도 승인을 구분한다.
|
||||
|
||||
```css
|
||||
.dashboard-status [data-status="active"] { --dashboard-status-color: var(--hm-dashboard-status-active); }
|
||||
.dashboard-status [data-status="hold"] { --dashboard-status-color: var(--hm-dashboard-status-hold); }
|
||||
@@ -73,6 +75,8 @@ Dashboard 운영 화면은 전용 Header/Menu·업무 상태 필터와 Content
|
||||
|
||||
HTML adapter는 같은 상태 변수를 자신의 `color` 등에 연결한다. package dist를 정적 자산으로 배치하면 `theme.css` 다음에 `dashboard-status.css`를 `<link>`로 로드한다. 저장소의 기존 Static HTML 예제는 호환 CSS 경로를 그대로 사용한다. React와 HTML 모두 `done`은 `--hm-dashboard-status-done`을 참조하며, 이 alias는 `:root`와 `[data-hm-theme]`에서 각 scope의 white token으로 재계산한다. active/hold/issue 색상과 Runtime Theme의 73개 계약은 유지한다.
|
||||
|
||||
Guard의 REUSE-003는 위 소비 mapping에도 검토 위치를 남긴다. Token 선언과 실제 Badge custom property/color/background/border를 통과해도 요청 디자인과의 의미적 일치는 자동 승인하지 않는다. [CSS Intent·동적 Token 증거 계약](../guidelines/ai-generation-guard.md#css-intent와-동적-token-검사-2026-10-10)에 따라 위치별 STATIC/RUNTIME/DESIGN_INTENT/FINAL을 보고하고, 실제 실행하지 않은 Theme와 상태는 NOT VERIFIED로 남긴다. 기존 대표 Story·상태 색상·Layout은 그대로 유지한다.
|
||||
|
||||
#### React 소비 예제: 데이터 → 상태 변수 → Badge
|
||||
|
||||
`active`(진행) → `--hm-dashboard-status-active`, `hold`(보류) → `--hm-dashboard-status-hold`, `done`(완료) → `--hm-dashboard-status-done`이다. 독립 `issue === true`는 `--hm-dashboard-status-issue`로 별도 Badge를 표시한다. `tone`은 의미 분류이며 Badge variant나 CSS를 자동 선택하지 않는다. 위 CSS mapping과 import 순서를 앱 CSS entry에 적용한 다음 아래 공개 API를 사용한다.
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# Data Table (Pattern)
|
||||
|
||||
> 2026-10-10 추가 수정 요청 기준: 기본 검색 가운데 / 추가 조건 검색 왼쪽, 조건→검색어→조회→초기화·8px. Header는 Card 밖, 검색·목록 도구·결과는 한 Card. 페이지 크기 label useId로 인스턴스 분리. 과거 검증 기록은 당시 결과이며 현재 검증은 [추가 수정 보고서](../guidelines/publisher-additional-review-2026-10-10.md)를 따릅니다.
|
||||
|
||||
현재 HM 구현의 기준 문서. 공통 원칙은 `docs/guidelines/프로젝트-지침.md`(§6, §7, Pattern 절)를 따른다. 이 문서는 Data Table Pattern 고유의 API·상태·결정만 기록한다.
|
||||
|
||||
## 1. 상태
|
||||
@@ -60,7 +62,7 @@ Table, Checkbox(header mixed), Pagination, Select(페이지 크기), Dropdown Me
|
||||
|
||||
## 8. Styling / Token
|
||||
|
||||
Header·cell·row·selected 면은 `packages/ui/src/theme/table.css`(`--hm-table-*`)가 소유하고 Pattern은 다시 정의하지 않는다. 컬러 역할(2026-10-06): 선택 행 면 = `--accent` 45%(hover·selected+hover와 같은 Soft Surface, Select Highlight / Selected와 동일한 Accent 45% 정책), 선택 Checkbox = `--hm-sem-state-active`(Light 2). 면은 hover와 같으므로 선택 여부는 Checkbox와 선택 수 요약으로 구분한다. Pattern 전용: `packages/ui/src/theme/data-table.css`의 `--hm-data-table-*`(footer gap·padding, summary 색·크기, 정렬 버튼 간격·아이콘 크기·활성 색, empty padding·색, skeleton 높이). 신규 Primitive·Semantic 없음.
|
||||
Header·cell·row·selected 면은 `packages/ui/src/theme/table.css`(`--hm-table-*`)가 소유하고 Pattern은 다시 정의하지 않는다. 컬러 역할(2026-10-06): 선택 행 면 = `--hm-sem-accent` 20%(hover·selected+hover와 같은 Soft Surface, Table에만 적용하는 20% 정책; Select 강조는 기존 45% 유지), 선택 Checkbox = `--hm-sem-state-active`(Light 2). 면은 hover와 같으므로 선택 여부는 Checkbox와 선택 수 요약으로 구분한다. Pattern 전용: `packages/ui/src/theme/data-table.css`의 `--hm-data-table-*`(footer gap·padding, summary 색·크기, 정렬 버튼 간격·아이콘 크기·활성 색, empty padding·색, skeleton 높이). 신규 Primitive·Semantic 없음.
|
||||
|
||||
- Loading: header 유지, body는 Skeleton 행(최대 5행), `aria-busy`.
|
||||
- Sort Direction Accent: `--hm-data-table-sort-active-color`는 현재 `--hm-sem-palette-green-light-3`(Green Light 3 palette)를 참조한다. 별도 State Semantic으로 승격하지 않았으며 Primary/Active/Accent 역할에 자동 연결되지 않는다. Token 이름의 `active`는 Control Active Semantic 계약을 뜻하지 않는다.
|
||||
@@ -79,6 +81,22 @@ semantic `<table>` 유지. 정렬 열 `<th aria-sort>`(ascending / descending),
|
||||
|
||||
Table primitive의 container가 가로 스크롤한다. Pattern은 `[data-slot="data-table"] { min-width: 0 }`로 grid / flex 부모 안에서 페이지를 밀지 않게 한다. 390px에서 페이지 가로 overflow 없음(표만 520px 안에서 스크롤), footer는 요약 / 페이지 크기 / 페이지 이동이 줄바꿈된다. 카드형 변환은 없다.
|
||||
|
||||
### 11.1 식별자 줄바꿈과 열 폭
|
||||
|
||||
Table의 `overflow-wrap: anywhere`는 긴 일반 콘텐츠를 보호하지만 좁은 ID 열에서 `JOB-001`을 여러 줄로 분절할 수 있다. ID·날짜 등 의미상 한 줄이어야 하는 값은 해당 cell의 콘텐츠만 보호한다. 제목 등 장문은 기존 줄바꿈을 유지한다.
|
||||
|
||||
```tsx
|
||||
const columns: DataTableColumnDef<Job>[] = [
|
||||
{ accessorKey: 'id', header: 'ID', enableSorting: false,
|
||||
cell: ({ row }) => <span className="whitespace-nowrap">{row.original.id}</span> },
|
||||
// 제목·그 외 열은 요구사항에 맞는 기존 cell composition을 유지한다.
|
||||
]
|
||||
```
|
||||
|
||||
현재 DataTable은 `ColumnDef.size/minSize`를 DOM의 th/td width 또는 min-width로 연결하지 않는다. 해당 값만 지정하고 폭이 확보됐다고 보고하지 않는다. `nowrap` 콘텐츠의 실제 폭·cell padding·표 내부 스크롤을 측정한다. 긴 식별자의 별도 최소 폭이 필요하면 소비 콘텐츠의 min-width composition과 실제 DOM 폭을 확인한다. Typography·Color·공통 Table CSS는 변경하지 않는다. Ellipsis를 쓰는 요구사항이라면 키보드/터치로 전체 값을 확인할 경로를 함께 제공하며 ID를 잘라서 식별 가능하다고 판단하지 않는다.
|
||||
|
||||
네 폭에서 ID 전체 텍스트·Range 줄 수·cell 내용 폭·table/container scrollWidth/clientWidth와 문서 가로 넘침을 기록한다. 긴 제목 줄바꿈, 표 내부 가로 스크롤과 마지막 열 접근을 함께 확인한다. `min-width: 0`만으로 ID 가독성을 보장하지 않는다.
|
||||
|
||||
## 12. 보류 / 비범위
|
||||
|
||||
- column resizing·pinning, grouping, tree, virtualization, infinite scroll, drag reorder, 서버 사이드 페이지/정렬, 편집 가능한 표.
|
||||
|
||||
+20
-13
@@ -1,5 +1,7 @@
|
||||
# Filter Bar (Pattern)
|
||||
|
||||
> 2026-10-10 추가 수정 요청 기준: 공통 FilterBar 기본 배치는 유지. 목록 소비자는 공개 `layout="list-basic" | "list-extended"` prop으로 가운데·왼쪽 정렬과 actions auto margin 제거를 선택한다. 기존 [src/list-screen.css](../../src/list-screen.css) 소비자는 호환성을 유지한다. PageHeader 밖의 흰 Card 하나에 조건→검색어→조회→초기화 순서, 간격 8px, 조회 Solid Green·초기화 Outline Gray를 적용한다. readOnly·disabled Search에는 Clear 버튼을 노출하지 않는다. 과거 검증 기록은 당시 결과이며 현재 검증은 [추가 수정 보고서](../guidelines/publisher-additional-review-2026-10-10.md)를 따릅니다.
|
||||
|
||||
현재 HM 구현의 기준 문서. 공통 원칙은 `docs/guidelines/프로젝트-지침.md`(§6, §7, Pattern 절)를 따른다.
|
||||
|
||||
## 1. 상태
|
||||
@@ -14,7 +16,7 @@
|
||||
|
||||
## 2. 목적 / 사용 범위
|
||||
|
||||
목록·업무 화면의 검색 조건 행. Data Table 없이도 쓸 수 있고, 값은 소비자가 소유한다. ui-viz의 Search Field(선택값 칩 + 후보)는 별개의 복합 컨트롤이라 이 Pattern에 넣지 않았다.
|
||||
목록·업무 화면의 검색 조건 행. Table·Card 목록·모바일 목록의 검색에서 우선 검토하며 Data Table 없이도 쓸 수 있고, 값은 소비자가 소유한다. 맞는 부분만 조합할 수 있다. 요구사항이 chips/복수 검색 등 공개 API·구조로 표현되지 않으면 구체적인 미사용 이유를 기록하고 HM Component로 조합한다. ui-viz의 Search Field(선택값 칩 + 후보)는 별개의 복합 컨트롤이라 이 Pattern에 넣지 않았다.
|
||||
|
||||
## 3. 구성 요소
|
||||
|
||||
@@ -23,16 +25,19 @@
|
||||
## 4. 구조
|
||||
|
||||
```tsx
|
||||
<FilterBar>
|
||||
<FilterBarSearch value={q} onValueChange={setQ} placeholder="이름·부서 검색" />
|
||||
<FilterBar layout="list-extended">
|
||||
<Select>…</Select> <Combobox … /> <DatePicker … />
|
||||
<FilterBarActions><Button variant="cancel" appearance="outline">초기화</Button></FilterBarActions>
|
||||
<FilterBarSearch value={q} onValueChange={setQ} placeholder="이름·부서 검색" />
|
||||
<FilterBarActions>
|
||||
<Button type="button" variant="primary" appearance="solid" onClick={apply}>조회</Button>
|
||||
<Button type="button" variant="cancel" appearance="outline" onClick={reset}>초기화</Button>
|
||||
</FilterBarActions>
|
||||
</FilterBar>
|
||||
```
|
||||
|
||||
## 5. Public API
|
||||
|
||||
- `FilterBar`, `FilterBarActions`: `div` props. wrapper에 role을 두지 않는다.
|
||||
- `FilterBar`: `div` props + 선택적 `layout: "default" | "list-basic" | "list-extended"`. 기본은 기존 배치 유지. `FilterBarProps` 공개 type 추가. `FilterBarActions`: `div` props. wrapper에 role을 두지 않는다.
|
||||
- `FilterBarSearch`: `value`, `onValueChange`(필수), `size`(Input size, 기본 `medium`), `placeholder`(기본 "검색"), 나머지 `input` props. `aria-label` 기본값은 placeholder. 값이 있으면 지우기 버튼(`aria-label="검색어 지우기"`).
|
||||
- Reset은 소비자가 Button과 callback으로 구성한다(Pattern에 `onReset` prop 없음).
|
||||
- Dashboard의 빠른 상태 전환(`all / active / hold / done / issue`)은 `FilterBar`가 소유하지 않는다. `FilterBar`는 검색·Select·Combobox·DatePicker 등의 조회 조건 layout으로 유지하고, 상태 필터는 Dashboard status contract를 소비하는 별도 조합으로 배치한다.
|
||||
@@ -41,9 +46,9 @@
|
||||
|
||||
Pattern은 상태가 없다. Data Table과 연결할 때는 검색 → `table.setGlobalFilter`, 열 선택 → `column.setFilterValue`로 소비자가 잇는다(`data-table.md` §6).
|
||||
|
||||
FilterBar에는 `onSearch / onSubmit / onReset` 공개 API나 조회 시점 강제가 없다. 검색어 지우기도 `onValueChange("")`만 호출한다. 즉시 적용할지 조회 버튼으로 적용할지, 초기화 후 바로 전체 목록을 복원할지는 소비자가 결정한다. [대표 Story](../../src/patterns/filter-bar.stories.tsx)의 조회 버튼에는 실행 callback이 없고 조건 수는 입력값으로 계산한다. [DataTable 연동 verification](../../src/patterns/data-table.stories.tsx)의 `WithFilterBarStory`는 입력 즉시 table 필터를 변경하며 조회 버튼은 없다. 이 둘을 조회 버튼 적용 계약으로 해석하지 않는다.
|
||||
FilterBar에는 `onSearch / onSubmit / onReset` 공개 API나 조회 시점 강제가 없다. 검색어 지우기도 `onValueChange("")`만 호출한다. 즉시 적용할지 조회 버튼으로 적용할지, 초기화 후 바로 전체 목록을 복원할지는 소비자가 결정한다. [대표 Story](../../src/patterns/filter-bar.stories.tsx)는 입력 조건 수와 조회 적용 조건 수를 구분하고 조회/초기화 callback을 실행한다. [DataTable 연동 verification](../../src/patterns/data-table.stories.tsx)의 `WithFilterBarStory`는 입력 즉시 table 필터를 변경하며 조회 버튼은 없다. 이 둘을 조회 버튼 적용 계약으로 해석하지 않는다.
|
||||
|
||||
DatePicker / Combobox는 대표 Story에서 `controlled={true}`로 사용한다. 부모가 각 `value`를 소유하고 초기화 시 `setDate(undefined)` / `setCategory(undefined)`로 비우므로, 선택값 초기화 목적의 `key` remount는 필요 없다. 검색·상태 등 나머지 조회 조건도 부모가 함께 초기화한다. FilterBar 공개 API와 초기화 / 조회 Outline 버튼 세트는 유지한다. 외부 값 초기화는 자식 `onValueChange`를 호출하지 않으며, 팝업 닫기·검색어·달력 월 초기화를 보장하지 않는다.
|
||||
DatePicker / Combobox는 대표 Story에서 `controlled={true}`로 사용한다. 부모가 각 `value`를 소유하고 초기화 시 `setDate(undefined)` / `setCategory(undefined)`로 비우므로, 선택값 초기화 목적의 `key` remount는 필요 없다. 검색·상태 등 나머지 조회 조건도 부모가 함께 초기화한다. FilterBar 공개 API는 유지하고 목록의 조회/초기화 버튼은 위 최신 소비 계약을 따른다. 외부 값 초기화는 자식 `onValueChange`를 호출하지 않으며, 팝업 닫기·검색어·달력 월 초기화를 보장하지 않는다.
|
||||
|
||||
### 6.1 조회 버튼으로 적용하는 소비 예제
|
||||
|
||||
@@ -52,7 +57,7 @@ DatePicker / Combobox는 대표 Story에서 `controlled={true}`로 사용한다.
|
||||
```tsx
|
||||
import { useMemo, useState } from "react"
|
||||
import {
|
||||
Button, DataTable, FilterBar, FilterBarActions, FilterBarSearch,
|
||||
Button, Card, CardContent, DataTable, FilterBar, FilterBarActions, FilterBarSearch,
|
||||
Select, SelectContent, SelectItem, SelectTrigger, SelectValue, useDataTable,
|
||||
type DataTableColumnDef,
|
||||
} from "@hm-design/ui"
|
||||
@@ -84,8 +89,8 @@ export function QueryList() {
|
||||
table.setPageIndex(0)
|
||||
}
|
||||
return <>
|
||||
<FilterBar>
|
||||
<FilterBarSearch value={draft.query} onValueChange={query => setDraft(s => ({ ...s, query }))} placeholder="이름 검색" />
|
||||
<Card><CardContent>
|
||||
<FilterBar layout="list-basic">
|
||||
<Select value={draft.status} onValueChange={status => setDraft(s => ({ ...s, status }))}>
|
||||
<SelectTrigger size="medium" aria-label="사용자 상태"><SelectValue /></SelectTrigger>
|
||||
<SelectContent>
|
||||
@@ -94,13 +99,15 @@ export function QueryList() {
|
||||
<SelectItem value="inactive">비활성</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FilterBarSearch value={draft.query} onValueChange={query => setDraft(s => ({ ...s, query }))} placeholder="이름 검색" />
|
||||
<FilterBarActions>
|
||||
<Button type="button" variant="primary" appearance="solid" size="default" onClick={apply}>조회</Button>
|
||||
<Button type="button" variant="cancel" appearance="outline" size="default" onClick={reset}>초기화</Button>
|
||||
<Button type="button" variant="primary" appearance="outline" size="default" onClick={apply}>조회</Button>
|
||||
</FilterBarActions>
|
||||
</FilterBar>
|
||||
<p role="status">조회 결과 {data.length}건</p>
|
||||
<DataTable table={table} emptyMessage="조건에 맞는 사용자가 없습니다." />
|
||||
</CardContent></Card>
|
||||
</>
|
||||
}
|
||||
```
|
||||
@@ -119,11 +126,11 @@ Input, Select, Combobox, Date Picker, Button(그 외 Popover 등 자유). 각
|
||||
|
||||
`Patterns/Data/Filter Bar` → `Filter Bar`: 검색, 상태 Select, 분류 Combobox, 날짜 Date Picker, 초기화 / 조회, 적용된 조건 수.
|
||||
|
||||
대표 Story의 초기화 / 조회는 목록의 반복 조회·보조 작업 세트다. [Button 사용 위치와 버튼 세트 규칙](../components/button.md#5-사용-위치와-버튼-세트)에 따라 둘 다 `appearance="outline"`, `size="default"`를 사용하고 역할만 `cancel` / `primary`로 구분한다. FilterBar는 Button appearance를 강제하지 않으며 소비자가 같은 세트의 appearance와 size를 맞춘다. 대표 Story의 조회는 실행 callback이 없는 조합 예시이고, 적용된 조건 수는 입력 상태에 즉시 반영된다.
|
||||
현재 대표 Story는 조건→검색어→조회→초기화, 조회 `variant="primary" appearance="solid"`·초기화 `variant="cancel" appearance="outline"`를 사용한다. 이는 [최신 목록 검색 계약](../guidelines/publisher-additional-review-2026-10-10.md)에 따른 Button 세트 예외다. FilterBar 자체가 Button appearance나 조회 시점을 강제하지 않는다. 대표 Story의 입력 조건 수는 즉시 변하지만 조회 적용 조건 수는 조회 클릭에만 반영되며 초기화는 둘 다 비운다. 업무 화면은 §6.1처럼 요청된 동작을 구현하며 Story의 부가 기능을 필수로 복사하지 않는다.
|
||||
|
||||
## 10. Accessibility
|
||||
|
||||
검색은 `type="search"` + `aria-label`, 아이콘은 `aria-hidden`. 컨트롤마다 `aria-label`을 준다(Story 기준). Reset·Clear는 `button`. wrapper는 시맨틱 변경 없음. 브라우저 기본 검색 지우기 버튼은 숨기고 자체 버튼을 쓴다.
|
||||
검색은 `type="search"` + `aria-label`, 아이콘은 `aria-hidden`. 컨트롤마다 `aria-label`을 준다(Story 기준). Reset·Clear는 `button`. wrapper는 시맨틱 변경 없음. 지우기 버튼이 사라질 때 검색 입력에 focus를 돌려주며 소비자 ref 전달을 유지한다. 브라우저 기본 검색 지우기 버튼은 숨기고 자체 버튼을 쓴다.
|
||||
|
||||
## 11. Responsive
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# GNB (Pattern)
|
||||
|
||||
> 2026-10-10 추가 수정 요청 기준: 기존 Reference 콘텐츠 LNB는 본문과 동일 배경·세로 divider 1개, 아이콘 기본 생략(선택적 허용), 해당 컬러 계열 선택·Hover. data-hm-color="brown" 범위는 Brown 색상. 신규 AI GNB_ONLY Sidebar 금지 정책 유지. 과거 검증 기록은 당시 결과이며 현재 검증은 [추가 수정 보고서](../guidelines/publisher-additional-review-2026-10-10.md)를 따릅니다.
|
||||
|
||||
> **SINGLE NAVIGATION MODE.** 독립 GNB / LNB / Dashboard Mode는 함께 사용하지 않는다. 2026-10-08 확정: GNB ONLY는 기존 LNB 부품을 재사용하는 내부 Sidebar를 포함할 수 있다(§15). [공통 정책](../guidelines/navigation-single-mode.md)이 이전 조합 기록보다 우선한다.
|
||||
|
||||
현재 HM 구현의 기준 문서. 공통 원칙은 `docs/guidelines/프로젝트-지침.md`(§6.10 Pattern 계층, §6.11 Layout 단계 기준)를 따른다.
|
||||
@@ -94,7 +96,7 @@ ui-viz에서 GNB(Variant B, top-header)와 LNB(Variant A, sidebar)는 서로 대
|
||||
## 6. Public API
|
||||
|
||||
- `GNB`: `header` props + `sticky`(기본 false). `data-slot="gnb"`, sticky면 `data-sticky`.
|
||||
- `GNBUser`: `button` props + `name`(필수), `description`, children = Avatar(default size, 이미지 실패 시 `AvatarFallback`). `aria-label` 기본 `"<name> 사용자 메뉴"`. `data-slot`은 spread 뒤에 둬서 `DropdownMenuTrigger asChild`가 덮지 않는다.
|
||||
- `GNBUser`: `button` props + `name`(필수), `description`, children = Avatar(default size, 이미지 실패 시 `AvatarFallback`). 기본 `aria-label`은 `"<name> <description> 사용자 메뉴"`이며 description이 없으면 `"<name> 사용자 메뉴"`다. 명시적 `aria-label`/`aria-labelledby`는 소비자가 지정할 수 있고, 화면에 보이는 이름·설명을 포함해야 한다. `data-slot`은 spread 뒤에 둬서 `DropdownMenuTrigger asChild`가 덮지 않는다.
|
||||
- `GNBMobileMenu`: 햄버거(`lg:hidden`)와 Sheet. `title`, `side`, `open`/`defaultOpen`/`onOpenChange`. `GNBMobileLink`는 router `preventDefault`가 있어도 닫히도록 context로 직접 닫는다(Radix Close는 prevented click을 건너뛴다).
|
||||
|
||||
## 7. Navigation 원칙
|
||||
@@ -180,10 +182,10 @@ src/patterns/gnb.stories.tsx
|
||||
|
||||
- 프레임: `data-hm-gnb-layout="sidebar"`. 소비자가 높이를 지정하며 Grid가 GNB의 자연 높이와 남은 본문 높이를 배분한다.
|
||||
- 본문: 프레임의 직계 `data-hm-gnb-body`. Desktop은 기존 `--hm-lnb-width` 열 + 가용 콘텐츠 열, Mobile은 콘텐츠 한 열이다.
|
||||
- Sidebar: 본문의 직계 `<LNB data-hm-gnb-sidebar>`. 기존 `data-slot="lnb"`는 유지한다. 이 범위의 `--hm-lnb-background`만 `var(--hm-sem-palette-green-light-2)`로 덮어쓴다. 기본 Green Light 2는 `#266651`이며 Runtime Theme override도 그대로 따른다. 측면 접점 배경은 LNB의 기존 `--hm-lnb-background-end`를 유지한다.
|
||||
- Sidebar: 본문의 직계 `<LNB data-hm-gnb-sidebar>`. 기존 `data-slot="lnb"`는 유지한다. 이 Reference 범위에서 본문과 같은 배경, 세로 divider 한 개를 사용한다. Green은 Primary, `data-hm-color="brown"`은 기존 Brown 팔레트로 선택·Hover를 표현한다. 펼침 화살표는 유지하며 아이콘은 선택적으로 전달한다. 신규 AI GNB_ONLY에는 Sidebar를 추가하지 않는다.
|
||||
- Main: 본문의 직계 `<main data-hm-gnb-main>`. 공용 CSS가 면·접점·스크롤을 제공하며 콘텐츠 padding은 소비자가 정한다. GNB의 상단 접점과 LNB의 측면 접점은 기존 값을 재사용한다.
|
||||
|
||||
메뉴 폭·폰트·높이·padding·gap·아이콘·Depth·Hover·선택·연결선·스크롤은 LNB 그대로다. 반투명 Hover/Open 면의 합성 결과만 배경 변경에 따라 달라질 수 있으며 별도 보정하지 않는다. 그룹은 기존 Collapsible의 `open / onOpenChange`를 사용하고 GNB NavigationMenu 열림과 독립적으로 관리한다. 선택 시 새 자동 펼침을 추가하지 않는다.
|
||||
메뉴 폭·폰트·높이·padding·gap·Depth·스크롤은 LNB 계약을 재사용한다. 이 콘텐츠 Reference에만 아이콘 기본 생략, 동일 배경·세로 구분선 한 개, 해당 컬러 계열 Hover·선택을 적용하고 Green LNB의 오목한 선택 접점은 사용하지 않는다. 그룹은 기존 Collapsible의 `open / onOpenChange`를 사용하고 GNB NavigationMenu 열림과 독립적으로 관리한다. 선택 시 새 자동 펼침을 추가하지 않는다.
|
||||
|
||||
Desktop은 ≥1024px, Mobile은 ≤1023px이다. Mobile에서 Sidebar는 기존 LNB CSS로 숨기고 **GNBMobileMenu 하나**에 `LNBMobileGroup / LNBMobileLink` 목록을 넣는다. `LNBMobileHeader`나 `LNBMobileMenu`를 함께 렌더하지 않는다. 모바일 Sheet 기본 면, 44px 링크, 14/20/500(current 700), 중첩 들여쓰기, Escape·포커스 복귀를 유지한다.
|
||||
|
||||
|
||||
+19
-3
@@ -1,5 +1,9 @@
|
||||
# LNB (Pattern)
|
||||
|
||||
> 2026-10-10 추가 수정 요청 기준: 독립 Green LNB 펼친 2Depth 그룹 배경만 Black 8%. 글자·아이콘 opacity와 선택·Hover 보존. GNB 콘텐츠 LNB는 별도 밝은 배경 범위. 과거 검증 기록은 당시 결과이며 현재 검증은 [추가 수정 보고서](../guidelines/publisher-additional-review-2026-10-10.md)를 따릅니다.
|
||||
|
||||
> 2026-10-10 추가 확정: Storybook 왼쪽 목차의 펼친 2Depth 그룹 배경도 Black 8%로 적용합니다. 컴포넌트는 [HM LNB CSS](../../packages/ui/src/theme/lnb.css), 목차는 [Storybook Manager CSS](../../.storybook/manager.css)의 기존 펼친 그룹 selector가 각각 담당합니다. 배경 Alpha만 적용하며 글자·아이콘 opacity, Selected·Hover·Focus, 검색·필터·펼침·접힘은 유지합니다. Selected inset depth 등에 쓰는 별도 Black 20%는 그룹 배경이 아니므로 유지하며, 공통 Theme·Token을 변경하지 않습니다.
|
||||
|
||||
> **2026-10-07 확정: SINGLE NAVIGATION MODE.** GNB / LNB / Dashboard는 함께 사용하지 않는다. AI 코드 생성·제안, 신규/기존 페이지, 프로토타입, Storybook, Production 전체에 적용한다. [공통 정책](../guidelines/navigation-single-mode.md)이 이전 조합 기록보다 우선한다.
|
||||
|
||||
현재 HM 구현의 기준 문서. 공통 원칙은 `docs/guidelines/프로젝트-지침.md`(§6.10, §6.11)를 따른다.
|
||||
@@ -156,7 +160,7 @@ LNB Mode가 Desktop Brand/Profile과 Mobile Header/Sheet Profile을 담당한다
|
||||
| 항목 | 18/28/700, 최소 56, padding 14 12 14 18, White, 아이콘 20 opacity .5, 글자 테두리 1.5px + 그림자 `1px 2px 1px` | 같음 | MATCHED |
|
||||
| hover | Black 10%, 콘텐츠 경계까지, 시작 쪽 radius 4 | 같음 | MATCHED |
|
||||
| current | Beige + `#123328`, 왼쪽 radius 8, 오른쪽 20+1 연장, 위·아래 18 오목 곡선, 안쪽 깊이 그림자(마지막 25% fade), 글자 효과 없음 | 같음. 깊이는 span 대신 background gradient 3겹으로 근사 | MATCHED / IMPLEMENTATION_CHANGE |
|
||||
| nested(2뎁스) | 상위 = disclosure 버튼, 화살표 접힘 → 펼침 90°, 펼친 그룹 Black 20% + 1px `#266651` 선 + 왼쪽 radius 8, 하위 padding-left 68, 하단 8, 하위 선택 시 상위 노랑 `#FFC600` | 같음. HM Collapsible(Radix) 사용 | MATCHED / IMPLEMENTATION_CHANGE |
|
||||
| nested(2뎁스) | 상위 = disclosure 버튼, 화살표 접힘 → 펼침 90°, 펼친 그룹 Black 8% + 1px `#266651` 선 + 왼쪽 radius 8, 하위 padding-left 68, 하단 8, 하위 선택 시 상위 노랑 `#FFC600` | 같음. HM Collapsible(Radix) 사용 | MATCHED / IMPLEMENTATION_CHANGE |
|
||||
| divider | Brand/Profile 구분선 없음, 그룹 구분선은 그룹이 둘 이상일 때만(현재 없음) | 없음 | MATCHED |
|
||||
| profile | 이름 16 + 역할 12, avatar 없음, 아래 22 | 위치·글자 같음 + Avatar 32px(gap 12, 세로 중앙) | INTENTIONAL_CHANGE |
|
||||
| 외곽 brand 테두리(`.sidebar::after`) | D-093 예시에 없음, FOLLOW_UP | 그리지 않음 | FOLLOW_UP |
|
||||
@@ -176,7 +180,7 @@ LNB Mode가 Desktop Brand/Profile과 Mobile Header/Sheet Profile을 담당한다
|
||||
| `--hm-lnb-background` / `-background-end` | 5-stop gradient / `#266651` |
|
||||
| item | min-height 56, 18/28/700, gap 12, 아이콘 20, 글자 테두리 1.5px |
|
||||
| current | `--hm-sem-bg-content` + `--hm-sem-action-primary`, radius 8 0 0 8 |
|
||||
| group | open face Black 20%, 선 1px `--hm-sem-palette-green-light-2`, 하위 padding-start 68, current 글자 `--hm-sem-palette-yellow-accent` |
|
||||
| group | open face Black 8%, 선 1px `--hm-sem-palette-green-light-2`, 하위 padding-start 68, current 글자 `--hm-sem-palette-yellow-accent` |
|
||||
| `--hm-lnb-third-*` | min-height 48, padding-block 12, text padding-start 88(메뉴 행 기준), line-height 24, weight 500 / current 700, connector x `= --hm-lnb-subitem-padding-start`(68)·length 12·width 1, 모든 상태에서 `--hm-sem-palette-green-tint` 40%. 실제 link는 connector 끝부터 시작 |
|
||||
|
||||
새 Primitive: `--hm-yellow-accent: #ffc600`(`primitives.css`). ui-viz `color.action.accent-on-green`이며 HM 팔레트에 없어 추가했다. 그 외 새 Semantic은 없다.
|
||||
@@ -188,9 +192,21 @@ LNB Mode가 Desktop Brand/Profile과 Mobile Header/Sheet Profile을 담당한다
|
||||
- 높이는 소비자가 정한다(열은 `min-height: 100%`).
|
||||
- GNB 또는 Dashboard와 조합하지 않는다. 콘텐츠 계산은 LNB 자체 변수만 사용한다.
|
||||
|
||||
### 내부 스크롤과 숨김 알림 Usage
|
||||
|
||||
viewport 높이 shell에서 모바일 Header와 main을 세로 flex로 배분할 때 부모와 main의 `min-height: 0`, main의 `flex: 1; overflow: auto`를 확인한다. 위 콘텐츠 면의 `position: relative`는 main 안의 absolute 숨김 status가 BODY를 기준으로 배치되어 바깥 빈 스크롤을 만드는 것도 방지한다. 숨김 알림은 Toast가 아니며 요청 없이 시각 알림 기능을 추가하지 않는다.
|
||||
|
||||
```css
|
||||
/* 소비 레이아웃의 높이·스크롤만 구성한다. 기존 HM 면·간격은 유지한다. */
|
||||
.content-stack { display: flex; flex-direction: column; min-height: 0; min-width: 0; }
|
||||
.page-content { position: relative; flex: 1; min-height: 0; min-width: 0; overflow: auto; }
|
||||
```
|
||||
|
||||
390/768/1280/1440px에서 초기·조회·초기화·완료 후 `document.documentElement.scrollHeight/clientHeight`, main의 같은 값, live region의 `offsetParent`·크기·문구를 기록한다. viewport 높이 shell이면 바깥 스크롤 없이 main 내부의 마지막 항목에 접근할 수 있어야 한다. 일반 문서 흐름 화면에는 viewport 높이를 강제하지 않는다. 완료 후 disabled 버튼 대신 유효한 focus 대상이 유지되는지도 확인한다. 전역 overflow:hidden은 해결책이 아니다.
|
||||
|
||||
## 7. Accessibility / 상호작용
|
||||
|
||||
`<aside>` + `<nav aria-label>`, 현재 `aria-current="page"`, 그룹 trigger는 Radix `aria-expanded`/`aria-controls`. `LNBProfile`은 native button + 기본 accessible name `"<name> 사용자 메뉴"`이며 Avatar·이름·역할의 inner content 폭에 interaction을 한정한다(`fit-content` + 안쪽 hit padding). 이 버튼에 pointer cursor와 LNB focus-visible outline을 쓴다. `DropdownMenuTrigger asChild`로 합성하면 Enter/Space 열기, Arrow 이동, Escape 닫기와 trigger focus 복귀는 Radix가 담당한다. 접힌 그룹의 하위는 DOM에서 빠져 focus되지 않는다. 아이콘은 장식(`aria-hidden`, 소비자가 지정).
|
||||
`<aside>` + `<nav aria-label>`, 현재 `aria-current="page"`, 그룹 trigger는 Radix `aria-expanded`/`aria-controls`. `LNBProfile`은 native button + 기본 accessible name `"<name> <description> 사용자 메뉴"`이며 description이 없으면 `"<name> 사용자 메뉴"`다. 명시적 `aria-label`/`aria-labelledby`를 소비자가 지정할 때도 화면에 보이는 이름·설명을 포함한다. Avatar·이름·역할의 inner content 폭에 interaction을 한정한다(`fit-content` + 안쪽 hit padding). 이 버튼에 pointer cursor와 LNB focus-visible outline을 쓴다. `DropdownMenuTrigger asChild`로 합성하면 Enter/Space 열기, Arrow 이동, Escape 닫기와 trigger focus 복귀는 Radix가 담당한다. 접힌 그룹의 하위는 DOM에서 빠져 focus되지 않는다. 아이콘은 장식(`aria-hidden`, 소비자가 지정).
|
||||
|
||||
## 8. 검증 (2026-10-03, Storybook)
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# Page Header (Pattern)
|
||||
|
||||
> 2026-10-10 추가 수정 요청 기준: 기본형은 Breadcrumb 없이 제목 중심. 설명·액션·Breadcrumb는 선택 적용. 대표 Story에서 두 구성을 비교하며 D-01/D-02는 유지. 과거 검증 기록은 당시 결과이며 현재 검증은 [추가 수정 보고서](../guidelines/publisher-additional-review-2026-10-10.md)를 따릅니다.
|
||||
|
||||
현재 HM 구현의 기준 문서. 공통 원칙은 [프로젝트 지침](../guidelines/프로젝트-지침.md), [Button 규칙](../components/button.md), [단일 Navigation 정책](../guidelines/navigation-single-mode.md)을 따른다.
|
||||
|
||||
```text
|
||||
@@ -73,19 +75,27 @@ Story의 Breadcrumb hash 링크와 등록 버튼은 조합 예제다. 실제 화
|
||||
|
||||
Breadcrumb는 HM Breadcrumb 그대로(14px, 링크). ui-viz는 12px 정적 텍스트였다(INTENTIONAL_CHANGE).
|
||||
|
||||
### 3.1 제목 아래 Tabs를 배치할 때
|
||||
|
||||
페이지 content 면에 바로 놓는 Tabs는 PageHeader 다음에 기본 Primary(`panelSurface="content"`)를 사용한다. PageHeader의 제목→설명 **8px**, 아래 첫 콘텐츠까지 **20px**을 유지한다. 탭을 감싸는 새 White Card·border·padding은 필요하지 않으며 내부 `TabsContent`는 `px-0 py-6`로 조합할 수 있다. [Tabs의 표면·여백 소유권](../components/tabs.md#16-publisher--developer-조합-안내-2026-10-09)을 따른다.
|
||||
|
||||
2026-10-09 실제 반영: 대표 Story의 Overview에서 기존 PageHeader 바로 뒤에 `내 업무 / 완료 업무` Tabs와 공개 Table을 조합한다. 선택 탭의 면은 [Primary 상단 White alpha 0.8](../components/tabs.md#163-d-02-상단-흰색-80-실제-반영) → content로 이어지고, 탭 전체 opacity는 1이다. PageHeader Component·Typography·8px/20px Token과 기존 단일 Brand Action은 유지한다. 별도 Pattern API를 추가하지 않는다.
|
||||
|
||||
이때 TabsContent의 상하 24px을 PageHeader 하단 20px에 더해 탭 바 앞 간격으로 사용하지 않는다. Card 안의 제목은 CardTitle 규격(20/28/600), 페이지 제목은 PageHeaderTitle 규격(28/36/700)을 사용한다. CardDescription과 PageHeaderDescription은 서로 다른 계약이다. 비교 이미지의 48px 간격이나 Card 전용 Token을 페이지 전체에 적용하지 않는다.
|
||||
|
||||
## 4. Responsive / Accessibility
|
||||
|
||||
`PageHeaderContent`는 `flex: 1 1 320px; min-width: 0`, 액션은 줄바꿈 후 오른쪽 정렬(390px에서 제목 아래 줄). 긴 제목은 `overflow-wrap: anywhere`. 화면당 `h1`은 하나만 둔다. wrapper에 role을 두지 않는다.
|
||||
|
||||
PageHeader는 콘텐츠의 제목 영역이며 Navigation Mode를 정의하지 않는다. 독립 대표 Story는 Navigation을 추가하지 않은 조합 예제다. 실제 페이지는 `GNB | LNB | DASHBOARD` 중 하나만 선택하고 반응형에서도 유지한다. Dashboard에서는 Dashboard 내부 Header/Menu/Sidebar와 합성하며 외부 GNB/LNB를 함께 넣지 않는다.
|
||||
PageHeader는 콘텐츠의 제목 영역이며 Navigation Mode를 정의하지 않는다. 독립 대표 Story는 Navigation을 추가하지 않은 조합 예제다. 실제 페이지는 `GNB | LNB | DASHBOARD` 중 하나만 선택하고 반응형에서도 유지한다. Dashboard 운영 화면에서는 전용 Header/업무 상태 필터/Content 안에 합성하며 Sidebar나 외부 GNB/LNB를 함께 넣지 않는다.
|
||||
|
||||
Dashboard Compact 최소 폭 960px(Sidebar 포함 1232px)과 내부 가로 스크롤은 Dashboard Layout 계약이다. PageHeader 단독 사용처에 이 최소 폭을 자동 적용하지 않는다. PageHeader 자체에는 고정 최소 폭이나 별도 breakpoint가 없으며 기존 flex wrapping과 Theme 규격을 유지한다. 외부 콘텐츠 padding은 소비 Layout이 소유한다.
|
||||
Dashboard 운영 화면은 전용 48px Header·업무 상태 필터·Content로 구성하고 Sidebar 없이 최소 폭 960px·내부 가로 스크롤을 유지한다. Sidebar 포함 1232px은 기존 호환성·verification 구성만의 값이다. PageHeader 단독 사용처에 Dashboard 최소 폭을 자동 적용하지 않는다. PageHeader 자체에는 고정 최소 폭이나 별도 breakpoint가 없으며 기존 flex wrapping과 Theme 규격을 유지한다. 외부 콘텐츠 padding은 소비 Layout이 소유한다.
|
||||
|
||||
## 5. 검증 / 관련 파일
|
||||
|
||||
### 현재 대표 Reference
|
||||
|
||||
- [독립 대표 Story 소스](../../src/patterns/page-header.stories.tsx): Breadcrumb + Title + Description + Actions. 운영 조합에 별도 Story CSS나 Dashboard 최소 폭을 추가하지 않는다.
|
||||
- [독립 대표 Story 소스](../../src/patterns/page-header.stories.tsx): Breadcrumb + Title + Description + Actions + Primary Tabs / Table의 직접 배치 조합. 운영 조합에 별도 Story CSS나 Dashboard 최소 폭을 추가하지 않는다.
|
||||
- Storybook 경로: `Patterns/Layout/Page Header → Page Header`, ID: `patterns-layout-page-header--all`.
|
||||
- 기존 Dashboard 대표 Story는 Dashboard 전체 Layout의 Reference로 유지한다. Verification Story는 운영 Reference로 사용하지 않는다.
|
||||
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
# HMDesign 접근성 잔여 검증 — 2026-10-10
|
||||
|
||||
RESULT: PARTIAL. 재현된 ARIA·접근성 이름 결함을 최소 수정했고 해당 동작의 선택 검증은 통과했다. 확정 색의 대비 부족, 실제 스크린리더·실기기 검증과 자동 도구의 일부 미확정 진단은 남아 있다. 전체 WCAG 적합성 승인으로 해석하지 않는다.
|
||||
|
||||
기준 Local/지정 GitHub main SHA: `8817135f504b836a8d1566f3672ed50b8dd392b9`. 시작 Working Tree는 CLEAN. 범위 BOTH, Runtime React. 기존 화면 생성 실험·Claude·하위 에이전트 호출 0, 승인 장부 10/12·잔여 2 보존. 공식 Gitea NOT ACCESSED / NOT MODIFIED.
|
||||
|
||||
## 실제 결함과 최소 수정
|
||||
|
||||
| 대상 | 재현·원인 | 변경·확인 |
|
||||
|---|---|---|
|
||||
| Combobox | Enter로 연 Trigger는 `aria-haspopup=listbox`지만 controls 대상은 실제 `role=dialog`. 내부 cmdk 검색 입력은 별도 listbox를 제어한다. | Trigger 기본값만 dialog로 수정. 기존 ID/이름/disabled/검색/값/API·연결형 스타일 보존. 네 폭에서 실제 키보드 선택·Escape·focus 복귀·expanded/controls 역할 정합 확인. |
|
||||
| GNBUser / LNBProfile | 화면은 이름+역할을 표시하지만 기본 이름은 이름+사용자 메뉴만 포함. 이름과 설명 DOM 텍스트 경계도 붙어 한국어 Label-in-Name 검사에 실패. | 기본 이름에 description 포함, 설명이 있을 때 이름 뒤의 의미상 공백 추가. 명시적 aria-label/labelledby 우선권 보존. 두 버튼의 실제 이름·키보드 메뉴/Arrow/Escape/focus 복귀 및 axe Label-in-Name 통과. GNB 138.64×53, LNB 140.64×48로 경계 보완 전후 크기 일치. |
|
||||
|
||||
구현·[Combobox MD](../components/combobox.md)·[GNB MD](../patterns/gnb.md)·[LNB MD](../patterns/lnb.md)·관련 All Story의 설명을 맞췄다. [AI 화면 계약](../guidelines/ai-screen-contract.md)에 팝업 실제 role과 명시적 접근성 이름의 소비 책임만 추가했다. AGENTS.md의 기존 Label/ID/키보드/모바일 규칙은 충분해 수정하지 않았다. 디자인·Token·Typography·Spacing·Radius·공개 export/API·Story ID·D-01/D-02·퍼블리셔 버튼 배치/Sheet radius 변경 없음.
|
||||
|
||||
## 실행 검증과 한계
|
||||
|
||||
- 신규 실제 TSX 렌더 회귀 3개 PASS. 이름 경계 보완 후 영향받는 GNB/LNB 2개만 재검사 PASS; Combobox PASS는 재실행하지 않음. 기존 publisher C5 반복 popup/ID 테스트 1개 PASS, 나머지 8개 선택 skip.
|
||||
- Combobox 390/768/1280/1440: Tab/Shift+Tab, Enter/Space 열기, 검색·ArrowDown·Enter 선택, Escape·focus 복귀, 팝업 bounds, 페이지 가로 overflow, 중복 ID 확인 PASS. 브라우저 CDP AX tree로 dialog 이름을 별도 확인. Playwright 일부 popup snapshot에서 이름을 생략하는 것과 Chrome AX tree의 실제 이름을 구분한다.
|
||||
- 최종 static Storybook 빌드에서 위 네 폭과 사용자 메뉴 두 경로의 6개 선택 회귀가 모두 PASS, pageerror 0. Button의 Enter·Space가 각각 실제 native click을 발생시키는 것도 별도 확인했다. 390px Combobox와 Drawer PNG를 시각 확인했다.
|
||||
- Dialog/AlertDialog/Sheet/Drawer: 1280에서 실제 열기·초기 focus·Tab 8회 순환·Escape·trigger 복귀 PASS. Sheet/Drawer는 열린 상태로 네 폭 변경 시 내부 focus와 페이지 overflow 유지, 모바일 버튼 크기/배치 측정 PASS. Drawer 모바일 시각 실행 위/취소 아래와 기존 DOM 취소→실행 순서 보존. 실제 손가락 drag·스크롤 충돌은 NOT VERIFIED.
|
||||
- Button의 키보드 진입·disabled Tab 제외, Input readonly 실제 키 입력 보호, Accordion collapsible Enter/Space·Arrow/Home/End, DataTable 페이지 크기 Label/키보드 선택·정렬 aria-sort, GNB/LNB 실제 Tab 50회에서 숨긴 배경 focus 잔류 없음을 선택 확인했다. 검사한 경로에 한정한다.
|
||||
- 모바일 GNB/LNB 단일 fixture 390/768px에서 Enter 열기·Tab 8회 modal 내부 탐색·Escape·trigger focus 복귀·페이지 overflow 확인 PASS. 두 메뉴 trigger는 32×32px. 전체 대상 간격·실제 터치·44px 강화 기준 적합성을 인증하지 않는다.
|
||||
- Table 자동 `scrollable-region-focusable` 경고는 Chrome 154에서 실제 Tab 진입·ArrowRight 0→40px 스크롤이 가능했다. 수정하지 않았다. 다른 브라우저의 스크롤 키보드 접근성은 NOT VERIFIED.
|
||||
- Select는 실제 Space/Home/End/Tab/escape·focus 복귀가 정상이며 숨긴 배경 focus 진단은 원본 보존했다. 독립 listbox 이름과 실제 보조기술의 Trigger 관계 안내는 NOT VERIFIED. 경고를 삭제하거나 SR PASS로 바꾸지 않았다.
|
||||
- 실제 스크린리더 발화, 음성 조작, 실기기 터치·safe area·확대/텍스트 확대 전체, 모든 Theme/상태/브라우저 조합은 NOT VERIFIED. NVDA 실행 세션과 일반 설치 위치의 실행 파일은 확인되지 않았다. 접근성 트리와 자동 결과를 스크린리더 검증으로 대체하지 않았다.
|
||||
|
||||
자동 검사는 axe-core 4.14.0의 관련 WCAG 2/2.1/2.2 A/AA 태그를 사용했다. 판정 근거는 [WCAG 2.2 검사 항목](https://www.w3.org/WAI/WCAG22/quickref/), [Combobox 팝업 역할](https://www.w3.org/WAI/ARIA/apg/patterns/combobox/), [Label in Name](https://www.w3.org/WAI/WCAG22/Understanding/label-in-name.html), [비텍스트 대비](https://www.w3.org/WAI/WCAG22/Understanding/non-text-contrast.html), [최소 터치 대상](https://www.w3.org/WAI/WCAG22/Understanding/target-size-minimum.html)을 구분해 적용했다. Disabled 대비 예외는 활성 placeholder/오류 문구/버튼에 적용하지 않는다. 24px 미만 대상은 연결 Label·간격 등 예외 판정이 필요하며 전체 모바일 AA PASS로 확대하지 않는다.
|
||||
|
||||
## 색상 대비 — 디자인 변경 보류
|
||||
|
||||
| 실제 적용 대상 | 대비·판정 |
|
||||
|---|---|
|
||||
| Combobox/DatePicker 빈 값 흰 Trigger | 이전 5.60:1 증거와 현재 mapping 동일 범위 REUSED PASS |
|
||||
| 일반 Input 값 / Field Label | 16.67:1 / Beige 배경 4.93:1, 확인 범위 PASS |
|
||||
| Input 활성 placeholder / Select 활성 placeholder | 약 2.85:1, FAIL. 확정 mapping/색 변경은 DEFERRED |
|
||||
| 기존 Input 오류 문구 | Red/Beige 4.38:1, 기존 소스·배경 동일 FAIL 증거 보존; 변경 DEFERRED |
|
||||
| Solid Modify Button | White/#cc5200 4.40:1, FAIL; 상태/확정색 변경 DEFERRED |
|
||||
| Destructive Outline hover/pressed | #d32f2f/#fbeeee 약 4.40:1, FAIL; 변경 DEFERRED |
|
||||
| Primary Brand 기본 gradient | 실제 스크린샷의 글자 없는 padding 세로 구간 합성 픽셀 기준 최소 5.68:1. 해당 gradient/샘플 범위 PASS, 다른 gradient/상태는 NOT VERIFIED |
|
||||
| Table selected·selected+hover | 실제 20% 반투명 면과 White 합성 배경의 본문 15.61:1, 해당 상태 PASS |
|
||||
| Focus | 실제 키보드 진입 확인. Input 최종 focus border는 내부 White 6.77:1·외부 Beige 5.96:1, Primary Solid 버튼 focus border는 외부 Beige 14.67:1. 해당 표시 PASS; 전체 아이콘/상태/ring/gradient의 대비는 NOT VERIFIED |
|
||||
|
||||
색 부족을 숨기기 위해 Token이나 확정 Component Color를 변경하지 않았다. Gradient는 투명 backgroundColor만으로 대비를 계산하지 않고 실제 렌더된 픽셀을 사용했다. 모든 픽셀·모든 Theme의 대비 인증은 아니다.
|
||||
|
||||
## 재사용과 중복 검증
|
||||
|
||||
- 이전 `8817135` 보고서의 Guard100/100과 로그, 이번 작업에서 미변경인 Guard/테스트/의존성 소스를 대조해 REUSED PASS. 새 전체 회귀를 실행한 것으로 세지 않는다.
|
||||
- 기존 Checkbox/Radio/Toggle/Tabs·보호 상태·Label/ID 증거는 해당 구현·CSS·테스트 본문이 동일한 범위만 재사용. 수정된 Combobox/GNB/LNB는 새 검증으로 대체.
|
||||
- 별도 실험 폴더 T01/T02/T06의 source fingerprint와 원래 Runtime source 연결·네 폭 PASS가 일치. T02 ID 한 줄, T06 숨김 알림 위치/내부 스크롤 수정 보존. 새 계약의 whole-screen Guard/결합 인증으로 확대하지 않음.
|
||||
- 전체 292 Story Runtime, 전체 Component/Guard/문서 링크, 외부 모델 화면 재생성, 의존성 재설치 반복 없음. 초기 테스트의 연결/locator/계약 오류와 실패 로그는 별도 보존하고 필요한 항목만 재개했다.
|
||||
- 최종 통합에서 root/UI/CENTER Typecheck, package 선언 build, root Vite 및 Storybook build PASS. 이름 경계 보완으로 소스가 변경된 뒤 영향받는 UI/산출물과 테스트만 다시 검증했다. 기존 500kB chunk·Storybook bundler 성능 경고는 남아 있다.
|
||||
- Storybook PARTIAL Guard의 FAIL은 0. 초기 세 Story 검사 후 이름 경계 수정의 영향 범위인 GNB/LNB만 PARTIAL 재검사했다. 최종 source/contract fingerprint는 현재 파일과 일치한다. 원본 status와 staticStatus는 `NOT VERIFIED`이며 native fixture·Reference slot·미해석 Story style의 미검증을 유지한다. styleEvidence는 STATIC PASS / RUNTIME NOT VERIFIED / DESIGN_INTENT NOT VERIFIED / FINAL NOT VERIFIED다. 별도 브라우저 동작 결과를 Guard의 스타일 인증에 연결하지 않았으므로 결합 styleVerification은 생성하지 않았다. 컴포넌트 자체의 WCAG 검증을 소비 화면 Guard가 수행한 것으로 해석하지 않는다.
|
||||
- 변경·연결 문서 10개의 내부 링크 27개 PASS. 최종 index의 292 Story ID가 기존 inventory와 모두 일치하고 공개 export·CSS·Theme 소스가 작업 기준과 동일하다.
|
||||
|
||||
## 선택 회귀 실행 방법
|
||||
|
||||
```powershell
|
||||
node --test scripts/accessibility-regression.test.mjs
|
||||
# 기존 C5 조합에 영향이 있는 경우만:
|
||||
node --test --test-name-pattern C5 scripts/publisher-components.test.mjs
|
||||
```
|
||||
|
||||
실제 브라우저 회귀는 이미 실행 중인 로컬 Storybook(개발 또는 최종 static)을 사용한다. Playwright/Chrome을 설치된 QA 환경에서 제공한다. 이 스크립트는 패키지 설치나 모델 호출을 수행하지 않는다.
|
||||
|
||||
```powershell
|
||||
$env:HM_PLAYWRIGHT_DIR='<설치된 playwright 패키지 디렉터리>'
|
||||
$env:HM_CHROME_PATH='<설치된 Chrome 실행 파일>'
|
||||
$env:HM_A11Y_URL='http://127.0.0.1:6024'
|
||||
$env:HM_A11Y_OUTPUT='_local/accessibility-runtime'
|
||||
# 선택: 설치된 axe.min.js. 없으면 해당 자동 검사는 NOT VERIFIED.
|
||||
$env:HM_AXE_PATH='<설치된 axe-core/axe.min.js>'
|
||||
node scripts/verify-accessibility-runtime.mjs
|
||||
# 사용자 메뉴만 변경됐을 때:
|
||||
node scripts/verify-accessibility-runtime.mjs --profiles-only
|
||||
```
|
||||
|
||||
이 검사는 named checks만 보고한다. 실제 발화·손가락 터치·전체 앱의 접근성을 인증하지 않는다. 로컬 상세 JSON·로그·PNG·재사용/보존 manifest·Git 결과는 `_local/a11y-residual-20261010/`에 보관한다. 원본 과거 자료는 수정하지 않는다. 최종 Commit/Remote SHA와 KST 완료 시간은 작업 최종 보고에 기록한다.
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,144 @@
|
||||
# HMDesign AI 화면 생성 품질 개선 — 2026-10-10
|
||||
|
||||
RESULT: PARTIAL. 검증한 구현·회귀 검사는 통과했다. 교차 모델 생성, 수치 디자인 점수, 전체 접근성 적합성은 NOT VERIFIED다. 이전 실험과 생성 조건이 달라 NON-COMPARABLE이며 품질 점수 상승을 주장하지 않는다.
|
||||
|
||||
TARGET: `D:\디자인시스템\hmdesign` / Runtime: React / Scope: BOTH(공개 Pattern·Storybook Reference 개선 + 독립 실험 화면). 초기 Working Tree는 clean이었다.
|
||||
|
||||
BASE_SHA: `0b2bc376aa8b6af9d2492b5620d8ae776391508d`
|
||||
|
||||
IMPLEMENTATION_SHA: `cb451b34363c72b50c1bb44a1f10b63b8f5e0163`
|
||||
|
||||
FINAL_SHA: 이 문서·집계 스크립트를 포함한 최종 HEAD는 제출 응답에 기록한다. 문서는 자신의 commit hash를 자체 포함할 수 없으므로 위 구현 기준과 분리한다.
|
||||
|
||||
## 원인과 개선 범위
|
||||
|
||||
기존 생성 화면 10개의 공통 RENDER-002는 React bootstrap 확인만으로 브라우저 실행을 증명할 수 없다는 판정이었다. Production Graph 실패라고 일괄 해석하거나 규칙을 완화해서는 해결되지 않는다. 일부 기존 소비 CSS의 의도 판단도 REUSE-003으로 남아 있었다. 낮은 추론의 보존된 02·06·07 결과에서는 미정의 HM Token 참조 17곳(고유 이름 8개)을 실제 확인했다.
|
||||
|
||||
| 우선순위 | 결과 | 근거와 영향 |
|
||||
|---|---|---|
|
||||
| P0_GUARD | PASS(검사 계약 범위) | entry별 연결 CSS·공개 Theme 정의로 TOKEN-001 감지. 계산된 참조/불완전 graph는 NOT VERIFIED. scope/profile/Production Graph 분리 유지. 그룹 근거·검사 파일·정적 상태 추가. source+contract hash가 일치하는 4개 폭·핵심 동작 증거만 별도 판정에 연결 |
|
||||
| P1_PATTERN | PASS(근거 있는 개선) | FilterBar `layout` opt-in으로 목록 기본/확장형 표현. 기본 동작 호환. Form/Empty/Error/Chart는 없는 API를 신설하지 않고 공개 Component composition으로 안내 |
|
||||
| P2_AI_GUIDELINES | PASS | AGENTS 핵심 계약 → 기능 선택표 → 선택한 Pattern/Component 문서 순서. Native 콘텐츠 HTML 허용, Label 연결, Navigation 한 모드, 미요청 기능 금지, 결과 보고 구분 명시 |
|
||||
| P3_STORYBOOK | PASS(선택한 Reference) | FilterBar All ID 유지, 실제 조회 적용/초기화·Label/useId·Do/Don't·layout 예제. 신규 업무 Story 등록 없음. 모든 Story를 재작성하지 않음 |
|
||||
| P4_ACCESSIBILITY | PARTIAL | Clear 버튼 Enter 후 focus가 BODY로 손실되는 문제를 Chrome에서 재현·수정. 외부 ref/Label focus도 packed consumer에서 검증. Dialog/Sheet/Drawer/mobile focus 복귀, Form 오류 focus, Checkbox/Switch/readOnly 검증. 전체 WCAG·스크린리더는 NOT VERIFIED |
|
||||
| P5_THEME_TOKEN | PASS(정적·테마 회귀 범위) | 연결 공개 CSS 목록 1,170개 선언 이름 inventory. Runtime override key 목록과 동일하다고 보지 않음. 새 Token/색/글꼴/간격 값 추가 없음. Theme Loader/Designer/실제 keyboard 검증 통과 |
|
||||
|
||||
## 주요 수정 파일
|
||||
|
||||
| 파일 | 변경 이유·내용 | 영향 범위 |
|
||||
|---|---|---|
|
||||
| `scripts/ai-generation-guard.mjs`, `guard-theme-analysis.mjs` | 미정의 Token 및 정적 판정의 근거 부족 → 연결 graph 검사·그룹 근거·hash·staticStatus | 기존 원본 status/exit/issues 유지; additive JSON schemaVersion 2 |
|
||||
| `scripts/guard-evidence.mjs` | Runtime 근거를 원본 Guard와 구분하여 연결 | stale source/contract, 정적 FAIL/NV, 미확인 bootstrap을 PASS로 덮어쓰지 않음; PARTIAL scope 유지 |
|
||||
| `packages/ui/src/patterns/filter-bar/filter-bar.tsx`, `src/theme/filter-bar.css`, `src/theme/dashboard-layout.css`, `src/index.ts` | 목록 구조 재사용·Clear focus 손실 | `layout` optional prop/공개 Props type, 기존 ref 전달 보존; default CSS 동작 유지 |
|
||||
| `src/patterns/filter-bar.stories.tsx` | draft와 applied 조건·접근성·사용 기준 명확화 | 기존 All Story 유지, 선택적 목록 layout과 사용 예제 |
|
||||
| `AGENTS.md`, `docs/guidelines/ai-screen-contract.md`, 관련 Guard/Pattern 문서 | 중복·암묵적 선택 기준 감소 | 문서 우선순위·API/상태/Native/Navigation 선택과 검증 계약 |
|
||||
| `examples/ai-quality/**` | 신규 React 생성 결과로 실제 계약 검증 | 10개 독립 bootstrap, Storybook/운영 메뉴와 별개; 공통 composition 사용 |
|
||||
| `scripts/verify-quality-*.mjs`, `audit-quality-contracts.mjs`, `summarize-quality-evidence.mjs` | 재현 가능한 브라우저·회귀·집계 | localhost와 로컬 evidence; Playwright/Chrome 경로는 환경 변수 필요 |
|
||||
|
||||
## 생성 실험
|
||||
|
||||
| ID | 화면 | 난이도 | Navigation | 필수 내용 Pattern |
|
||||
|---|---|---|---|---|
|
||||
| 01 | 사용자 목록 | Easy | GNB | FilterBar/DataTable |
|
||||
| 02 | 현장 업무 카드 | Medium | GNB | FilterBar |
|
||||
| 03 | 승인 결재 | Hard | GNB | FilterBar/DataTable + Dialog |
|
||||
| 04 | 채용 관리 | Hard | GNB | FilterBar/DataTable + Sheet |
|
||||
| 05 | 업무 요청 | Medium | GNB | 별도 Form API 없음; Label/Input/Textarea/Checkbox |
|
||||
| 06 | 권한 설정 | Medium | LNB | Checkbox/Switch/readOnly Input |
|
||||
| 07 | 업무 Dashboard | Medium | Dashboard | DashboardLayout/Tabs/Progress |
|
||||
| 08 | 통계 Dashboard | Medium | Dashboard | DashboardLayout/DataTable 분류별 집계 |
|
||||
| 09 | 작업 변경 | Hard | GNB | Drawer |
|
||||
| 10 | 처리 상태 | Easy | LNB | Skeleton/Alert/빈 결과 composition |
|
||||
|
||||
SCREEN_COUNT: 10
|
||||
|
||||
MODEL: GPT-6(session identity), 같은 Codex 세션의 공유 composition. 이전 실험 소스를 정답 코드로 제공하지 않았다.
|
||||
|
||||
REASONING_LEVEL: UNAVAILABLE / RANDOM_SEED: UNAVAILABLE. 조건은 화면별 requirements.json에 보존. 독립 모델 실행·낮은 추론 재생성은 NOT VERIFIED.
|
||||
|
||||
TYPECHECK: PASS(strict, skipLibCheck:false) / BUILD: PASS / RUNTIME: PASS(10화면 × 4폭 = 40렌더, 핵심 동작 그룹 24/24).
|
||||
|
||||
AVERAGE_DESIGN_SCORE: NOT VERIFIED. 점수 rubric/독립 평가를 실행하지 않았다. 10개 화면 대표 캡처의 시각 확인은 수행했지만 점수로 환산하지 않았다.
|
||||
|
||||
COMPONENT_REUSE_RATE: 소스 JSX site 기준 100%(121 HM 공개 API site / 121 HM+native widget site, native widget 0). 공유 TSX를 한 번씩 계산, 콘텐츠/레이아웃 HTML 및 local composition wrapper 제외. 이 수치는 mounted DOM 비율이나 디자인 품질 점수가 아니다. 실제 HM slot 렌더는 10화면에서 확인했다.
|
||||
|
||||
PATTERN_REUSE_RATE: 요구된 내용 Pattern 10/10(100%)이 4개 폭 모두 실제 렌더. Navigation은 별도 모드 검사. Pattern이 없는 기능은 분모에서 제외하고 composition 이유를 기록했다.
|
||||
|
||||
GUARD_PASS: 원본 0 / 정적 계약 10 / Runtime 연결 판정 10
|
||||
|
||||
GUARD_FAIL: 원본 0 / 연결 0
|
||||
|
||||
GUARD_NOT_VERIFIED: 원본 10(RENDER-002) / 연결 0. 원본 issue를 삭제하지 않았다.
|
||||
|
||||
ACCESSIBILITY_ISSUES: 검사한 visible control 이름 누락·중복 ID·active tab 연결 오류 0; tested focus/keyboard 통과. 전체 접근성 문제 0을 의미하지 않는다.
|
||||
|
||||
UNREQUESTED_FEATURES: 정의한 허용 main 액션·단일 업무 메뉴 기준 0. 기본 공개 DataTable 페이지 기능/검색 clear/Overlay close는 Component 기본 기능이다. 의미적 전체 요구사항 평가는 NOT VERIFIED.
|
||||
|
||||
THEME_TOKEN: 새 화면의 연결 HM Token 위반 0, 실제 Theme/font/utilities 적용 확인. 임의 Chart·CSV·다운로드·외부 API·추가 운영 메뉴 없음.
|
||||
|
||||
## 회귀 검증
|
||||
|
||||
| 항목 | 최종 결과 |
|
||||
|---|---|
|
||||
| TYPECHECK | root/UI/CENTER/신규화면 PASS |
|
||||
| UI_BUILD | UI/CENTER package build PASS |
|
||||
| PRODUCTION_BUILD | root, Dashboard export+finalizer, Recruit, Publisher PASS |
|
||||
| STORYBOOK_BUILD | PASS, 기존 292 ID → 292 ID(add/delete 0) |
|
||||
| COMPONENT_TEST | 9/9 PASS, 기존 8개 test AST 본문 동일 |
|
||||
| GUARD_TEST | 63/63 PASS, 기존 51개 test AST 본문 동일 |
|
||||
| EVIDENCE_TEST / THEME_TEST | 5/5 / 3/3 PASS |
|
||||
| GUARD_FULL_SCREEN | 기존 root NOT VERIFIED(CSS 의도 13+RENDER-002); FAIL 0 |
|
||||
| GUARD_PARTIAL | root NOT VERIFIED(SCOPE-001: graph 밖 tailwind.css + RENDER-002); 신규01 static PASS/raw NV |
|
||||
| GUARD_STORYBOOK | FULL NOT VERIFIED(wrapper1/CSS19/native33/computed token2); FAIL 0. FilterBar PARTIAL PASS |
|
||||
| GUARD_GENERATED_SCREEN | raw 10 NV / static 10 PASS / 연결 10 PASS |
|
||||
| CSS_IMPORTS | 연결 73개 누락 0 |
|
||||
| EXPORTS | UI/CENTER 선언 export target 16개 누락 0 |
|
||||
| DOC_LINKS | 96문서·429 내부 링크 PASS |
|
||||
| THEME_JSON_LOADER | PASS(service primary #6837a8 → default #123328) |
|
||||
| THEME_DESIGNER | 96 checks PASS |
|
||||
| RUNTIME_THEME | 자동136/58 parts PASS, 실제 keyboard138 checks PASS(R3 보존) |
|
||||
| PACKAGE_CONSUMER | npm pack 설치, 독립 엄격 TS·Vite build·public CSS·Label/ref/Clear focus PASS |
|
||||
| GIT_CLONE_RUNTIME | --no-hardlinks clone, 자체 npm ci/typecheck/build; 01/08 각각4폭·검색/집계 PASS |
|
||||
| RESPONSIVE | 신규40렌더, 기존 app/publisher/dashboard/recruit16렌더 PASS. Dashboard Header48/frame≥960·내부 scroll 확인 |
|
||||
|
||||
최초 실행에서 검사 harness의 Storybook bin 경로, test server `/themes/` 경로, 숨겨진 Radix input·중복 status locator 문제가 확인됐다. harness를 수정하고 영향받은 항목만 재검사했다. 실패 로그는 삭제하지 않았다. 최신 Loader/FilterBar·Storybook 결과가 초기 로그를 대체하는 근거다. 전체 검사를 동일 조건으로 반복하지 않았다.
|
||||
|
||||
## 보존 확인
|
||||
|
||||
D-01/D-02 및 PUBLISHER_ADDITIONAL: 확정 기준 문서 unchanged, 관련 기존 Component 테스트·Publisher/운영 브라우저 검증 PASS. 전체 문서 조항의 독립 수동 재인증은 NOT VERIFIED.
|
||||
|
||||
COMPONENT_API: 제거/이름 변경 없음; optional FilterBar layout/Props export만 추가. 기존 consumer ref도 검증.
|
||||
|
||||
THEME_TOKEN: default JSON·primitive/default/generated values·Tabs·Carousel TS/CSS 및 추가 요청 기준 9개 보호 파일 SHA256 일치. 기존 approved Theme 값과 미확정 항목을 변경하지 않음.
|
||||
|
||||
STORYBOOK_ID: 292개 보존 / EXISTING_TESTS: Guard51·Component8 AST 본문 보존.
|
||||
|
||||
## 증거·재현
|
||||
|
||||
Git 추적 요약은 같은 폴더 `ai-quality-improvement-2026-10-10.json`에 있다. 원본 결과·실패 시도·PNG는 gitignored `_local/quality-20261010`에 보존된다. 이전 실험/퍼블리셔 폴더는 읽기만 했다. 기존 증거 삭제·ZIP 배포 없음.
|
||||
|
||||
대표 최신 파일: `final-evidence.json`, `guard-01..10.json`, `runtime-01..10.json`, `combined-01..10.json`, `contract-audit.json`, `reference-runtime.json` + 후속 `reference-THEME_JSON_LOADER.json`/`reference-FILTERBAR_REFERENCE_USAGE.json`, `regression-*.json`, `consumer-runtime.json`, `clone-runtime/`, `clone-typecheck.log`, `clone-build.log`.
|
||||
|
||||
기본 재현 명령은 [실험 README](../../examples/ai-quality/README.md)와 [이전 준비 문서](../guidelines/gitea-source-transfer-preparation-2026-10-10.md)에 있다. aggregate는 per-screen 파일을 읽으므로 마지막 subset summary로 전체 성공 수를 대체하지 않는다. source 또는 Guard/Component 계약이 바뀌면 연결 판정은 stale이 된다.
|
||||
|
||||
## GitHub·이전 준비
|
||||
|
||||
PREVIOUS_HEAD: BASE_SHA와 동일. 구현 commit: `9ae2ab3`(Guard), `332c614`(FilterBar), `6034ac4`(10화면/검증), `cb451b3`(통계 집계).
|
||||
|
||||
COMMIT_SHA / REMOTE_HEAD / SHA_MATCH / WORKING_TREE / PUSH_RESULT: 제출 응답에서 최종 보고 commit을 포함한 일반 push와 실제 remote SHA 확인 결과를 기록한다. force push/reset/clean/remote 변경을 하지 않는다.
|
||||
|
||||
SOURCE_READY: 검증한 GitHub 소스·필수 파일/의존성/명령/위험을 [월요일 이전 준비](../guidelines/gitea-source-transfer-preparation-2026-10-10.md)에 정리했다. 이번에는 이전 실행 없음.
|
||||
|
||||
공식 Gitea: NOT ACCESSED / NOT MODIFIED. GitHub 연결 유지.
|
||||
|
||||
## 잔여 문제·최종 판단
|
||||
|
||||
연결 graph 기반 Token 감지, Pattern 표현/포커스 수정, 선택 지침과 실제 예제, 증거 연결·회귀 도구까지 구현했다. 기존 화면의 관측한 회귀는 0이다. 원본 Guard를 PASS로 만드는 것보다 판정 근거와 범위를 명확히 했다.
|
||||
|
||||
모델별 재현성·낮은 추론 신규 생성은 NOT VERIFIED. 기존 낮은 추론 3개 산출물의 Token 재검사만 수행했으며 새 cross-model 실험으로 보고하지 않는다. 공유 composition이므로 10개 독립 생성의 성공률로 일반화할 수 없다.
|
||||
|
||||
다음 우선순위는 같은 prompt/seed/모델별 독립 생성 및 실제 점수 rubric, 그 뒤 기존 전체 Storybook의 native/CSS intent 예외 검토·스크린리더/색 대비 검증이다. 과거 보고의 contrast 미충족/일부 clear icon 문제는 approved Theme를 임의 변경하지 않고 잔여 항목으로 유지한다. Combobox/DatePicker/Carousel/실기기 drag 전체 상태 재검증은 NOT VERIFIED.
|
||||
|
||||
Guard 한계: import/AST/CSS 선언 확인은 실제 cascade·미디어 활성 상태·모든 inline 변수 scope·실제 렌더 횟수를 보증하지 않는다. JS로 생성되는 동적 CSS/Token 및 의미적 미요청 기능은 별도 Runtime·사람 검토가 필요하다. Runtime evidence는 제공된 assertion이며 독립 보안 attestation이 아니다.
|
||||
|
||||
Started At: 2026-10-10 17:31:43 KST / Estimated Duration: 120~180분. Completed At·Actual Duration·Variance는 원격 확인이 끝난 제출 응답에 정확한 시각으로 기록한다.
|
||||
@@ -0,0 +1,616 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"source": "https://github.com/shkim25027/HMDesignSystemTest.git",
|
||||
"branch": "main",
|
||||
"baseHead": "4fe549da01683c363b0715aedeb82a089717f685",
|
||||
"finalHead": "Resolve the enclosing committed revision; exact final SHA is in the local release-manifest.json and final delivery report",
|
||||
"trackedFileCount": 595,
|
||||
"paths": [
|
||||
".gitignore",
|
||||
".storybook/main.ts",
|
||||
".storybook/manager-navigation.js",
|
||||
".storybook/manager.css",
|
||||
".storybook/manager.js",
|
||||
".storybook/preview-head.html",
|
||||
".storybook/preview.tsx",
|
||||
".storybook/pseudo-states.ts",
|
||||
".storybook/qa/LAN-PREVIEW-REPORT.md",
|
||||
".storybook/qa/LAN-PREVIEW.md",
|
||||
".storybook/qa/STORY-INVENTORY.md",
|
||||
".storybook/qa/generate-inventory.mjs",
|
||||
".storybook/qa/story-inventory.json",
|
||||
"AGENTS.md",
|
||||
"CLAUDE.md",
|
||||
"PORTABLE-R4-VERIFICATION.md",
|
||||
"PORTABLE-R5-CANDIDATE-VERIFICATION.md",
|
||||
"PORTABLE-R5-VERIFICATION.md",
|
||||
"PORTABLE-R6-VERIFICATION.md",
|
||||
"README.md",
|
||||
"docs/center-graphic/README.md",
|
||||
"docs/components/accordion.md",
|
||||
"docs/components/alert-dialog.md",
|
||||
"docs/components/alert.md",
|
||||
"docs/components/aspect-ratio.md",
|
||||
"docs/components/avatar.md",
|
||||
"docs/components/badge.md",
|
||||
"docs/components/breadcrumb.md",
|
||||
"docs/components/button.md",
|
||||
"docs/components/calendar.md",
|
||||
"docs/components/card.md",
|
||||
"docs/components/carousel.md",
|
||||
"docs/components/checkbox.md",
|
||||
"docs/components/collapsible.md",
|
||||
"docs/components/combobox.md",
|
||||
"docs/components/command.md",
|
||||
"docs/components/context-menu.md",
|
||||
"docs/components/date-picker.md",
|
||||
"docs/components/dialog.md",
|
||||
"docs/components/drawer.md",
|
||||
"docs/components/dropdown-menu.md",
|
||||
"docs/components/field.md",
|
||||
"docs/components/hover-card.md",
|
||||
"docs/components/input.md",
|
||||
"docs/components/label.md",
|
||||
"docs/components/menubar.md",
|
||||
"docs/components/navigation-menu.md",
|
||||
"docs/components/pagination.md",
|
||||
"docs/components/popover.md",
|
||||
"docs/components/progress.md",
|
||||
"docs/components/radio-group.md",
|
||||
"docs/components/resizable.md",
|
||||
"docs/components/scroll-area.md",
|
||||
"docs/components/select.md",
|
||||
"docs/components/separator.md",
|
||||
"docs/components/sheet.md",
|
||||
"docs/components/skeleton.md",
|
||||
"docs/components/slider.md",
|
||||
"docs/components/sonner.md",
|
||||
"docs/components/switch.md",
|
||||
"docs/components/table.md",
|
||||
"docs/components/tabs.md",
|
||||
"docs/components/textarea.md",
|
||||
"docs/components/toggle-group.md",
|
||||
"docs/components/toggle.md",
|
||||
"docs/components/tooltip.md",
|
||||
"docs/guidelines/ai-generation-guard.md",
|
||||
"docs/guidelines/ai-generation-improvement-2026-10-10.md",
|
||||
"docs/guidelines/ai-generation-stabilization-2026-10-10.md",
|
||||
"docs/guidelines/ai-implementation-details.md",
|
||||
"docs/guidelines/ai-screen-contract.md",
|
||||
"docs/guidelines/component-pattern-reference.md",
|
||||
"docs/guidelines/consistency-audit-2026-10-06.md",
|
||||
"docs/guidelines/designer-theme-guide.md",
|
||||
"docs/guidelines/designer-theme-report.md",
|
||||
"docs/guidelines/gitea-source-transfer-preparation-2026-10-10.md",
|
||||
"docs/guidelines/gitea-source-transfer-preparation-2026-10-11.md",
|
||||
"docs/guidelines/guard-accuracy-2026-10-10.md",
|
||||
"docs/guidelines/hm-custom-implementation.md",
|
||||
"docs/guidelines/navigation-single-mode.md",
|
||||
"docs/guidelines/portable-test-distribution.md",
|
||||
"docs/guidelines/publisher-additional-review-2026-10-10.md",
|
||||
"docs/guidelines/publisher-distribution-guide.md",
|
||||
"docs/guidelines/publisher-integration-2026-10-09.md",
|
||||
"docs/guidelines/publisher-stabilization-2026-10-10.md",
|
||||
"docs/guidelines/publisher-validation-2026-10-10.md",
|
||||
"docs/guidelines/runtime-portability.md",
|
||||
"docs/guidelines/runtime-theme-contract.md",
|
||||
"docs/guidelines/runtime-theme-hardcode-audit.csv",
|
||||
"docs/guidelines/runtime-theme-report.md",
|
||||
"docs/guidelines/runtime-theme.md",
|
||||
"docs/guidelines/shadcn-기반-구현-원칙.md",
|
||||
"docs/guidelines/theme-delivery.md",
|
||||
"docs/guidelines/개발-적용-가이드.md",
|
||||
"docs/guidelines/운영-배포-가이드.md",
|
||||
"docs/guidelines/테마-토큰-가이드.md",
|
||||
"docs/guidelines/프로젝트-지침.md",
|
||||
"docs/patterns/dashboard-layout.md",
|
||||
"docs/patterns/dashboard-status-static.html",
|
||||
"docs/patterns/data-table.md",
|
||||
"docs/patterns/filter-bar.md",
|
||||
"docs/patterns/gnb.md",
|
||||
"docs/patterns/lnb.md",
|
||||
"docs/patterns/loading-screen.md",
|
||||
"docs/patterns/page-header.md",
|
||||
"docs/reports/accessibility-residual-2026-10-10.md",
|
||||
"docs/reports/ai-quality-improvement-2026-10-10.json",
|
||||
"docs/reports/ai-quality-improvement-2026-10-10.md",
|
||||
"docs/reports/gitea-source-inventory-2026-10-11.json",
|
||||
"docs/reports/guard-css-intent-dynamic-token-2026-10-10.md",
|
||||
"docs/reports/pre-gitea-finalization-2026-10-11.md",
|
||||
"docs/reports/publisher-a11y-guard-2026-10-10.md",
|
||||
"examples/ai-quality/01/index.html",
|
||||
"examples/ai-quality/01/main.tsx",
|
||||
"examples/ai-quality/01/requirements.json",
|
||||
"examples/ai-quality/02/index.html",
|
||||
"examples/ai-quality/02/main.tsx",
|
||||
"examples/ai-quality/02/requirements.json",
|
||||
"examples/ai-quality/03/index.html",
|
||||
"examples/ai-quality/03/main.tsx",
|
||||
"examples/ai-quality/03/requirements.json",
|
||||
"examples/ai-quality/04/index.html",
|
||||
"examples/ai-quality/04/main.tsx",
|
||||
"examples/ai-quality/04/requirements.json",
|
||||
"examples/ai-quality/05/index.html",
|
||||
"examples/ai-quality/05/main.tsx",
|
||||
"examples/ai-quality/05/requirements.json",
|
||||
"examples/ai-quality/06/index.html",
|
||||
"examples/ai-quality/06/main.tsx",
|
||||
"examples/ai-quality/06/requirements.json",
|
||||
"examples/ai-quality/07/index.html",
|
||||
"examples/ai-quality/07/main.tsx",
|
||||
"examples/ai-quality/07/requirements.json",
|
||||
"examples/ai-quality/08/index.html",
|
||||
"examples/ai-quality/08/main.tsx",
|
||||
"examples/ai-quality/08/requirements.json",
|
||||
"examples/ai-quality/09/index.html",
|
||||
"examples/ai-quality/09/main.tsx",
|
||||
"examples/ai-quality/09/requirements.json",
|
||||
"examples/ai-quality/10/index.html",
|
||||
"examples/ai-quality/10/main.tsx",
|
||||
"examples/ai-quality/10/requirements.json",
|
||||
"examples/ai-quality/README.md",
|
||||
"examples/ai-quality/shared/Dashboard.tsx",
|
||||
"examples/ai-quality/shared/GNBFrame.tsx",
|
||||
"examples/ai-quality/shared/Heading.tsx",
|
||||
"examples/ai-quality/shared/LNBFrame.tsx",
|
||||
"examples/ai-quality/shared/OverlayWorkflow.tsx",
|
||||
"examples/ai-quality/shared/Permissions.tsx",
|
||||
"examples/ai-quality/shared/RequestForm.tsx",
|
||||
"examples/ai-quality/shared/SearchList.tsx",
|
||||
"examples/ai-quality/shared/StateWorkflow.tsx",
|
||||
"examples/ai-quality/shared/hm-theme.css",
|
||||
"examples/ai-quality/shared/index.css",
|
||||
"examples/ai-quality/tsconfig.json",
|
||||
"examples/ai-quality/vite.config.ts",
|
||||
"examples/publisher-list/README.md",
|
||||
"examples/publisher-list/hm-theme.css",
|
||||
"examples/publisher-list/index.css",
|
||||
"examples/publisher-list/index.html",
|
||||
"examples/publisher-list/main.tsx",
|
||||
"examples/publisher-list/tsconfig.json",
|
||||
"examples/publisher-list/vite.config.ts",
|
||||
"index.html",
|
||||
"package-lock.json",
|
||||
"package.json",
|
||||
"packages/center-graphic/README.md",
|
||||
"packages/center-graphic/package.json",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/교량/실사화/오른쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/교량/실사화/왼쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/교량/실사화/중앙.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/교량/위치도/오른쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/교량/위치도/왼쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/교량/위치도/중앙.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/교차로/실사화/오른쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/교차로/실사화/왼쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/교차로/실사화/중앙.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/교차로/위치도/오른쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/교차로/위치도/왼쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/기타 시설물/실사화/오른쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/기타 시설물/실사화/왼쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/기타 시설물/실사화/중앙.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/기타 시설물/위치도/위치도.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/분기점, 나들목/나들목/실사화/오른쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/분기점, 나들목/나들목/실사화/왼쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/분기점, 나들목/나들목/실사화/중앙.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/분기점, 나들목/나들목/위치도/오른쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/분기점, 나들목/나들목/위치도/왼쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/분기점, 나들목/분기점/실사화/오른쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/분기점, 나들목/분기점/실사화/왼쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/분기점, 나들목/분기점/실사화/중앙.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/분기점, 나들목/분기점/위치도/오른쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/분기점, 나들목/분기점/위치도/왼쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/고속도로, 국도/교량/실사화/오른쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/고속도로, 국도/교량/실사화/왼쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/고속도로, 국도/교량/실사화/중앙.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/고속도로, 국도/교량/위치도/오른쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/고속도로, 국도/교량/위치도/왼쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/고속도로, 국도/교량/위치도/중앙.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/고속도로, 국도/교차로/실사화/오른쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/고속도로, 국도/교차로/실사화/왼쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/고속도로, 국도/교차로/실사화/중앙.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/고속도로, 국도/교차로/위치도/오른쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/고속도로, 국도/교차로/위치도/왼쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/고속도로, 국도/나들목/시설물/실사화/오른쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/고속도로, 국도/나들목/시설물/실사화/왼쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/고속도로, 국도/나들목/시설물/실사화/중앙.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/고속도로, 국도/나들목/시설물/위치도/오른쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/고속도로, 국도/나들목/시설물/위치도/왼쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/고속도로, 국도/나들목/위치도/오른쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/고속도로, 국도/나들목/위치도/왼쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/고속도로, 국도/분기점/실사화/오른쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/고속도로, 국도/분기점/실사화/왼쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/고속도로, 국도/분기점/실사화/중앙.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/고속도로, 국도/분기점/위치도/오른쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/고속도로, 국도/분기점/위치도/왼쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/고속도로, 국도/터널/실사화/오른쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/고속도로, 국도/터널/실사화/왼쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/고속도로, 국도/터널/실사화/중앙.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/고속도로, 국도/터널/위치도/오른쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/고속도로, 국도/터널/위치도/왼쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/고속도로, 국도/터널/위치도/중앙.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/구도,면도, 이도/교량/실사화/오른쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/구도,면도, 이도/교량/실사화/왼쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/구도,면도, 이도/교량/실사화/중앙.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/구도,면도, 이도/교량/위치도/오른쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/구도,면도, 이도/교량/위치도/왼쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/구도,면도, 이도/교량/위치도/중앙.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/구도,면도, 이도/교차로/실사화/오른쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/구도,면도, 이도/교차로/실사화/왼쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/구도,면도, 이도/교차로/실사화/중앙.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/구도,면도, 이도/교차로/위치도/오른쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/구도,면도, 이도/교차로/위치도/왼쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/구도,면도, 이도/터널/실사화/오른쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/구도,면도, 이도/터널/실사화/왼쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/구도,면도, 이도/터널/실사화/중앙.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/구도,면도, 이도/터널/위치도/오른쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/구도,면도, 이도/터널/위치도/왼쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/구도,면도, 이도/터널/위치도/중앙.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/시도,군도/교량/실사화/오른쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/시도,군도/교량/실사화/왼쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/시도,군도/교량/실사화/중앙.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/시도,군도/교량/위치도/오른쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/시도,군도/교량/위치도/왼쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/시도,군도/교량/위치도/중앙.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/시도,군도/교차로/실사화/오른쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/시도,군도/교차로/실사화/왼쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/시도,군도/교차로/실사화/중앙.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/시도,군도/교차로/위치도/오른쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/시도,군도/교차로/위치도/왼쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/시도,군도/터널/실사화/오른쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/시도,군도/터널/실사화/왼쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/시도,군도/터널/실사화/중앙.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/시도,군도/터널/위치도/오른쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/시도,군도/터널/위치도/왼쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/시도,군도/터널/위치도/중앙.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/지방도/교량/실사화/오른쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/지방도/교량/실사화/왼쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/지방도/교량/실사화/중앙.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/지방도/교량/위치도/오른쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/지방도/교량/위치도/왼쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/지방도/교량/위치도/중앙.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/지방도/교차로/실사화/오른쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/지방도/교차로/실사화/왼쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/지방도/교차로/실사화/중앙.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/지방도/교차로/위치도/오른쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/지방도/교차로/위치도/왼쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/지방도/터널/실사화/오른쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/지방도/터널/실사화/왼쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/지방도/터널/실사화/중앙.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/지방도/터널/위치도/오른쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/지방도/터널/위치도/왼쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/지방도/터널/위치도/중앙.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/특별시도/교량/실사화/오른쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/특별시도/교량/실사화/왼쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/특별시도/교량/실사화/중앙.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/특별시도/교량/위치도/오른쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/특별시도/교량/위치도/왼쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/특별시도/교량/위치도/중앙.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/특별시도/교차로/실사화/오른쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/특별시도/교차로/실사화/왼쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/특별시도/교차로/실사화/중앙.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/특별시도/교차로/위치도/오른쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/특별시도/교차로/위치도/왼쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/특별시도/터널/실사화/오른쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/특별시도/터널/실사화/왼쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/특별시도/터널/실사화/중앙.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/특별시도/터널/위치도/오른쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/특별시도/터널/위치도/왼쪽.svg",
|
||||
"packages/center-graphic/src/assets/facility/batch/source/연계 시설물/특별시도/터널/위치도/중앙.svg",
|
||||
"packages/center-graphic/src/assets/facility/tunnel/actual-detail/center.svg",
|
||||
"packages/center-graphic/src/assets/facility/tunnel/actual-detail/left.svg",
|
||||
"packages/center-graphic/src/assets/facility/tunnel/actual-detail/right.svg",
|
||||
"packages/center-graphic/src/assets/facility/tunnel/position-map/center.svg",
|
||||
"packages/center-graphic/src/assets/facility/tunnel/position-map/left.svg",
|
||||
"packages/center-graphic/src/assets/facility/tunnel/position-map/right.svg",
|
||||
"packages/center-graphic/src/components/CenterInformationDisplay.css",
|
||||
"packages/center-graphic/src/components/CenterInformationDisplay.tsx",
|
||||
"packages/center-graphic/src/components/CenterRepresentation.css",
|
||||
"packages/center-graphic/src/components/CenterRepresentation.tsx",
|
||||
"packages/center-graphic/src/components/CenterSpatialInformation.css",
|
||||
"packages/center-graphic/src/components/CenterSpatialInformation.tsx",
|
||||
"packages/center-graphic/src/components/CenterTitle.css",
|
||||
"packages/center-graphic/src/components/CenterTitle.tsx",
|
||||
"packages/center-graphic/src/components/CompactFacilityConnection.css",
|
||||
"packages/center-graphic/src/components/CompactFacilityConnection.tsx",
|
||||
"packages/center-graphic/src/components/FacilityBatch.css",
|
||||
"packages/center-graphic/src/components/FacilityBatch.tsx",
|
||||
"packages/center-graphic/src/components/TunnelFacility.css",
|
||||
"packages/center-graphic/src/components/TunnelFacility.tsx",
|
||||
"packages/center-graphic/src/env.d.ts",
|
||||
"packages/center-graphic/src/index.ts",
|
||||
"packages/center-graphic/src/reference.ts",
|
||||
"packages/center-graphic/tsconfig.build.json",
|
||||
"packages/center-graphic/tsconfig.json",
|
||||
"packages/ui/README.md",
|
||||
"packages/ui/components.json",
|
||||
"packages/ui/package.json",
|
||||
"packages/ui/src/components/ui/accordion.tsx",
|
||||
"packages/ui/src/components/ui/alert-dialog.tsx",
|
||||
"packages/ui/src/components/ui/alert.tsx",
|
||||
"packages/ui/src/components/ui/aspect-ratio.tsx",
|
||||
"packages/ui/src/components/ui/avatar.tsx",
|
||||
"packages/ui/src/components/ui/badge.tsx",
|
||||
"packages/ui/src/components/ui/breadcrumb.tsx",
|
||||
"packages/ui/src/components/ui/button.tsx",
|
||||
"packages/ui/src/components/ui/calendar.tsx",
|
||||
"packages/ui/src/components/ui/card.tsx",
|
||||
"packages/ui/src/components/ui/carousel.tsx",
|
||||
"packages/ui/src/components/ui/checkbox.tsx",
|
||||
"packages/ui/src/components/ui/collapsible.tsx",
|
||||
"packages/ui/src/components/ui/combobox.tsx",
|
||||
"packages/ui/src/components/ui/command.tsx",
|
||||
"packages/ui/src/components/ui/context-menu.tsx",
|
||||
"packages/ui/src/components/ui/date-picker.tsx",
|
||||
"packages/ui/src/components/ui/dialog.tsx",
|
||||
"packages/ui/src/components/ui/drawer.tsx",
|
||||
"packages/ui/src/components/ui/dropdown-menu.tsx",
|
||||
"packages/ui/src/components/ui/hover-card.tsx",
|
||||
"packages/ui/src/components/ui/input.tsx",
|
||||
"packages/ui/src/components/ui/label.tsx",
|
||||
"packages/ui/src/components/ui/menubar.tsx",
|
||||
"packages/ui/src/components/ui/navigation-menu.tsx",
|
||||
"packages/ui/src/components/ui/pagination.tsx",
|
||||
"packages/ui/src/components/ui/popover.tsx",
|
||||
"packages/ui/src/components/ui/progress.tsx",
|
||||
"packages/ui/src/components/ui/radio-group.tsx",
|
||||
"packages/ui/src/components/ui/resizable.tsx",
|
||||
"packages/ui/src/components/ui/scroll-area.tsx",
|
||||
"packages/ui/src/components/ui/select.tsx",
|
||||
"packages/ui/src/components/ui/separator.tsx",
|
||||
"packages/ui/src/components/ui/sheet.tsx",
|
||||
"packages/ui/src/components/ui/skeleton.tsx",
|
||||
"packages/ui/src/components/ui/slider.tsx",
|
||||
"packages/ui/src/components/ui/sonner.tsx",
|
||||
"packages/ui/src/components/ui/switch.tsx",
|
||||
"packages/ui/src/components/ui/table.tsx",
|
||||
"packages/ui/src/components/ui/tabs.tsx",
|
||||
"packages/ui/src/components/ui/textarea.tsx",
|
||||
"packages/ui/src/components/ui/toggle-group.tsx",
|
||||
"packages/ui/src/components/ui/toggle.tsx",
|
||||
"packages/ui/src/components/ui/tooltip.tsx",
|
||||
"packages/ui/src/components/ui/use-connected-popup-ref.ts",
|
||||
"packages/ui/src/index.ts",
|
||||
"packages/ui/src/lib/utils.ts",
|
||||
"packages/ui/src/patterns/dashboard-layout/dashboard-layout.tsx",
|
||||
"packages/ui/src/patterns/dashboard-layout/index.ts",
|
||||
"packages/ui/src/patterns/dashboard-status/contract.ts",
|
||||
"packages/ui/src/patterns/dashboard-status/dashboard-status.css",
|
||||
"packages/ui/src/patterns/dashboard-status/index.ts",
|
||||
"packages/ui/src/patterns/data-table/data-table.tsx",
|
||||
"packages/ui/src/patterns/data-table/index.ts",
|
||||
"packages/ui/src/patterns/filter-bar/filter-bar.tsx",
|
||||
"packages/ui/src/patterns/filter-bar/index.ts",
|
||||
"packages/ui/src/patterns/gnb/gnb.tsx",
|
||||
"packages/ui/src/patterns/gnb/index.ts",
|
||||
"packages/ui/src/patterns/lnb/index.ts",
|
||||
"packages/ui/src/patterns/lnb/lnb-mobile.tsx",
|
||||
"packages/ui/src/patterns/lnb/lnb.tsx",
|
||||
"packages/ui/src/patterns/loading-screen/index.ts",
|
||||
"packages/ui/src/patterns/loading-screen/loading-screen.tsx",
|
||||
"packages/ui/src/patterns/page-header/index.ts",
|
||||
"packages/ui/src/patterns/page-header/page-header.tsx",
|
||||
"packages/ui/src/tailwind.css",
|
||||
"packages/ui/src/theme.css",
|
||||
"packages/ui/src/theme/accordion.css",
|
||||
"packages/ui/src/theme/alert-dialog.css",
|
||||
"packages/ui/src/theme/alert.css",
|
||||
"packages/ui/src/theme/avatar.css",
|
||||
"packages/ui/src/theme/badge.css",
|
||||
"packages/ui/src/theme/breadcrumb.css",
|
||||
"packages/ui/src/theme/button.css",
|
||||
"packages/ui/src/theme/calendar.css",
|
||||
"packages/ui/src/theme/card.css",
|
||||
"packages/ui/src/theme/carousel.css",
|
||||
"packages/ui/src/theme/checkbox.css",
|
||||
"packages/ui/src/theme/collapsible.css",
|
||||
"packages/ui/src/theme/combobox.css",
|
||||
"packages/ui/src/theme/command.css",
|
||||
"packages/ui/src/theme/context-menu.css",
|
||||
"packages/ui/src/theme/contract.ts",
|
||||
"packages/ui/src/theme/dashboard-layout.css",
|
||||
"packages/ui/src/theme/data-table.css",
|
||||
"packages/ui/src/theme/date-picker.css",
|
||||
"packages/ui/src/theme/default-values.generated.ts",
|
||||
"packages/ui/src/theme/default.css",
|
||||
"packages/ui/src/theme/dialog.css",
|
||||
"packages/ui/src/theme/drawer.css",
|
||||
"packages/ui/src/theme/dropdown-menu.css",
|
||||
"packages/ui/src/theme/filter-bar.css",
|
||||
"packages/ui/src/theme/gnb.css",
|
||||
"packages/ui/src/theme/hover-card.css",
|
||||
"packages/ui/src/theme/index.ts",
|
||||
"packages/ui/src/theme/input.css",
|
||||
"packages/ui/src/theme/label.css",
|
||||
"packages/ui/src/theme/lnb.css",
|
||||
"packages/ui/src/theme/loader.ts",
|
||||
"packages/ui/src/theme/loading-screen.css",
|
||||
"packages/ui/src/theme/menubar.css",
|
||||
"packages/ui/src/theme/navigation-menu.css",
|
||||
"packages/ui/src/theme/overlay.css",
|
||||
"packages/ui/src/theme/page-header.css",
|
||||
"packages/ui/src/theme/pagination.css",
|
||||
"packages/ui/src/theme/popover.css",
|
||||
"packages/ui/src/theme/primitives.css",
|
||||
"packages/ui/src/theme/progress.css",
|
||||
"packages/ui/src/theme/radio-group.css",
|
||||
"packages/ui/src/theme/requests.ts",
|
||||
"packages/ui/src/theme/resizable.css",
|
||||
"packages/ui/src/theme/runtime.ts",
|
||||
"packages/ui/src/theme/scroll-area.css",
|
||||
"packages/ui/src/theme/select.css",
|
||||
"packages/ui/src/theme/separator.css",
|
||||
"packages/ui/src/theme/sheet.css",
|
||||
"packages/ui/src/theme/skeleton.css",
|
||||
"packages/ui/src/theme/slider.css",
|
||||
"packages/ui/src/theme/sonner.css",
|
||||
"packages/ui/src/theme/switch.css",
|
||||
"packages/ui/src/theme/table.css",
|
||||
"packages/ui/src/theme/tabs.css",
|
||||
"packages/ui/src/theme/textarea.css",
|
||||
"packages/ui/src/theme/toggle-group.css",
|
||||
"packages/ui/src/theme/toggle.css",
|
||||
"packages/ui/src/theme/tooltip.css",
|
||||
"packages/ui/tsconfig.build.json",
|
||||
"packages/ui/tsconfig.json",
|
||||
"public/fonts/NotoSansKR-OFL.txt",
|
||||
"public/fonts/NotoSansKR-variable.ttf",
|
||||
"scripts/accessibility-regression.test.mjs",
|
||||
"scripts/ai-generation-guard.mjs",
|
||||
"scripts/ai-generation-guard.test.mjs",
|
||||
"scripts/audit-quality-contracts.mjs",
|
||||
"scripts/build-package.mjs",
|
||||
"scripts/check-doc-links.mjs",
|
||||
"scripts/create-ai-reference-package.mjs",
|
||||
"scripts/create-publisher-distribution.mjs",
|
||||
"scripts/finalize-dashboard-export.mjs",
|
||||
"scripts/guard-evidence.mjs",
|
||||
"scripts/guard-evidence.test.mjs",
|
||||
"scripts/guard-navigation-analysis.mjs",
|
||||
"scripts/guard-requirements.mjs",
|
||||
"scripts/guard-requirements.test.mjs",
|
||||
"scripts/guard-style-analysis.mjs",
|
||||
"scripts/guard-style-evidence.mjs",
|
||||
"scripts/guard-theme-analysis.mjs",
|
||||
"scripts/h2-preview.mjs",
|
||||
"scripts/portable-preview/preview-server.cjs",
|
||||
"scripts/portable-preview/start-preview.bat",
|
||||
"scripts/prepare-quality-experiments.mjs",
|
||||
"scripts/public-theme-tokens.mjs",
|
||||
"scripts/publisher-components.test.mjs",
|
||||
"scripts/serve-quality-reference.mjs",
|
||||
"scripts/start-storybook.mjs",
|
||||
"scripts/summarize-quality-evidence.mjs",
|
||||
"scripts/theme-artifacts.mjs",
|
||||
"scripts/theme-contract.mjs",
|
||||
"scripts/theme-defaults.mjs",
|
||||
"scripts/theme-templates/default.css",
|
||||
"scripts/theme-templates/primitives.css",
|
||||
"scripts/theme-verification.test.mjs",
|
||||
"scripts/verify-accessibility-runtime.mjs",
|
||||
"scripts/verify-quality-reference.mjs",
|
||||
"scripts/verify-quality-regression.mjs",
|
||||
"scripts/verify-quality-runtime.mjs",
|
||||
"src/App.tsx",
|
||||
"src/center/center-facility.stories.tsx",
|
||||
"src/center/center-information.stories.tsx",
|
||||
"src/center/center-overview.stories.tsx",
|
||||
"src/center/center-shared.tsx",
|
||||
"src/center/center-spatial.stories.tsx",
|
||||
"src/center/center-stories.css",
|
||||
"src/center/center-title.stories.tsx",
|
||||
"src/components/accordion.stories.tsx",
|
||||
"src/components/alert-dialog.stories.tsx",
|
||||
"src/components/alert.stories.tsx",
|
||||
"src/components/aspect-ratio.stories.tsx",
|
||||
"src/components/avatar.stories.tsx",
|
||||
"src/components/badge.stories.tsx",
|
||||
"src/components/breadcrumb.stories.tsx",
|
||||
"src/components/button.stories.tsx",
|
||||
"src/components/calendar.stories.tsx",
|
||||
"src/components/card.stories.tsx",
|
||||
"src/components/carousel.stories.tsx",
|
||||
"src/components/checkbox.stories.tsx",
|
||||
"src/components/collapsible.stories.tsx",
|
||||
"src/components/combobox.stories.tsx",
|
||||
"src/components/command.stories.tsx",
|
||||
"src/components/context-menu.stories.tsx",
|
||||
"src/components/date-picker.stories.tsx",
|
||||
"src/components/dialog.stories.tsx",
|
||||
"src/components/drawer.stories.tsx",
|
||||
"src/components/dropdown-menu.stories.tsx",
|
||||
"src/components/hover-card.stories.tsx",
|
||||
"src/components/input.stories.tsx",
|
||||
"src/components/label.stories.tsx",
|
||||
"src/components/menubar.stories.tsx",
|
||||
"src/components/navigation-menu.stories.tsx",
|
||||
"src/components/pagination.stories.tsx",
|
||||
"src/components/popover.stories.tsx",
|
||||
"src/components/progress.stories.tsx",
|
||||
"src/components/publisher-regression.stories.tsx",
|
||||
"src/components/radio-group.stories.tsx",
|
||||
"src/components/resizable.stories.tsx",
|
||||
"src/components/scroll-area.stories.tsx",
|
||||
"src/components/select.stories.tsx",
|
||||
"src/components/separator.stories.tsx",
|
||||
"src/components/sheet.stories.tsx",
|
||||
"src/components/skeleton.stories.tsx",
|
||||
"src/components/slider.stories.tsx",
|
||||
"src/components/sonner.stories.tsx",
|
||||
"src/components/story-board.tsx",
|
||||
"src/components/story-page.css",
|
||||
"src/components/story-page.tsx",
|
||||
"src/components/switch.stories.tsx",
|
||||
"src/components/table.stories.tsx",
|
||||
"src/components/tabs.stories.tsx",
|
||||
"src/components/textarea.stories.tsx",
|
||||
"src/components/toggle-group.stories.tsx",
|
||||
"src/components/toggle.stories.tsx",
|
||||
"src/components/tooltip.stories.tsx",
|
||||
"src/exports/dashboard/dashboard-export.css",
|
||||
"src/exports/dashboard/index.html",
|
||||
"src/exports/dashboard/main.tsx",
|
||||
"src/exports/recruit/index.html",
|
||||
"src/exports/recruit/main.tsx",
|
||||
"src/foundation/color.stories.tsx",
|
||||
"src/foundation/foundation.css",
|
||||
"src/foundation/layout.stories.tsx",
|
||||
"src/foundation/reference-data.ts",
|
||||
"src/foundation/reference.tsx",
|
||||
"src/foundation/typography.stories.tsx",
|
||||
"src/hm-theme.css",
|
||||
"src/index.css",
|
||||
"src/list-screen.css",
|
||||
"src/main.tsx",
|
||||
"src/patterns/dashboard-composition.css",
|
||||
"src/patterns/dashboard-composition.tsx",
|
||||
"src/patterns/dashboard-layout.stories.css",
|
||||
"src/patterns/dashboard-layout.stories.tsx",
|
||||
"src/patterns/dashboard-status-contract.css",
|
||||
"src/patterns/dashboard-work-status.ts",
|
||||
"src/patterns/data-table.stories.tsx",
|
||||
"src/patterns/filter-bar.stories.tsx",
|
||||
"src/patterns/gnb.stories.tsx",
|
||||
"src/patterns/lnb.stories.tsx",
|
||||
"src/patterns/loading-screen.stories.tsx",
|
||||
"src/patterns/page-header.stories.tsx",
|
||||
"src/patterns/sample-users.ts",
|
||||
"src/recruit/recruit-data.ts",
|
||||
"src/recruit/recruit-screen.tsx",
|
||||
"src/theme/designer-extras.tsx",
|
||||
"src/theme/designer-preview.tsx",
|
||||
"src/theme/designer-theme.css",
|
||||
"src/theme/designer-theme.stories.tsx",
|
||||
"src/theme/preview.ts",
|
||||
"src/theme/runtime-loader.stories.tsx",
|
||||
"src/theme/runtime-theme.stories.tsx",
|
||||
"src/theme/specimens.tsx",
|
||||
"src/theme/verification-baseline.json",
|
||||
"src/theme/verification-state.tsx",
|
||||
"src/vite-env.d.ts",
|
||||
"src/work-dashboard/WorkDashboard.tsx",
|
||||
"src/work-dashboard/data.ts",
|
||||
"src/work-dashboard/work-dashboard.css",
|
||||
"start-storybook.bat",
|
||||
"tailwind.css",
|
||||
"themes/default.json",
|
||||
"themes/drafts/preview-warm.json",
|
||||
"themes/service-example.json",
|
||||
"tsconfig.app.json",
|
||||
"tsconfig.json",
|
||||
"tsconfig.node.json",
|
||||
"vite.config.ts",
|
||||
"vite.dashboard-export.config.ts",
|
||||
"vite.recruit-export.config.ts"
|
||||
],
|
||||
"excluded": [
|
||||
".git",
|
||||
"node_modules",
|
||||
"_local",
|
||||
"dist",
|
||||
"storybook-static",
|
||||
"theme-dist",
|
||||
"ZIP",
|
||||
"independent experiment artifacts"
|
||||
],
|
||||
"giteaAccess": "NOT EXECUTED"
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
# Guard CSS Intent·동적 Token 검증 개선
|
||||
|
||||
RESULT: PARTIAL — 요청한 Guard·문서 구현과 필수 검증 PASS. T01 사용자 디자인 의도 및 미실행 Theme/동적 상태는 NOT VERIFIED.
|
||||
|
||||
TARGET: `D:\디자인시스템\hmdesign`
|
||||
|
||||
BASE_SHA: `512cd280554b385dbfa7606ea8a7e557ccf7b197`
|
||||
|
||||
최종 commit/push SHA·작업 시간은 이 보고서를 포함한 커밋을 만든 뒤 로컬 `_local/css-intent-20261010/FINAL_REPORT.md`에 기록한다. 자기 커밋 SHA를 동일 커밋 파일 안에 넣지 않는다. 실험 source·측정 JSON/PNG·기존 실패 증거는 GitHub에 추가 전송하지 않는다.
|
||||
|
||||
## 개선 결과와 판정 범위
|
||||
|
||||
| 항목 | 결과 |
|
||||
|---|---|
|
||||
| CSS_INTENT | STATIC/RUNTIME/DESIGN_INTENT/FINAL 분리. 명확한 Component HEX/RGB/HSL·spacing/radius override는 STYLE-001 FAIL. 일반 콘텐츠 CSS·Token override·중요도/승인 의도는 별도 inventory/NOT VERIFIED |
|
||||
| DYNAMIC_TOKEN | 최대 32개 유한 후보 전체 선언 검사. const/conditional/concatenation/template, shadowing, fallback, Props/style spread/className 미해석 위치를 구분. 실제 Runtime 미정의 Token은 computed fallback 일치에도 FAIL |
|
||||
| STATIC_ANALYSIS | 공개 import/CSS entry·Production graph·PARTIAL·Storybook 격리 보존. non-HM host 변수 미확인과 명확한 HM 미정의를 구분. 명백히 잘못된 var() TOKEN-003 FAIL |
|
||||
| RUNTIME_EVIDENCE | source/contract + site/file/rule/Component/DOM/property/state/browser/viewport 대응, 실제 값 비교. 원본 issues 보존, 중복 측정 PASS가 FAIL을 가리지 않음 |
|
||||
| DESIGN_INTENT | 자동 승인 기능 없음. 문서 recipe·해시·유효 행 검토도 NOT VERIFIED. 새 Theme 편집 방식이나 CSS override 허용 없음 |
|
||||
| MEDIUM_T01 | 기존 원본 화면만 사용. Theme/Status import와 연결 Token 정적 PASS. 4폭×4상태의 기존 종류 CSS 64건 + 3개 Badge override custom property 48건 = 112/112 PASS. 세 위치 STATIC PASS/RUNTIME PASS/DESIGN_INTENT NOT VERIFIED/FINAL NOT VERIFIED |
|
||||
|
||||
T01의 기존 `REUSE-003`는 `src/index.css:15`의 `[data-slot="badge"]` 규칙이다. 세 기존 Badge Token에 상태 변수·공식 background/border recipe를 연결한다. 연결 선언 존재와 브라우저 적용값은 검증할 수 있으나, 사용자가 요청한 화면 의미 및 예외 override 승인 여부는 이 근거만으로 확정할 수 없다. 기존 raw/static/combined NOT VERIFIED를 삭제하지 않았다. 새 결합의 raw/static도 NOT VERIFIED이며 전체 Runtime만 PASS다. 구체적인 CSS 검토 결과는 정적 PASS·위치별 Runtime PASS·디자인 의도 NOT VERIFIED로 구분한다.
|
||||
|
||||
`styleVerification.runtimeStatus`는 검토가 필요한 override/동적 위치에 대응하는 명명된 측정의 결과다. inventory의 모든 일반 레이아웃 선언, 모든 상태와 Theme 전환을 검증했다는 뜻이 아니다. `styleEvidence.checks`의 나머지 Runtime NOT VERIFIED를 전체 PASS로 바꾸지 않는다.
|
||||
|
||||
## 수정 파일과 영향
|
||||
|
||||
| 파일 | 원인 / 변경 내용 | 영향 |
|
||||
|---|---|---|
|
||||
| scripts/ai-generation-guard.mjs | 스타일 inventory·동적 위치·선언 출처/행·새 분석기 contract hash 연결 | 기존 소비 graph/Navigation/Storybook 범위 유지 |
|
||||
| scripts/guard-theme-analysis.mjs | 동적 문자열·Props와 var fallback 검사의 한계 | 유한 후보/미해석 위치/외부 변수/잘못된 참조를 구분 |
|
||||
| scripts/guard-style-analysis.mjs | 선언 존재와 디자인 의도가 기존 REUSE-003 하나에 묶임 | 명확한 위반·일반 CSS·Global/scoped·Token override 분리 |
|
||||
| scripts/guard-style-evidence.mjs | 측정 PASS가 특정 source site에 대응하지 않음 | 실제 DOM/Component/rule/state/browser와 위치별 네 판정 연결 |
|
||||
| scripts/guard-evidence.mjs | 상태 이름·문서 행·충돌/위반 처리 보강 필요 | 원본 보존, 임의 supplied PASS 대신 계산, FAIL 우선 |
|
||||
| scripts/ai-generation-guard.test.mjs | 회귀 coverage 확대 | 기존 63개 본문 보존 + 12개 신규 |
|
||||
| scripts/guard-evidence.test.mjs | Runtime false PASS 방지 | 기존 11개 본문 보존 + 9개 신규 |
|
||||
| AGENTS.md / docs/guidelines/ai-screen-contract.md | AI 화면의 Token/override 보고 계약 명확화 | 기존 Theme 편집 권한·Runtime 공개 계약 확대 없음 |
|
||||
| docs/guidelines/ai-generation-guard.md | 세 영역·동적 후보·위치별 JSON/실행 명령·한계 설명 | 과거 테스트 수와 기존 증거는 역사 기록으로 보존 |
|
||||
| docs/components/badge.md / docs/patterns/dashboard-layout.md | 기존 상태 recipe와 승인 의도의 구분 | Component·Pattern API/디자인 예제 자체는 미변경 |
|
||||
| 이 보고서 | 실제 검증 범위와 잔여 한계 기록 | 저장소 보고 근거 |
|
||||
|
||||
## 검증
|
||||
|
||||
| 검사 | 결과 / 근거 |
|
||||
|---|---|
|
||||
| GUARD_EXISTING | EXECUTED PASS — 기존 63개 본문 보존, 최종 suite에서 통과 |
|
||||
| GUARD_NEW | EXECUTED PASS — 12개 추가, 현재 Guard 75/75 |
|
||||
| CSS_INTENT_TEST | EXECUTED PASS — Component HEX/RGB/HSL/numeric spacing/radius/utility, Token override, Global/general CSS, literal 동적 분기, graph 밖/Storybook 범위 |
|
||||
| DYNAMIC_TOKEN_TEST | EXECUTED PASS — 유한 후보·미정의 분기·fallback·shadowed/destructured binding·외부 Props/style/class·Runtime 미정의 참조 |
|
||||
| RUNTIME_EVIDENCE_TEST | EXECUTED PASS — 기존 11 + 신규 9 = 20/20. stale/hash·scope·불가능한 문서 행·site/selector/Component/browser/state·중복 이름과 static 충돌 검사 |
|
||||
| REQUIREMENTS_LINK | EXECUTED PASS — 기존 연결 검사 5/5 |
|
||||
| 통합 테스트 | EXECUTED 100/100 PASS, `_local/css-intent-20261010/tests-release-final.log` |
|
||||
| MEDIUM_T01 | EXECUTED 112/112 CSS 측정 + 20개 필터 동작 + 4 viewport PASS. Dashboard 48px/960px 유지. FINAL NOT VERIFIED |
|
||||
| TYPECHECK | EXECUTED PASS — npm run typecheck, Theme defaults 71/73 일치 및 packages build hook 포함 |
|
||||
| BUILD | EXECUTED PASS — npm run build --ignore-scripts. 이미 성공한 Theme/package hook 중복 생략. 기존 500kB chunk 경고는 별도 보존 |
|
||||
| DOC_CONSISTENCY | EXECUTED — 변경된 로컬 링크/anchor·실행 명령·결과 필드·원칙을 변경 범위에서 점검 |
|
||||
| RELATED_STORY | 관련 Badge/Dashboard/Runtime Theme/Designer source 설명 확인. 이번 Guard의 Production 하드코드 FAIL은 Storybook에 강제하지 않음. 설명 충돌 없음, Story source/ID 수정 0. 전체 렌더 NOT VERIFIED |
|
||||
|
||||
초기 기존 suite 1건은 반복 Token 목록으로 JSON이 spawnSync 출력 버퍼를 초과한 도구 오류였다. 동적 위치가 있는 entry에만 선언 목록을 출력해 같은 검사 재실행 PASS, 최종 100개 전체 PASS다. 초기 T01 추가 32건은 기대 source `var()` 문자열과 computed 치환 값의 비교 형식 오류였다. 해당 실패 JSON/로그를 보존하고 실패 32건만 재측정했으며 당시 통과 80건은 재사용했다. 최종 source-selector/Component 연결 및 하드코드 분기 규칙 변경으로 contract fingerprint가 달라진 뒤에는 이전 해시를 이식하지 않고 최종 112건을 새 계약에서 다시 측정했다. 이는 동일 조건 중복 검사가 아니라 최종 계약 증거 생성이다.
|
||||
|
||||
## 중복 검증·보존
|
||||
|
||||
- EXECUTED: 변경 Guard/증거/요구사항 연결 100개, T01 새 계약 CSS112와 동작/네 폭, Typecheck/Build 1회, 문서 영향 범위·Git diff 점검.
|
||||
- REUSED PASS: 미변경 T01 source fingerprint와 기존 dist·공개 Theme/Component/Pattern/Story source 보존 근거. 중간 실패 보정 시 유효한 CSS80건 재사용. 이전 frozen f78cc206 공통80/80은 당시 결과로만 인용하며 현재 HEAD 전체 인증으로 확대하지 않음.
|
||||
- NOT VERIFIED: 사용자 CSS intent, 실행하지 않은 Theme/상태/외부 입력, 전체 Story별 Runtime, 실제 스크린리더·touch·backend·CSS 전 문법/cycle.
|
||||
- SKIPPED — 중복 검사: 전체 292 Story 렌더, 전체 Component 테스트, 기존 정상 화면 재생성, 별도 의존성 설치, 이미 성공한 prebuild package/Theme 재실행.
|
||||
|
||||
Git diff에서 `src/`, `packages/`, `themes/`, `.storybook/` 변경 0. Foundation·Typography·Spacing·Radius·Button/Tabs/Table·Green LNB 8%·목차 LNB 8%·D-01/D-02·퍼블리셔 확정 요구·공개 API/Theme Token/Designer 기능과 Theme 적용·전환 구현은 미변경이다. 실험 경로는 읽기 전용으로 사용했으며 T01 기존 guard/runtime/combined 3개 원본 SHA-256은 작업 전후 같다. 신규 로컬 실패도 revision1 및 별도 로그로 보존한다. `preservation.json`이 근거다.
|
||||
|
||||
## 오탐·미탐과 잔여 검토
|
||||
|
||||
FALSE_POSITIVE: 이번 정상 fixture 회귀 범위에서 발견되지 않음. 일반 HTML/layout·documented Token override·Storybook을 일괄 FAIL로 바꾸지 않았다. 임의 CSS 전체 무오탐 인증은 아니다.
|
||||
|
||||
FALSE_NEGATIVE: 이번 위반 fixture 범위에서 발견되지 않음. 기존 CSS entry/Navigation/Token/공개 API FAIL 보존. 유한/미확정 분기의 명확한 하드코드와 Runtime fallback 미정의 참조를 추가 탐지한다.
|
||||
|
||||
REMAINING_LIMITATIONS: named color·일반 utility class·%, calc와 외부 CSS/selector cascade·변수 cycle·opaque wrapper/객체 style·모든 Theme/상태/외부 입력은 전수 인증하지 않는다. Token 선언 PASS는 실제 적용을 뜻하지 않는다. Runtime 자료는 제출 증거이며 독립 실행 인증이 아니다. 사용자 CSS 승인 기능과 Theme 편집 기능은 만들지 않았다. Theme 기능 자체의 결함/개선 필요성은 이번 검사에서 확정하지 않았으며 추가로 발견되면 별도 이슈로 검토한다.
|
||||
|
||||
## 외부 호출과 Git 정책
|
||||
|
||||
APPROVED_SESSIONS: 12 / USED_SESSIONS: 10 / REMAINING_SESSIONS: 2 — 사용자 제공 기존 실험 장부 유지. 이번 유지보수의 외부 AI 생성 세션·신규 모델·Claude·하위 에이전트·신규 화면 실험 호출 0. 현재 대화 자체를 외부 실험 장부에 추가하지 않았다.
|
||||
|
||||
GitHub origin은 `https://github.com/shkim25027/HMDesignSystemTest.git` 그대로다. 시작 main/local/remote SHA는 모두 BASE_SHA와 같고 기존 미커밋 작업은 없었다. 관련 Guard/테스트/MD만 stage·diff 검토 후 일반 main commit/push하며 결과는 최종 로컬 보고서에 기록한다. force/reset/clean/이력 삭제/연결 변경/ZIP 배포 없음.
|
||||
|
||||
공식 Gitea: NOT ACCESSED / NOT MODIFIED. 월요일 이전·GitHub 연결 해제는 별도 작업으로 유지한다.
|
||||
@@ -0,0 +1,78 @@
|
||||
# HMDesign Gitea 이전 전 최종 정합성 확인
|
||||
|
||||
RESULT: **PARTIAL**. 최근 구현·문서·Story·Guard의 정합성을 확인하고 현재 기준과 충돌하는 문서 설명을 최소 수정했다. 최종 타입 검사와 앱 build, 실행기 모의검사, 소스 무결성 확인은 PASS다. 기존 T03 생성·CSS 디자인 의도·개발 의존성 위험·실제 SR/터치와 공식 사내 환경의 미검증은 그대로 남긴다. 디자인 변경 없이 소스 이전 준비를 마쳤으며 공식 Gitea 이전은 2026-10-12 별도 작업이다.
|
||||
|
||||
TARGET: `D:/디자인시스템/hmdesign`. 범위는 기존 React Component/Pattern/Storybook/AI 계약의 정합성 확인이며 신규 업무 화면 구현은 없다. 시작 Local HEAD와 GitHub main은 모두 `4fe549da01683c363b0715aedeb82a089717f685`, branch main, working tree CLEAN이었다. 최종 문서 commit SHA와 원격 일치는 종료 보고 및 로컬 `_local/finalization-20261011/release-manifest.json`에 기록한다. 이전 보고서의 SHA를 최신으로 가정하지 않았다.
|
||||
|
||||
## T03 실행기 원인과 보완
|
||||
|
||||
원본 근거는 독립 실험 `codex-only-20261010-203444/t03-resume-20261011-001217/FINAL_REPORT.md`, Medium item_3, High item_2 및 medium-stop-diagnosis.json이다. 원 생성 기준은 frozen `f78cc206a5a9af6b61c42cfb989ed26fbe9da948`이며 최신 HMDesign HEAD와 혼용하지 않는다.
|
||||
|
||||
| 대상 | 원인과 판정 | 이번 처리 |
|
||||
|---|---|---|
|
||||
| Medium T03 | Get-Content·Story 목록·브라우저 도구 검색 복합 명령. 실제 분리 결과 0/0/1, 마지막 stdout/stderr 빈 값. 기존 실행기의 좁은 예외 문법이 PROJECT_COMMAND_FAILURE로 중단 | 명령별 구조화 exit/stdout/stderr를 확인하는 V3 후보. 원문과 모든 step의 대응·출력/종료 일치 필수. 근거 없는 복합 exit1은 계속 STOP |
|
||||
| High T03 | 사본에 `.storybook`이 없는데 검색 root에 포함. 후속 명령으로 wrapper exit0이어도 실제 rg 읽기 오류 발생 | 실제 경로 목록 기반 preflight. 대표 Story 소스·필수 문서/패키지/bootstrap은 필수, Storybook 실행을 요청하지 않은 `.storybook` 설정은 선택. 실제 읽기 오류는 계속 STOP |
|
||||
|
||||
로컬 21/21 검사에서 실제 Medium 명령을 읽기 전용으로 재생해 0/0/1을 확인했다. High 원본 이벤트는 `ACTUAL_RG_READ_ERROR_EVEN_IF_WRAPPER_EXIT_ZERO`로 유지한다. 앞선 실패·stderr·exit2·누락/변조된 step·wrapper 불일치·파이프/치환/실행 옵션·중복 이벤트·실패 후 정지를 확인했다. 기존 22/22와 16/16 proof는 원래 controller SHA `70b35c127b14c2f97fd9df330783dd15b86f363f5238f743813995a3f27047f7` 및 proof 해시가 같은 범위에서 REUSED PASS다.
|
||||
|
||||
수정 후보와 읽기 결과 수집기·preflight·테스트/proof는 독립 실험 `finalization-20261011/runner/`에 별도로 저장했다. active controller/launcher·과거 proof·승인·STOP·장부는 덮어쓰지 않았다. 실제 모델 launcher에 V3를 연결해 실행한 결과는 NOT VERIFIED다. 향후에는 별도 승인과 새 proof/입력/참조 manifest로 실행하거나, 구조화 결과가 없는 CLI에서는 읽기·각 검색을 별도 호출한다. 기존 승인 12/12 사용·잔여 0, NEW_MODEL_CALLS 0, T03_GENERATION/QUALITY NOT VERIFIED를 보존한다.
|
||||
|
||||
## 문서와 구현 정합성
|
||||
|
||||
| 연결 | 실제 확인과 결과 |
|
||||
|---|---|
|
||||
| AGENTS → AI 계약 → Reference | 규칙 우선순위·공개 API·Pattern 우선·Label·Navigation·Runtime/스타일 판정 일치. AGENTS 자체 수정 없음. 독립 사본의 필수/선택 참조와 검색 결과 계약 보완 |
|
||||
| Component MD ↔ 구현 ↔ Story | 최근 Combobox dialog popup, GNBUser/LNBProfile 이름+description과 명시 label 우선권이 일치. Label/Badge 및 관련 공개 API 예제도 누락 없음. 정상 Props/Variant/Size/State/API 수정 없음 |
|
||||
| Pattern MD ↔ 구현 ↔ Story | FilterBar `layout` 3종·draft/applied·부모 초기화·보호 상태·focus, DataTable ID 줄바꿈 예제, PageHeader/Tabs, Form composition, GNB/LNB 모바일, Dashboard 48px/960px 계약 확인 |
|
||||
| Theme/Token | 실제 공개 CSS 선언 1,170개, source exports Component 222/Pattern 63, runtime exports UI 255/Theme 8/CENTER 25/Reference 10. JSON key와 CSS 선언 수를 혼용하지 않음 |
|
||||
| Guard ↔ 가이드 | FULL_SCREEN/PARTIAL scope와 STORYBOOK profile, result의 Production 제한, CSS Intent·유한 동적 후보·외부 host 변수·위치별 Runtime 증거·원본 보존 계약을 구현과 대조 |
|
||||
| README | 현재 실행 scripts/Node 조건/6024·workspace build·React bootstrap 확인. 최신 Guard/접근성/최종 준비 문서 연결 |
|
||||
| 문서 링크 | 최종 수정·신규 문서와 직접 참조 문서의 내부 경로/heading을 선택 검사. 당시 과거 보고서는 편집하지 않음 |
|
||||
|
||||
확인된 수정은 다음과 같다. 실제 정상 구현을 오래된 문서에 맞추지 않았다.
|
||||
|
||||
- Reference의 “현재 최신 포터블 ZIP” 안내를 현재 Git checkout 기준으로 정정하고 ZIP은 과거 스냅샷으로 구분.
|
||||
- Guard의 과거 46/63/11개를 현재 수처럼 안내한 문장을 당시 기록으로 명시. 현재 75/20/5로 구분.
|
||||
- Guard 앞부분의 계산된 Token 일괄 미검증·non-HM 변수 검사 제외 설명을 실제 유한 후보/외부 host 변수 검사와 일치시킴.
|
||||
- STORYBOOK은 profile이라는 CLI 계약, 독립 실험의 선택 `.storybook`과 명령별 결과 확인을 보강.
|
||||
- README의 최신 검증 근거 연결과 10월 12일 이전 준비·595개 전체 소스 목록 작성.
|
||||
|
||||
## 기존 구현 보존
|
||||
|
||||
이번 diff의 `packages/`, `src/`, `.storybook/`, `themes/`, `scripts/`, package/lock, AGENTS 변경은 0이다. 원본 추적 파일 592개 해시에서 기존 문서 4개만 수정했다. 실행기 수정은 독립 실험의 새 폴더에만 저장했다.
|
||||
|
||||
D-01/D-02 Tabs/대표 Fill·PageHeader 조합은 기존 퍼블리셔 기준과 동일하다. `padding: 24px 0`, Primary White alpha 0.8, Secondary/Legacy 보존. 퍼블리셔 Button/Table/Progress/Accordion/Sheet/Drawer/Navigation·Foundation·React C2~R3는 관련 구현/API·CSS의 변경 영향을 비교해 이전 PASS를 재사용한다. Sheet 최종 radius·색 의미 등 미확정 값은 확정하지 않았다.
|
||||
|
||||
Green LNB 2Depth와 오른쪽 LNB 예제는 기존 `lnb.css`의 Black 8%를 소비한다. Storybook 왼쪽 목차는 `manager.css`의 별도 rgba alpha .08이다. 선택 깊이의 Black 20%는 그룹 배경과 별개다. 이 mapping과 선택/Hover/Focus 소스는 미변경이다. 기존 292개 Story ID는 inventory와 최종 static index가 일치한다.
|
||||
|
||||
## 선택 회귀와 재사용
|
||||
|
||||
| 검사 | 판정과 유효 범위 |
|
||||
|---|---|
|
||||
| TYPECHECK | EXECUTED PASS, root/UI/CENTER. Theme default 확인·workspace build hook 포함 |
|
||||
| BUILD | EXECUTED PASS, 최종 root build. 이미 성공한 hook는 `--ignore-scripts`로 중복 생략. 500kB chunk 경고 유지 |
|
||||
| 실행기 | EXECUTED 21/21 PASS, 모델 호출 없음. 기존 22+16은 원래 V2 해시 범위에서 REUSED PASS |
|
||||
| CSS_IMPORTS/EXPORTS | EXECUTED PASS, 추적 CSS import 73개·export artifact 16개 누락 0. 관련 8개 MD 공개 import 심볼 누락 0 |
|
||||
| Guard100 | REUSED PASS, 8817135 이후 Guard/회귀 소스·package/lock 미변경 및 기존 final 로그 100/100 확인. 최신 선택 Story Guard source/contract 해시 일치 |
|
||||
| Component | REUSED PASS, 기존 C2~R3 및 FilterBar 검증의 소스/영향 대조. 최신 Combobox 1개·최종 GNB/LNB 2개 렌더 회귀를 각각 재사용 |
|
||||
| 관련 Story/반응형 | REUSED PASS, 최신 static 선택 6/6·pageerror 0, Combobox 390/768/1280/1440, 사용자 메뉴와 모바일 navigation 명명된 기존 검사. 미변경 대표/Theme 범위만 이전 결과 재사용 |
|
||||
| Storybook build | REUSED PASS, 최신 접근성 최종 build·source/환경 동일. index 292개 ID 일치. 전체 292 Runtime을 새로 수행한 것으로 집계하지 않음 |
|
||||
| Theme | REUSED PASS, JSON/Runtime/Designer·미변경 CSS의 기존 119/96·키보드 138/58 근거. 새 Theme/상태 전수 인증 없음 |
|
||||
| 공통80 | REUSED PASS **역사적 frozen f78cc206 한정**. 원 log/exit 및 baseline 기록 유지. 최신 HEAD 전체 검증으로 확대하지 않음 |
|
||||
| 기존 AI 화면 | 앱 source 및 당시 Guard/Runtime 연결이 같은 범위만 재사용. 옛 T01 contract는 최신 4fe와 달라 최신 결합 PASS로 승격하지 않음. T06 원본 FAIL과 수정 복제본 PASS 구분 |
|
||||
|
||||
기존 최종 선택 Story Guard는 원본 status/staticStatus **NOT VERIFIED**, FAIL 0이다. CSS styleEvidence는 STATIC PASS / RUNTIME NOT VERIFIED / DESIGN_INTENT NOT VERIFIED / FINAL NOT VERIFIED, styleVerification은 생성하지 않았다. 브라우저 동작 PASS를 스타일 승인으로 연결하지 않는다. T01 당시 112개 CSS 측정 PASS도 해당 source/옛 contract의 역사적 결과이며 사용자 디자인 의도는 계속 NOT VERIFIED다.
|
||||
|
||||
SKIPPED_DUPLICATES: 전체 292 Story Runtime, 정상 Component/Theme/Guard suite 재실행, 외부 모델·화면 재생성, 동일 반응형 재촬영, npm 재설치/audit, 정상 package hook 중복. 현재 수정이 문서와 독립 실행기 후보라 새 시각 영향을 만들지 않았다.
|
||||
|
||||
## 보안과 소스 이전 한계
|
||||
|
||||
과거 감사는 개발 High 7·Critical 0, 운영 0이다. package/lock은 감사 기준 이후 같다. shadcn → registry/ts-morph/common/fast-glob → micromatch → braces 전파를 유지하며 안전한 patch 미확인이다. 새로운 audit/레지스트리 조회/업데이트는 실행하지 않았다. STORYBOOK의 비신뢰 glob/config 제한을 유지한다. 운영 0은 과거 감사 기준이며 현재 인터넷 advisory의 갱신 부재를 인증하지 않는다.
|
||||
|
||||
추적 파일명/고신뢰 secret 패턴에서 개인 환경·key·생성 dist·실험/임시파일 후보는 발견되지 않았다. 비밀정보 부재의 전수 인증은 아니다. 제품 manifest의 로컬 절대경로 의존성은 없다. `audit-quality-contracts.mjs`의 역사 비교 BASE와 외부 증거 절대경로 2개는 이관 후 그대로 실행 가능한 필수 검증 도구가 아니며 준비 문서에 제외/대체 조건을 명시했다.
|
||||
|
||||
남은 상태는 T03 생성/품질, CSS 사용자 의도·미실행 동적 분기, 확정색 접근성 대비 FAIL/DEFERRED, 실제 SR·실기기 touch/drag·확대·모든 Theme/브라우저, 공식 Gitea 전용 파일/분기·회사 실행 환경 NOT VERIFIED다. 현재 발견은 디자인/정상 API를 변경할 근거로 확대하지 않는다.
|
||||
|
||||
[이전 준비 문서](../guidelines/gitea-source-transfer-preparation-2026-10-11.md)는 공식 기존 이력을 보존한 추적 소스 비교·반영, 공식 전용 파일 보존, 설치/검증 명령, 이후 GitHub remote의 정확한 URL을 확인한 해제 순서를 제공한다. GitHub 일반 main push 결과는 작업 종료 보고에 기록한다. 공식 Gitea ACCESS/CLONE/COMMIT/PUSH/연결 전환, force/reset/clean/이력 삭제, GitHub 연결 해제, ZIP 배포 모두 NOT EXECUTED다.
|
||||
|
||||
로컬 상세 근거는 `_local/finalization-20261011/`의 baseline/evidence-inspection/integrity/preservation/reuse-ledger/doc-links/release-manifest/FINAL_REPORT와 로그에 보관한다. 이 문서는 최종 commit의 자기 SHA를 포함하지 않으며 로컬 최종 보고와 실제 HEAD 조회로 연결한다.
|
||||
@@ -0,0 +1,56 @@
|
||||
# 퍼블리셔·접근성·Guard 선택 개선 — 2026-10-10
|
||||
|
||||
RESULT: 요청한 수정과 선택 검증 PASS. 교차 모델 미완료 실험, 전체 접근성 인증은 NOT VERIFIED. 기준 HEAD는 `f78cc206a5a9af6b61c42cfb989ed26fbe9da948`. 기존 READ-ONLY 보고서·검증 JSON은 수정 전에 별도로 보존하고 변경 후 SHA256 일치를 확인했다.
|
||||
|
||||
## 실제 수정
|
||||
|
||||
| 파일 | 변경 |
|
||||
|---|---|
|
||||
| `.storybook/manager.css` | 기존 펼침 그룹 selector의 배경만 검정 20% → 8%. 선택 면의 20% inset, hover/focus·메뉴 JS·공통 Token 보존 |
|
||||
| `packages/ui/src/theme/lnb.css`, `docs/patterns/lnb.md` | 오른쪽 Green LNB의 기존 8% 유지. 오래된 20% 주석 수정, Manager/Component 적용 범위 설명 |
|
||||
| `packages/ui/src/theme/combobox.css`, `date-picker.css` | 흰 Trigger의 빈 값 안내를 기존 보조 텍스트 Semantic에 연결. 기본 #999/흰색 2.85:1 → #6e6759/흰색 5.60:1. 공통 Theme·Token 값, 선택값·아이콘·disabled opacity 보존 |
|
||||
| `docs/components/combobox.md`, `date-picker.md` | 현재 mapping 설명. 과거 실측 기록은 당시 기록으로 보존 |
|
||||
| `scripts/guard-requirements.mjs`, `guard-requirements.test.mjs` | 명시한 액션 이름 허용 목록을 검사하는 별도 도구와 5개 회귀 테스트. 미요청 정적 CSV/다운로드 액션 FAIL; 동적 이름/불완전 정책/오래된 fingerprint는 NOT VERIFIED |
|
||||
| `docs/guidelines/ai-generation-guard.md`, `navigation-single-mode.md` | 보조 검사 사용법·한계, T04 정상 혼합 거부 응답과 별도 평가 기준 |
|
||||
|
||||
원본 Guard status/issues 및 기존 회귀 테스트 본문은 변경하지 않았다. 정책 예외·새 공통 Token·Story ID·업무 화면 생성은 추가하지 않았다.
|
||||
|
||||
## 실제 실행한 검사
|
||||
|
||||
- 변경 전/후 실제 Storybook: 왼쪽 펼침 그룹 rgba(0,0,0,0.08), 오른쪽 Green LNB color(srgb 0 0 0 / 0.08), opacity 1. CSSOM에서 그룹 selector의 적용 규칙·priority 확인. 펼침 면의 20% 잔여 적용 없음. 선택 inset의 20%는 요청 범위 밖의 기존 효과다.
|
||||
- 선택·hover·focus computed style 변경 전/후 일치. 선택/펼침/접힘, 검색 결과 및 tag filter 열기 통과. 변경 전/후와 최종 빌드 화면 PNG 직접 확인.
|
||||
- 최종 Storybook Combobox/DatePicker 각각 390/768/1280/1440: 안내 문구 대비 5.60395679:1, 가로 overflow·중복 ID 없음, Enter로 popup 열기·Escape 닫기·trigger focus 복귀 통과. 선택값/disabled opacity/배경/아이콘은 변경 전후 일치.
|
||||
- 신규 요구사항 검사 5/5 PASS. Theme 연결에 영향받는 기존 Guard 테스트 8/8 PASS(55개는 선택 실행에서 skip). 기존 전체 80개를 다시 실행한 결과로 표현하지 않는다.
|
||||
- 최종 통합 상태 UI package build(선언 Typecheck 포함), root Vite build, Storybook build 각 1회 PASS. root의 기존 chunk size 경고는 잔여 경고다. Story ID 292 → 292, 추가/삭제 0.
|
||||
- Git diff whitespace 검사, 공통 Guard/검사 소스·package-lock hash 일치 및 보존 자료 hash 일치 확인.
|
||||
|
||||
## 재사용한 검사
|
||||
|
||||
기존 별도 교차 모델 실험의 `logs/baseline-regression.log`는 동일 기준 SHA에서 Guard63/Evidence5/Component9/Theme3 총 80/80 PASS다. 검증 ledger·검사 소스·의존성 hash를 확인해 변경과 관계없는 범위의 회귀 증거로 재사용했다. CSS mapping 변경 영역은 새 브라우저 검사와 선택 Guard 8개로 보완했다. 최종 소스 전체에 80개를 다시 실행했다고 보고하지 않는다.
|
||||
|
||||
READ-ONLY 단계의 root/UI/CENTER/publisher Typecheck, 기능 C2~C5/PT1~PT2/R1~R3, 나머지 퍼블리셔 대표 Story·운영 화면 검증은 변경된 메뉴·안내 문구와 관계없는 범위에서 재사용했다. TSX/API/tsconfig·의존성은 변경하지 않았다. UI 선언 검사는 최종 package build에서 수행했다. 전체 Typecheck·모든 앱/292개 Story Runtime은 반복하지 않았다.
|
||||
|
||||
## 교차 모델 작업표 복원
|
||||
|
||||
원본 `D:\디자인시스템\HMDesign-AI-CrossModel-Test`의 requirements·reports·evaluation·모델별 산출물을 읽어 다음 매핑을 복원했다. requirements frozen hash와 성공 화면 4개의 source/contract fingerprint는 각 원본 실험 사본에서 일치한다.
|
||||
|
||||
| 모델/요청 effort | 테스트 | Typecheck/Build/4폭 Runtime | 원본 Guard 연결 |
|
||||
|---|---|---|---|
|
||||
| claude-sonnet-5 medium | T01 | PASS | NOT VERIFIED(CSS intent) |
|
||||
| claude-sonnet-5 medium | T03 | PASS | PASS |
|
||||
| claude-sonnet-5 high | T01 | PASS | NOT VERIFIED(CSS intent) |
|
||||
| claude-sonnet-5 high | T02 | PASS | PASS |
|
||||
|
||||
high T01은 실제 평가 가능한 산출물이 있으나 원래 세션의 정상 완료로 세지 않는다. 이 4개를 다시 생성하지 않았다. 원본 실험 사본의 유효한 증거를 현재 수정된 HM 계약 전체의 인증으로 일반화하지 않는다. 기존 점수·원본 판정을 덮어쓰지 않았다.
|
||||
|
||||
나머지 20개 조합(운영 화면 16개 + 정책 T04 4개)은 NOT VERIFIED 작업표로 별도 보존했다. 모든 T05/T06, GPT 두 effort의 모든 항목, Claude medium T02/high T03 및 T04가 포함된다. T04는 생성 성공률·평균 디자인 점수에서 제외한다. 기존 24개 세션 한도는 소진됐으며 이번 추가 외부 모델 세션은 0개다. 새 승인 전 실행하지 않는다.
|
||||
|
||||
## 미검증·한계
|
||||
|
||||
전체 WCAG/스크린리더 발화/실기기 touch/전체 Theme·상태의 대비, 전체 292 Story Runtime은 NOT VERIFIED. 현재 대비 PASS는 기본 Theme의 활성 빈 값 Trigger에 한정한다. Input 등 공통 placeholder Token은 변경하지 않았으며 전체 placeholder 대비를 해결했다고 주장하지 않는다.
|
||||
|
||||
요구사항 도구는 명시적 정책과 static literal Button/button/link 이름만 검사한다. wrapper/namespace/동적 액션/API 호출의 의미와 자유 형식 요구사항은 별도 검토가 필요하다. 보조 PASS는 원본 Guard의 CSS intent·Runtime 미검증을 제거하지 않는다. 실험 환경·모델 품질·전체 디자인 점수 개선을 추정하지 않는다.
|
||||
|
||||
원본 READ-ONLY 보고서와 이번 PNG/JSON/log/교차 모델 작업표는 Codex 작업의 `publisher-readonly-audit/minimal-lnb-fix`에 보존한다. 공식 Gitea 접근·수정 없음. GitHub 일반 push의 최종 commit/remote SHA는 제출 응답과 별도 로컬 결과에 기록한다.
|
||||
|
||||
Started At: 2026-10-10 19:37:37 KST. Estimated Duration: 60–90분. 완료 시각·실제 시간·Variance는 최종 제출 응답에 기록한다.
|
||||
Reference in new issue
Block a user