dream-app-onboarding

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

꿈 해몽 앱 온보딩 (Dream-App Onboarding)

梦境解析应用用户引导(Dream-App Onboarding)

소스:
검증일: 2026-05-15
짝 스킬:
  • frontend/voice-input-ui
    — 마이크 권한 요청·상태 머신·시각 피드백 구현. 본 스킬은 권한 요청 시점만 다루고, 실제 마이크 UI는 voice-input-ui를 따른다.
  • frontend/dream-privacy-consent-ui
    — 동의 화면 컴포넌트 구조·체크박스 UX·동의 철회 흐름. 본 스킬은 동의 단계가 5단계 중 어디에 위치하는지만 다루고, 동의 UI 자체는 짝 스킬을 따른다.
  • humanities/crisis-intervention-resources-korea
    — 109·1577-0199 등 위기 자원 핫라인 번호와 안전 가드 문구. 본 스킬은 온보딩 5단계 중 어디에 어떤 톤으로 위기 자원을 노출하는지만 다룬다. 실제 번호·문구·법적 의무는 짝 스킬을 그대로 인용한다.

参考资料:
验证日期: 2026-05-15
关联技能:
  • frontend/voice-input-ui
    — 麦克风权限请求·状态机·视觉反馈实现。本技能仅处理权限请求时机,实际麦克风UI遵循voice-input-ui。
  • frontend/dream-privacy-consent-ui
    — 同意页面组件结构·复选框UX·同意撤回流程。本技能仅处理同意阶段在5阶段中的位置,同意UI本身遵循关联技能。
  • humanities/crisis-intervention-resources-korea
    — 109·1577-0199等危机资源热线号码及安全提示语。本技能仅处理引导5阶段中何时以何种语气展示危机资源,实际号码·提示语·法律义务直接引用关联技能。

0. 언제 사용 / 사용하지 않을지

0. 适用场景/不适用场景

상황적합
꿈 해몽·꿈 일기 앱의 첫 실행 온보딩 설계
정신건강·자가 진단·감정 추적 앱의 첫 실행 온보딩 (안전 가드 적용 필요)
기존 사용자에 재방문 온보딩(새 기능 소개·튜토리얼) 표시△ (5단계 구조는 과함, 3단계 이하로 축소)
마케팅 랜딩 페이지 투어❌ (별도 패턴 — intro.js·driver.js가 더 적합)
로그인된 B2B 대시보드 온보딩❌ (
react-joyride
·
@reactour/tour
만 활용, 본 스킬의 위기/학술 한계 섹션은 불필요)

场景是否适用
梦境解析·梦境日记应用首次启动引导设计
心理健康·自我诊断·情绪追踪应用首次启动引导(需应用安全防护)
向现有用户展示重访引导(新功能介绍·教程)△(5阶段结构过于繁琐,需压缩至3阶段以内)
营销落地页导览❌(需单独模式 — intro.js·driver.js更合适)
已登录的B2B仪表盘引导❌(仅使用react-joyride·
@reactour/tour
,本技能的危机/学术局限性章节无需保留)

1. 온보딩 5단계 구조

1. 引导5阶段结构

NN/G는 첫 실행 온보딩 자체를 가능한 한 피하라고 권고하지만(스킵 가능성이 높음), 꿈 해몽 앱은 다음 두 가지 이유로 축약형 온보딩이 필수다.
  1. 학술·법적 한계 사전 고지가 불가피 — 의학적·심리학적 진단이 아니며 민속학적 자료라는 점은 첫 사용 전에 알려야 한다. 사용 중 발견하면 사용자가 잘못된 기대를 형성한다.
  2. 위기 자원 사전 노출이 필요 — 자살·자해 신호가 입력된 후에야 109를 보여주는 것은 늦다. 사용자가 신호를 입력하기 전부터 도움 받을 곳을 알게 둔다.
따라서 5단계는 다음 순서로 고정한다. 단계당 1화면, 전체 30~60초 이내가 목표다.
[1] 환영 + 가치 한 줄
[2] 기능 3개 소개 (꿈 기록 · 해몽 카드 · 다시 꺼내보기)
[3] 학술 한계 + 위기 자원 안내   ← 권한 요청 *전*에 가치·한계·안전 자원을 먼저 보여준다
[4] 동의 (개인정보·민감정보·필수/선택)
[5] 첫 꿈 입력 가이드 (지금 텍스트로 / 음성으로 / 나중에)
       └─ 음성을 선택한 *그 시점*에만 마이크 권한 요청 (in-context)
          알림 권한은 *최소 1회 사용 후* 별도 priming 화면에서 요청
5단계 콘텐츠 정의표:
단계목적길이 권장스킵 허용필수/선택
1. 환영가치 한 줄 + 사용자 호명헤드라인 1줄 + 부제 1줄✅ (스킵 시 [3]으로)필수 표시, 스킵 가능
2. 기능 3개"무엇을 할 수 있나"를 카드 3장카드 3장, 각 1줄 설명필수 표시, 스킵 가능
3. 학술 한계 + 위기 자원진단 아님 + 109 1줄 노출짧은 카드 1장❌ (스킵 금지·동의로 대체)필수
4. 동의개인정보/민감정보 동의동의 화면 (별도 스킬)필수
5. 첫 꿈 입력 가이드텍스트/음성/나중에 선택버튼 3개✅ (나중에 = 메인으로)선택
주의: 3·4단계는 절대 스킵 가능으로 두지 않는다. 학술 한계 고지·동의를 우회한 상태에서 앱이 동작하면 사용자 기대 형성 실패법적 리스크 양쪽 모두 발생한다.

NN/G建议尽可能避免首次启动引导本身(跳过概率高),但梦境解析应用因以下两个原因必须保留精简版引导
  1. 学术·法律局限性必须提前告知 — 明确说明非医学·心理学诊断、基于民俗学资料,需在首次使用前告知。若用户在使用中才发现,会形成错误预期。
  2. 危机资源需提前展示 — 等用户输入自杀·自伤信号后再展示109热线为时已晚,需让用户在输入信号前就知晓求助渠道。
因此,5阶段固定为以下顺序。每阶段1页,整体耗时控制在30~60秒以内。
[1] 欢迎 + 一句话价值点
[2] 3项功能介绍(梦境记录 · 解析卡片 · 重温梦境)
[3] 学术局限性 + 危机资源引导   ← 权限请求*前*先展示价值·局限性·安全资源
[4] 同意(个人信息·敏感信息·必填/可选)
[5] 首次梦境输入引导(现在文字输入 / 语音输入 / 稍后输入)
       └─ 仅当用户选择语音输入*时*请求麦克风权限(场景化)
          通知权限在*至少使用1次后*通过单独引导页请求
5阶段内容定义表:
阶段目的建议长度是否允许跳过必填/可选
1. 欢迎一句话价值点 + 用户称呼标题1行 + 副标题1行✅(跳过则直接进入[3])必须展示,可跳过
2. 3项功能通过3张卡片说明“能做什么”3张卡片,每张1行说明必须展示,可跳过
3. 学术局限性 + 危机资源说明非诊断类应用 + 展示109热线1行短卡片1张❌(禁止跳过·需确认同意)必填
4. 同意个人信息/敏感信息同意同意页面(单独技能)必填
5. 首次梦境输入引导选择文字/语音/稍后输入3个按钮✅(稍后输入 = 进入主页)可选
注意:绝对不能允许跳过3·4阶段。若用户绕过学术局限性告知·同意就使用应用,会导致用户预期偏差法律风险

2. 라이브러리 비교

2. 库对比

5단계 풀스크린 온보딩은 라이브러리 없이 직접 구현이 가장 효율적이다. 라이브러리는 기존 화면에 코치 마크를 띄우는 투어에 적합하다. 다음 표는 두 용도를 분리해 비교한다.
5阶段全屏引导最适合自定义实现,无需依赖库。库更适合在现有页面上展示引导标记的导览。下表按两种用途分别对比:

2-1. 풀스크린 5단계 온보딩 (직접 구현 우선)

2-1. 全屏5阶段引导(优先自定义实现)

라이브러리라이선스적합도판단
직접 구현 (Headless UI / Radix Dialog)(없음)⭐⭐⭐5단계 화면은 각 단계의 UI가 다르고(카드 3장 / 한 줄 고지 / 동의 체크박스 / 버튼 3개) 라이브러리의 step 추상화가 오히려 방해. 단계 관리는
useState
로 충분.
framer-motion
+ 라우터
MIT⭐⭐⭐단계 간 전환 애니메이션이 필요할 때만 추가.
prefers-reduced-motion
자동 존중.
react-joyrideMIT풀스크린에는 과함. 5단계를 모달로만 띄우면 spotlight·floater 기능을 안 쓰게 된다.
授权协议适配度判断理由
自定义实现(Headless UI / Radix Dialog)⭐⭐⭐5阶段页面每个阶段的UI都不同(3张卡片 / 一行告知 / 同意复选框 / 3个按钮),库的步骤抽象反而会造成阻碍。使用
useState
即可完成阶段管理。
framer-motion
+ 路由
MIT⭐⭐⭐仅在需要阶段切换动画时添加。自动兼容
prefers-reduced-motion
react-joyrideMIT对于全屏引导过于冗余。若仅用模态框展示5阶段,spotlight·floater功能会被闲置。

2-2. 기존 화면 위 코치 마크 투어 (재방문·신기능 안내용)

2-2. 现有页面上的引导标记导览(重访·新功能介绍用)

라이브러리최신 버전라이선스키보드/ARIA/포커스 트랩비고
react-joyride3.1.0 (2026-04)MIT✅ (공식 명시)가장 보편적. React 16.8+~19 지원.
useJoyride
훅 (v3 신규) / Floating UI / SVG spotlight. 상용 무제한 가능.
@reactour/tour3.8.0MIT✅ (포커스 트랩 지원)react-joyride 대비 더 가벼움. 모노레포(
@reactour/popover
등) 구조.
intro.js-react7.xAGPL-3.0 / 상용 별도 구매△ (키보드 일부)22.9k stars로 가장 인기지만 상용 앱은 라이선스 비용 발생. 꿈 해몽 앱이 상용이면 회피.
shepherd.js15.xAGPL-3.0 / 상용 별도 구매Floating UI 기반. intro.js와 동일하게 상용 라이선스 이슈.
주의 (라이선스): intro.js와 shepherd.js는 AGPL-3.0이다. 무료 앱·오픈소스 학습 프로젝트면 문제없지만, 상용 앱·수익 모델 있는 앱은 상용 라이선스 구매가 필요하다. 라이선스 비용을 피하려면 MIT인 react-joyride 또는 @reactour/tour를 선택한다.
最新版本授权协议键盘/ARIA/焦点陷阱支持备注
react-joyride3.1.0 (2026-04)MIT✅(官方明确支持)最通用。支持React 16.8+~19。提供
useJoyride
钩子(v3新增) / Floating UI / SVG spotlight。可无限制用于商业项目。
@reactour/tour3.8.0MIT✅(支持焦点陷阱)相比react-joyride更轻量。采用单仓(
@reactour/popover
等)结构。
intro.js-react7.xAGPL-3.0 / 需单独购买商业授权△(部分支持键盘)拥有22.9k星标,人气最高,但商业应用需支付授权费用。若梦境解析应用为商业项目,建议避免使用。
shepherd.js15.xAGPL-3.0 / 需单独购买商业授权基于Floating UI。与intro.js存在相同的商业授权问题。
注意(授权协议):intro.js和shepherd.js采用AGPL-3.0协议。免费应用·开源学习项目可正常使用,但商业应用·有盈利模式的应用需购买商业授权。若想避免授权费用,选择MIT协议的react-joyride或@reactour/tour。

2-3. 선택 가이드

2-3. 选择指南

풀스크린 5단계 온보딩이 필요한가?
 ├─ YES → 직접 구현 (Dialog 컴포넌트 5개를 state로 전환)
 └─ NO (기존 화면 위 코치 마크 투어인가?)
        ├─ React 프로젝트 + 상용 가능성 → react-joyride
        ├─ React 프로젝트 + 더 가벼운 것 → @reactour/tour
        ├─ Vue/Angular/순수 JS → shepherd.js (상용이면 라이선스 구매)
        └─ 단순 마케팅 페이지 투어 → intro.js (상용이면 라이선스 구매)

是否需要全屏5阶段引导?
 ├─ 是 → 自定义实现(用state切换5个Dialog组件)
 └─ 否(是否为现有页面上的引导标记导览?)
        ├─ React项目 + 可能用于商业 → react-joyride
        ├─ React项目 + 追求轻量 → @reactour/tour
        ├─ Vue/Angular/纯JS项目 → shepherd.js(商业项目需购买授权)
        └─ 简单营销页面导览 → intro.js(商业项目需购买授权)

3. 권한 요청 — 순서와 맥락

3. 权限请求 — 顺序与场景

핵심 원칙: 권한은 첫 화면이 아니라, 그 기능을 처음 사용하는 순간에 요청한다. (web.dev "Permission UX" / Google Meet 사례에서 이 패턴으로 허용률 14% 상승.)
核心原则: 权限不在首次页面请求,而是在首次使用对应功能时请求。(web.dev "Permission UX" / Google Meet案例显示,该模式可使权限接受率提升14%。)

3-1. 권한 요청 절대 타이밍

3-1. 权限请求绝对时机

권한요청 시점사전 priming거부 시
마이크5단계에서 사용자가 "음성으로 입력" 버튼을 눌렀을 때만1줄 — "꿈을 떠올리며 말씀해 주세요. 마이크 접근이 필요해요."텍스트 입력 fallback 제시, 차단하지 않음
알림첫 꿈 입력 완료 후 별도 priming 화면가치 설명 — "꿈은 아침에 빠르게 잊혀져요. 일어날 시간에 1줄 알림을 드릴까요?"정상 사용 유지. 설정 화면에서 재활성화 안내
카메라/사진꿈 일기에 사진 첨부 기능 처음 사용 시"꿈 이미지를 그려서 첨부할 수 있어요."첨부 없이 저장 가능
위치꿈 해몽 앱에서는 요청 금지— (요청 자체가 부적절)
权限请求时机提前引导语被拒绝时处理
麦克风仅当用户在5阶段点击“语音输入”按钮1行引导语 — “请回忆梦境并说出内容,需要访问麦克风权限。”提供文字输入备选方案,不阻断使用
通知首次梦境输入完成后通过单独引导页请求价值说明 — “梦境会在清晨快速遗忘,是否在起床时间发送1条提醒?”可正常使用应用,在设置页提示重新开启
相机/照片首次使用梦境日记添加照片功能“可以绘制梦境图片并添加。”可跳过添加直接保存
位置梦境解析应用禁止请求—(请求本身不合适)

3-2. priming 패턴 (마이크 예시)

3-2. 引导语模式(麦克风示例)

tsx
// 5단계 화면에서 "음성으로 입력"을 사용자가 누른 직후
function MicPriming({ onConfirm, onCancel }: Props) {
  return (
    <Dialog aria-labelledby="mic-priming-title">
      <h2 id="mic-priming-title">마이크로 꿈을 말씀해 주세요</h2>
      <p>
        말씀하신 내용은 *이 기기에서만* 처리되고, 동의 없이 외부로 전송되지 않아요.
      </p>
      <button onClick={onConfirm}>마이크 켜기</button>
      <button onClick={onCancel}>텍스트로 입력할게요</button>
    </Dialog>
  );
}

// onConfirm 콜백 안에서 비로소 getUserMedia 호출 (= 브라우저 권한 다이얼로그)
권한을 한 번 거부당하면 그 도메인에서 자동 재요청 불가(web.dev). 따라서 priming 화면에서 명백히 거부 의사가 있는 사용자는 절대 권한 다이얼로그까지 보내지 않는다. 텍스트 입력으로 우회시켜야 한다.
tsx
// 用户在5阶段点击“语音输入”按钮后立即展示
function MicPriming({ onConfirm, onCancel }: Props) {
  return (
    <Dialog aria-labelledby="mic-priming-title">
      <h2 id="mic-priming-title">用麦克风说出你的梦境</h2>
      <p>
        你所说的内容*仅在本机处理*,未经同意不会传输至外部。
      </p>
      <button onClick={onConfirm}>开启麦克风</button>
      <button onClick={onCancel}>我要文字输入</button>
    </Dialog>
  );
}

// 仅在onConfirm回调中调用getUserMedia(即浏览器权限弹窗)
权限被拒绝一次后,该域名无法自动重新请求(web.dev)。因此,若用户在引导页明确表示拒绝,绝对不要展示权限弹窗,应直接引导至文字输入。

3-3. 권한 일괄 요청 금지

3-3. 禁止批量请求权限

iOS·Android 네이티브 앱처럼 "마이크·알림·카메라를 한 번에 모두 요청"하는 패턴을 웹에서 흉내내는 것은 금지다. 사용자는 왜 지금 이 권한이 필요한가를 모르고 거부한다.

禁止模仿iOS·Android原生应用“一次性请求麦克风·通知·相机权限”的模式,在Web端绝对不能这么做。用户会因“不知道为什么现在需要这些权限”而拒绝。

4. 학술 한계 사용자 친화 변환

4. 学术局限性的用户友好转化

학술 박스("본 자료는 민속학적 자료로 의학적·심리학적 진단이 아닙니다")는 정확하지만 온보딩에 그대로 노출하면 사용자가 읽지 않는다. 다음 변환을 적용한다.
学术声明(“本资料为民俗学资料,非医学·心理学诊断”)虽然准确,但直接放在引导中用户不会阅读。需按以下方式转化:

4-1. 변환 원칙

4-1. 转化原则

학술 표현사용자 친화 표현
"민속학적 자료에 기반""옛 사람들이 꿈을 어떻게 해석했는지 모아둔 이야기예요"
"의학적 진단이 아님""병원 진료를 대신할 수는 없어요"
"심리학적 평가가 아님""심리 상담이 필요하면 전문가에게 닿게 해드릴게요"
"재미·자기 성찰 목적""꿈을 곱씹어 보는 조용한 시간이에요"
学术表述用户友好表述
“基于民俗学资料”“这是古人总结的梦境解读故事哦”
“非医学诊断”“不能替代医院诊疗”
“非心理学评估”“若需要心理咨询,我们会帮你对接专业人士”
“用于娱乐·自我反思”“这是一段让你细细品味梦境的安静时光

4-2. 3단계 화면 권장 문구 템플릿

4-2. 3阶段页面推荐文案模板

┌─────────────────────────────────────────────┐
│  🌙  꿈은 이야기지, 진단이 아니에요          │
│                                             │
│  이 앱의 해몽은 옛 사람들이 모은 이야기에    │
│  뿌리를 두고 있어요. 병원 진료나 상담을     │
│  대신할 수는 없어요.                         │
│                                             │
│  마음이 많이 무겁다면 언제든 도움을 청해도   │
│  괜찮아요.                                   │
│                                             │
│  ☎ 자살예방상담  109 (24시간·무료·익명)       │
│  ☎ 정신건강위기  1577-0199                   │
│                                             │
│  [ 알겠어요, 계속 ]                          │
└─────────────────────────────────────────────┘
주의: 위기 자원 번호·운영 시간은
humanities/crisis-intervention-resources-korea
짝 스킬을 반드시 그대로 인용한다. 본 스킬에서 임의로 다른 번호를 쓰지 않는다 (2024-01 109 통합 후
1393
은 사용 금지).
┌─────────────────────────────────────────────┐
│  🌙  梦境是故事,不是诊断哦          │
│                                             │
│  本应用的解读基于古人流传的故事,    │
│  不能替代医院诊疗或心理咨询。                         │
│                                             │
│  若你心情沉重,随时都可以寻求帮助哦。   │
│                                             │
│  ☎ 自杀预防咨询  109(24小时·免费·匿名)       │
│  ☎ 心理健康危机咨询  1577-0199                   │
│                                             │
│  [ 我知道了,继续 ]                          │
└─────────────────────────────────────────────┘
注意:危机资源号码·运营时间必须直接引用
humanities/crisis-intervention-resources-korea
关联技能
。本技能不得随意使用其他号码(2024-01起109整合后,禁止使用
1393
)。

4-3. 학술 한계를 어디에 한 번 더 노출하는가

4-3. 学术局限性额外展示位置

  • 3단계 온보딩 화면 1회 (위 템플릿)
  • 꿈 해몽 결과 화면 하단 영구 표시 ("이 해몽은 민속학적 이야기예요" 한 줄)
  • 설정 → 이 앱에 대하여 (전체 학술 박스 원문 + 출처)
3개 위치에 모두 두는 이유: 사용자는 해몽 결과를 본 순간에 한 번 더 한계를 인식해야 의학적 결정으로 오인하지 않는다.

  • 3阶段引导页面1次(上述模板)
  • 梦境解析结果页面底部永久展示(1行文字:“本解读为民俗学故事”)
  • 设置 → 关于本应用(完整学术声明原文 + 来源)
在3个位置都展示的原因:用户在看到解析结果时需再次知晓局限性,避免误将其作为医学决策依据。

5. 안전 자원 사전 안내

5. 安全资源提前告知

humanities/crisis-intervention-resources-korea
스킬이 언제, 어디서, 어떤 톤으로 노출되는지를 본 스킬이 정의한다.
노출 위치노출 형태
3단계 온보딩 화면한 줄씩 2개 (109 + 1577-0199)"도움을 청해도 괜찮아요" 초대형
메인 화면 햄버거 메뉴"도움이 필요할 때" 메뉴 항목상시 접근 가능
꿈 입력 화면 위기 키워드 감지 시인라인 안전 가드 (짝 스킬 문구)사용자 입력 직후 자연스럽게
설정 → 위기 자원 전체 목록짝 스킬 전체 내용상세
금지 패턴:
  • "자살하지 마세요" 같은 부정 명령 → 짝 스킬의 "그 마음 그대로 109에 전해도 괜찮아요" 톤으로 대체.
  • 109 번호만 노출하고 왜 전화해도 괜찮은지(무료·익명·24시간) 생략 → 사용자는 비용·신원 노출을 우려한다. 한 줄 자격 정보 함께 노출.

本技能定义
humanities/crisis-intervention-resources-korea
技能的展示时机·位置·语气
展示位置展示形式语气
3阶段引导页面2条1行内容(109 + 1577-0199)“随时可以寻求帮助哦”的邀请语气
主页汉堡菜单“需要帮助时”菜单项随时可访问
梦境输入页面检测到危机关键词时内嵌安全提示(关联技能文案)用户输入后自然展示
设置 → 危机资源完整列表关联技能全部内容详细正式
禁止模式:
  • 使用“不要自杀”等否定命令 → 替换为关联技能的*“你的心情可以直接告诉109哦”*语气。
  • 仅展示109号码,省略为什么可以拨打(免费·匿名·24小时) → 用户会担心费用·身份泄露,需同时展示1行说明信息。

6. 페르소나 분기

6. 用户分群

5단계 동일하나, 톤·기본값·기본 안내 위기 자원이 달라진다.
페르소나식별 시점기본 위기 자원기능 기본값
일반 사용자기본값친근·평어체 가능109·1577-0199음성/텍스트 동등
청소년 (만 14~18)만 19세 미만 자가 선택 또는 동의 화면 분기더 평이한 문구·이모지 가능1388 우선 + 109 병행 (짝 스킬 권고)텍스트 우선 (학교·가정에서 음성은 부담)
전문가 (연구·심리학 종사자)설정에서 자가 활성화학술 톤 허용109·1577-0199 + 학술 원문 노출학술 박스 접지 않고 펼친 상태
식별 방법:
  1. 1단계 환영 화면에서 "사용자에게 묻지 않는다" — 차별/낙인 위험.
  2. 4단계 동의 화면에서 법적으로 필요한 경우만 연령 확인(만 14세 미만 보호자 동의 필수). 청소년 페르소나는 연령 확인의 부산물로 자동 적용.
  3. 전문가 페르소나는 온보딩에서 묻지 않는다. 일반 온보딩을 끝낸 후 설정에서 opt-in.
주의: 청소년 페르소나에 1388을 대체가 아닌 우선으로 둔다. 자살 위기 직전에는 109가 더 빠른 응급 연계가 가능하므로 109 병행 노출이 필수다 (짝 스킬 정책).

5阶段结构相同,但语气·默认值·默认展示的危机资源会有所不同:
用户群识别时机语气默认危机资源功能默认值
普通用户默认值亲切·可使用口语109·1577-0199语音/文字输入同等优先级
青少年(14~18岁)用户自行选择未满19岁,或在同意页面分流可使用更平实的文案·表情优先展示1388 + 同时展示109(关联技能推荐)优先文字输入(在学校·家庭使用语音有压力)
专业人士(研究·心理学从业者)在设置中自行开启允许使用学术语气109·1577-0199 + 展示学术原文学术声明默认展开,不折叠
识别方法:
  1. 1阶段欢迎页面不主动询问 — 避免歧视·污名化风险。
  2. 仅在法律要求时在4阶段同意页面确认年龄(未满14岁需监护人同意)。青少年用户群作为年龄确认的副产品自动应用。
  3. 专业人士用户群不在引导中询问。用户完成普通引导后,在设置中主动开启
注意:青少年用户群需优先展示1388而非替代109。自杀危机紧急情况下109的应急响应更快,因此必须同时展示109(关联技能政策)。

7. 스킵·재방문 UX

7. 跳过·重访UX

7-1. 스킵 버튼

7-1. 跳过按钮

┌─────────────────────────────────────────────┐
│  [ 건너뛰기 ]                                │  ← 우측 상단에 항상 표시
│                                             │
│            (단계 콘텐츠)                     │
│                                             │
│       ●●○○○                                 │  ← 진행 점도 인터랙티브 (점 클릭 시 해당 단계로)
│                                             │
│  [ 이전 ]                       [ 다음 ]    │
└─────────────────────────────────────────────┘
  • 건너뛰기 위치: 우측 상단 (왼쪽은 뒤로가기와 혼동).
  • 3·4단계에서만 비활성화: 학술 한계·동의는 스킵 금지.
  • 건너뛰기 확인 다이얼로그 금지: 한 번 더 묻는 것은 사용자 학대다. 누르면 즉시 5단계로 이동.
┌─────────────────────────────────────────────┐
│  [ 跳过 ]                                │  ← 始终显示在右上角
│                                             │
│            (阶段内容)                     │
│                                             │
│       ●●○○○                                 │  ← 进度点可交互(点击跳转到对应阶段)
│                                             │
│  [ 上一步 ]                       [ 下一步 ]    │
└─────────────────────────────────────────────┘
  • 跳过按钮位置: 右上角(左侧易与返回键混淆)。
  • 仅在3·4阶段禁用: 学术局限性·同意阶段禁止跳过。
  • 禁止跳过确认弹窗: 再次询问属于用户骚扰,点击后直接进入5阶段。

7-2. 다시 보기

7-2. 重新查看

  • 설정 → "온보딩 다시 보기" 항목 영구 제공.
  • 신기능 출시 시 기존 사용자에게 5단계 전체를 다시 보여주지 않는다. 신기능만 코치 마크 1~2개로 (react-joyride 활용).
  • 设置中永久提供“重新查看引导”选项。
  • 发布新功能时不要向现有用户展示完整5阶段引导,仅用1~2个引导标记介绍新功能(使用react-joyride)。

7-3. 중단 후 재진입

7-3. 中断后重新进入

  • 사용자가 온보딩 중 앱을 종료했을 때, 다음 실행에서 처음부터 다시 시작. 중간 재개는 컨텍스트 혼동.
  • 단, 동의(4단계)를 완료했다면 그 결과는 보존하고 5단계로 점프.

  • 用户在引导中关闭应用,下次启动时从头开始。中途恢复会造成上下文混淆。
  • 但如果用户已完成同意(4阶段),则保留同意结果,直接跳转到5阶段。

8. 접근성

8. 可访问性

8-1. 키보드 (WCAG 2.1.1 Level A)

8-1. 键盘支持(WCAG 2.1.1 Level A)

  • 모든 단계 이동·스킵·동의 체크박스가 키보드만으로 조작 가능.
  • 단계 전환 시 포커스를 새 단계의 헤딩으로 이동 (
    heading.focus()
    또는
    aria-live="polite"
    영역에 단계 변경 안내).
  • 모달/Dialog 컴포넌트는 포커스 트랩 필수 — react-joyride·@reactour/tour는 기본 지원, 직접 구현 시
    focus-trap-react
    활용.
  • Esc
    키로 스킵 가능 (단, 3·4단계는 스킵 금지이므로
    Esc
    무시).
  • 所有阶段切换·跳过·同意复选框均可仅用键盘操作。
  • 阶段切换时将焦点移至新阶段的标题(使用
    heading.focus()
    aria-live="polite"
    区域提示阶段变更)。
  • 模态框/Dialog组件必须支持焦点陷阱 — react-joyride·@reactour/tour默认支持,自定义实现时使用
    focus-trap-react
  • 可使用
    Esc
    键跳过(但3·4阶段禁止跳过,因此忽略
    Esc
    键)。

8-2. 스크린 리더

8-2. 屏幕阅读器

  • 단계 인디케이터(진행 점)는
    aria-label="2단계 / 전체 5단계"
    동적 갱신.
  • 위기 자원 번호는
    <a href="tel:109">
    으로 감싸 원터치 발신 지원 (sr이 "전화 걸기 109" 안내).
  • 학술 한계 카드는
    role="region" aria-labelledby="limit-title"
    반드시 읽히게 한다 (지나치지 않게).
  • 阶段指示器(进度点)需动态更新
    aria-label="第2阶段 / 共5阶段"
  • 危机资源号码用
    <a href="tel:109">
    包裹,支持一键拨号(屏幕阅读器会提示“拨打109”)。
  • 学术局限性卡片需设置
    role="region" aria-labelledby="limit-title"
    ,确保一定会被读取(不会被跳过)。

8-3. 모션 감소 (WCAG C39)

8-3. 减少动画(WCAG C39)

css
/* 단계 전환 슬라이드 애니메이션 */
.step-enter { transform: translateX(20px); opacity: 0; transition: all 0.3s; }

@media (prefers-reduced-motion: reduce) {
  .step-enter { transform: none; transition: opacity 0.01s; }
}
  • framer-motion
    useReducedMotion()
    훅을 제공하므로 그 결과로 분기.
  • 스플래시 별·달 애니메이션도 동일하게 정지 처리.

css
/* 阶段切换滑动动画 */
.step-enter { transform: translateX(20px); opacity: 0; transition: all 0.3s; }

@media (prefers-reduced-motion: reduce) {
  .step-enter { transform: none; transition: opacity 0.01s; }
}
  • framer-motion
    提供
    useReducedMotion()
    钩子,可根据结果分支处理。
  • 启动页的星星·月亮动画也需做同样的停止处理。

9. 측정 — 온보딩 완료율과 단계별 이탈

9. 衡量 — 引导完成率与阶段流失率

data-analyst
에이전트와 협업해 다음 지표를 추적한다.
data-analyst
协作追踪以下指标:

9-1. 핵심 지표

9-1. 核心指标

지표정의산업 평균 / 목표
온보딩 완료율5단계 완료 사용자 / 1단계 진입 사용자34단계 투어 산업 평균 7274% — 5단계는 60% 이상 목표
단계별 이탈률(해당 단계 이탈) / (해당 단계 진입)첫 단계 이탈 산업 평균 약 38% — 2단계 이내 25% 미만 목표
평균 완료 시간1단계 시작 ~ 5단계 완료30~60초 이내
마이크 권한 허용률priming 후 권한 허용 / priming 노출Google Meet 사례 +14% — 55% 이상 목표
알림 권한 허용률priming 후 권한 허용 / priming 노출첫 사용 후 priming 적용 시 30~40%
동의 거부율4단계 동의 거부 사용자 / 4단계 진입5% 미만 (높으면 동의 문구 재검토)
指标定义行业平均 / 目标
引导完成率完成5阶段的用户数 / 进入1阶段的用户数34阶段导览行业平均7274% — 5阶段目标60%以上
阶段流失率(该阶段流失用户数) / (进入该阶段用户数)第一阶段流失率行业平均约38% — 2阶段以内流失率目标25%以下
平均完成时间1阶段开始 ~ 5阶段完成30~60秒以内
麦克风权限接受率引导后同意权限的用户数 / 看到引导的用户数Google Meet案例提升14% — 目标55%以上
通知权限接受率引导后同意权限的用户数 / 看到引导的用户数首次使用后引导的情况下为30~40%
同意拒绝率4阶段拒绝同意的用户数 / 进入4阶段用户数目标5%以下(若过高需重新优化同意文案)

9-2. 이벤트 정의 예시

9-2. 事件定义示例

ts
// 분석 도구(Amplitude/Mixpanel/PostHog)에 전송할 이벤트
trackEvent('onboarding_step_view', { step: 1, persona: 'general' });
trackEvent('onboarding_step_complete', { step: 1, duration_ms: 4200 });
trackEvent('onboarding_skip', { from_step: 2 });
trackEvent('onboarding_complete', { total_duration_ms: 38000, persona: 'general' });

trackEvent('permission_priming_view', { permission: 'microphone' });
trackEvent('permission_priming_accept', { permission: 'microphone' });
trackEvent('permission_priming_decline', { permission: 'microphone' });
trackEvent('permission_native_result', { permission: 'microphone', result: 'granted' });
주의: 위 이벤트는 민감정보가 아닌 사용 흐름 데이터다. 꿈 텍스트·음성은 절대 분석 이벤트로 전송하지 않는다 (
dream-privacy-consent-ui
짝 스킬 정책).
ts
// 发送至分析工具(Amplitude/Mixpanel/PostHog)的事件
trackEvent('onboarding_step_view', { step: 1, persona: 'general' });
trackEvent('onboarding_step_complete', { step: 1, duration_ms: 4200 });
trackEvent('onboarding_skip', { from_step: 2 });
trackEvent('onboarding_complete', { total_duration_ms: 38000, persona: 'general' });

trackEvent('permission_priming_view', { permission: 'microphone' });
trackEvent('permission_priming_accept', { permission: 'microphone' });
trackEvent('permission_priming_decline', { permission: 'microphone' });
trackEvent('permission_native_result', { permission: 'microphone', result: 'granted' });
注意:上述事件仅包含非敏感的使用流程数据。绝对不能将梦境文字·语音内容作为分析事件发送(遵循
dream-privacy-consent-ui
关联技能政策)。

9-3. 이탈 단계 우선순위 진단

9-3. 流失阶段优先级诊断

  • 절대 수 가 큰 단계부터 개선 (50%×100명 > 50%×10명).
  • 2단계 기능 소개에서 이탈이 크면 → 카드 수 줄이거나 카드별 문구 단축.
  • 4단계 동의에서 이탈이 크면 → 동의 문구 친근 톤 재변환, 선택 동의를 기본 OFF로.

  • 优先优化用户基数大的阶段(50%×100用户 > 50%×10用户)。
  • 若2阶段功能介绍流失率高 → 减少卡片数量或缩短每张卡片的文案。
  • 若4阶段同意流失率高 → 将同意文案转化为亲切语气,可选同意项默认关闭

10. 흔한 함정

10. 常见陷阱

함정왜 문제인가해결
권한 일괄 요청"왜 지금?"이 없으면 거부율 폭증, 한 번 거부 시 재요청 불가기능 사용 직전 priming 후 단일 권한만 요청
7단계 이상 온보딩산업 데이터상 7+단계는 완료율 16%로 급락5단계 고정. 콘텐츠 추가 시 기능 카드에 흡수, 단계 늘리지 않음
강제 동의 (필수 + 선택을 한 체크박스)법적 무효 가능 + 신뢰 손상필수와 선택을 별도 체크박스로 분리 (
dream-privacy-consent-ui
짝 스킬)
학술 박스 원문 그대로 노출사용자는 읽지 않고 스킵4-1 변환표대로 사용자 친화 문구로 변환
위기 자원을 위기 신호 입력 후에만 노출신호가 오기 전 사용자는 도움받을 곳을 모름3단계 온보딩 + 메뉴 + 결과 화면 하단에 상시 노출
청소년에게 1388 없이 109만청소년은 109 콜에 심리 장벽 (짝 스킬 정책)1388 우선·109 병행
1393 번호 사용2024-01부 109로 통합됨109로 갱신 (짝 스킬 변경 이력 확인)
스킵 시 학술 한계까지 건너뛰기사용자가 기대 형성 실패 → 잘못된 의학적 해석3·4단계는 스킵 불가로 분리
단계 변경 시 포커스 미이동스크린 리더 사용자가 상태 변경 인지 불가새 단계 헤딩에
focus()
스킵 후 확인 다이얼로그사용자 학대 ("정말 건너뛰시겠어요?")즉시 5단계로 이동, 묻지 않음
prefers-reduced-motion
무시
멀미·전정 장애 사용자에게 고통모든 단계 전환·스플래시 애니메이션에 미디어 쿼리 적용
마이크 권한 거부 시 기능 차단텍스트로도 입력 가능한데 막힘텍스트 입력 fallback 항상 유지
알림 권한을 1단계에서 요청가치 인지 전 거부 → 도메인 단위 영구 거부첫 꿈 입력 완료 후 priming
페르소나를 질문으로 파악차별·낙인 위험연령 확인의 부산물로만 자동 분기
한 줄 동의 "동의함" 단일 체크박스무엇에 동의하는지 모호 → 법적 무효필수/선택 분리 + 항목별 링크 (
dream-privacy-consent-ui
)

陷阱问题原因解决方案
批量请求权限用户因“不知道为什么现在需要”而拒绝率暴增,且拒绝后无法自动重新请求功能使用前添加引导语,仅请求单个权限
7阶段以上引导行业数据显示7+阶段引导完成率骤降至16%固定为5阶段。新增内容需融入功能卡片,不得增加阶段数
强制同意(必填+可选合并为一个复选框)可能导致法律无效 + 用户信任受损将必填和可选同意拆分为单独复选框(遵循
dream-privacy-consent-ui
关联技能)
直接展示学术声明原文用户不会阅读直接跳过按4-1转化表改为用户友好文案
仅在检测到危机信号后展示危机资源用户在发出信号不知道求助渠道在3阶段引导 + 菜单 + 结果页面底部永久展示
仅向青少年展示109,不展示1388青少年对109电话存在心理障碍(关联技能政策)优先展示1388·同时展示109
使用1393号码2024-01起已整合为109更新为109(确认关联技能变更记录)
跳过引导时同时跳过学术局限性告知用户形成错误预期 → 误将解读作为医学依据将3·4阶段设置为不可跳过
阶段切换时不移除焦点屏幕阅读器用户无法感知状态变化将焦点移至新阶段标题
跳过引导时弹出确认弹窗用户骚扰(“确定要跳过吗?”)直接跳转到5阶段,不询问
忽略
prefers-reduced-motion
会给晕车·前庭障碍用户带来不适对所有阶段切换·启动页动画应用媒体查询
麦克风权限被拒绝时阻断功能用户仍可使用文字输入,不应阻断始终保留文字输入备选方案
在1阶段请求通知权限用户未感知价值就拒绝 → 域名级永久拒绝在首次梦境输入完成后添加引导语
通过提问识别用户群存在歧视·污名化风险仅作为年龄确认的副产品自动分流
单一复选框“同意”用户不清楚同意内容 → 法律无效拆分必填/可选 + 添加每项的链接(遵循
dream-privacy-consent-ui

11. 직접 구현 스켈레톤 (Next.js / React)

11. 自定义实现框架(Next.js / React)

tsx
// app/(onboarding)/page.tsx
'use client';

import { useState } from 'react';
import { WelcomeStep } from './_steps/WelcomeStep';
import { FeaturesStep } from './_steps/FeaturesStep';
import { LimitsStep } from './_steps/LimitsStep';
import { ConsentStep } from './_steps/ConsentStep';
import { FirstDreamStep } from './_steps/FirstDreamStep';

type StepIndex = 1 | 2 | 3 | 4 | 5;
const NON_SKIPPABLE: ReadonlySet<StepIndex> = new Set([3, 4]);

export default function OnboardingPage() {
  const [step, setStep] = useState<StepIndex>(1);

  const goNext = () => setStep((s) => Math.min(5, s + 1) as StepIndex);
  const goPrev = () => setStep((s) => Math.max(1, s - 1) as StepIndex);
  const skip = () => {
    if (NON_SKIPPABLE.has(step)) return; // 3·4단계 스킵 차단
    setStep(5);
  };

  return (
    <main role="region" aria-labelledby="onboarding-title">
      <ProgressDots current={step} total={5} />
      <SkipButton onClick={skip} disabled={NON_SKIPPABLE.has(step)} />

      {step === 1 && <WelcomeStep onNext={goNext} />}
      {step === 2 && <FeaturesStep onNext={goNext} onPrev={goPrev} />}
      {step === 3 && <LimitsStep onNext={goNext} />}     {/* 스킵 불가 */}
      {step === 4 && <ConsentStep onNext={goNext} />}    {/* 스킵 불가 */}
      {step === 5 && <FirstDreamStep />}
    </main>
  );
}
tsx
// app/(onboarding)/_steps/LimitsStep.tsx
'use client';
import { useEffect, useRef } from 'react';

export function LimitsStep({ onNext }: { onNext: () => void }) {
  const headingRef = useRef<HTMLHeadingElement>(null);

  // 단계 진입 시 헤딩에 포커스 (스크린 리더 안내)
  useEffect(() => { headingRef.current?.focus(); }, []);

  return (
    <section>
      <h2 ref={headingRef} tabIndex={-1} id="limits-title">
        꿈은 이야기지, 진단이 아니에요
      </h2>
      <p>
        이 앱의 해몽은 옛 사람들이 모은 이야기에 뿌리를 두고 있어요.
        병원 진료나 상담을 대신할 수는 없어요.
      </p>
      <p>마음이 많이 무겁다면 언제든 도움을 청해도 괜찮아요.</p>

      <ul role="list" aria-label="위기 자원">
        <li><a href="tel:109">자살예방상담 109</a> (24시간·무료·익명)</li>
        <li><a href="tel:1577-0199">정신건강위기상담 1577-0199</a> (24시간)</li>
      </ul>

      <button onClick={onNext}>알겠어요, 계속</button>
    </section>
  );
}
tsx
// app/(onboarding)/_steps/FirstDreamStep.tsx
'use client';
import { useState } from 'react';
import { MicPriming } from '@/components/MicPriming';

export function FirstDreamStep() {
  const [primingOpen, setPrimingOpen] = useState(false);

  return (
    <section>
      <h2>지금, 꿈을 적어볼까요?</h2>

      <button onClick={() => goToTextInput()}>텍스트로 입력</button>
      <button onClick={() => setPrimingOpen(true)}>음성으로 입력</button>
      <button onClick={() => goToHome()}>나중에</button>

      {primingOpen && (
        <MicPriming
          onConfirm={async () => {
            // 사용자 명시 동의 후에만 getUserMedia 호출 (= 브라우저 권한 다이얼로그)
            await navigator.mediaDevices.getUserMedia({ audio: true });
            goToVoiceInput();
          }}
          onCancel={() => setPrimingOpen(false)}
        />
      )}
    </section>
  );
}
주의: 위 스켈레톤의
getUserMedia
·마이크 상태 관리는 최소 예시다. 실제 구현은
frontend/voice-input-ui
스킬의 상태 머신·에러 처리·정리(
stream.getTracks().stop()
)를 그대로 따른다.

tsx
// app/(onboarding)/page.tsx
'use client';

import { useState } from 'react';
import { WelcomeStep } from './_steps/WelcomeStep';
import { FeaturesStep } from './_steps/FeaturesStep';
import { LimitsStep } from './_steps/LimitsStep';
import { ConsentStep } from './_steps/ConsentStep';
import { FirstDreamStep } from './_steps/FirstDreamStep';

type StepIndex = 1 | 2 | 3 | 4 | 5;
const NON_SKIPPABLE: ReadonlySet<StepIndex> = new Set([3, 4]);

export default function OnboardingPage() {
  const [step, setStep] = useState<StepIndex>(1);

  const goNext = () => setStep((s) => Math.min(5, s + 1) as StepIndex);
  const goPrev = () => setStep((s) => Math.max(1, s - 1) as StepIndex);
  const skip = () => {
    if (NON_SKIPPABLE.has(step)) return; // 3·4阶段禁止跳过
    setStep(5);
  };

  return (
    <main role="region" aria-labelledby="onboarding-title">
      <ProgressDots current={step} total={5} />
      <SkipButton onClick={skip} disabled={NON_SKIPPABLE.has(step)} />

      {step === 1 && <WelcomeStep onNext={goNext} />}
      {step === 2 && <FeaturesStep onNext={goNext} onPrev={goPrev} />}
      {step === 3 && <LimitsStep onNext={goNext} />}     {/* 不可跳过 */}
      {step === 4 && <ConsentStep onNext={goNext} />}    {/* 不可跳过 */}
      {step === 5 && <FirstDreamStep />}
    </main>
  );
}
tsx
// app/(onboarding)/_steps/LimitsStep.tsx
'use client';
import { useEffect, useRef } from 'react';

export function LimitsStep({ onNext }: { onNext: () => void }) {
  const headingRef = useRef<HTMLHeadingElement>(null);

  // 进入阶段时将焦点移至标题(屏幕阅读器提示)
  useEffect(() => { headingRef.current?.focus(); }, []);

  return (
    <section>
      <h2 ref={headingRef} tabIndex={-1} id="limits-title">
        梦境是故事,不是诊断哦
      </h2>
      <p>
        本应用的解读基于古人流传的故事,
        不能替代医院诊疗或心理咨询。
      </p>
      <p>若你心情沉重,随时都可以寻求帮助哦。</p>

      <ul role="list" aria-label="危机资源">
        <li><a href="tel:109">自杀预防咨询 109</a>(24小时·免费·匿名)</li>
        <li><a href="tel:1577-0199">心理健康危机咨询 1577-0199</a>(24小时)</li>
      </ul>

      <button onClick={onNext}>我知道了,继续</button>
    </section>
  );
}
tsx
// app/(onboarding)/_steps/FirstDreamStep.tsx
'use client';
import { useState } from 'react';
import { MicPriming } from '@/components/MicPriming';

export function FirstDreamStep() {
  const [primingOpen, setPrimingOpen] = useState(false);

  return (
    <section>
      <h2>现在,来记录你的梦境吧?</h2>

      <button onClick={() => goToTextInput()}>文字输入</button>
      <button onClick={() => setPrimingOpen(true)}>语音输入</button>
      <button onClick={() => goToHome()}>稍后再记录</button>

      {primingOpen && (
        <MicPriming
          onConfirm={async () => {
            // 仅在用户明确同意后调用getUserMedia(即浏览器权限弹窗)
            await navigator.mediaDevices.getUserMedia({ audio: true });
            goToVoiceInput();
          }}
          onCancel={() => setPrimingOpen(false)}
        />
      )}
    </section>
  );
}
注意:上述框架中的
getUserMedia
·麦克风状态管理仅为最简示例。实际实现需完全遵循
frontend/voice-input-ui
技能的状态机·错误处理·资源清理(
stream.getTracks().stop()
)逻辑。

12. 체크리스트

12. 检查清单

스킬을 실제 코드에 적용할 때 빠진 항목이 없는지 확인:
  • 5단계가 정확히 5개인가 (확장 시 카드 흡수, 단계 추가 금지)
  • 3·4단계에서 스킵 버튼이 비활성화되어 있는가
  • 학술 한계 문구가 4-1 변환표대로 친근화되었는가
  • 109·1577-0199 번호가 짝 스킬 기준과 일치하는가 (
    1393
    없음)
  • 마이크 권한이 5단계 버튼 클릭 후에만 요청되는가
  • 알림 권한이 온보딩 외부 (첫 사용 후)로 분리되었는가
  • 청소년 페르소나에 1388 우선·109 병행이 적용되었는가
  • 단계 전환 시 새 헤딩에 포커스가 이동하는가
  • prefers-reduced-motion
    이 모든 애니메이션에 적용되었는가
  • 분석 이벤트에 꿈 텍스트·음성 본문이 포함되지 않는가
  • 라이선스 호환성 확인 (intro.js / shepherd.js는 상용 라이선스 필요)
将本技能应用到实际代码时,确认以下项目是否完成:
  • 阶段数严格为5个(新增内容融入卡片,不得增加阶段)
  • 3·4阶段的跳过按钮已禁用
  • 学术局限性文案已按4-1转化表改为用户友好表述
  • 109·1577-0199号码与关联技能标准一致(无
    1393
  • 麦克风权限仅在5阶段按钮点击后请求
  • 通知权限已分离至引导外(首次使用后)
  • 青少年用户群已应用优先展示1388·同时展示109的设置
  • 阶段切换时焦点已移至新阶段标题
  • prefers-reduced-motion
    已应用到所有动画
  • 分析事件中未包含梦境文字·语音内容
  • 已确认授权协议兼容性(intro.js / shepherd.js商业项目需购买授权)