Brand and design · Hi-fi screens · S16 Home · Home
Data-binding map: S16 Home · Home
Data-binding map of Home · Home: every field to its source, and what each required state shows.
Generated by
botgumi-design indexfrom../../screens.json. Edit that file, not this page.
Every field S16 shows and where it comes from.
| Field | Source (endpoint or local state) | Format | Fallback |
|---|---|---|---|
| streak pill | api GET /home streak.current · home.streak.current / today_done / at_risk |
amber; filled flame when today_done; outline when at_risk; grey at 0 |
cached |
| streak pill | api GET /home streak.today_done |
||
| streak pill | api GET /home streak.at_risk |
||
| date label | api GET /home local_date_label · home.local_date_label (Accept-Language) |
as is | weekday from device |
| greeting + name | api GET /home greeting · home.greeting (Accept-Language) + home.display_name |
home.greeting.format |
name fallback "练习者 / Learner" from API |
| greeting + name | api GET /home display_name |
||
| level | api GET /home level.level · home.level.level / title (Accept-Language) / xp_into_level / xp_for_next |
lime-on-ink bar | — |
| level | api GET /home level.title |
||
| level | api GET /home level.xp_into_level |
||
| level | api GET /home level.xp_for_next |
||
| quest badge | api GET /home today_quest.xp_reward · home.today_quest.xp_reward (CCR-4) |
+N XP |
hide badge |
| quest meta | api GET /home today_quest.article.topic.name · today_quest.article.topic.name (Accept-Language), article.length.label (Accept-Language), est_read_seconds |
topic · length · read time |
drop missing parts |
| quest meta | api GET /home today_quest.article.length.label |
||
| quest meta | api GET /home today_quest.article.est_read_seconds |
||
| quest title | api GET /home today_quest.article.title · today_quest.article.title (article language) |
lang= |
— |
| plan day tag | api GET /home today_quest.plan_day · today_quest.plan_day |
home.quest.plan_day |
hide when null |
| focus chip | api GET /home focus.title · home.focus.title (Accept-Language) |
home.quest.focus.last (or .diagnostic when focus.suggested_count = 1 and no completed sessions) |
hide when focus null |
| 3-step path | api GET /home today_quest.steps[].key · today_quest.steps[].key / label (Accept-Language) / state |
done = lime ✓, current = white ring | — |
| 3-step path | api GET /home today_quest.steps[].label |
||
| 3-step path | api GET /home today_quest.steps[].state |
||
| CTA | api GET /home today_quest.status · today_quest.status, session_id |
start / continue (home.quest.cta.resume.<stage>) |
— |
| CTA | api GET /home today_quest.session_id |
||
| completed summary | api GET /home today_quest.summary · CCR-2 today_quest.summary |
68 → 79, secs_delta, +XP |
hide row |
| streak-risk card | api GET /home streak.at_risk · home.streak.at_risk, freezes |
home.risk.* |
hide card |
| streak-risk card | api GET /home streak.freezes |
||
| topic chips | api GET /home topics[].name · home.topics[].name (Accept-Language) |
— | hide row |
| quick pick | local home.selected_topic · home.quick_picks[topic = selected] → title, subtitle (Accept-Language), article, topic.glyph/color_token |
— | none for topic → empty card (home.picks.empty.*) |
| quick pick | api GET /home quick_picks[].title |
||
| quick pick | api GET /home quick_picks[].subtitle |
||
| quick pick | api GET /home quick_picks[].article |
||
| quick pick | api GET /home quick_picks[].topic.glyph |
||
| quick pick | api GET /home quick_picks[].topic.color_token |
||
| resume sheet | api GET /home resume_session.article.title · home.resume_session.article.title / stage / created_at / round1_overall |
resume.stage |
not shown when null |
| resume sheet | api GET /home resume_session.stage |
||
| resume sheet | api GET /home resume_session.created_at |
||
| resume sheet | api GET /home resume_session.round1_overall |
||
| offline banner | device network · NWPathMonitor + local:cache.home.fetchedAt |
home.offline (HH:mm) |
— |
| offline banner | local cache.home.fetchedAt |
||
NWPathMonitor + local:cache.home.fetchedAt |
device network · From the board's data-bind; no row in data-binding.md yet. |
||
NWPathMonitor + local:cache.home.fetchedAt |
local cache.home.fetchedAt |
||
POST /v1/sessions {article_id, kind: daily} |
call POST /sessions · From the board's data-bind; no row in data-binding.md yet. |
||
error.code |
status GET /home 5XX internal · pending CCR-14 · From the board's data-bind; no row in data-binding.md yet. |
||
error.message (Accept-Language) |
status GET /home 5XX internal · pending CCR-14 · From the board's data-bind; no row in data-binding.md yet. |
||
home.focus.title (Accept-Language) |
api GET /home focus.title · From the board's data-bind; no row in data-binding.md yet. |
||
home.greeting (Accept-Language) |
api GET /home greeting · From the board's data-bind; no row in data-binding.md yet. |
||
home.level.title (Accept-Language) |
api GET /home level.title · From the board's data-bind; no row in data-binding.md yet. |
||
home.level.xp_into_level / xp_for_next |
api GET /home level.xp_into_level · From the board's data-bind; no row in data-binding.md yet. |
||
home.level.xp_into_level / xp_for_next |
api GET /home level.xp_for_next |
||
home.local_date_label (Accept-Language) |
api GET /home local_date_label · From the board's data-bind; no row in data-binding.md yet. |
||
home.quick_picks[0].article.id |
api GET /home quick_picks[].article.id · From the board's data-bind; no row in data-binding.md yet. |
||
home.quick_picks[0].subtitle |
api GET /home quick_picks[].subtitle · From the board's data-bind; no row in data-binding.md yet. |
||
home.quick_picks[0].title |
api GET /home quick_picks[].title · From the board's data-bind; no row in data-binding.md yet. |
||
home.quick_picks[0].topic.glyph / color_token |
api GET /home quick_picks[].topic.glyph · From the board's data-bind; no row in data-binding.md yet. |
||
home.quick_picks[0].topic.glyph / color_token |
api GET /home quick_picks[].topic.color_token |
||
home.quick_picks[topic=tech] = ∅ (topic.article_count = 0) |
api GET /home quick_picks[] · From the board's data-bind; no row in data-binding.md yet. |
||
home.streak.at_risk + freezes |
api GET /home streak.at_risk · From the board's data-bind; no row in data-binding.md yet. |
||
home.streak.at_risk + freezes |
api GET /home streak.freezes |
||
home.today_quest = null (CCR-1) |
api GET /home today_quest · From the board's data-bind; no row in data-binding.md yet. |
||
home.today_quest.article.title |
api GET /home today_quest.article.title · From the board's data-bind; no row in data-binding.md yet. |
||
home.today_quest.article.topic.name / length.label / est_read_seconds |
api GET /home today_quest.article.topic.name · From the board's data-bind; no row in data-binding.md yet. |
||
home.today_quest.article.topic.name / length.label / est_read_seconds |
api GET /home today_quest.article.length.label |
||
home.today_quest.article.topic.name / length.label / est_read_seconds |
api GET /home today_quest.article.est_read_seconds |
||
home.today_quest.plan_day |
api GET /home today_quest.plan_day · From the board's data-bind; no row in data-binding.md yet. |
||
home.today_quest.session_id → GET /v1/sessions/{id} |
api GET /home today_quest.session_id · From the board's data-bind; no row in data-binding.md yet. |
||
home.today_quest.session_id → GET /v1/sessions/{id} |
call GET /sessions/{id} |
||
home.today_quest.status |
api GET /home today_quest.status · From the board's data-bind; no row in data-binding.md yet. |
||
home.today_quest.steps[0].state + label |
api GET /home today_quest.steps[].state · From the board's data-bind; no row in data-binding.md yet. |
||
home.today_quest.steps[0].state + label |
api GET /home today_quest.steps[].label |
||
home.today_quest.steps[1].state + label |
api GET /home today_quest.steps[].state · From the board's data-bind; no row in data-binding.md yet. |
||
home.today_quest.steps[1].state + label |
api GET /home today_quest.steps[].label |
||
home.today_quest.steps[2].state + label |
api GET /home today_quest.steps[].state · From the board's data-bind; no row in data-binding.md yet. |
||
home.today_quest.steps[2].state + label |
api GET /home today_quest.steps[].label |
||
home.today_quest.summary (CCR-2) → round1_overall / round2_overall / duration_delta_ms / xp_awarded |
api GET /home today_quest.summary · From the board's data-bind; no row in data-binding.md yet. |
||
home.topics[0].name |
api GET /home topics[].name · From the board's data-bind; no row in data-binding.md yet. |
||
home.topics[1].name |
api GET /home topics[].name · From the board's data-bind; no row in data-binding.md yet. |
||
home.topics[2].name |
api GET /home topics[].name · From the board's data-bind; no row in data-binding.md yet. |
||
home.topics[3].name |
api GET /home topics[].name · From the board's data-bind; no row in data-binding.md yet. |
||
home.topics[4].name |
api GET /home topics[].name · From the board's data-bind; no row in data-binding.md yet. |
Contract change requests
Fields above that no endpoint sends yet. Until each lands, the screen falls back as noted.
| Change | Request | Fallback until it lands |
|---|---|---|
| CCR-14 | Document the error responses on every operation the screens read: 4XX and 5XX → #/components/responses/Error (ErrorEnvelope), and 402 entitlement_required on the hard-paywalled reads the API description lists (/home, /articles*, /topics, /sessions, /growth, /achievements, /weekly-quests, /plan). Today only a few operations list any error, GET /home none. |
The client decodes any non-2xx body as ErrorEnvelope, as the API description says. |
Binds on the boards
The data-bind values across every state.
NWPathMonitor + local:cache.home.fetchedAtPOST /v1/sessions {article_id, kind: daily}error.codeerror.message (Accept-Language)home.display_namehome.focus.title (Accept-Language)home.greeting (Accept-Language)home.level.levelhome.level.title (Accept-Language)home.level.xp_into_level / xp_for_nexthome.local_date_label (Accept-Language)home.quick_picks[0].article.idhome.quick_picks[0].subtitlehome.quick_picks[0].titlehome.quick_picks[0].topic.glyph / color_tokenhome.quick_picks[topic=tech] = ∅ (topic.article_count = 0)home.streak.at_risk + freezeshome.streak.current / today_done / at_riskhome.today_quest = null (CCR-1)home.today_quest.article.titlehome.today_quest.article.topic.name / length.label / est_read_secondshome.today_quest.plan_dayhome.today_quest.session_id → GET /v1/sessions/{id}home.today_quest.statushome.today_quest.steps[0].state + labelhome.today_quest.steps[1].state + labelhome.today_quest.steps[2].state + labelhome.today_quest.summary (CCR-2) → round1_overall / round2_overall / duration_delta_ms / xp_awardedhome.today_quest.xp_rewardhome.topics[0].namehome.topics[1].namehome.topics[2].namehome.topics[3].namehome.topics[4].name
States
- Loading: Skeleton mirrors the real layout so nothing jumps; shown only on cold start with no cache.
- Empty: From states.md (Home): home--no-quest (CCR-1); home--topic-empty; first-time = home--first-time
- Error (retryable / not): GET /v1/home failed with a retryable error and no cache available.
- Offline: No network: cached /v1/home with timestamp; training still starts (article cached, upload queued).