제품 UI
애플리케이션은 작업 표면입니다: 사람들은 작업을 완료하기 위해 돌아옵니다. 모든 요소는 그 작업을 수행하는 데 기여함으로써 자리를 얻습니다. 목표는 습득된 친숙함입니다 — 이 카테고리의 도구에 능숙한 사람은 각 컨트롤을 보고 신뢰하며, 인터페이스는 작업 속으로 사라집니다.
이 규칙은 모든 앱에 적용됩니다. 특정 프로젝트(기기 대상, 디자인 시스템, 구성 요소, 방향, 알려진 편차)에 관한 내용은 프로젝트 파일에 있으며, 이를 기반으로 구축합니다. 화면이 완료되었다고 판단하기 전에 review.md를 실행하세요.
프로젝트 파일
다음 순서로 찾으세요: CLAUDE.md 또는 AGENTS.md에 명명된 경로, 그다음 .claude/product-ui.md. 없으면 첫 번째 빌드 전에 templates/project.md에서 .claude/product-ui.md를 생성하세요:
- 디자인 시스템을 찾습니다: 토큰 파일(CSS 사용자 정의 속성, Tailwind 테마, 토큰 JSON), 컴포넌트 라이브러리(저장소 내
components/ui, shadcn, MUI, Radix, …), 스토리 파일. - 화면에 필요한 구성 요소(페이지 스캐폴드, 테이블, 폼 필드, 빈 상태, 대화상자, 토스트, …)를 경로와 함께 나열합니다. 누락된 각 항목은 누락으로 표시하고, 경로를 임의로 만들지 마세요.
- 그 과정에서 발견한 편차(코드가 아래 규칙을 위반하는 부분)를 기록합니다.
- 사용자에게 앱별 기기 대상과 시각적 언어를 소유한 사람(디자인 팀 또는 개발자)을 물어봅니다. 앱의 의도에서 대상을 제안합니다.
확인한 것만 작성하세요. CLAUDE.md가 파일을 가리키도록 하여 이후 세션에서 찾을 수 있게 합니다.
프로젝트에 시각적 방향이 없고 표면이 일반적으로 보이지 않아야 하는 경우, 먼저 design-direction 스킬을 실행하세요. 해당 스킬은 결과를 같은 파일에 기록합니다.
목적 우선
레이아웃 전에 각각 한 줄씩 작성하세요:
- 화면이 제공하는 작업과 이를 수행하는 사람;
- 첫 번째 읽기: 화면이 열릴 때 그들이 보는 첫 번째 것;
- 기본 동작과 반복 빈도;
- 대상 기기: 프로젝트 파일에서 전화, 태블릿, 노트북, 대형 화면.
화면의 모든 영역은 해당 줄 중 하나에 매핑됩니다. 매핑되지 않은 영역은 제거됩니다.
실제 콘텐츠
프로덕션과 같은 형태의 콘텐츠로 구축하고 판단하세요: 실제 이름(현실적인 길이), 가장 긴 그럴듯한 제목, 0, 1, 7, 500개의 항목, 누락된 선택적 값, 영어보다 30% 더 긴 번역. "John Doe", "Acme Inc", "Lorem ipsum", "Item 1" 및 반올림된 숫자는 모든 레이아웃 문제를 숨기며 화면이 생성된 것처럼 보이게 하는 첫 번째 요인입니다. 도메인의 데이터를 모르는 경우 샘플을 요청하거나 스키마에서 파생하세요.
모든 크기
화면은 기본 기기에 최적화되며 다른 모든 중단점에서 동일한 기능으로 작동합니다. 각 크기에는 데스크톱의 축소 복사본이 아닌, 맞는 패턴이 적용됩니다: 사이드바는 드로어나 아이콘 레일이 되고, 테이블은 스택된 목록이 되고, 분할 창은 뒤로 가기 단계가 있는 페이지가 되고, 호버는 보이는 컨트롤이 되고, 조밀한 도구 모음은 오버플로 메뉴가 됩니다. 중단점 아래에서 사라지는 기능은 발견 사항입니다.
대상 너비에서 어떤 것도 가로로 스크롤되지 않습니다: 페이지도, 자체 컨테이너 내부의 목록도 마찬가지입니다. 자유 텍스트 열(이름, 제목, 이메일, 파일 이름)은 축소 및 말줄임표 처리되며 호버 시 전체 텍스트가 표시됩니다. 진정으로 넓은 그리드(매트릭스, 타임라인)만 스크롤될 수 있으며, 그렇게 명시되어야 합니다.
대형 모니터에서 콘텐츠는 읽을 수 있는 측정값을 유지합니다: 텍스트 블록은 줄당 ~75자 미만, 폼은 열 너비를 유지, 테이블은 자유 텍스트 열이 공간을 차지하면서 커질 수 있습니다.
네비게이션
- 글로벌 네비게이션은 앱의 섹션을 나열하며 모든 화면에서 동일하게 유지됩니다.
- 자체 하위 영역이 있는 섹션은 로컬 레이어(두 번째 열 또는 탭)를 하나 추가할 수 있습니다. 각 레이어는 자체 레벨만 표시합니다: 어떤 레이어도 다른 레이어의 항목을 반복하지 않으며, 두 항목이 레이블을 공유하지 않습니다.
- 범위(화면이 작동하는 조직, 작업 공간 또는 계정)는 스위처로 한 번 설정됩니다.
- 모든 페이지는 글로벌 네비게이션에서 최대 두 번 선택하며, 로컬 네비게이션은 기본 기기에서 계속 표시됩니다.
- 첫 번째 컨트롤 위의 크롬은 작게 유지됩니다: 브레드크럼은 그 아래의 페이지 제목을 반복하지 않습니다.
- 소수의 섹션보다 많거나 많은 레코드가 있는 앱은 페이지와 레코드를 이름이나 붙여넣은 ID로 찾는 전역 검색(⌘K / Ctrl+K)을 제공합니다.
밀도
-
작업 세트를 한 번에 표시하세요. 사람이 스캔하거나 비교하는 목록은 항목당 한 행의 테이블입니다. 카드 그리드는 사진이나 미리보기가 콘텐츠인 소수의 항목에 사용됩니다.
-
행 높이는 콘텐츠를 따릅니다: 한 줄 행은 36–44px, 두 번째 줄이나 썸네일이 있는 행은 최대 64px; 패딩은 콘텐츠보다 더 많은 높이를 차지하지 않습니다.
-
관련 항목 간의 간격은 그룹 간 간격보다 작아서, 그룹화가 간격만으로도 읽힙니다.
-
행의 모든 요소는 그 자리를 얻을 자격이 있습니다. 각 요소를 테스트하세요:
- 작업: 이 화면의 작업을 위해 항목을 찾고, 비교하고, 열거나, 조작하는 데 도움이 됩니다;
- 제거: 제거하면 사람에게 필요한 것을 잃게 됩니다. 그렇지 않으면 제거되거나 상세 보기로 이동합니다;
- 중복: 열, 활성 필터 또는 페이지 제목을 반복하지 않습니다;
- 자명: 호버, 도구 설명 또는 범례 없이 읽을 수 있으며, 상태는 단어로 표시되며 색상만으로 표시되지 않습니다;
- 순서: 항목을 식별하는 것 먼저, 그다음 사람들이 비교하는 사실, 마지막으로 동작.
누락된 사실도 발견 사항입니다: 사람들이 하나의 값을 비교하기 위해 항목을 계속 열어야 한다면, 그 값은 행에 속합니다.
-
기본적으로 행당 한 줄. 보조 정보는 자체 열 또는 음소거된 두 번째 줄에 배치되며, 비교를 위해 호버해야 하는 도구 설명에 절대 배치되지 않습니다.
-
제목, 설명 및 도움말 텍스트는 작업이 허용하는 범위 내에서 가능한 한 짧게 유지됩니다. 제목을 반복하는 페이지 설명은 제거됩니다.
-
공백은 그룹을 분리하며, 희박한 화면을 채우는 데 사용되지 않습니다.
-
상자(테두리, 배경, 그림자)는 사람이 단위로 조작하는 대상을 표시합니다. 그룹화만으로는 공간 또는 구분선으로 처리됩니다. 카드 안의 카드는 발견 사항입니다.
계층
- 보기당 하나의 기본 동작, 시각적으로 기본, 범위(페이지 헤더 또는 패널 헤더)의 오른쪽 상단에 배치됩니다. 보조 동작은 윤곽선 또는 고스트입니다. 파괴적인 동작은 마지막에 배치됩니다.
- 모든 크기, 공간, 색상 및 반경은 표면의 디자인 시스템에서 비롯되며 그 안에 유지됩니다. 임의 값(
text-[10px],p-[13px], 원시 16진수)은 발견 사항입니다. 수정은 가장 가까운 단계이거나, 적합한 단계가 없을 때 새 토큰입니다. - 가중치와 색상은 크기보다 먼저 계층을 전달합니다.
- 색상은 의미를 전달합니다: 강조색은 기본 동작, 선택 및 상태를 표시합니다. 상태 색상은 상태가 있는 곳에만 나타납니다.
- 아이콘은 인식을 빠르게 하는 곳(네비게이션, 빈번한 동작)에서 레이블과 함께 사용되며, 접근 가능한 이름이 있는 보편적 동작(닫기, 검색, 더보기)에만 단독으로 사용됩니다. 모든 버튼, 제목 또는 카드의 아이콘은 장식입니다.
- 읽기 전용 값은 입력이 아닌 텍스트로 렌더링됩니다.
- 뷰어의 역할이 사용할 수 없는 컨트롤은 숨겨지며, 서버가 확인하는 것과 동일한 기능으로 결정됩니다. 동작의 존재를 아는 것이 중요한 경우, 비활성화된 상태로 이유와 함께 표시됩니다("관리자만 초대할 수 있습니다").
- 복사본은 인프라가 아닌 사람들이 인식하는 이름을 사용합니다: 대상자가 직접 작업하지 않는 한 공급업체나 파이프라인 이름은 없습니다. 네비게이션에는 구축되지 않았거나 비활성화된 기능이 나열되지 않습니다.
카피
인터페이스 텍스트는 디자인의 일부이며 생성된 화면의 가장 빠른 지표입니다.
- 버튼은 동작과 대상을 동사와 목적어로 명시합니다: "멤버 초대", "CSV 내보내기". 앱 내에서 "제출", "확인", "여기를 클릭", "시작하기"는 절대 사용하지 마세요.
- 확인 버튼은 질문의 동사를 반복합니다: "파일 3개를 삭제하시겠습니까?" → "파일 삭제".
- 모든 레이블, 제목 및 버튼에는 문장형 대소문자를 사용합니다. 느낌표, "이런", "성공적으로", "제발"은 없습니다.
- 피드백은 사람의 관점에서 결과를 명시합니다: "송장이 finance@…로 전송되었습니다", "작업이 성공적으로 완료되었습니다"가 아닙니다.
- 빈 상태는 여기에 무엇이 속하는지와 어떻게 여기에 도달하는지 한두 문장으로 설명합니다. 재치, 일러스트레이션 채움, "여기 볼 것이 없습니다"는 없습니다.
- 도구 내에서 마케팅 음성은 사용하지 마세요: "완벽한", "수월한", "강력한", "잠금 해제", "향상", "마법", "AI 기반" 및 제품을 칭찬하는 모든 문장을 제거하세요.
- 앱 전체에서 개념당 하나의 용어를 사용합니다. 용어집은 프로젝트 파일에 있습니다.
- 숫자, 날짜 및 단위는 앱당 하나의 형식을 따릅니다. 개수는 올바른 복수형을 사용합니다("파일 1개", "파일 2개").
목록 및 테이블
- 숫자는
tabular-nums로 오른쪽 정렬됩니다. 텍스트는 왼쪽 정렬됩니다. - 타임스탬프는 앱당 하나의 고정 형식을 사용하며, 브라우저의 로케일 기본값을 사용하지 않으며 절대 잘리지 않습니다. 모니터링 화면은 상대 시간("3분 전")을 호버 시 절대 시간과 쌍으로 표시하거나 그 반대로 표시합니다.
- 헤더는 열 이름을 한두 단어로 명명합니다. 정렬 가능한 헤더는 클릭 시 정렬합니다.
- 검색, 필터, 정렬, 페이지 및 열린 항목은 URL에 저장되어 새로 고침, 뒤로 가기 및 공유 링크에서도 보기가 유지됩니다.
- 행은 해당 항목에 대한 실제 링크입니다: 전체 행이 항목을 열고, Cmd-클릭은 새 탭을 엽니다.
- 행의 모든 참조(사람, 조직, 작업, ID)는 자체 페이지에 연결됩니다.
- 행별 동작은 행 끝의 안정적인 열에 위치하며, 기본적으로 표시됩니다. 최소한 터치 스크린에서는 표시됩니다. 보이지 않는 상태에서 클릭을 받는 컨트롤은 버그입니다.
- 대량 작업에는 선택 확인란, 모두 선택 및 사람이 항목을 배치로 처리할 때 대량 동작 표시줄이 필요합니다.
- 약 50행 이후에는 페이지 매기기 또는 윈도잉이 필요합니다. 개수는 항상 표시됩니다. 집합을 제한하는 필터(월 범위)는 범위가 표시될 때 페이지 매기기를 대체합니다.
- 필터 칩은 개수를 포함할 수 있습니다. 그런 다음 페이지 요약 역할을 합니다.
폼
- 레이블은 필드 위에, 한 열로, 사람이 데이터에 대해 생각하는 순서대로 배치합니다.
- 블러 시와 제출 시 유효성 검사를 수행합니다. 오류는 해당 필드 아래에 위치하며 수정 방법을 알려줍니다.
- 기본값은 가장 일반적인 답변입니다. 선택적 필드는 선택적이라고 표시되고, 필수 필드는 표시되지 않습니다.
- 생성 또는 동작 폼의 제출 버튼은 활성화된 상태로 유지됩니다. 잘못된 입력을 제출하면 첫 번째 잘못된 필드로 포커스가 이동하고 해당 필드 아래에 수정 방법을 표시합니다.
- 편집 폼의 저장 버튼은 변경 사항이 있을 때까지 비활성화된 상태로 유지될 수 있습니다. 변경 사항이 생기면 활성화되고, 위 규칙이 적용되며, 옆에 "저장되지 않은 변경 사항" 힌트가 상태를 표시합니다.
- 보기당 하나의 저장. 저장되지 않은 변경 사항이 있는 상태에서 나가려면 먼저 확인을 요청합니다.
- 컨트롤은 자체 동작이 처리되는 동안 비활성화되어 두 번 제출되지 않도록 합니다.
- 짧은 폼 또는 단일 필드는 인라인으로 편집합니다. 대화상자는 컨텍스트를 잃지 않아야 하는 집중된 작업에 사용됩니다.
- 입력은 올바른 유형과
autocomplete(이메일, 전화, 일회용 코드, …)를 사용하여 휴대폰이 올바른 키보드를 표시하고 브라우저가 자동으로 채울 수 있도록 합니다. - 파일 업로드 트리거는 포커스 가능한 버튼으로, 선택기를 열고 드롭도 허용합니다.
- 다른 표면(온보딩, 브랜드, 템플릿)을 구성하는 페이지는 설정 옆에 해당 표면의 미리보기를 표시합니다.
동작 및 피드백
- 되돌릴 수 있는 동작(복원, 보관 해제, 재활성화)은 즉시 실행되며 실행 취소를 제공하고, 추가 확인이 필요하지 않습니다. 토글은 자체 실행 취소이며 즉각적인 피드백만 필요합니다.
- 되돌릴 수 없는 동작은 잃는 것을 명시하는 확인을 받습니다("문서 3개 삭제"). 되돌릴 수 있는 것처럼 보이지만 되돌릴 수 없는 동작은 되돌릴 수 있는 방법이 생길 때까지 되돌릴 수 없는 것으로 취급됩니다.
- 모든 동작은 100ms 이내에 응답합니다: 낙관적 업데이트, 컨트롤의 보류 상태, 또는 콘텐츠가 도착할 위치의 스켈레톤.
- 몇 초 이상 걸리는 작업은 백그라운드에서 실행되며 진행 상황을 표시하고 네비게이션을 유지합니다.
- 오류는 발생한 위치 옆에 발생한 내용과 다음에 할 작업을 표시합니다.
상태 매트릭스
모든 보기는 모든 상태를 함께 제공하며, 기본값이 아닌 설계된 상태입니다:
| 상태 | 형태 |
|---|---|
| 로딩 | 콘텐츠가 들어갈 레이아웃의 스켈레톤 |
| 빈 상태 | 여기에 무엇이 속하는지 설명하고 추가하는 동작을 제공 |
| 필터-빈 상태 | 필터가 일치하는 항목이 없음을 알리고 지우는 동작을 제공 |
| 부분 | 로드된 부분은 렌더링하고, 실패한 부분은 자체 오류를 표시하며 0이 아님 |
| 접근 불가 | 누가 이것을 볼 수 있고 어떻게 접근 권한을 얻는지 알리고, 진행 방법을 제공 |
| 오류 | 실패한 내용, 재시도, 나머지 화면은 계속 사용 가능 |
| 전체 | 실제 볼륨의 실제 콘텐츠, 긴 이름과 많은 행 포함 |
모든 대화형 컨트롤은 기본, 호버, 포커스-표시, 활성, 비활성 및 보류 상태를 가집니다.
대시보드에서 각 타일과 차트는 자체 상태를 소유합니다: 읽기 실패는 자체 오류를 표시하며 0이나 빈 차트가 아닙니다. 대시보드는 주의가 필요한 항목에서 열리며, 메트릭 카드 행에서 열리지 않습니다. 숫자는 의미 있는 비교(목표, 이전 기간)와 팀이 동의한 정의와 함께만 나타납니다. 차트는 dataviz 스킬이 설치된 경우 해당 스킬을 따릅니다.
접근성 및 테마
- 본문 텍스트는 모든 테마에서 4.5:1 대비를, 큰 텍스트와 컨트롤 경계는 3:1을 충족합니다. 회색 위의 음소거된 회색이 가장 일반적인 실패입니다.
- 포커스는 항상 표시되고 절대 잘리지 않습니다. 포커스 링은 설계되어야 하며 브라우저 기본값을 제거하지 않습니다.
- 모든 컨트롤에는 접근 가능한 이름이 있습니다. 아이콘 전용 버튼은
aria-label을 받습니다. 랜드마크(nav,main)와 페이지당 하나의h1. - 텍스트는 200%로 크기가 조정되며 레이아웃은 유지됩니다.
- 앱이 다크 테마를 지원하는 경우, 설계되어야 합니다: 자체 표면 단계와 재조정된 강조색, 반전된 색상이 아닙니다. 모든 화면을 두 테마 모두에서 검토하세요.
인체공학
- 기본 작업은 키보드로 완료됩니다: 탭 순서는 읽기 순서를 따르고, Enter는 제출, Escape는 닫기, 포커스는 원래 위치로 돌아갑니다.
- 클릭 대상은 최소 24×24px이며, 빈번한 대상은 더 크고(44px, 터치용), 히트 영역은 아이콘뿐만 아니라 전체 행이나 레이블을 포함합니다.
- 빈번한 동작은 동작 대상 가까이에 배치합니다. 거리와 클릭 수는 작업의 빈도와 반비례합니다.
- 대화상자 내에서 폼은 완료될 때까지 포커스를 유지합니다. 포커스를 대화상자 내로 제한합니다. 대화상자가 열리면 시각적으로 관련된 컨트롤이 포커스를 받습니다.
- 단계는 보여지고 서술됩니다: "3/5단계". 각 단계는 이전 단계로 돌아갈 수 있습니다. 마법사는 저장하지 않은 데이터를 경고 없이 종료되지 않습니다.
- 지속적인 작업에는 키보드 단축키가 있으며, 앱 전체 일관성을 유지합니다. 단축키는 기록되거나 찾을 수 있습니다.
검토 절차
화면이 완료되었다고 판단하기 전에 review.md를 실행하여 상태를 문서화하고 모든 규칙에 대해 확인하세요. 스크린샷 스크립트를 포함하여 각 화면 및 상태의 스크린샷을 캡처합니다. 발견 사항을 해결하고 다시 검토하세요.
모든 규칙에 대해? 모든 규칙에 대해.