Document 03 · Reverse-engineered implementation map
Frontend and backend architecture
Where each flow starts, where its business decisions are made, how the client crosses the API boundary, and which system owns the durable result.
index.ts and App.tsx. Backend statements were then re-verified against the copied buzzbaby-be-main Fastify service, its route registry, handlers, services, Prisma schema, migrations, and OpenAPI document. The analysis-only SQL under appAnalysis/postgresql/ is not production backend code.1. How to read this document
| Evidence label | Meaning | What may safely be concluded |
|---|---|---|
| Verified client | The file is in this checkout and is imported by the running app or by a reachable module. | The described UI, orchestration, calculation, request mapping, and local persistence are implemented in the current client snapshot. |
| Verified backend | The copied backend file was inspected directly in buzzbaby-be-main. | The described route, handler, service, auth/tenant boundary, and persistence behavior is present in this backend snapshot. |
| API boundary | The client constructs and calls the endpoint in current code. | The request/response behavior expected by the app is implemented client-side. Internal server logic cannot be proven from this checkout alone. |
appAnalysis/postgresql/ is a standalone analysis schema built from app data. It helps query the milestone/tracker corpus but does not represent or migrate the backend database. Production persistence is defined by buzzbaby-be-main/prisma/schema.prisma plus buzzbaby-be-main/db/migrations/.2. Frontend/backend boundary at a glance
flowchart LR
subgraph FE[Frontend - this repository]
UI[React Native screens and sheets]
ORCH[App.tsx and AppStateContext orchestration]
RULES[src/services business and presentation rules]
REPO[src/data repositories and DTO mappers]
LOCAL[(AsyncStorage or localStorage)]
UI --> ORCH
ORCH --> RULES
ORCH --> REPO
RULES --> REPO
RULES <--> LOCAL
end
REPO -->|authorized fetch and JSON| HTTP[REST API]
subgraph BE[Backend - separate sb-app-be repository]
HTTP --> ROUTER[OpenAPI route validation and handler registry]
ROUTER --> HANDLER[Handlers and server services]
HANDLER --> DB[(PostgreSQL and server state)]
end
SDK[Apple, Google, Expo Push, RevenueCat, Sentry, PostHog] <--> FE
- Frontend owns presentation and immediate interaction. Screens render state,
App.tsxcoordinates cross-screen flows, andsrc/services/contains reusable client decisions and calculations. - Client repositories own transport.
src/data/*Repository.tsbuilds typed payloads, callsauthorizedFetch, validates expected statuses, and maps API DTOs into app models. - Backend owns signed-in durable/shared data and enforcement. The API supplies account/child state, Home and Portrait read models, scans, sessions, queue items, notifications, entitlements, and the server copy of tracker/resource progress.
- Some flows are deliberately hybrid. Tracker, resource progress, timers, photo consent, and milestone display combine server state with immediate device state.
3. Runtime stack
| Concern | Implemented choice | Code location |
|---|---|---|
| Application | Expo SDK 57, React 19, React Native 0.86, TypeScript. | package.json, app.json |
| Entry | Initialize crash reporting, then register the root React component. | index.ts → src/services/crashReporting.ts → App.tsx |
| Navigation | React state; five tabs plus modal, sheet, play-state, and onboarding-state substitutions. No Expo Router or React Navigation. | App.tsx, src/app/constants.ts |
| Shared state | A large composition context plus feature-local state and subscribed module stores. | src/app/AppStateContext.tsx, src/services/* |
| Network | REST over fetch with one base URL, endpoint registry, bearer token, and account header. | src/config/api.ts, src/config/apiEndpoints.ts, src/data/authRepository.ts |
| Device persistence | AsyncStorage on native, localStorage on web, injectable memory storage in tests. | src/data/deviceStorage.ts |
| Native/external SDKs | Image picker/manipulation, Apple and Google identity, Expo notifications, RevenueCat, Sentry, and PostHog. | src/services/*Auth.ts, pushNotifications.ts, purchasesService.ts, crashReporting.ts, analytics.ts |
4. Frontend code map
flowchart TD
ENTRY[index.ts] --> APP[App.tsx]
APP --> SCREENS[src/screens and src/features]
APP --> CONTEXT[src/app/AppStateContext.tsx]
SCREENS --> COMPONENTS[src/components]
APP --> SERVICES[src/services]
SCREENS --> SERVICES
APP --> DATA[src/data]
SERVICES --> DATA
DATA --> CONFIG[src/config]
DATA --> TYPES[src/types]
SERVICES --> TYPES
| Frontend layer | Responsibility in the implemented app | Representative code |
|---|---|---|
App.tsx and src/app/ | Composition root. Owns app/onboarding phase, active tab, active child, loaded server read models, cross-screen callbacks, overlays, auth reaction, and flow handoffs. | App.tsx, AppStateContext.tsx, updatesQueueFlow.ts, playTabRouting.ts |
src/features/onboarding/ | Onboarding presentation and auth form surfaces. The visible step flow is controlled by state passed from App.tsx. | OnboardingFlow.tsx, EmailAuthForm.tsx, provider sign-in buttons |
src/screens/ | The five primary product screens and app-wide modals/sheets. Screen-local interaction state belongs here. | HomeScreen.tsx, PortraitScreen.tsx, PlayScreen.tsx, TrackerScreen.tsx, ResourcesScreen.tsx |
src/components/ | Reusable UI and interaction grammar. Components accept data/callbacks and should not decide feature-specific business policy. | appChrome.tsx, AppButton.tsx, activity/resource headers, tracker icon primitives |
src/providers/ | Reactive hooks around cross-cutting stores. In the current checkout these are entitlement and payment-enabled hooks, not a complete auth/locale provider layer. | useEntitlements.ts, usePaymentsEnabled.ts |
src/services/ | Client business rules and reusable calculations: selection, ranking, validation, gates, reports, local stores, and SDK seams. | milestoneEngine.ts, activityPlanner.ts, trackerStore.ts, trackerInsights.ts, resourceProgress.ts, childGate.ts |
src/data/ | HTTP repositories, authorization transport, DTO conversion, bundled content access, and device-storage abstraction. | authRepository.ts, screenRepository.ts, trackerRepository.ts, contentMappers.ts, deviceStorage.ts |
src/config/ | API URL resolution and stable client configuration/domain constants. | api.ts, apiEndpoints.ts, domains.ts |
src/types/ | Shared TypeScript contracts without decision-making logic. | auth.ts, screens.ts, activity.ts, notifications.ts |
5. Backend code map
The copied backend is a Fastify/TypeScript service in buzzbaby-be-main. It loads openapi/initial-api.yaml, turns every operation into a validated route, looks up the operation in src/handlers/index.ts, and sends unimplemented operations through an explicit 501 not_implemented stub. All paths in this section are relative to buzzbaby-be-main/.
| Backend concern | Verified server code | How it implements the flow |
|---|---|---|
| Route registration and validation | buzzbaby-be-main/src/openapi/registerRoutes.ts, src/openapi/spec.ts, src/openapi/toFastifySchema.ts | Dereferences the YAML spec, converts paths to Fastify routes, applies body/query/header schemas, attaches operation-specific rate limits, and selects real handler versus named 501 stub. Current registry comparison: 98 operations, 93 handlers, 5 stubs (createInvite, dismissSuggestion, ingestEvents, ingestFeedback, getMedia). |
| Server boot and middleware | src/app.ts, src/server.ts | Registers CORS, global/per-route rate limits, Prisma, JWT auth, tenant resolution, entitlements, push sweeper, health check, centralized request logging, and OpenAPI routes. |
| Authentication and identity | src/handlers/auth.ts, src/handlers/identity.ts, src/plugins/auth.ts, src/lib/password.ts, src/lib/googleIdToken.ts, src/lib/appleIdentityToken.ts | Supports password auth in local HS256 mode and Google/Apple token exchange; verifies bearer JWTs (JWKS in deployed mode), creates/updates users/accounts, persists devices/consents, and deletes account data. |
| Tenant isolation | src/plugins/tenant.ts | Resolves membership from X-Account-Id, caches the tenant on the request, runs protected queries in withTenant transactions with app.current_account_id, and keeps explicit account predicates alongside PostgreSQL RLS. |
| Entitlements and enforcement | src/plugins/entitlements.ts, src/services/entitlements.ts, src/services/entitlementGate.ts, src/handlers/entitlements.ts | Resolves account tier/features/limits once per request, then supports feature checks, quotas, rate consumption, and server-side clamps for child, scan, saved-item, history, and billing flows. |
| Home/Portrait/Report read models | src/handlers/readModels.ts, src/services/resourceShelf.ts, src/services/scanContext.ts | Runs tenant-scoped Prisma queries, computes area/skill progress, next skills, activity/resource shelves, daily plan/spark data, and serializes the exact client read-model envelopes. |
| Care queue and updates | src/handlers/careQueue.ts | Builds actionable queue items from milestone/resource/session state, removes/resolves completed items, and applies queue actions inside tenant-scoped transactions. |
| Tracker | src/handlers/tracker.ts, db/migrations/0009_tracker_client_gaps.sql | Uses raw SQL (tracker tables are intentionally not Prisma-modeled) for a six-kind union timeline; validates nested blocks, batches/deduplicates by client_event_id, supports create/update/delete/day totals, and persists pump/sleep/solids/potty fields added by migration. |
| Milestones and assessments | src/handlers/framework.ts, src/handlers/assessments.ts, src/handlers/growth.ts, src/handlers/onboarding.ts | Serves framework content, creates/submits/completes assessments, persists child milestone observations, and recomputes area/skill rollups consumed by Portrait. |
| Activities, scans, and sessions | src/handlers/activities.ts, src/handlers/scans.ts, src/handlers/sessions.ts; src/services/openaiVision.ts, openaiActivity.ts, scanPrompt.ts, scanContext.ts | Serves activity catalog entries; sends room photos to OpenAI Responses vision, stores detections/suggestions without storing the raw photo, applies scan/regeneration gates, and persists play sessions/feedback. |
| Resources and saved items | src/handlers/library.ts, src/services/resourceShelf.ts | Lists/creates/deletes polymorphic saved items, embeds article/activity summaries, lists and marks article reads, and supplies resource shelves through the Home read model. |
| Notifications and push | src/handlers/notifications.ts, src/services/notifications.ts, src/services/pushDelivery.ts | Stores event types/subscriptions/settings, renders feed rows, marks viewed/dismissed state, and sweeps pending Expo push deliveries/receipts. |
| Billing, jobs, and support | src/handlers/billing.ts, src/handlers/jobs.ts, src/handlers/support.ts, src/services/supportEmail.ts, src/handlers/progressReports.ts | Consumes RevenueCat webhooks idempotently, polls asynchronous jobs/reports, sends support requests through server-owned SES, and schedules progress-report work. |
| Database boundary | buzzbaby-be-main/prisma/schema.prisma, db/migrations/, src/plugins/prisma.ts | Prisma models 54 server entities across core/growth/content/scan/notification schemas; the tracked migration set currently contains 27 files. Tracker remains raw SQL because its tables are outside the Prisma model. |
Actual backend request pipeline
flowchart TD
REQ[HTTP request] --> FASTIFY[Fastify app.ts]
FASTIFY --> CORS[CORS and rate limit]
CORS --> SPEC[Spec-driven OpenAPI route]
SPEC --> VALIDATE[AJV params, query, headers, body]
VALIDATE --> AUTH{bearerAuth?}
AUTH -- yes --> JWT[plugins/auth.ts JWT verify]
AUTH -- no --> REGISTRY
JWT --> REGISTRY[handlers/index.ts lookup]
REGISTRY -- missing --> STUB[501 not_implemented]
REGISTRY -- found --> TENANT[resolveTenant and optional gate]
TENANT --> HANDLER[domain handler]
HANDLER --> TX[withTenant transaction and explicit account predicate]
TX --> PRISMA[Prisma or tracker raw SQL]
PRISMA --> DB[(PostgreSQL schemas and migrations)]
HANDLER --> EXTERNAL[OpenAI, Expo Push, SES, Apple/Google JWKS]
VALIDATE --> ERR[plugins/errorHandler.ts RFC 9457 problem]
HANDLER --> ERR
DB --> RESP[JSON envelope]
RESP --> CLIENT[src/data repository mapper]
6. Startup, authentication, and child hydration
sequenceDiagram
participant Entry as index.ts
participant App as App.tsx
participant Auth as authRepository
participant ScreenRepo as screenRepository
participant API as Backend REST API
participant Local as Device storage and module stores
Entry->>Entry: initialize Sentry
Entry->>App: register root component
App->>Auth: read persisted AuthSession
App->>Local: begin local feature hydration
alt signed-in session
App->>API: GET /v1/me and /v1/children as needed
API-->>App: account and children
App->>App: adoptAccountChild and reset prior child state
par signed-in read models
App->>ScreenRepo: loadSignedInScreens(childId)
ScreenRepo->>API: GET home, portrait, completed sessions, care queue
and secondary account/child state
App->>API: notifications, entitlements, config, milestone observations
and hybrid stores
App->>Local: begin child resource/tracker/growth sessions
App->>API: article reads, saved items, tracker entries
end
API-->>App: typed responses
App->>App: map and publish through AppStateContext
else signed out
App->>App: render onboarding or localhost preview fixture path
end
Frontend decisions: initial phase, active tab, active child adoption, resetting cross-child state, loading concurrency, preview fixtures, and error/empty presentation. Backend decisions: authenticated identity, available children, read-model content, queue state, entitlements, and durable user records.
7. Flow-by-flow implementation ownership
This is the shortest map from a product flow to the code that actually executes it. In the table, frontend paths are relative to the app root; backend paths are relative to buzzbaby-be-main/.
| Flow | Frontend UI and orchestration | Client business logic | Client repository and API | Backend responsibility / recorded code | Durable authority |
|---|---|---|---|---|---|
| Email, Google, or Apple sign-in | OnboardingFlow.tsx, auth forms/buttons, App.tsx handleAuthSuccess | emailAuth.ts, providerSignIn.ts, googleAuth.ts, appleAuth.ts, postAuthNavigation.ts | authRepository.ts → POST /v1/auth/*, GET /v1/me | buzzbaby-be-main/src/handlers/auth.ts validates password/provider identities, creates/finds the user/account, and issues a local HS256 token; src/plugins/auth.ts verifies bearer JWTs at ingress. | Backend; session token is cached on device. |
| Onboarding and first child | OnboardingFlow.tsx; App.tsx goNextOnboarding, finishAuthenticatedOnboarding | milestoneEngine.ts selects questions; childAge.ts computes age; onboardingRegister.ts builds the payload | childProfileRepository.ts → POST /v1/onboarding; registration may carry onboarding data | buzzbaby-be-main/src/handlers/onboarding.ts writes child/profile/interest/trait/assessment data in tenant scope; assessments.ts handles assessment responses/completion. | Backend after authentication; pre-submit answers live in React memory. |
| Switch/add/edit/delete child | ProfileModal.tsx, AddChildModal.tsx, ProfileEditModal.tsx; App.tsx adoptAccountChild | childGate.ts, childGender.ts, mockProfileFactory.ts, profileInterestDisplay.ts | childProfileRepository.ts → children/interests/traits/jobs endpoints | handlers/children.ts persists child/caregiver changes; handlers/childProfile.ts persists interests/traits; handlers/jobs.ts exposes asynchronous delete status; services/entitlementGate.ts enforces server quotas. | Backend; selected child is current React state. |
| Home dashboard | HomeScreen.tsx, App.tsx | homeJournalTime.ts, app-level activity/resource mapping, saved/read stores | screenRepository.ts fetchHomeScreen → GET /v1/children/{id}/home | Compose the signed-in Home read model. Recorded starting point: handlers/readModels.ts. | Backend for signed-in content; local state for transient presentation. |
| Updates bell and queue | HomeScreen.tsx, Updates tray wired in App.tsx | updatesQueueFlow.ts determines renderable counts/routes; fixture helpers are localhost-only | screenRepository.ts care-queue calls; notificationsRepository.ts feed/preferences calls | Generate/resolve queue items in handlers/careQueue.ts; notification state in handlers/notifications.ts. | Backend for queue and feed status; client owns badge combination and presentation. |
| Portrait and milestone editing | PortraitScreen.tsx, WebDomainSheet.tsx, milestone modal; save handlers in App.tsx | milestoneEngine.ts maps domains and calculates star progress; portraitStar.ts hydrates; skillPot.ts; milestoneJournal.ts | screenRepository.ts portrait read; growthRepository.ts list/PUT/DELETE milestone observations | handlers/readModels.ts composes Portrait/skill-pot data; handlers/growth.ts persists observations and recomputes area/skill rollups; handlers/framework.ts serves framework definitions. | Backend observation/read model plus an append-only local answer journal. |
| Play from library or milestone | PlayScreen.tsx; session lifecycle callbacks in App.tsx | activityPlanner.ts ranks the available age-safe set; activityPresentation.ts; feedback mapping in playRepository.ts | contentRepository.ts activities; playRepository.ts create/complete/feedback session calls | handlers/activities.ts serves catalog rows; handlers/sessions.ts persists play sessions and feedback; handlers/readModels.ts includes server-composed suggestions. | Backend for signed-in catalog/session history; React state for active guide. |
| Play from a room photo | PlayScreen.tsx, PhotoConsentSheet.tsx; capture/generation handlers in App.tsx | photoConsent.ts, scanPhoto.ts, scanGate.ts, customActivityGuardrails.ts | scanRepository.ts → create/poll scan, detections, suggestions; consentRepository.ts | handlers/scans.ts orchestrates scan state, quota, persistence, and polling; services/openaiVision.ts analyzes the image; services/openaiActivity.ts generates suggestions; services/scanContext.ts/scanPrompt.ts build child-fit context. Raw images are not stored. | Backend for scan job/results; device/React memory for consent gate and captured image preparation. |
| Tracker log, edit, report, and sync | TrackerScreen.tsx and src/screens/tracker/* sheets/reports | trackerEntryMapping.ts, trackerStore.ts, trackerTimers.ts, trackerInsights.ts, growthReport.ts, trackerExport.ts | trackerRepository.ts → list, sync, PATCH, DELETE | buzzbaby-be-main/src/handlers/tracker.ts validates, deduplicates, persists, updates, and deletes server rows. | Hybrid: device working copy is immediate; backend is the signed-in durable/shared copy. |
| Resources, reading, and saves | ResourcesScreen.tsx, ResourceReadModal.tsx, ResourceReadingBookModal.tsx, ResourceTopicModal.tsx | resourceProgress.ts owns new/read/saved/session semantics; resourcePersistence.ts mirrors completed reads; resourceDisplay.ts | screenRepository.ts gets signed-in resources via Home; resourceProgressRepository.ts article reads; libraryRepository.ts saved items | handlers/readModels.ts selects the Home resource shelf; handlers/library.ts persists saved items and article reads; services/resourceShelf.ts ranks the server shelf. | Hybrid: local state drives instant/session UX; backend stores signed-in reads and remote saves. |
| Entitlements and purchase | src/screens/paywall/*, add-child/save/scan gate surfaces | paymentsGate.ts, childGate.ts, scanGate.ts, purchasesService.ts, trialDoor.ts | entitlementsRepository.ts, clientConfigRepository.ts → entitlements/config; RevenueCat SDK outside REST | handlers/entitlements.ts reads account grants; services/entitlementGate.ts enforces feature/quota/rate decisions; handlers/billing.ts consumes idempotent RevenueCat webhooks. | Backend entitlement state; RevenueCat/store supplies transaction events. Client never self-grants Plus. |
| Push and notification preferences | ProfileModal.tsx, Home Updates tray, App.tsx | pushNotifications.ts, pushRegistration.ts, notificationDripRules.ts | notificationsRepository.ts, deviceRepository.ts → notifications/preferences/devices | handlers/notifications.ts and services/notifications.ts render/raise feed events; services/pushDelivery.ts sweeps Expo delivery; device routes are in handlers/identity.ts. | Backend feed/preferences/device record; OS controls permission; client owns opt-in timing. |
| Support and account deletion | ProfileModal.tsx, DeleteAccountModal.tsx | supportRequestCopy.ts, logout cleanup services | supportRepository.ts → POST /v1/support/requests; accountDeletion.ts → DELETE /v1/me | handlers/support.ts validates and sends support mail through services/supportEmail.ts; handlers/identity.ts deletes the account in a transaction and revokes Apple refresh tokens when configured. | Backend; client clears its local session/state after deletion/logout. |
8. Where the important business rules live
| Business decision | Primary owner | How it is implemented | Server role |
|---|---|---|---|
| Which onboarding milestone questions appear | Frontend service — src/services/milestoneEngine.ts | Calculates age, applies logic bands/caps, groups four assessment areas, and formats the rows consumed by onboarding. | Receives the resulting assessment payload and persists it. |
| Which primary screen is visible | Frontend composition — App.tsx, src/app/constants.ts | State selects one of five tabs or a modal/sheet/flow state. Localhost query parameters only initialize QA paths. | No production navigation ownership. |
| What Home and Portrait contain for a signed-in child | Backend read model | The client displays/maps server HomeScreenData and PortraitScreenData. | Chooses and composes signed-in read-model content; recorded entry is handlers/readModels.ts. |
| Portrait star calculation shown in the client | Frontend service — milestoneEngine.ts, hydrated by portraitStar.ts | Maps local and remote checks into five domains and calculates current/behind/beyond visual progress. | Supplies milestone observations and Portrait/skill-pot inputs. |
| Ordering of available Play activities | Frontend service — activityPlanner.ts | Ranks the already available age-safe activity set using milestone/domain need. It does not authorize server-only content. | Serves the remote activity/suggestion pool and persists sessions. |
| Room-scan quota and generated result | Backend enforcement with client UX gate | scanGate.ts interprets offline/402 failures and chooses the paywall/retry presentation. | Enforces quota and produces scan detections/suggestions. |
| Tracker entry validity, immediate history, totals, and reports | Frontend services | Sheets map inputs through trackerEntryMapping.ts; trackerStore.ts persists; trackerInsights.ts and growth services calculate reports. | Validates API DTOs, deduplicates client event IDs, and provides durable/shared storage. |
| Resource new/read/saved/session behavior | Frontend service — resourceProgress.ts | Determines what is new/read, what stays visible this session, and what appears on the Home shelf. | Provides article content and persists completed reads/saved objects for signed-in users. |
| Care-queue item generation and lifecycle | Backend generation, frontend rendering rules | updatesQueueFlow.ts combines queue and notification counts, hides non-renderable activity feedback, and routes CTAs. | careQueue.ts creates items and applies complete/later/clear-style actions. |
| Plan access and quotas | Backend authority, frontend capability gates | UI asks can(), limitOf(), payment switch, and error classifiers; it does not branch on a plan name. | Returns entitlements/config and must enforce quotas even if client checks are bypassed. |
| Push pacing | Shared contract | notificationDripRules.ts is an executable client-side rule/test reference; permission and registration are client-side. | The actual scheduler/delivery service must enforce the production pacing. |
9. Detailed hybrid flow: Tracker
sequenceDiagram
participant UI as Tracker sheet
participant Map as trackerEntryMapping
participant Store as trackerStore
participant Disk as Device storage
participant Repo as trackerRepository
participant API as Backend tracker handler
UI->>Map: entered values
Map-->>UI: normalized TrackerEntry
UI->>Store: add, update, or delete
Store->>Disk: persist working copy or deletion tombstone
Store-->>UI: notify subscribers immediately
alt new local entry
Store->>Repo: pending create batch
Repo->>API: POST /children/{id}/tracker/sync
else correction to synced row
Store->>Repo: syncedId plus changed entry
Repo->>API: PATCH /tracker/entries/{id}
else delete synced row
Store->>Repo: persisted tombstone
Repo->>API: DELETE /tracker/entries/{id}
end
API-->>Repo: accepted/duplicate/server row or error
Repo->>Store: acknowledge or retain pending mutation
Store->>Disk: persist reconciled state
The frontend does not wait for the network before closing a sheet. That is an intentional business/UX contract: device state is the working copy, while failed server writes remain pending. Corrections must use PATCH; replaying them through sync can be treated as a duplicate. Deletes need tombstones so a later server load cannot resurrect the row.
10. Detailed hybrid flow: Resources
sequenceDiagram
participant UI as Resource reader
participant Progress as resourceProgress
participant Disk as Device storage
participant Repo as Resource repositories
participant API as Backend
UI->>Progress: open, finish, or toggle save
Progress->>Disk: update child-scoped progress immediately
Progress-->>UI: notify resource and Home shelf subscribers
alt completed remote article
Progress->>Repo: markResourceReadForChild
Repo->>API: PUT /children/{id}/article-reads/{articleId}
else save remote article/activity
Progress->>Repo: createSavedArticle or createSavedActivity
Repo->>API: POST /children/{id}/saved-items
else unsave remote item
Progress->>Repo: deleteSavedItem
Repo->>API: DELETE /saved-items/{id}
else local-only content id
Progress-->>Disk: remain local because backend has no object reference
end
Signed-in resource content currently arrives inside the Home read model, not from the configured standalone /v1/resources path. The local session rule intentionally lets a just-finished card keep its place until the next launch, even after the completion has been mirrored to the API.
11. Detailed server flow: room-photo Play
sequenceDiagram
participant UI as PlayScreen and App.tsx
participant Local as Client services
participant Repo as scanRepository/playRepository
participant API as Backend
UI->>Local: check photo consent and request OS camera permission
Local-->>UI: permitted photo
UI->>Local: resize/compress/encode photo and apply guardrails
UI->>Repo: createSceneScan with prompt/tags
Repo->>API: POST /children/{id}/scans
loop until terminal or timeout
Repo->>API: GET scan status/suggestions/detections
API-->>Repo: processing or terminal result
end
Repo-->>UI: mapped activity cards
UI->>Repo: start selected activity
Repo->>API: POST /children/{id}/sessions
UI->>Repo: finish and submit feedback
Repo->>API: PATCH session and PUT feedback
The client owns consent timing, media preparation, timeout/error classification, and the visible activity flow. The backend owns image processing, generated suggestions, quota enforcement, and durable session/feedback records.
12. Milestone data path and current split
flowchart TD
CORPUS[(Bundled consolidatedMilestones.json)] --> ENGINE[milestoneEngine selection and star rules]
API[(Backend milestone observations and Portrait)] --> HYDRATE[portraitStar and DTO mapping]
ENGINE --> ANSWERS[App.tsx answer map]
HYDRATE --> ANSWERS
ANSWERS --> PORTRAIT[PortraitScreen and WebDomainSheet]
PORTRAIT --> JOURNAL[(Local append-only milestone journal)]
PORTRAIT --> GROWTH[growthRepository PUT or DELETE]
GROWTH --> API
API --> REFRESH[Refresh Portrait and milestone hydration]
REFRESH --> HYDRATE
The bundled corpus defines the questionnaire and client star math; backend observations make signed-in answers survive reload and feed the server read model. The separate milestone analysis documents the exact selection/status mapping and the currently inconsistent write paths across onboarding, Portrait, and Home Updates.
13. Network implementation
flowchart LR
CALLER[App, service, or screen] --> REPO[Typed data repository]
REPO --> ENDPOINT[getApiEndpointUrl]
ENDPOINT --> ENV[EXPO_PUBLIC_API_BASE_URL plus path override]
REPO --> AUTH[authorizedFetch]
AUTH --> HEADERS[Accept, Bearer token, X-Account-Id]
AUTH --> FETCH[fetch with no-store]
FETCH --> EXPECT[Explicit expected HTTP status]
EXPECT -- success --> MAP[Envelope and DTO mapping]
EXPECT -- problem --> ERROR[AuthApiError]
ERROR -- invalid or expired session --> CLEAR[Clear local auth session]
src/config/api.tsis the only base-host reader. An absent base URL makes most repository functions return an empty/null result instead of inventing a production host.src/config/apiEndpoints.tsowns default paths and endpoint-specific environment overrides.src/data/authRepository.ts authorizedFetchowns auth headers, error parsing, expected-status enforcement, and invalid-session clearing.- Repositories own snake_case/camelCase mapping and omission of unsupported optional values. Screens should not construct backend URLs or raw DTOs.
14. State and persistence ownership
| State kind | Owner | Examples | Lifetime |
|---|---|---|---|
| Composition/navigation | App.tsx | Phase, tab, onboarding step, active child, active overlays, Play flow state | React process unless reconstructed |
| Shared screen data/actions | AppStateContext | Home/Portrait/queue/session models and cross-screen callbacks | React process; refetched after auth/child changes |
| Subscribed local stores | src/services/ | Tracker, timers, resource progress, custom/tried foods, growth profile, paywall controller state | Module memory, often mirrored to device storage |
| Device cache/working copy | deviceStorage.ts consumers | Auth session, pending tracker mutations, timers, preferences, avatar URI/data, local consent, milestone journal | Across launches on one device/browser |
| Signed-in truth | Backend API | Account, children, assessments, read models, sessions, scans, tracker copy, saved/read records, queue, notifications, entitlements | Across devices and sessions |
| Bundled reference content | src/data/*.json and content modules | Milestone corpus, onboarding options, food list, growth standards, signed-out/preview content | App build version |
15. Where to make a change
| If the requested change is… | Start here | Then verify |
|---|---|---|
| Visual layout or local interaction on one screen | The relevant src/screens/*.tsx or src/features/*.tsx | Whether the behavior belongs in an existing shared component or service |
| A rule reused across screens | src/services/ | Callers, focused *.test.ts, and the owning product contract |
| A request/response shape | src/types/, the relevant src/data/*Repository.ts, and docs/api/README.md | Backend OpenAPI and handler registry in sb-app-be |
| A signed-in content-selection or durable enforcement rule | The backend handler/service after opening the backend checkout | Client DTO mapping, loading/error states, and server tests |
| A local-first/offline behavior | The feature service/store and src/data/deviceStorage.ts | Merge, retry, version-migration, and cross-child behavior |
| An entitlement or quota | Backend entitlement/config/enforcement | Client capability gate and 402 handling; never rely only on the UI |
16. Current structural facts and risks
App.tsxis both composition root and a very large orchestration module. Many cross-screen handlers and modal states meet there, so flow changes can have wide impact even when the visible edit is small.- Production navigation is state-based, not route-object based. Localhost query parameters are QA entry points, not deployable deep links.
- Signed-in Home, Portrait, sessions, care queue, and resource catalog depend on backend responses. Bundled content is not a general authenticated fallback.
- Tracker and resource progress are intentionally dual-path. Treating either the local or remote copy as disposable can lose offline work or break immediate UX.
- Business rules are split by design: presentation/selection/calculation often lives in the client, while durable truth, read-model composition, quotas, and cross-device behavior belong to the backend.
- The backend route registry is spec-driven: adding an OpenAPI operation creates a validated route, but it remains a named 501 until its
operationIdis added tobuzzbaby-be-main/src/handlers/index.ts. - The backend Prisma schema intentionally does not model
tracker.*;buzzbaby-be-main/src/handlers/tracker.tsuses raw SQL and the migration set is the schema authority for that domain. - The avatar preference remains device-wide rather than child-keyed, and the avatar image path does not upload the selected photo.
- The milestone journal is device-local and separate from backend milestone observations; the milestone analysis records current write-path inconsistencies.
- The current environment reader does not expose the RevenueCat iOS/Android public key names used by the purchase service, so purchase configuration remains unavailable in this snapshot even though paywall and entitlement code exist.
17. Verification
The architecture map was checked against the current app entry/composition files, layer READMEs, repositories, services, screen imports, endpoint registry, all backend handler/service modules, prisma/schema.prisma, db/migrations/, and openapi/initial-api.yaml. No product source was changed.
npm run typecheck
npm run lint
npm run test:logic
The app checks could not run in this checkout because its node_modules is absent (tsc and eslint were not found). The backend has the corresponding commands npm run typecheck and npm run smoke:routes; run them after installing dependencies when validating code changes.