Table of Contents
18 — Session prep and coach report
Technical reference. For task-based help, see the corresponding user guide.
Documentation status: complete for the current implementation
Reviewed: 2026-07-22
Primary users: authorized coaches
Surfaces: coach admin portal, mobile coach workspace and platform API
Purpose
Session prep assembles one family's recent tracking, selected baby, questionnaire answers, sleep-plan context and coach-private notes into a review workspace. It provides explainable summary metrics, a sleep-by-logged-nap-count comparison, two timeline orientations, daily sleep totals, a detailed activity log and a downloadable/printable coach report.
The calculations are deterministic client-side summaries of the selected logs. They are preparation aids, not medical advice, a clinical diagnosis or an AI-generated conclusion.
User outcomes
| User need | Outcome |
|---|---|
| Prepare quickly | Select a family, baby and time window and load all authorized tracking for that context. |
| Understand a metric | Open each card to read its meaning and exact calculation basis. |
| Compare logged nap patterns | Compare average day, night and total sleep by exact daytime-sleep-entry count, with the contributing sleep-day sample shown. |
| Review chronology | Swap the timeline axes, inspect daily sleep totals and scan the complete activity log. |
| Include intake context | Review answered questions from every assigned questionnaire snapshot. |
| Keep working notes | Edit the baby-level private note and activity-level private notes without exposing them to the family. |
| Share/save a review artifact | Download the generated PDF or use browser print, with the privacy distinction documented below. |
Entry points
| Surface | Route | Function |
|---|---|---|
| Coach portal | /session-prep?familyUserId=:id&babyId=:id | Full family/baby/range controls, report, private notes and artifact authoring. |
| Mobile | /coach/families/:familyId/session-prep?babyId=:id | Branded metrics, graphs, questionnaire answers and activity log. |
| Caseload | Session prep action | Opens the selected family directly. |
Context and data loading
Coach portal
- Family options put current families before past/expired compatibility rows, then sort by name. Backend record access still decides whether a selection can load.
- When several babies exist, the coach selects one; all report activities are filtered to that baby.
- Ranges are 7-day report (default), Last 14, Last 30 or a custom inclusive start/end date.
- Portal dates are interpreted in the family timezone. The activity query starts at local midnight on the first selected date and extends to 16:00 local time on the day after the final selected date so early-morning split-night fragments can still be attributed to the final sleep day.
- The client loads up to 100 activities per page and at most 20 pages (2,000 rows). If the all-activity API method is unavailable, it falls back to sleep-only activity loading.
- Changing family or baby while the baby private note is dirty prompts before discarding the unsaved draft.
Mobile
- Ranges are fixed to 7, 14 or 30 days, defaulting to 7.
- Calendar days are interpreted in the family timezone. The UTC query interval includes the same following-day 16:00 attribution tail used by the portal.
- The client loads 100 activities per page and at most 12 pages (1,200 rows), bypassing cached activity pages for the report refresh.
- Family detail and all questionnaires load together with the selected baby's range activities.
- Bottom navigation jumps to Metrics, Graphs or Activity logs.
All API dates use a half-open interval: since ⇐ activity < until.
Summary metrics
Every card displays a value and basis hint and opens an explanation dialog. Durations are rounded to whole minutes unless noted.
| Metric | Exact basis |
|---|---|
| Day sleep | Sum daytime nap minutes for each qualifying sleep day, then average the day totals. A normal qualifying day contains at least one day and one night sleep. |
| Night sleep | Sum night-sleep minutes for the same qualifying sleep days, then average. |
| Total sleep | Add the qualifying day's day + night totals, then average. |
| Longest night / shortest night | Maximum/minimum duration of one individual night-sleep log, not the combined night. |
| Longest nap / shortest nap | Maximum/minimum duration of one individual daytime sleep log. |
| Night wakes | Group night stretches by baby and attributed sleep day; infer max(stretch count - 1, 0), then average over represented nights. This is inferred fragmentation, not a separately entered wake count. |
| Feeds | Count breastfeed + bottle logs and divide by the number of calendar days containing at least one of those logs; display a rounded whole count. |
| Bottle total/volume | Sum bottle amounts per logged bottle day and average those daily totals. No volume conversion is performed. |
| Longest / shortest awake period | Maximum/minimum positive gap across previous night → first nap, between naps, or final nap → following night. |
| Average settling | Average the usable time-to-sleep/settling values and round to whole minutes. |
Sleep-day attribution
Night sleep that starts after midnight but before 16:00 is attributed to the previous sleep day. This lets split stretches after midnight remain with the bedtime/night they belong to. Activity timezone/local-date metadata is preferred; family timezone is the fallback.
Sleep by logged nap count
Both Session Prep clients build the comparison deterministically from normalized sleep intervals:
- Filter intervals to the complete selected sleep-day key set. The portal does not use its 14-day timeline cap for this comparison.
- Group intervals by attributed sleep day.
- Count each positive-duration daytime sleep interval as one logged nap.
- Sum daytime and nighttime minutes for the sleep day.
- Exclude a sleep day when it has no positive nighttime sleep total.
- Group the remaining days by their exact logged nap count and sort groups from the lowest count to the highest.
- For each group, average day, night and combined total sleep across its contributing days and round to the nearest whole minute.
The UI shows the contributing dayCount beside every group. A zero-count group is labelled No logged naps; that label describes the absence of daytime sleep entries and does not assert that no nap occurred. When only one group exists, the clients explain that there is no second logged pattern in the range to compare.
The coach portal renders the comparison as a table and includes it on dedicated generated-PDF pages. Mobile renders the same data as compact cards. The two pure aggregation helpers and their conformance cases are intentionally kept aligned while the applications consume independently released shared-package versions.
Complete-day and night-only behavior
The two report engines currently differ:
- The coach-portal report averages day/night/total only across groups containing both day and night sleep. If no such group exists, those three cards show No data.
- The mobile report uses the same complete-day rule when possible. If no naps were logged anywhere in the range but night sleep exists, it falls back to night-only days: day sleep is treated as zero and night/total are averaged across those nights.
This means a night-only dataset can legitimately show a mobile average while the coach portal says No data. It is an implementation difference, not additional server data.
Other cross-client calculation differences
- The portal excludes awake gaps over 18 hours. The mobile day-structured calculation does not apply that same explicit cap.
- Portal bottle volume keeps units separate and can show results such as
120ml + 4oz. Mobile sums numeric amounts without conversion and labels with the last encountered unit, so mixed-unit mobile totals must not be treated as meaningful. - Portal settling maps stored categories to representative values: under 10 → 5, 10–20 → 15, 20–30 → 25, 30–40 → 35, 30–45/30–60 → 38, and over 60/45+ → 60 minutes. Mobile also accepts numeric settling fields and parses numeric ranges, so edge values can differ.
- Portal night-wake averages may retain a simple decimal; mobile displays one decimal.
Report presentation
Metric preferences
- Both clients let the coach hide/show summary cards.
- Visibility is stored in browser local storage under the coach user identifier, so it is a device/browser preference rather than synchronized account data.
- The coach portal also supports drag reorder and Alt+Arrow keyboard reorder. Its order key is local to the browser; visible cards and order feed the generated PDF.
- Hiding all cards leaves a recoverable No summary metrics selected state.
Timeline
- Sleep, feed, nappy and other activities are visually distinguished.
- The coach can place time on the X axis with dates as rows or dates on X with time vertically.
- Point activities and very short sleeps receive a minimum visual width/height so they remain selectable/visible. That visual minimum is not the measured duration.
- Portal timeline/PDF date keys are limited to the most recent 14 days even when the selected report/activity-log range is longer. Mobile renders its selected preset, up to 30 days.
Daily sleep totals
Each sleep day shows separately stacked day and night minutes plus the combined total. A zero day remains visible in the selected calendar sequence rather than being omitted.
Questionnaire answers
- Every assigned questionnaire snapshot is included, not only the latest.
- Only questions with a meaningful answer are rendered, grouped by the snapshot's section.
- Choice identifiers are resolved back to their snapshot labels; optional free text is shown alongside the selected choice.
- Status and answered/total counts remain tied to each snapshot.
Activity log
The log includes activity day/type/time/duration, type-specific details and the family-facing note. Derived wake-window rows are added between eligible sleep logs. In the coach portal, a separate editable Private coach note column appears when the private-note API is available.
Deterministic prep engine
The portal builds a SessionPrepBrief containing age reference range, data coverage, night fragmentation, nap balance, bedtime variation, settling, environment, questionnaire context and sleep-plan context. The type permits inferenceMode: ai, but the current call uses deterministic and makes no model request.
The current panel mainly uses that brief for selected subject/context while the visible SessionPrepCoachReport performs its own metric calculations. The engine's aiReadyFacts are structured future-facing data, not evidence that AI advice is currently shown.
Artifacts, messaging and feedback
- The portal's artifact panel loads all questionnaires, current sleep plan and archived plan history.
- Add questionnaire creates another immutable snapshot; sleep-plan draft/publish/history controls are documented in Features 20 and 21.
- Message family appears only when chat UI is enabled and the selected family's support status is active. Chat still performs its own server capability and participant checks.
- Feedback opens the coach product-feedback form prefilled for session-prep feedback.
PDF and browser print
Download PDF generates a PDF entirely in the browser. It contains the selected visible summary metrics, sleep-by-logged-nap-count pages, timeline, daily sleep chart, questionnaire pages and activity log. The PDF activity detail includes the family note but intentionally does not read or include coach-private note bodies.
Print calls window.print() on the rendered portal report. Current print CSS does not hide the visible Private coach note table column. A browser printout/PDF can therefore include private-note text that is present on screen.
Use Download PDF when a private-note-free generated report is required. Treat browser print as coach-private output unless the private-note column is removed/hidden in a future implementation. See Feature 19.
Current private-note batch limit
The activity-note query accepts at most 100 activity identifiers. The portal report can load up to 2,000 activities and currently sends the full identifier array in one private-note request rather than chunking it. A report with more than 100 activities therefore receives a non-fatal private-note load error: the report remains available, but activity private notes are absent until this client limit mismatch is fixed or a smaller range is selected.
Platform/API dependencies
| Method and path | Role |
|---|---|
GET /coach/families/:familyId | Family/baby context and trusted subject permissions. |
GET /activities?familyUserId=…&babyId=…&since=…&until=… | Cursor-paginated authorized report activities. |
GET /coach/families/:familyId/questionnaires | All questionnaire snapshots and answers. |
GET /coach/families/:familyId/sleep-plan | Current plan and history for the portal artifacts panel. |
GET /coach/families/:familyId/sleep-plans | Published-only family-facing plans where needed. |
GET/PUT …/babies/:babyId/private-note | Baby-level coach-private prep note. |
POST …/activity-private-notes/query and PUT …/activities/:id/private-note | Batch read and edit activity notes. |
Authorization and privacy rules
- Loading requires the coach's matching active assignment, active organization membership, eligible organization/subscription,
canViewLogsand support record access. - Baby and activity identifiers are validated against the selected family; client filtering is not the boundary.
- Private notes require a genuine coach session and are unavailable to owner view-as, family endpoints and other coaches.
- Generated metric values are computed only from the authorized selected range/baby rows.
- The report does not inspect PDF sleep-plan contents; it only knows attached metadata unless the coach opens the document.
- All summaries are descriptive and should be interpreted alongside data coverage and family context.
Loading and failure states
| State | Expected behavior |
|---|---|
| No client families | Explain that a family must be added first. |
| Invalid custom range | Require an end on/after start and do not query. |
| Summary/activity failure | Show a retryable API error and no stale cross-family report. |
| Private notes failure | Keep the report available and show a dedicated warning. |
| No activities | Show No data cards, empty timeline/log and zero calendar totals. |
| No questionnaire answers | Identify the snapshot and explain no answers are present. |
| Family/baby switch with dirty note | Ask before discarding the local private-note draft. |
Acceptance checklist
- Family, baby and range changes reload a correctly scoped report and cannot leak the previous selection.
- Portal and mobile pagination/range limits are understood and incomplete pagination never masquerades as complete server history.
- Each of the 13 metrics follows the formula above and exposes calculation copy.
- Nap-count groups use exact positive daytime-entry counts, include only days with logged night sleep, show their sample size and use the full selected sleep-day range.
- Night wakes are labeled inferred and mixed bottle units are not silently treated as converted volume.
- Timeline minimum widths are not interpreted as duration and portal graph truncation to 14 days is visible/understood.
- All questionnaire snapshots and only answered rows are included.
- Downloaded PDF excludes coach-private notes; browser print is treated as potentially private.
- More than 100 report activities does not break the main report even when private-note batch loading fails.
- Backend access expiry blocks session-prep data regardless of a saved route.
Source evidence
Coach portal
admin-web/src/routes/SessionPrepPanel.tsxadmin-web/src/routes/SessionPrepCoachReport.tsxadmin-web/src/routes/SessionPrepSleepByNapCount.tsxadmin-web/src/routes/session-prep-sleep-by-nap-count.tsadmin-web/src/routes/session-prep-date-range.tsadmin-web/src/routes/session-prep-engine.tsadmin-web/src/routes/SessionPrepArtifactsPanel.tsxadmin-web/src/styles.css
Mobile web
mobile-web/src/routes/SessionPrepScreen.tsxmobile-web/src/components/SessionPrepSleepByNapCount.tsxmobile-web/src/sessionPrep/reportModel.tsmobile-web/src/sessionPrep/sleepByNapCount.tsmobile-web/src/utils/activity-time.ts
Platform and contracts
platform/apps/api/src/routes/coach-routes.tsplatform/apps/api/src/routes/family-routes.tsplatform/apps/api/src/routes/coach-private-note-routes.tsplatform/packages/shared/src/family.tsplatform/packages/shared/src/family-profile-artifacts.tsplatform/packages/shared/src/coach-private-notes.ts
