Brand and design · Specs
Onboarding
Rationale, questions, mapping to /v1/onboarding and the plan.
Screens: screens/onboarding/* (welcome + 6 steps, each with default and selected states), then screens/diagnostic/diag-intro. All copy is in copy.md under Onboarding, in en and zh-Hans.
Rationale
- Get to the real thing fast. Onboarding exists to feed the diagnostic and the plan, so it asks only what changes the product: practice language, goal, scenario (+ optional topics), self-level, weekly days, reminder time. Six taps, one question per screen, under 60 seconds.
- Every answer has a visible consequence. The practice language sets the diagnostic article. The goal and scenario pick articles and advice phrasing. Weekly days pre-fill the paywall slider and calendar. Reminder time drives the single daily notification. Self-level is only a prior; the diagnostic overrides it.
- Honesty up front. The welcome screen states under the CTA that third-party AI processes recordings and never trains on them (D6). The diagnostic intro states it is a real assessment and free. The mic sheet explains before the system prompt.
- No account wall. An anonymous server account already exists (
POST /auth/anonymous). Sign in with Apple is offered later, in Profile, once there is something to lose. - Language is two separate things (D13). The UI language follows the device (overridable in Settings). The practice language is what you read and speak in. The language step defaults to the device locale and says where the UI language is changed, so a Chinese-UI user can practise English and the other way round.
Steps, copy and mapping
| # | Screen | Question (en / zh-Hans) | Options → OnboardingAnswers value |
Default | Used for |
|---|---|---|---|---|---|
| 0 | welcome | "Ten minutes a day. Say complex things clearly." / 每天十分钟,把复杂的事讲清楚。 | — | — | Legal + AI disclosure |
| 1 | language | "Which language do you want to practise?" / 你想练习哪种语言? | English → practice_language: en · 中文(简体) → zh-Hans (options from config.supported_practice_languages, shown as endonyms) |
device locale, pre-selected | Diagnostic article language; settings.practice_languages = [x]; daily quest / library filter |
| 2 | goal | "What do you most want to improve?" / 你最想提升哪一点? | Explain clearly at work → report_clearly · Remember what I read → remember_more · Create content → create_content · Be more concise → speak_concisely |
none (CTA disabled) | Plan copy emphasis; quick-pick subtitles; candidate one-actions |
| 3 | scenario | "Where do you need to speak most?" / 你常在哪里需要表达? | Meetings and updates → work_meeting · Study and exams → study · Video and podcasts → creator · Everyday conversations → social; + optional topic chips → preferred_topics[] |
none | Article selection (topics); example sentences in the scenario's register |
| 4 | self-level | "How do you speak today?" / 你现在讲得怎么样? | beginner · sometimes_clear · mostly_clear |
none | Prior for the first article's difficulty if the diagnostic is unreliable; copy tone |
| 5 | commitment | "How many days a week?" / 每周想练几天? + "When should we remind you?" / 什么时候提醒你? | 3 / 5 / 7 → weekly_days; wheel → reminder_time (HH:mm local) |
5 · 08:30 | Paywall slider default (CCR-7), plan calendar practice days, reminder schedule |
| 6 | notification-priming | "One reminder a day" / 每天提醒你一次 | Turn on reminders → iOS prompt → PUT /me/push-token; Not now → reminders_enabled: false |
— | D10: max 1 notification/day |
On step 6, either button sends POST /v1/onboarding with every answer. The response returns {diagnostic_session, article}. The article is in practice_language and is prefetched so the diagnostic read screen opens instantly.
How answers feed the plan
diagnostic assessment (in practice_language)
└─ weakest dimension (lowest score; ties → structure > key_info > efficiency > fluency)
└─ target_micro_skill = diagnostic one_action.micro_skill_id
└─ Plan.days[1..14].micro_skill_id (server, D9)
├─ days 1, 2, 4, 7, 11, 14 = target skill (7 = weekly review, 14 = re-test vs baseline)
└─ other days rotate supporting skills, biased by goal:
report_clearly / speak_concisely → three_points, cut_fillers, drop_repeats
remember_more → keep_constraints, name_the_claim
create_content → one_example, name_the_claim
weekly_days → which plan days are practice days in the paywall calendar (pattern in paywall.md);
the plan never "fails" a missed day — status becomes `missed`, nothing to make up
reminder_time → local notification schedule (engagement.md)
preferred_topics + practice_languages → daily quest article selection (highest unlocked tier, unseen first)
Edge cases
- Device locale isn't supported (e.g. ja): UI falls back to
en, and the language step pre-selectsen. - User changes the practice language later: the plan stays (micro-skills are language-independent). New quests come in the new language. Ability is per user (D13), and growth can filter by language.
- Diagnostic unreliable twice: offer "Skip for now" → plan built from self-level (prior) with
baseline_overall = null; the paywall hides the projection. This is a backend follow-up and is listed in Known gaps. - Kill during onboarding: answers persist locally; relaunch resumes at the last unanswered step (
me.onboarding.status = not_started). - Notification permission previously denied at OS level: step 6 shows "Turn on reminders" → opens Settings instead of the prompt.