d3ro-voice/design.md
Yun Chan a0abda7a5c
Some checks failed
ci / 정본·보안·린트·타입·테스트 (push) Successful in 53s
ci / 모바일 린트·타입·Jest (push) Successful in 45s
ci / Supabase Edge Functions + Cloudflare Worker (push) Successful in 21s
ci / .NET API 서버 테스트 (push) Successful in 13s
deploy-site / deploy (push) Failing after 27s
ci / 워크스페이스 빌드 검증 (push) Successful in 36s
feat(site): prerender every locale and publish structured data, llms.txt and sitemaps
Crawlers received an empty client-rendered shell (107 characters of text);
most AI crawlers do not run JavaScript, so the product was invisible to them.

- Build renders each locale to static HTML (/ for Korean, /en/ … /vi/) with
  src/entry-server.tsx + scripts/prerender.mjs; the browser hydrates the same
  locale. The language menu links to those pages instead of switching in place.
- Per-locale head: title, description, canonical, hreflang (+ x-default /en/),
  Open Graph and X cards with a per-locale 1200x630 image.
- JSON-LD graph: Organization, WebSite, WebPage, SoftwareApplication (KRW
  offers, version, release date, download URL from the canonical sources),
  HowTo and FAQPage. No invented ratings.
- robots.txt (search, ai-input and ai-train allowed; /app, /api, invites
  excluded), sitemap.xml with language alternates, llms.txt and llms-full.txt
  generated from the same translations and canonical values.
- IndexNow key and a post-deploy ping (Bing, Naver, Yandex).
- A factual "at a glance" section and two FAQ answers (recognised languages,
  where data is stored) in all 10 languages.
- Icons, apple-touch-icon and web manifest; asset base is now absolute so
  sub-path pages load the same bundle.

Verified: 3.6k-7.7k characters of text per page, no hydration warnings,
no overflow at 320/1440 in six locales, axe 0, Lighthouse mobile SEO,
accessibility and best practices 100.
2026-09-27 10:45:05 +09:00

219 lines
20 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 Pro→Apple 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 700→500, h6/button/caption 600→500,
body1 1.5→1.6, Chip/Tab/ListItemButton 600→500.
- `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.14→1.22, ls -0.035em→-0.02em 등 한글 보정.
## 표면별 변경 요약
| 표면 | 변경 |
|---|---|
| packages/ui (SSOT) | d3roTypo v3, MUI 오버라이드 탈볼드, 한글 폰트 스택 |
| packages/ui-native | 타이포 v3, sans 스택, PhosphorText 텍스트 글로우 제거, PhysicalButton uppercase·과도 트래킹 제거, StatusBar 8px→10px |
| 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×84→500/800×2→600, 프리셋(table/filter/badge/button) 600→500, `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 mono→11px sans, LoginScreen 세이프에어리어 추가, 스택 화면 8곳 하단 인셋 Math.max(insets.bottom,24), letterSpacing 디-모노화, 700×3→500 |
## 표준 준수 노트
- **모바일 세이프에어리어**: 모든 화면 `useSafeAreaInsets` 기반. 탭 화면은 탭 바가
인셋을 담당, 스택 화면은 화면이 담당. 고정 padding(60/120) 잔여 없음.
- **iOS/macOS**: 데스크톱 macOS는 hiddenInset(교통신호 유지 — HIG 준수).
모바일 iOS는 시스템 폰트+자동 폴백. KeyboardAvoidingView 플랫폼 분기 유지.
- **웹**: `font-display: swap` + preconnect. 웹뷰 폰트 이중 로드 제거.
## 성능 예산과 실측
- 폰트: admin 2회 로드→1회, site 2패밀리→1패밀리+mono, web 0→1(다이나믹 서브셋).
- 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`는 금지(예외: 조건부 400↔500 전환).
- 한글 문자열에 `letterSpacing` 양수 값을 직접 넣지 않는다.
- 11px 미만 텍스트를 추가하지 않는다 (라틴 텔레메트리 예외 하한 9px).
## 2026-09-22 Local Flow Intelligence extension
- 기존 **swiss-minimal × dark-instrument** 방향과 token/typography/a11y 규칙을 그대로 적용한다. Flow Radar·Edit Friction·App Quality는 색만으로 상태를 구분하지 않고 텍스트 라벨과 수치를 함께 보인다.
- Privacy Receipt은 `dl`의 정의/값 구조로 보존 기간과 실제 row count를 짝지어 읽게 한다. raw key 이벤트/키코드/콘텐츠 스트림 미저장과, 옵트인 학습 텍스트의 별도 보존 정책을 혼동시키지 않는다. `personal_phrases`는 나이 기반 자동 만료가 없고 개별 삭제·전체 삭제·동의 철회로 제거됨을 정확히 보인다.
- suggestion overlay는 좁은 폭을 유지한다. Why This Suggestion은 한 줄의 provenance와 count만 보이며 raw memory evidence를 노출하지 않는다.
## 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 업그레이드 시
서명 형식이 바뀌면 검증이 전면 실패할 수 있음. 테스트 픽스처는 RAW→DER 변환기로
실 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 발급이 다음 관문)
## 2026-09-26 랜딩 사이트(site/) 정리 — 진실성 · 접근성 · 단순화
연장 경로(`design.md` 방향 유지: swiss-minimal × dark-instrument, 탈볼드, Pretendard).
레퍼런스 1′: superwhisper.com 실측 — 히어로 CTA 2개, 히어로 수치 없음, 가격 3단 "이전 티어 전부 +".
- 브리프: 무엇을 = Windows 음성 받아쓰기 홍보 사이트 / 누구에게 = 한국어 기본 지식노동자·개발자,
목표 행동 = **다운로드 1순위 + 구독(Pro/Pro+)** / 제약 = 10개 로케일 전부 번역, 기존 토큰 유지.
- 확정한 사실(사용자): 가격 Free ₩0 · Pro ₩2,900/월 · Pro+ ₩8,900/월(원화, 월간만), 오픈 소스 주장 삭제(저장소 비공개).
- 섹션: 히어로(예시 1개) → 기능 → 작동 방식 → 개인정보 → 요금 → 다운로드 → FAQ → 푸터.
레이아웃 패밀리: 분할(히어로) / 제목 고정+목록(기능·FAQ) / 4열 번호 행(작동 방식) / 사양서 `dl`(개인정보) / 카드 3장(요금) / 8:4 패널(다운로드).
- 사실 SSOT: 단축키 = `packages/core/src/keybinding.ts`(오른쪽 Alt 누른 채), 사용량 = `packages/core/src/constants.ts`
`PREMIUM_MODEL_LIMITS`, 가격·결제 URL = `site/src/pricing.ts`, 버전·게시일 = `site/src/release.ts`(version:sync 대상).
- 토큰 변경: `brand.blue-deep #1d4ed8` 추가(주 버튼 hover). 주 버튼 채움은 `blue-dark`(흰 글자 5.2:1) —
`blue`(3.7:1)는 본문 크기 버튼 글자에 AA 미달. 그림자는 `chassis`만, 애니메이션은 `glow-pulse`만 남김.
- 컴포넌트 클래스: `.btn/.btn-primary/.btn-secondary`(최소 44px, 줄바꿈 허용), `.kbd`(sans — 한글 키 이름), `.link`, `.skip-link`.
- 한글 줄바꿈 클래스는 `keep-ko`(`:lang(ko)`에서만 keep-all). **Tailwind 내장 `break-keep`을 쓰지 말 것** —
중국어·일본어에서 줄바꿈 기회를 없애 320px에서 가로 넘침이 났다(실측).
- 접근성: 본문 건너뛰기 링크, 섹션 `aria-labelledby`, 모바일 메뉴·언어 선택 `aria-expanded`+Esc+포커스 복귀,
FAQ 디스클로저(`aria-controls`/`region`), 예시 상태 `aria-live`, 감소 모션(전역 CSS + 예시는 결과로 바로),
앵커 `scroll-margin-top`, 새 탭 링크 표기, `<html lang>`·title·description 로케일 추종.
- 검증: 10개 로케일 × 320/390/1440 가로 넘침 0, axe(wcag2a/aa/21aa/22aa/best-practice, ko·ja) 위반 0,
390 터치 타깃 24px 미만 0, 페이지 길이 1440 10,536→5,062px / 390 14,753→7,826px,
빌드 JS 111.0→98.0KB gzip, CSS 7.8→5.2KB gzip.
### 의도적으로 하지 않은 것
- **히어로 수치·상태 뱃지 없음.** "3배 빠름", "10/10", "<1.2s", "시스템 정상 가동", "프로토콜" 등은 근거가 없어 삭제. 되살리지 말 것.
- **경쟁사 비교표·광고/리워드 문구·SHA-256 계산기·릴리스 히스토리 없음.** 계산기는 비교 기준이 없어 무의미했고, 무결성은 `latest.yml` 링크로 대신한다.
- **설치 파일 크기 표기 없음.** `version:sync`가 갱신하지 않는 값이라 다음 릴리스에 틀린 숫자가 된다. 게시일(동기화 대상)만 쓴다.
- **"인기" 뱃지·연간 요금·통화 토글·Team·14일 체험 없음.** 결제 카탈로그·앱에 근거 없음.
- **기능 카드에 FREE/PRO 태그 없음.** 로컬 기능은 전부 free다(`LicenseService.FEATURE_MIN_TIER`).
- **화자 분리·RAG를 대표 기능으로 내세우지 않음.** 화자 구분은 추정 단계라 약속하지 않는다.
- **CRT 움직이는 스캔 효과 제거**(정지 주사선만 히어로 예시 패널에 유지). 이전 기록의 "CRT CSS 유지"는 예시 패널 한 곳으로 좁혔다.
- ~~미확정: 서버 가격 불일치·결제 URL 이원화~~ → 2026-09-26 Wave 3에서 해소(`packages/core` plan-catalog/web-urls 단일 정본, `/app/billing` 하나).
### 2026-09-26 추기 · 히어로 반복 예시(앱 녹음 캡슐 재현)
- 사용자 요청: "작동 방식 보기" CTA 대신 우측에서 앱과 똑같은 예시가 계속 돌게. 히어로 CTA는 다운로드 1개로 줄였다.
- `site/src/components/AppLoopDemo.tsx` — 메모 창 + 화면 아래 녹음 캡슐. 대기 → 오른쪽 Alt 누른 채 말하기(파형·경과 시간·부분 전사)
→ 처리 중(점근 진행 막대) → 커서 자리에 붙여넣기 → 다음 예시. 언어마다 예시 2개.
- 수치는 앱 `apps/desktop/src/renderer/popups/recording-tip`과 같다: 막대 9개 cos 가중치, 100ms 갱신, 스무딩 0.5, 무작위 ±35%,
높이 2–28px, 막대별 색, 진행 막대 120px `min(95, (1-1/(1+1.5t))*100)%`. 캡슐 CSS 값은 앱 style.css를 옮겨 적었다
(Electron 팝업 CSS는 전역 리셋을 포함해 사이트에서 직접 import할 수 없다 — 값이 바뀌면 두 곳을 함께 고친다).
- 접근성: 5초 넘게 움직이므로 일시정지 버튼(WCAG 2.2.2, aria-pressed). 화면 밖·숨은 탭에서 멈춤. 감소 모션은 정지 화면 한 장.
애니메이션은 aria-hidden, 화면 낭독용 설명문(demo.description)을 둔다. 중·일은 띄어쓰기가 없어 세 글자씩 나타난다.
- 하지 않은 것: 실제 음성 녹음·마이크 권한 데모(브라우저에서 로컬 모델을 돌릴 수 없고, 가짜 인식은 진실성 위반).
- 제거: 이전 버튼식 예시(DictationDemo), WaveBars, Crosshair, CRT 화면 CSS — 이전 기록의 "CRT CSS 유지"는 이로써 종료.
- 부수: `site/public/404.html`(없는 경로가 첫 화면으로 떨어지던 SPA 폴백 종료), 법률 페이지의 옛 주황 강조색을 파랑으로.
- 앱 쪽 발견(미수정): 녹음 캡슐의 "처리 중..."은 HTML에 한국어로 고정돼 있어 앱 언어를 따르지 않는다.
### 2026-09-27 추기 · 검색·AI 검색 최적화 (SEO + GEO)
- 문제: 사이트가 클라이언트 렌더링이라 크롤러가 받는 HTML 본문이 107자였다(Googlebot·GPTBot·ClaudeBot·PerplexityBot·네이버 Yeti 동일). AI 크롤러 대부분은 JS를 실행하지 않는다.
- **빌드 때 언어별 정적 HTML을 미리 그린다**(`site/scripts/prerender.mjs` + `src/entry-server.tsx`, React hydrateRoot로 이어받음). 주소: 한국어 `/`, 나머지 `/{en,ja,zh,es,fr,de,pt,ru,vi}/`. 언어 선택은 해당 주소로 가는 링크(크롤링 가능). 자동 언어 리다이렉트는 하지 않는다(구글 권장).
- `<head>`는 언어마다 title·description·canonical·hreflang(10+x-default=/en/)·Open Graph·X 카드. 구조화 데이터(JSON-LD @graph): Organization, WebSite, WebPage, SoftwareApplication(가격 3종 KRW·버전·게시일·다운로드 URL — 정본에서), HowTo(작동 방식 4단계), FAQPage. 가짜 평점(aggregateRating)은 넣지 않는다.
- AI 검색용: `/llms.txt`(llmstxt.org 형식, 영어+한국어 요약·핵심 사실·주요 주소), `/llms-full.txt`(영·한 전문). 모두 i18n 번역과 정본 값에서 빌드 때 생성 — 사이트 문구와 어긋날 수 없다.
- `robots.txt`: 전체 허용 + `Content-Signal: search=yes, ai-input=yes, ai-train=yes`(홍보 목적), `/app/`·`/api/`·`/accept-invite/` 제외, sitemap 안내. Cloudflare의 AI 봇 차단·Bot Fight Mode는 꺼져 있음을 확인.
- `sitemap.xml`: 언어별 페이지(xhtml:link 대체 언어)+법률 문서. IndexNow 키 파일(`/5d886cca….txt`)과 배포 후 알림(`scripts/ci/ping-indexnow.mjs`) — Bing(ChatGPT·Copilot 검색 기반)·네이버·Yandex.
- 보이는 내용 보강: "한눈에 보기" 사실 요약 섹션(정의형 문장 8개, 버전·가격은 정본), FAQ 2개 추가(인식 언어 — 앱 설정의 자동/한·영·일·중, 데이터 저장 위치).
- 공유·아이콘: 언어별 1200×630 공유 이미지(`public/og/<lang>.png`), 파비콘 PNG·apple-touch-icon·PWA 아이콘·manifest. 생성: `npx vite-node site/scripts/render-brand-assets.ts`(문구·로고가 바뀌면 다시 실행해 커밋).
- 빌드 경로 `base: '/'`(언어 하위 경로에서도 자산 경로가 맞도록).
- 검증: 본문 3,600~7,700자/언어, 하이드레이션 경고 0, 10개 언어 320/1440 넘침 0, axe 0, Lighthouse(모바일) SEO·접근성·권장사항 100.
- 하지 않은 것: 언어별 별도 콘텐츠(번역 외 추가 페이지)·블로그, 가짜 후기·평점, 자동 언어 리다이렉트.