technical:features:25_embedded_mobile_coach_app
Table of Contents
25 — Embedded mobile coach app
Technical reference. For task-based help, see the corresponding user guide.
Documentation status: reviewed against implementation · Reviewed: 2026-07-21 · Primary users: authenticated coaches · Surfaces: coach portal, mobile web and native wrapper hand-off
Purpose
The coach portal exposes mobile-first coach workflows without asking desktop users to sign in twice. On a phone it first offers the installed native app; otherwise it hosts the mobile web coach experience in a viewport-aware iframe and hands over the current portal access token in memory.
User outcomes
| Context | Outcome |
|---|---|
| Desktop/tablet coach | Opens the mobile coach app inside the portal at /mobile-app. |
| Mobile-browser coach with native app | The dreamsforlittles:// scheme attempts to open the installed app. |
| Mobile-browser coach without native app | The browser falls back to the embedded experience after approximately 1.4 seconds. |
| Coach following an activity alert | The embedded presentation lands on the corresponding /coach/… route; the current generic native scheme does not carry that path. |
Entry points
- Coach portal navigation → Mobile web.
/mobile-appfor the default coach dashboard./mobile-app?path=<encoded coach route>from coach activity-notification navigation.
Functional flow
1. Choose native or embedded presentation
- Non-mobile browsers navigate directly to
/mobile-appand render the iframe. - A likely iOS/Android browser clicks the
dreamsforlittles://custom scheme. - A 1,400 ms timer navigates to the iframe only if the document stayed visible. Page-hide/visibility events cancel the fallback after a successful native hand-off.
- A scheme-launch exception triggers the iframe immediately.
2. Build a coach-only initial route
- The portal reads the optional
pathquery value. - Values beginning with
/coachare passed as the initial mobile route; anything else becomes/coach. - The hosted URL adds
adminMobileWeb=1andadminMobileWebInitialPath=…. - Production defaults to the portal's
/mobile-web/build; development defaults tohttp://localhost:5177/;VITE_MOBILE_WEB_URLcan explicitly replace it.
3. Hand over authentication
- On iframe load and on route entry, the portal obtains its current access token.
- It posts
littles:admin-mobile-web-authto the iframe's exact calculated origin. The access token is in the message payload, never in the iframe URL. - Mobile web enables its admin-hosted auth client only in admin-portal mode, validates the sender origin, constructs an in-memory session and uses the token for normal platform API calls.
- The receiver accepts its own origin in production. Development additionally permits HTTP localhost/127.0.0.1 origins.
- Mobile web waits up to three seconds for the hand-off. Account recovery, OAuth and password changes remain owned by the portal rather than the embedded auth client.
4. Maintain a usable viewport
- The portal sizes the route using
visualViewport.heightwhen available, with a 320 px minimum. - Resize, orientation and visual-viewport events update the height and keep the portal at the top of the page.
- The iframe re-posts authentication after a load so a navigation/reload can recover its in-memory session.
Validation and user-visible states
| State | Behaviour |
|---|---|
| Native app opens | The portal becomes hidden and the iframe fallback is cancelled. |
| Scheme unavailable | The embedded app opens after the short fallback window. |
Missing path or a value without the /coach prefix | Initial route falls back to /coach. |
| Portal token missing | No credential is posted; embedded bootstrap eventually behaves as unauthenticated/failed auth. |
| Message late | The receiver waits three seconds and can accept a later valid message through its installed listener. |
| Iframe reload | onLoad posts the current token again. |
| Backend denies a route | The mobile error/denied state is shown; embedding never bypasses API authorization. |
Security boundaries
- The token is sent only with an exact
postMessagetarget origin, and the receiver validatesevent.origin. - The URL contains mode and initial-route hints only; it must never contain an access token.
- The current path check is a navigation guard based on the
/coachprefix, not an authorization mechanism. - Platform endpoints still validate the JWT, actor role, organization, assignment, subscription and permission for every operation.
- The embedded session is memory-only. The native custom-scheme attempt does not transfer the browser token to the native app.
- The current
dreamsforlittles://launch is also pathless. A notification destination is preserved by the iframe fallback, not handed to the native app by this scheme.
Do not treat iframe origin checks or the/coachpath prefix as the security boundary. Adding a new deployment origin requires deliberate sender-and-receiver configuration, and every new mobile route must remain server-authorized.
Acceptance checklist
- [ ] Desktop navigation renders the configured mobile-web build in the full-height portal frame.
- [ ] Mobile navigation attempts the native scheme and only falls back while the page remains visible.
- [ ] Initial values that do not begin with
/coachresolve to/coach. - [ ] The access token never appears in the URL, logs or persistent embedded storage.
- [ ] Sender target origin and receiver origin validation agree in production and development.
- [ ] Iframe reload re-establishes the hand-off.
- [ ] Activity notification links preserve an authorized
/coach/…destination in the embedded presentation without claiming path hand-off through the generic native scheme. - [ ] API denial remains effective inside the iframe.
Source evidence
- Coach portal:
admin-web/src/App.tsx,admin-web/src/mobile-web-build-url.ts,admin-web/src/components/AdminShell.tsx - Mobile web:
mobile-web/src/api/admin-portal-mobile-auth.ts,mobile-web/src/webview/bridge.ts,mobile-web/src/App.tsx
