Document 02 · Current implementation
Data structure
The models the client currently reads, writes, derives, or persists.
Field names follow the TypeScript app model. API-only snake_case mappings are shown in the API reference.
1. Data ownership
| Store | Owns | Behavior |
|---|---|---|
| Backend API | Accounts, memberships, children, interests, traits, screen read models, play sessions, scans, milestones, saved items, article reads, care queue, tracker copy, notifications, entitlements, devices, consents, jobs, support requests. | Authoritative for signed-in shared data. |
| Device storage | Session, tracker working copy, pending sync, timers, preferences, reading progress, avatar, photo consent, custom/tried foods, growth reference, trial-door markers. | AsyncStorage on native, localStorage on web, memory in logic tests. |
| Bundled app data | Activities and reading content used by signed-out/preview paths, food list, milestone content, WHO growth standards. | Ships with the app; not user data. |
| React memory | Current child, active tab, loaded screen models, modal/sheet state, draft interactions, current language. | Lost on process restart unless mirrored in device/API storage. |
2. Main relationships
erDiagram
USER ||--o{ ACCOUNT_MEMBERSHIP : has
ACCOUNT ||--o{ ACCOUNT_MEMBERSHIP : contains
ACCOUNT ||--o{ CHILD : owns
CHILD ||--o{ CHILD_INTEREST : has
CHILD ||--o{ CHILD_TRAIT : has
CHILD ||--o{ MILESTONE_OBSERVATION : records
CHILD ||--o{ PLAY_SESSION : completes
PLAY_SESSION ||--o| SESSION_FEEDBACK : receives
CHILD ||--o{ SCAN : requests
SCAN ||--o{ ACTIVITY_SUGGESTION : returns
CHILD ||--o{ TRACKER_ENTRY : logs
CHILD ||--o{ ARTICLE_READ : reads
CHILD ||--o{ SAVED_ITEM : saves
CHILD ||--o{ CARE_QUEUE_ITEM : receives
ACCOUNT ||--o{ NOTIFICATION : receives
ACCOUNT ||--|| ENTITLEMENTS : controls
ACCOUNT ||--o{ DEVICE : registers
3. Identity and child profile
| Model | Fields used by the app |
|---|---|
AuthSession | access_token, optional token metadata, user, active account. |
User | id, email, given/family name, display name, locale and status fields returned by the server. |
Account | id, name/status and active membership context. Sent as X-Account-Id. |
MeProfile | user plus account memberships; the active membership refreshes the session's user/account snapshot. |
ChildRecord | id, name, preferred name, birth date, sex/gender value, locale/time zone, status, timestamps, and server-provided profile fields. |
ChildCreateInput | Name, optional preferred name, birth date, optional sex, locale, and time zone. |
RegisterOnboardingPayload | Child profile, four-area milestone answers, interests, optional traits, and onboarding metadata used during registration/submission. |
ChildInterestRecord | Record id, child id, interest code/label, optional custom value, timestamps. |
ChildTraitRecord | Record id, child id, trait code/value and timestamps. |
4. Screen and content models
| Model | Purpose and notable fields |
|---|---|
HomeScreenData | Child summary, welcome copy, suggested activities, saved preview, updates data, and related Home display sections. |
PortraitScreenData | Child identity, developmental domains/bands, skill pot, interests, streak and server-calculated portrait content. |
ActivitySummary | Activity id, title, description, domain/category, age/setting, materials, safety, instructions, and optional target milestone/suggestion links. |
PlaySessionRecord | Session id, child/activity/suggestion references, context, start/end/completed state, timestamps, and optional feedback. |
ResourceContent | Stable local id, optional server apiId, title, teaser/body/read sections, category, age range, debut/pin/display rules. |
ResourceProgress | status: new|read, saved, optional finishedInSession. |
CareQueueItem | Queue id/type/status/order, child scope, payload and actions for feedback, resource, or milestone work. |
AppNotification | Notification id/type/title/body, timestamps, viewed/dismissed state, child context, and action payload. |
NotificationPreferences | Push/email channel switches returned and updated as one preference object. |
5. Tracker model
Every tracker row shares the following envelope. Detail blocks are present according to kind.
TrackerEntry {
id, kind, childId, occurredAt,
endedAt?, durationSeconds?, note?,
clientEventId, createdAt,
pendingSync, syncedId?,
feeding?, sleep?, diaper?, measurement?, health?, pump?
}
| Block | Fields |
|---|---|
feeding | method, amountMl, foodItems[], mealType, reactedTo[], moodAfter. Nursing duration can use common duration plus side-specific data in the local model. |
sleep | kind, quality, location, wakeCount, moodBefore, moodAfter, sleptThrough. |
diaper | kind, consistency, color, hasRash, inPotty. |
measurement | kind: weight|height|head, numeric value, canonical unit: kg|cm. |
health | kind, description, temperatureC. Supported in storage/API mapping; no current Quick Log entry point. |
pump | leftMl, rightMl, leftSeconds, rightSeconds, totalMl. |
kind is feeding | sleep | diaper | measurement | health | pump. New rows use a client event id for idempotency. Synced rows retain the server id. A deleted synced row creates a tombstone until the server acknowledges it.
6. Milestones, access, and asynchronous work
| Model | Fields used |
|---|---|
MilestoneAnswer | yes | not_yet | unanswered in local interaction/journal; server writes carry milestone id or code, value and observation metadata. |
MilestoneJournalEntry | milestoneId, answer, ISO answered_at. Append-only on the device. |
Entitlements | Plan/tier display, active/trial dates, features: Record<string, boolean>, limits: Record<string, number>, promotions, optional payments switch. -1 means unlimited. |
Job | id, kind, status, optional poll_after, progress, result and error. Used after child deletion. |
Device | Device id, platform, Expo push token, locale/time zone and app/device metadata used for notification registration. |
SupportRequestInput | type, message, optional child_id, current_url, and client_context. Types: bug, feedback, account/subscription, feature request, other. |
7. Device persistence keys
| Key | Stored shape | Scope |
|---|---|---|
buzzbaby.authSession.v1 | AuthSession | Device/browser |
buzzbaby.authMethod.v1 | email | google | apple | Device/browser |
buzzbaby.pushDevice.v1 | Registered server device id | Device |
buzzbaby.resourceProgress.v1.<childId> | {version, session, cards: {resourceId: {status, saved, finishedInSession?}}} | Child |
buzzbaby.tracker.v1 | {version, entries[], deletions?: [{syncedId, deletedAt}]} | All children on device; rows contain child id |
buzzbaby.trackerTimers.v1 | {version, timers: {key: {startedAt?, accumulatedMs, entryPointId?}}} | Device |
buzzbaby.trackerPrefs.v1 | {version, preferences: {hiddenGroups, hiddenEntryPoints, entryMode, units, hiddenBottleTypes}} | Device/family |
buzzbaby.customFoods.v1 | {version, foods[], hidden?} | Device/family |
buzzbaby.triedFoods.v1.<childId> | {version, foods[]} | Child |
buzzbaby.growthProfileSex.v1.<childId> | {version, sex: boys|girls|null} | Child |
buzzbaby.avatarChoice.v1 | {avatarId?, photo?}; photo is native file URI or downsized web data URI | Device; not child-keyed |
privacy.photo_scan_consent.<accountId> | granted | revoked | unset | Account; unsuffixed while signed out |
milestones.journal.<childId> | MilestoneJournalEntry[] | Child |
buzzbaby.googleForceAccountPicker.v1 | Boolean | Device/browser |
monetization.trial_door_resolved.event.<eventId> | Boolean | Backend event on device |
monetization.trial_door_pending_event.v1 | {eventId, accountId} | Device |
Versioned files are validated before use. Unknown versions normally reset that local feature's state; tracker data is handled especially defensively because it contains caregiver-entered records.
8. Data movement
flowchart LR
UI[Screen and sheet] --> CTX[App state / feature hooks]
CTX --> SVC[Business services]
SVC --> DATA[Repositories]
DATA --> API[(Backend API)]
SVC --> STORE[(Device storage)]
BUNDLE[(Bundled content)] --> SVC
API --> DATA --> CTX --> UI
STORE --> SVC
- Signed-in child/profile/read-model data flows primarily from API to React state.
- Tracker writes flow to device storage first, then to the API.
- Resource progress is written locally first and mirrored to saved-item/article-read APIs when a server id exists.
- Photo consent is a local gate plus a best-effort append-only server consent record.
- Avatar photos are local and are not uploaded by the implemented avatar path.