# CBMC LINK MVP Component Specification

기준일: 2026-09-22  
제품 방향: V2-first, Article Reading First

## 1. 공통 계약

모든 컴포넌트 문서는 다음 항목을 가진다.

```text
Purpose
Semantic anatomy
Required data
Optional data
Variants
States
Responsive behavior
Accessibility
CMS mapping
```

공통 규칙:

- 제목·요약은 하드 문자 수 제한과 강제 ellipsis를 사용하지 않는다.
- 영어 kicker는 선택이며 한국어만으로 의미가 완결되어야 한다.
- 카드 전체 링크와 카드 내부 중복 링크를 함께 사용하지 않는다.
- 링크와 버튼을 동작에 맞게 구분한다.
- 공개 영역에 `/admin` 링크를 표시하지 않는다.
- 이미지 누락 시 선택 이미지는 제거하고, 필수 이미지는 발행을 차단한다.
- 모든 조작 요소는 최소 44×44px와 `:focus-visible`을 제공한다.

## 2. MVP 컴포넌트

### 2.1 `SkipLink`

- **Purpose:** 키보드 사용자가 반복 내비게이션을 건너뛴다.
- **Anatomy:** 페이지 첫 포커스 요소인 `<a href="#main-content">본문으로 바로가기</a>`.
- **States:** hidden, focus-visible.
- **Responsive:** 모든 화면 동일.
- **Accessibility:** 포커스 시 화면 안에 노출하며 실제 `main` ID와 연결한다.

### 2.2 `BrandHeader`

- **Purpose:** 브랜드 식별과 최신 Issue/기사 접근.
- **Anatomy:** `<header>` → 브랜드 링크, `<nav>`, 주요 기사 CTA, 모바일 메뉴 버튼.
- **Required:** 승인 로고 또는 브랜드명, 주요 메뉴.
- **Variants:** light, dark, paper, static, sticky, compact.
- **States:** default, scrolled, menu-open, current-item, focus-visible.
- **Responsive:** 모바일은 브랜드·메뉴 버튼·기사 CTA만 우선 노출한다.
- **Accessibility:** nav label, `aria-current`, 메뉴 focus return.
- **CMS:** 사이트 설정과 메뉴 데이터. `/admin` 항목은 허용하지 않는다.

### 2.3 `MobileNavigationSheet`

- **Purpose:** 모바일에서 주요 내비게이션 제공.
- **Anatomy:** trigger button → modal/sheet → nav list → close button.
- **States:** closed, opening, open, closing.
- **Responsive:** 768px 미만 기본, 이상에서는 인라인 내비게이션.
- **Accessibility:** `aria-expanded`, `aria-controls`, Escape, focus trap/return.
- **Motion:** reduced motion에서는 즉시 표시한다.

### 2.4 `ButtonLink`

- **Purpose:** 행동과 이동을 명확히 구분한다.
- **Variants:** primary, secondary, tertiary, icon, previous, next, external, download.
- **States:** default, hover, focus-visible, pressed, disabled, loading.
- **Responsive:** 모바일 full-width는 선택, 최소 높이 44px.
- **Accessibility:** 이동은 `<a>`, 상태 변경은 `<button>`을 사용한다.

### 2.5 `IssueMasthead`

- **Purpose:** 최신 Issue와 대표 기사를 소개하고 기사 읽기로 연결한다.
- **Anatomy:** issue label, title, theme/dek, optional media, primary article CTA.
- **Required:** Issue title, primary Story destination.
- **Variants:** V2 hero, compact, text-only, V3 cover adapter.
- **States:** media-present, text-only, preview, published.
- **Responsive:** desktop 7/5 또는 8/4, mobile text-first stack.
- **Accessibility:** 페이지의 H1 또는 홈의 핵심 H2 역할을 명확히 한다.
- **CMS:** Issue + primary Story.

### 2.6 `EditorialKicker`

- **Purpose:** 형식·주제·편집 맥락 표시.
- **Anatomy:** 한국어 라벨 + 선택적 영문 보조 라벨.
- **Variants:** issue, story-format, region, chapter, editor-pick.
- **States:** linked, current, text-only.
- **Content:** 12px 미만 금지, 영어만으로 의미 전달 금지.
- **CMS:** format, topic, region/chapter, featured flag.

### 2.7 `FeaturedStory`

- **Purpose:** 가장 먼저 읽을 대표 기사 강조.
- **Anatomy:** optional media, kicker, title link, dek, ArticleMeta, optional CTA.
- **Variants:** horizontal, stacked, text-only, paper.
- **States:** default, hover, focus-visible, visited, media-missing.
- **Responsive:** desktop 8/12 또는 12/12, mobile 4/4.
- **Accessibility:** 제목 링크를 유일한 대표 링크로 사용한다.
- **CMS:** Story title/dek/media/meta/canonical URL.

### 2.8 `StoryCard`

- **Purpose:** 기사 목록의 기본 단위.
- **Anatomy:** optional media, kicker, title link, optional dek, meta.
- **Variants:** standard, horizontal, compact, no-image, dark, paper.
- **States:** default, hover, focus-visible, visited, loading, unavailable.
- **Responsive:** mobile 4/4, tablet 4/8, desktop 4/12.
- **Content:** 제목 길이 제한·고정 높이·강제 말줄임 없음.
- **CMS:** title, dek, media, format, publishedAt, readingTime, canonical URL.

### 2.9 `ArticleHeader`

- **Purpose:** 기사 제목과 읽기 맥락 제공.
- **Anatomy:** breadcrumb, kicker, H1, dek, ArticleMeta, optional hero media.
- **Variants:** standard, interview, field-report, media-led.
- **States:** full-meta, partial-meta, text-only.
- **Responsive:** desktop title max-width 960px, mobile single column.
- **Accessibility:** 페이지당 단일 H1, `<time datetime>` 사용.
- **CMS:** Story + author + Issue + hero media.

### 2.10 `ArticleMeta`

- **Purpose:** 작성자·발행일·읽기 시간·지회 정보를 제공한다.
- **Anatomy:** 의미 있는 텍스트 그룹 또는 `<dl>`.
- **Variants:** inline, stacked, compact-card.
- **States:** full, partial, anonymous.
- **Responsive:** 줄바꿈을 허용하고 정보 순서를 유지한다.
- **Accessibility:** 아이콘만으로 값을 표현하지 않는다.
- **CMS:** author, organization/chapter, publishedAt, updatedAt, readingTime.

### 2.11 `ArticleBody`

- **Purpose:** V2 canonical 본문을 읽기 좋게 렌더링한다.
- **Supported blocks:** paragraph, heading, list, link, image, figure, quote, callout, divider, video/embed, source, inline CTA.
- **Variants:** standard, long-form, interview, field-report.
- **States:** loading, rendered, unsupported-block, error.
- **Responsive:** 최대 720px, 표·코드·임베드는 안전한 overflow 처리.
- **Accessibility:** heading order, 명확한 링크명, 자막, reduced motion.
- **CMS:** Payload rich text를 표준 block adapter로 변환한다.

### 2.12 `PullQuote`

- **Purpose:** 핵심 발언을 편집적으로 강조한다.
- **Anatomy:** `<figure>` → `<blockquote>` → optional attribution/source.
- **Variants:** inline, full-width, dark, paper.
- **States:** attributed, unattributed, long.
- **Content:** 원문을 임의로 축약하지 않는다.
- **CMS:** quote, speaker, organization, source URL.

### 2.13 `ImageFigure`

- **Purpose:** 이미지와 설명·출처를 하나의 의미 단위로 제공한다.
- **Anatomy:** `<figure>` → media → `<figcaption>` caption/credit/AI disclosure.
- **Variants:** body, wide, portrait, gallery.
- **States:** loading, loaded, optional-missing, required-missing, error.
- **Responsive:** 비율과 focal point를 유지하며 srcset을 사용한다.
- **Accessibility:** alt와 caption을 분리한다.
- **CMS:** media, alt, caption, credit, rights, consent, AI flag, focal point.

### 2.14 `RelatedStories`

- **Purpose:** 기사를 읽은 뒤 다음 기사로 이동시킨다.
- **Anatomy:** section heading + StoryCard list.
- **Variants:** next-story, two-card, three-card, text-list.
- **States:** loading, ready, none, error.
- **Responsive:** desktop 2–3 columns, mobile single column.
- **CMS:** manual related first; 없으면 같은 Issue의 다음 Story.

### 2.15 `ParticipationCTA`

- **Purpose:** 제보·교육·행사 등 기사 이후의 구체적 행동을 제공한다.
- **Anatomy:** title, reason, optional deadline/owner, action.
- **Variants:** inline, section, paper, external.
- **States:** open, deadline-soon, closed, unavailable, success, error.
- **Responsive:** mobile button stack.
- **Accessibility:** 외부 링크·다운로드 여부를 알린다.
- **CMS:** action type, label, URL, deadline, owner, status.

### 2.16 `ProgressIndicator`

- **Purpose:** V3 현재 페이지와 전체 진행 상태를 전달한다.
- **Anatomy:** text status + semantic progress + optional visual bar.
- **States:** first, middle, last, turning, reduced-motion.
- **Accessibility:** `aria-valuemin/max/now` 또는 `<progress>`, 현재 페이지 제목을 함께 제공한다.
- **CMS:** V3 presentation order.

### 2.17 `V3PageControls`

- **Purpose:** 모바일과 데스크톱에서 버튼만으로 페이지를 이동한다.
- **Anatomy:** previous button, current label, next button, optional contents button.
- **States:** first-page, middle, last-page, turning/input-locked, reduced-motion.
- **Responsive:** 모바일에서 항상 보이는 44px 이상 버튼. swipe나 corner click은 선택 보조다.
- **Accessibility:** disabled 상태, 목적지가 포함된 accessible name, 전환 후 페이지 제목에 포커스하지 않고 live status를 갱신한다.
- **CMS:** page index, title, total, contents map.

### 2.18 `SystemState`

- **Purpose:** Loading, Empty, Error, Offline을 일관되게 표현한다.
- **Variants:** loading-skeleton, empty, error, offline, unavailable.
- **Anatomy:** 상태 제목, 설명, 선택적 재시도/이동 action.
- **Accessibility:** 상태 변화는 필요한 경우 live region으로 전달한다.
- **Content:** 내부 에러 코드나 승인 상태를 공개하지 않는다.

### 2.19 `SiteFooter`

- **Purpose:** 공식 정보·정책·연락처·보조 링크 제공.
- **Anatomy:** footer, secondary nav, organization info, policy links, copyright.
- **Variants:** standard, compact, paper.
- **Responsive:** desktop grouped columns, mobile stacked.
- **CMS:** organization settings and secondary menu.
- **Rule:** `/admin` 링크 금지.

## 3. State matrix

| State | Visual | Semantic behavior |
|---|---|---|
| hover | surface/border 변화 | 의미 변화 없음 |
| focus-visible | 3px focus ring + offset | 키보드 포커스 |
| pressed | 짧은 active 피드백 | `aria-pressed`는 toggle에만 사용 |
| current | label/icon/weight | `aria-current` |
| disabled | 색·cursor·opacity | 실제 `disabled` 또는 조작 차단 |
| loading | 진행 또는 skeleton | 중복 제출 방지 |
| error | error 색 + 문구 + action | 색만으로 표현 금지 |
| visited | 링크 색상 | CTA 버튼에는 적용하지 않음 |
| reduced-motion | 즉시 전환 | 정보와 순서 유지 |

## 4. MVP 제외 컴포넌트

다음은 콘텐츠 규모가 증가한 뒤 추가한다.

- SearchField / SearchResults
- MultiFilter / FilterSheet
- IssueArchive 전용 컴포넌트
- 지도·지회 탐색
- 개인화 추천
- 다국어 전환
