d3ro-voice/design.md
2026-08-29 18:33:45 +09:00

152 lines
11 KiB
Markdown
Raw Permalink 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.

# design.md — D3RO Voice 크로스플랫폼 디자인 결정 기록
> 2026-08-22 전면 타이포그래피 개편 ("타이포그래피 퍼스트 v3").
> 다음 실행(사람이든 에이전트든)은 이 파일을 읽고 같은 결정을 이어간다.
## 브리프 3줄
- 무엇을: 로컬 AI 음성 어시스턴트의 6개 표면(데스크톱 Electron / 관리자 / 웹앱 /
마케팅 사이트 / React Native 모바일 / 공유 DS 패키지)의 통합 타이포그래피·폰트 개편.
- 누구에게: 한국어 기본 사용자(개발자·지식노동자). 도구는 하루 종일 켜져 있다.
- 제약: 기존 스택 유지(MUI 7 / Tailwind 3 / RN StyleSheet), 기능 파괴 금지,
성능 예산(히어로까지 JS 150KB gzip, 이번 개편은 폰트 로드 정리로 감소).
## 컨셉 한 문장 · 프리셋 · 리스크
- 한 문장: **볼드를 버리고 크기·행간·명도로 위계를 만드는 한국형 스위스 미니멀**
"정밀 계기판의 고요한 밤"에서 "조용히 읽히는 정밀 도구"로.
- 프리셋: swiss-minimal(그리드와 침묵) × dark-instrument(계기판의 정확함).
- 감수한 리스크 하나: 헤드라인 최대 웨이트를 500으로 내린 것. 라틴 마케팅 관례
(700-800 디스플레이)를 버리는 선택이지만, 한글 낱글자의 시각 밀도에서는
500+큰 크기+타이트 트래킹이 더 고급스럽다 (Apple 한국어 페이지가 같은 길).
## 한글 폰트 결정 (리서치 기반)
- **웹/데스크톱: Pretendard Variable 단일 패밀리.**
근거: Inter 기반 네오그로테스크로 한/영 조화(혼용 시 별도 조정 불필요),
크로스플랫폼 웨이트 일관성, 9단계+가변 폰트, 사실상 한국 UI 표준.
SUIT(본문 특화)·Paperlogy(마케팅 특화)를 검토했으나 교체 이득 < 전환 비용.
- **로딩 방식: 다이나믹 서브셋 + woff2 + preload(preconnect)** 2025-26 표준.
화면에 쓰인 글리프만 분할 로드한다. 기존 정적 pretendard.css 전체 로드를 폐기.
- **모바일(RN): 시스템 폰트 스택.** bare RN이라 커스텀 한글 폰트 번들링(2MB+ ttf,
네이티브 재빌드) 대신 iOS=SF ProApple SD Gothic Neo, Android=Roboto→Noto Sans KR
자동 폴백. Apple HIG/Material 권장 표준. **Menlo/monospace 전면 폐기**
Menlo에 한글 글리프가 없어 / 혼용 입력이 뒤섞이는 버그였음.
- **site: Plus Jakarta Sans 제거.** + 혼용 헤드라인에서 라틴/한글 스트로크
불일치. Pretendard가 Inter 기반이므로 라틴도 Pretendard로 통일(로딩 1종 감소).
## 타이포그래피 원칙 (W3C klreq / 요즘IT DS / KRDS 종합)
1. **볼드 금지(700/800/900 → 0회)**. 최대 600(의미 강조 `strong` 전용),
헤드라인 500, 몸통 400, 라벨 500. 위계는 크기·행간·명도(text token).
2. 한글 행간 1.5~1.7 (body 1.6), 헤드라인도 1.2 이상. 블록 글자의 쉬는 공간.
3. 자간 0 근처. 음수는 대형 헤드라인만 -0.01~-0.02em. 양수(+0.02~0.04em)
라틴 대문자 라벨에만. 한글에 양수 트래킹 금지.
4. **한글 최소 크기 11px**. 8-9px 토큰(engrave/micro/nano) 상향
(engrave/micro 10px, nano 9px 라틴 전용 텔레메트리).
5. 폰트 1패밀리 + 웨이트 3종(400/500/600). mono는 텔레메트리·코드·숫자에만.
## 토큰 변경 (SSOT: packages/ui/src/theme.ts `d3roTypo` v3)
| 토큰 | v2 () | v3 () |
|---|---|---|
| hero | 32px/700/-0.5px/1.2 | 32px/500/-0.02em/1.3 |
| title | 24px/700/-0.3px/1.25 | 24px/500/-0.01em/1.35 |
| value | 20px/600/0/1.1 | 20px/500/0/1.2 |
| heading | 16px/600/0/1.4 | 16px/500/0/1.5 |
| body | 14px/400/0/1.55 | 14px/400/0/1.6 |
| label | 11px/600/0.08em/1.2 | 11px/500/0.04em/1.3 |
| engrave | 9px/700/1px | 10px/500/0.06em/1.2 |
| nano | 8px/700/0.5px | 9px/500/0.03em/1.15 |
- MUI 기본값 동반 변경: h4/h5 700500, h6/button/caption 600500,
body1 1.51.6, Chip/Tab/ListItemButton 600500.
- `d3roFontSans` 한글 폴백 추가: Apple SD Gothic Neo, Noto Sans KR, Malgun Gothic.
- RN 대응(`packages/ui-native/theme.ts` `d3roNativeTypo`) 동일 철학으로 동기화.
label 10px/700/ls2 11px/500/ls0.4.
- site(Tailwind) type scale: hero lh 1.141.22, ls -0.035em-0.02em 한글 보정.
## 표면별 변경 요약
| 표면 | 변경 |
|---|---|
| packages/ui (SSOT) | d3roTypo v3, MUI 오버라이드 탈볼드, 한글 폰트 스택 |
| packages/ui-native | 타이포 v3, sans 스택, PhosphorText 텍스트 글로우 제거, PhysicalButton uppercase·과도 트래킹 제거, StatusBar 8px10px |
| apps/desktop | **보더리스**: Win/Linux `frame:false` + 커스텀 TitleBar, macOS `titleBarStyle:'hiddenInset'` + 네이티브 교통신호(커스텀 컨트롤 숨김, 78px 여백). 기존 `frame:true`+커스텀 타이틀바 이중 크롬 버그 해소. 인라인 700×95/800×10/900×2 500/600, 팝업 CSS 동일 |
| apps/admin | Pretendard 이중 로드(link+@import)→다이나믹 서브셋 단일, 미사용 JetBrains Mono 로드 제거, 700×84500/800×2600, 프리셋(table/filter/badge/button) 600500, `strong`600 CSS |
| apps/web | **Pretendard 다이나믹 서브셋 로드 추가**(기존 폰트 0로딩OS 폴백 렌더 버그 수정), login 하드코딩 스택 교체, 700×24/800×13/900×2 스윕 |
| site | font-bold 13/semibold 37 medium, Plus Jakarta 제거, 한글 type scale 보정, `strong` 600 |
| apps/mobile-rn | Menlo/monospace 전면 제거(입력창 18곳), TabBar 인셋 기반(52+insets.bottom)+라벨 9px mono11px sans, LoginScreen 세이프에어리어 추가, 스택 화면 8곳 하단 인셋 Math.max(insets.bottom,24), letterSpacing 디-모노화, 700×3500 |
## 표준 준수 노트
- **모바일 세이프에어리어**: 모든 화면 `useSafeAreaInsets` 기반. 화면은 바가
인셋을 담당, 스택 화면은 화면이 담당. 고정 padding(60/120) 잔여 없음.
- **iOS/macOS**: 데스크톱 macOS는 hiddenInset(교통신호 유지 HIG 준수).
모바일 iOS는 시스템 폰트+자동 폴백. KeyboardAvoidingView 플랫폼 분기 유지.
- ****: `font-display: swap` + preconnect. 웹뷰 폰트 이중 로드 제거.
## 성능 예산과 실측
- 폰트: admin 2회 로드1회, site 2패밀리1패밀리+mono, web 01(다이나믹 서브셋).
- site 빌드 실측: 360.53KB JS(gzip 111.04KB), CSS 40.37KB(gzip 7.81KB) 예산 .
- 애니메이션 정책 변화 없음(transform/opacity만, 기존 유지).
## 의도적으로 하지 않은 것
- **관리자 상태값 라벨은 대문자 유지.** ACTIVE/DISABLED/PRO+ VIP/POST/PATCH 등은
코드 비교·API 값이라 문장형 변환 금지. 대신 페이지 부제(• 구분 설명문)
사이드바 그룹 라벨·대시보드 카드 라벨은 문장형으로 전환했다(2026-08-22).
- **site의 CRT/crosshair CSS는 유지.** 감사에서 '레거시' 분류했으나 실사용
확인(HowItWorks·Privacy·Crosshair) 제거하지 않는다.
## 2026-08-22 추가 완료 (2차: 브랜드 통일 + 오프시스템 정리)
- **브랜드 통일 amber blue 완료.** site(brand-amber 134곳brand-blue,
favicon/download.html/LED 시맨틱 포함), mobile-rn(다크 #3b82f6/pressed #2563eb/
onAccent 흰색 반전, 라이트 #2563eb), ui-native 레거시(#3b82f6).
근거: 데스크톱··관리자 + 6개 테마가 이미 blue(Midnight Glass)인데 site/모바일만
CRT amber 시대 잔재였다. 이제 표면 단일 액센트.
- **apps/web 오프시스템 전면 토큰화.** download(잔여 hex 0), login(잔여 0),
chat-panel/mic-recorder/commands/billing/history/sidebar의 amber #ff5c35
37곳 + zinc 표면 90여 d3roPalette/--d3-* var로 교체. 6테마 연동.
download·login은 이제 테마 반응형. on-accent 대비 보정( 전송 버튼 hover
흰색). `--d3-tag-*` CSS 변수를 SSOT buildCssVars에 추가(color-mix 틴트 파생용).
- **관리자 라벨 문장형 전환.** 페이지 부제 10곳(• 나열 쉼표 문장형, 약어
STT/LLM/SLA/RAG/VIP 보존), 사이드바 그룹·대시보드 카드 라벨 CSS uppercase 제거
(원본 문자열은 이미 문장형). 죽은 "Service Telemetry NOT CONNECTED" 패널 제거.
- **관리자 globals.css :root 죽은 변수 제거.** SSOT와 이름이 충돌하는 19개 로컬
변수(소비자 0) 삭제, body는 --d3-bg-app/--d3-text-primary으로 직결.
- **모바일 커스텀 한글 폰트 번들링 최종 결정: 하지 않음(확정).** Apple HIG와
Material 가이드가 모두 시스템 폰트를 권장하고, iOS Apple SD Gothic Neo /
Android Noto Sans KR 폴백 품질이 이미 우수하며, 정적 ttf 번들(2웨이트
5-10MB) 다이나믹 서브셋이 없는 RN에서 비용 대비 효과가 낮다. 항목은
미확정이 아니라 확정된 결정이다.
## 다음 실행을 위한 지침
- 텍스트는 `d3roTypo`/`d3roNativeTypo` 토큰 또는 MUI 기본값만 쓴다.
인라인 `fontWeight` 금지(예외: 조건부 400500 전환).
- 한글 문자열에 `letterSpacing` 양수 값을 직접 넣지 않는다.
- 11px 미만 텍스트를 추가하지 않는다 (라틴 텔레메트리 예외 하한 9px).
## 2026-08-24 광고 수익화 E2E RED 스위트 (652 시나리오)
- 위치: `apps/desktop/tests/red/ads/` (ads-mediation 370 / admob-ssv 142 / ad-settlement 140)
- 계열: A 입찰 거버넌스 110 · B 크리에이티브 안전성 80 · C 노출·클릭 추적 70 ·
D 리워드 60 · E SSV 검증 142 · F 정산 원장 90 · G 설정 거버넌스 40 · H 엔진정산 60
- 실측: **GREEN 582 / RED 70** (전체 데스크톱 스위트 1,242개, 기존 590개 회귀 0)
- RED 백로그(구현해야 수입 무결성 확보):
1. SSV 리플레이 방지 60 동일 transaction_id 재검증·과거/미래 timestamp 수용(미구현)
2. setConfig 검증 10 음수 rewardTokensAmount 허용(미검증)
- 이식성 경고: admob-ssv의 derEcdsaSignatureToRaw는 Deno WebCrypto가 DER 서명을
반환한다는 동작에 의존. Node(≥22) RAW(r||s) 반환한다 Deno 업그레이드
서명 형식이 바뀌면 검증이 전면 실패할 있음. 테스트 픽스처는 RAWDER 변환기로
AdMob 형식을 재현한다.
## 2026-08-24 RED→GREEN 완료 + 수익화 계획
- admob-ssv.ts: 리플레이 방지(tx_id 25h 캐시) + 타임스탬프 신선도1h) 구현 엣지함수 재배포
- AdMediationEngine.setConfig: 음수/0 이하 설정값 검증 추가
- 광고 스위트 652/652 GREEN, 데스크톱 전체 1,242/1,242 GREEN, tsc 0
- 수익화 로드맵: docs/monetization-plan.md (AdMob 프로덕션 ID 발급이 다음 관문)