Files
Pier_v1/RAG/design system_v0.1.1/webapp/module.webapp.md
T
ahnyongjooandClaude Sonnet 5.5 964a841de1 chore(rebar): Pier_T_rebar 작업 폴더 초기 구성 및 외부 의존 파일 통합
- Code\rebar_pipeline, review_pipeline, pier-program을 정션에서 실제 폴더로 전환
- Code\rhino_mcp 및 CLAUDE_rhino배경.md 추가, .mcp.json은 PYTHONPATH로 새 위치 사용
- pier-program 내부 .git 제거(이력은 backup\pier-program_20261028.bundle에 보관)
- worktree 가이드 반영(CLAUDE.local.md, HANDOFF.md)
- D:\Rhino-MCP 경로 참조를 새 위치로 치환

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-28 11:20:18 +09:00

287 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Prism — M3 웹앱 실행 명세 (Layer 3)
| 버전 | 수정일 | 수정자 | 주요 변경 내용 | 비고 |
| :--- | :--- | :--- | :--- | :--- |
| v0.1.0 | 2026-07-29 | HMCM | 신규 제정 — 웹앱(HTML·대시보드·폼·문서 사이트) 실행 명세. CSS 변수 정본 내보내기 수록, 구조 검증 12항 통과 | `active` 등록 (modules §4.4) |
| 메타 | 값 |
| :--- | :--- |
| 모듈 | **M3 `webapp`** — 웹앱 |
| 계층 | Layer 3 (실행 명세 · **자기완결형**) |
| 대상 산출물 | HTML/CSS/JS 웹앱 — 대시보드·관리도구·폼·문서 사이트·웹 보고서 |
| 상위 의존 | `Design.md` 0.1.1 · foundations 0.1.2 · medium.screen 0.1.1 · components 0.1.1 · tokens.json 0.1.1 |
| 접근성 목표 | **WCAG 2.2 AA** (CI 게이트: axe·pa11y·stylelint) |
```yaml
module:
id: webapp
name: 웹앱
version: 0.1.0
status: active
brand: saman
medium: screen
medium_variant: screen.web
dual_medium: false
format: responsive # 브레이크포인트 5단계
columns: 12 # lg·xl 기준 (BP별 §2)
type_set: compact
component_count: 20
variant_count: 35
patterns: [w1-shell, w2-dashboard, w3-form, w4-document, w5-list-detail]
depends_on: { foundations: 0.1.2, medium.screen: 0.1.1, components: 0.1.1 }
```
---
## 1. 적용 조건
| 적용 | 제외 |
| :--- | :--- |
| 웹앱·대시보드·관리도구·폼 | 모바일·태블릿 네이티브 앱 → M4 (`mobile/`) |
| 문서·가이드 사이트, 웹 보고서 | 발표 슬라이드 → M2 (`ppt/`) |
| 화면 열람용 HTML 산출물 | 인쇄 배포물 → M5 (`A3/`) — 인쇄 스타일시트는 §9 참조 |
---
## 2. 브레이크포인트·그리드 (정본 값)
| BP | 범위 (px) | 컬럼 | 마진 | 거터 | 기준 컬럼 폭 | 정합 |
| :--- | :--- | :-: | ---: | ---: | ---: | :--- |
| `xs` | 0–599 | 4 | 16 | 16 | 70 | 4×70+3×16=328 ✓ |
| `sm` | 600–903 | 8 | 24 | 16 | 55 | 8×55+7×16=552 ✓ |
| `md` | 904–1239 | 8 | 32 | 24 | 84 | 8×84+7×24=840 ✓ |
| `lg` | 1240–1599 | 12 | 32 | 24 | 76 | 12×76+11×24=1176 ✓ |
| `xl` | 1600– | 12 | 24 | 24 | 94 (**컨테이너 1440 고정**) | 12×94+11×24=1392 ✓ |
| ID | 규칙 |
| :--- | :--- |
| **WA-1** | 미디어 쿼리는 min-width(mobile-first)·px 단위. 임의 브레이크포인트 금지 (BP-1·BP-3) |
| **WA-2** | `xl` 컨테이너 1440px 고정 — 무한 확장은 measure를 파괴한다 (BP-2) |
| **WA-3** | **연속 본문 `max-width: 38em` 강제** (MS-1). 컨테이너 폭 ≠ 본문 폭. md 6col=624px(39.0em)·lg 8col=776px(48.5em)·xl 8col=920px(57.5em) 전부 38em 초과 — 본문 블록에는 반드시 max-width 적용 |
| **WA-4** | 최상위 레이아웃 영역만 그리드 정렬. 내부는 스페이싱 토큰 (GD-1~3) |
---
## 3. CSS 변수 정본 (`:root` — 이 블록이 곧 토큰 정의부다)
> 산출물 CSS에는 아래 변수만 사용한다. **변수 정의부 외 HEX·px 리터럴 0건**이 빌드 게이트다 (W1·W2).
```css
:root {
/* ── color (light) ─────────────────────────────── */
--prism-bg-canvas: #F4F3F0; /* sand G4 — 순백 전면 금지 */
--prism-bg-card: #FFFFFF; /* white G0 */
--prism-text-body: #474235; /* brown G72 — on sand 9.02 AAA */
--prism-text-heading: #1F524B; /* green G69 — on sand 8.00 AAA */
--prism-text-subtle: #474235; /* 저강조는 색이 아니라 크기·웨이트로 */
--prism-text-accent: #D05C26; /* orange G47 — 대형 전용(24px+/19px+Bold) */
--prism-border-default: #474235;
--prism-border-strong: #1F524B;
--prism-status-do: #005A4E; --prism-status-do-bg: #DCEAE6;
--prism-status-dont: #8F2A11; --prism-status-dont-bg: #F6DFDA;
--prism-status-caution: #6B4A00; --prism-status-caution-bg: #F5E7CC;
--prism-status-tip: #0A4E86; --prism-status-tip-bg: #DDE8F3;
--prism-dv-1: #C08A2E; --prism-dv-2: #6E8F3C; --prism-dv-3: #3C6E9F;
--prism-dv-4: #8C3B14; --prism-dv-5: #1B4A43; --prism-dv-6: #5E4370;
/* ── space (base 8px = 0.5rem) ──────────────────── */
--prism-space-025: 0.125rem; /* 2px */
--prism-space-050: 0.25rem; /* 4px */
--prism-space-100: 0.5rem; /* 8px */
--prism-space-150: 0.75rem; /* 12px */
--prism-space-200: 1rem; /* 16px — card padding */
--prism-space-300: 1.5rem; /* 24px — block gap */
--prism-space-400: 2rem; /* 32px — zone gap */
--prism-space-600: 3rem; /* 48px */
--prism-space-800: 4rem; /* 64px */
/* ── type (root 16px 미고정 — html font-size 선언 금지) ── */
--prism-type-caption: 0.8125rem; --prism-lh-caption: 1.55;
--prism-type-body-sm: 0.875rem; --prism-lh-body: 1.70;
--prism-type-body: 1rem;
--prism-type-body-lg: 1.125rem;
--prism-type-title-sm: 1.25rem; --prism-lh-title: 1.50;
--prism-type-title: 1.625rem;
--prism-type-title-lg: 2rem;
--prism-type-display: 2.875rem; --prism-lh-display: 1.25;
--prism-type-display-lg: 4.125rem;
/* ── radius · stroke · z · motion ───────────────── */
--prism-radius-sm: 4px; --prism-radius-md: 8px; --prism-radius-lg: 12px;
--prism-radius-pill: 9999px;
--prism-stroke-hairline: 1px; --prism-stroke-regular: 2px; --prism-stroke-bold: 3px;
--prism-z-raised: 100; --prism-z-sticky: 200; --prism-z-dropdown: 300;
--prism-z-scrim: 400; --prism-z-modal: 500; --prism-z-popover: 600;
--prism-z-toast: 700; --prism-z-tooltip: 800;
--prism-scrim: rgba(0, 0, 0, 0.32);
--prism-motion-fast: 100ms; --prism-motion-moderate: 200ms; --prism-motion-slow: 300ms;
--prism-ease-standard: cubic-bezier(0.2, 0, 0, 1);
--prism-ease-enter: cubic-bezier(0, 0, 0, 1);
--prism-ease-exit: cubic-bezier(0.3, 0, 1, 1);
--prism-focus-ring: 3px; --prism-focus-offset: 2px;
--prism-measure-max: 38em;
}
/* ── dark theme (data-theme + OS 연동) ─────────────── */
:root[data-theme="dark"] {
--prism-bg-canvas: #111111; /* obsidian G95 */
--prism-bg-card: #111111; /* 카드는 보더로 분리 */
--prism-text-body: #F4F3F0; /* sand on obsidian 17.02 AAA */
--prism-text-heading: #F4F3F0; /* ⚠ green 텍스트 금지 (2.13:1) — 면·도형만 */
--prism-text-subtle: #D3D3D3; /* subtle 12.61 AAA */
--prism-text-accent: #D05C26; /* 4.71 AA — 대형 권장 */
--prism-border-default: #D3D3D3;
--prism-border-strong: #F4F3F0;
/* 상태색 다크: container↔on 반전 (tokens v0.1.1, 실측 동일) */
--prism-status-do: #DCEAE6; --prism-status-do-bg: #005A4E;
--prism-status-dont: #F6DFDA; --prism-status-dont-bg: #8F2A11;
--prism-status-caution: #F5E7CC; --prism-status-caution-bg: #6B4A00;
--prism-status-tip: #DDE8F3; --prism-status-tip-bg: #0A4E86;
}
@media (prefers-color-scheme: dark) {
:root:not([data-theme="light"]) { /* 위 dark 값셋 동일 적용 */ }
}
```
| ID | 규칙 |
| :--- | :--- |
| **CSS-1** | `html { font-size: <px> }` 선언 금지 (UN-2) — 사용자 브라우저 설정 존중 |
| **CSS-2** | 타입·간격은 rem, 보더·헤어라인은 px (UN-1·UN-3) |
| **CSS-3** | 다크 테마는 `data-theme` 속성 + `prefers-color-scheme` 연동, 사용자 재정의 3택(light/dark/system) 영속 저장 (TC-1~TC-4) |
| **CSS-4** | 다크에서 `--prism-text-heading`에 green을 재정의하지 않는다 — **실측 2.13:1 판독 불가** (TM-S3) |
| **CSS-5** | 텍스트 색에 알파 금지. 알파는 스크림·오버레이·상태 레이어만 (AL-1·AL-2) |
---
## 4. 인터랙션·접근성 핵심 (요약 정본)
| 항목 | 값 · 규칙 |
| :--- | :--- |
| 상태 표현 | **GRADE 시프트**: hover ±4 · active ±8 · selected ±12 (라이트 +, 다크 −). focus는 색 변화 없이 **링만** |
| disabled | 불투명도 금지 — 저강조 토큰 사용, 형태 판별 가능 유지. 가능하면 활성 + 오류 메시지 우선 (DS-1~4) |
| 포커스 링 | **3px 이중 링 + 오프셋 2px**, `:focus-visible`, `outline: none` 대체 없는 선언 금지 (FC-1·FC-2) |
| 히트 영역 | **최소 44×44px** (권장 48), 인접 간격 ≥ 8px, `pointer: coarse`에서 48px (HT-1~3·PT-1) |
| hover | 보강 수단일 뿐 — hover 없이 기능 완전, `@media (hover: hover)` 격리 (HV-3·HV-4) |
| 대비 | 본문 ≥ 4.5:1 (AA) 필수 — 등록 페어는 전부 AAA로 여유 충족. 비텍스트 ≥ 3:1 |
| 모션 | `transform`·`opacity`만 애니메이션, `prefers-reduced-motion` 필수 구현 (MT-3·RM-1) |
| 시맨틱 | 네이티브 요소 우선, 헤딩 레벨 건너뜀 금지, 아이콘 버튼 접근 가능한 이름 (SM-1~5) |
| Elevation | **보더 우선**, 그림자는 보조 (`raised` 0 1px 2px / `overlay` 0 4px 12px / `modal` 0 8px 24px + 스크림 32%). 다크에서는 표면 톤 상향으로 대체 |
---
## 5. 화면 패턴 (5종)
| ID | 구조 | 구성 | 적용 |
| :--- | :--- | :--- | :--- |
| **W1 앱 셸** | sticky header + 콘텐츠 | header(메타 4슬롯: 화면ID·권한·갱신시각·환경) + main. lg 이상에서 좌측 내비 레일(`4:8`의 4col 또는 고정 240~280px) | 전 화면 공통 골격 |
| **W2 대시보드** | 카드 그리드 | stat·chartframe·table 카드 배치. xs 1열 → sm·md 2열 → lg·xl 3~4열. 존당 stat ≤ 3 | 현황·지표 |
| **W3 폼** | 1열 수직 | input 수직 나열 (**다열 폼 금지**), max-width 38em, 레이블 상단, primary 버튼 1개 | 입력·설정 |
| **W4 문서** | 목차 + 본문 | md 이상 `4:8`(toc 레일 + 본문 38em), 미만 단일 흐름 + 상단 앵커 toc. 아코디언은 1순위 아님 (AD-1) | 가이드·규정 열람 |
| **W5 목록-상세** | 분할 뷰 | lg 이상 `4:8`(목록+상세), 미만 스택 내비게이션. 행 hover는 보강만 | 데이터 관리 |
공통: 결론·핵심 지표는 viewport당 1개 존에 집약 (PD-1). 본문이 있는 패턴은 전부 WA-3(38em) 적용.
---
## 6. 컴포넌트 선별 (20종 / 변형 35종)
`eyebrow`(2) · `header`(1) · `rule`(1) · `card`(4) · `table`(4) · `stat`(1) · `chartframe`(1) · `specsheet`(1) · `directive`(3) · `badge`(4) · `scope`(1) · `toc`(1) · `stepper`(1) · `xref`(1) · `mediaframe`(1) · **`button`(4)** · **`input`(1)** · **`modal`(1)** · **`toast`(1)** · **`disclosure`(1)**
**미선별**: `hero`(랜딩 제작 시 조건부 추가), `footer`(screen 비적용 — 매트릭스 준수), `stagecard`·`connector`·`principle`(문서 패턴 W4에서 조건부 추가 가능 — 추가 시 카탈로그 규정 준수).
주요 사용 규정: `primary` 버튼 화면당 1개, 레이블 동사 시작 ≤ 8자 · input 레이블 플레이스홀더 대체 금지, 오류 3요소(무엇이·왜·어떻게) + 색·기호·텍스트 3중 · modal 포커스 트랩 + Esc + 중첩 금지 · toast ≥ 5초, 동시 1개, 중요 정보 토스트 단독 전달 금지 · table sticky 헤더 + 가로 스크롤 허용(MS-3 예외) · disclosure 인쇄 시 전체 전개.
---
## 7. 분량 예산
| 슬롯 | 권장 | 최대 | 근거 |
| :--- | :-: | :-: | :--- |
| 화면 제목 (title) | 12자 | 20자 | 헤더 1행 |
| 카드 제목 / 본문 | 12 / 60자 | 20 / 120자 | 카탈로그 승계, 최소 카드 폭(xs 328px) 기준 |
| 버튼 레이블 | 4자 | 8자 | "저장"·"제출" — 결과를 말한다 |
| input 레이블 / 도움말 / 오류 | 8 / 30 / 40자 | 12 / 40 / 60자 | 1~2행 |
| toast 메시지 | 20자 | 40자 | 1~2행, 5초 내 판독 |
| 표 셀 | 20자 | 40자 | 초과 시 상세 화면 이관 |
| 빈 상태(empty state) 안내 | 30자 | 60자 | 원인 + 다음 행동 |
---
## 8. HTML 골격 (정본 시작점)
```html
<!doctype html>
<html lang="ko"><!-- font-size 선언 금지 -->
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>화면 제목 — 서비스명</title><!-- 페이지 제목 필수 (A12) -->
</head>
<body>
<a class="skip-link" href="#main">본문 바로가기</a><!-- FO-4 -->
<header><!-- W1 셸: 화면ID·권한·갱신시각·환경 --></header>
<nav aria-label="주 메뉴"><!-- lg+ 레일 --></nav>
<main id="main"><!-- 패턴 W2~W5 --></main>
</body>
</html>
```
## 9. 인쇄 스타일시트 (`@media print`)
그림자 전부 제거 (EV-4) · 알파 평탄화 (AL-4) · disclosure 전체 전개 (AD-5) · 링크 뒤 목적지 명시 · 색상은 등록 페어 유지, 본문 검정 계열. 본격 인쇄물은 M5로 재조판한다.
---
## 10. 제작 절차
| 단계 | 작업 | 판정 |
| :-: | :--- | :--- |
| 1 | 화면 목록 작성, 각 화면에 패턴(W1~W5) 배정 | 매핑 완료 |
| 2 | §3 CSS 변수 블록을 그대로 탑재 (수정 금지 — 개정은 상위 계층에) | 리터럴 0건 |
| 3 | §8 골격에서 시작, 시맨틱 마크업 (SM-1~5) | 랜드마크·제목 |
| 4 | 컴포넌트 구현 — §6 선별 + §4 인터랙션 규정 | 카탈로그 외 0건 |
| 5 | 반응형 — §2 BP, 본문 38em, 히트 영역 44px | WA-1~4 |
| 6 | 다크 테마 — §3 dark 블록 + 전 화면 다크 렌더 확인 | green 텍스트 0건 |
| 7 | CI 게이트 — stylelint·axe·pa11y 연결 | 통과 없이 머지 금지 (QG-2) |
| 8 | 검증 §11 | 전항 PASS |
---
## 11. 검증 체크리스트
### 자동 (CI 게이트 — W1~W18 승계 핵심)
| # | 항목 | 기준 |
| :-: | :--- | :--- |
| A1 | 색·치수 리터럴 | 변수 정의부 외 0건 |
| A2 | root font-size 고정 | 0건 |
| A3 | `outline: none` 대체 없는 선언 | 0건 |
| A4 | z-index·양수 tabindex | 토큰 외 0건 / 양수 0건 |
| A5 | 그리드 정합 | 전 BP 잔차 0 (§2) |
| A6 | axe 색 대비·이름·alt | 위반 0건 |
| A7 | 헤딩 레벨 건너뜀 | 0건 |
| A8 | `prefers-reduced-motion` | 구현 존재 |
| A9 | 히트 영역 | ≥ 44px (인라인 링크 제외) |
| A10 | 본문 max-width | ≤ 38em |
| A11 | 다크 페어 재계산 | 전 페어 통과, green 텍스트 0건 |
| A12 | 텍스트 알파·hover 의존 | 0건 |
### 수동
| # | 항목 |
| :-: | :--- |
| V1 | 키보드 단독 전 기능 조작 + Tab 순서 = 시각 순서 |
| V2 | 스크린리더 주요 흐름 1회 낭독 |
| V3 | 200% 확대 시 손실·가로 스크롤 없음 |
| V4 | 그레이스케일 판독 (색 단독 의존 검출) |
| V5 | 터치 기기 실기 (hover 의존·히트 영역) |
| V6 | 인쇄 스타일시트 (§9) 출력 확인 |
### 구조 검증 결과 (modules §8.1 — `active` 등록 근거)
12항 전항 **PASS** (2026-07-29, HMCM): 스키마 충족 · depends_on 기록 · 정량 명시(20종/35변형) · 완화 0건 · 전 슬롯 예산 · 패턴-콘텐츠 매핑 · 그리드 정합(624·920 정정 반영) · 카탈로그 외 0건 · 미사용 0건(조건부 선별 명시) · 역할 중복 0건 · 결론 존 규정 · 겸용 해당 없음
---
*본 모듈은 참조 사양이다 (DC-3). "접근 가능한 컴포넌트로 만들었다"가 접근 가능한 서비스를 보증하지 않는다 — 서비스 단위 검증은 별도로 수행한다 (AT-4).*