Help centre Families Coaches Support

Littles Baby Tracker

Help for families and coaches

Site Tools


technical:features:19_coach_private_notes

19 — Coach-private notes

Technical reference. For task-based help, see the corresponding user guide.
Documentation status: complete for the current implementation

Reviewed: 2026-07-21

Primary users: the genuine assigned coach only

Surfaces: coach admin portal, mobile coach workspace and platform API

Purpose

Coach-private notes give a coach a durable scratchpad about a baby and individual activity logs without altering the family's own notes. They are deliberately scoped to the specific coach, organization and current family relationship.

“Private” here means the notes have no family API, are unavailable to other coaches and owner view-as, and are excluded from analytics and the generated coach-review PDF. It does not mean every possible local output is automatically redacted; the current browser-print caveat is documented below.

User outcomes

User need Outcome
Keep a running baby note Store one substantial note for a baby within this coach/family relationship.
Annotate a log Store one private note against an individual activity.
Avoid stale-tab loss Receive a conflict instead of silently overwriting a newer saved note.
Remove a note Clear the body and save to delete the durable note.
Protect family boundaries Keep coach text out of family notes, family endpoints, analytics and ordinary exports.

Note model and scope

Target Uniqueness scope Typical presentation
Baby note One per organization + coach + family + baby. Collapsible Private notes about [baby] card on mobile family view-as and portal session prep.
Activity note One per organization + coach + activity. Family and baby identifiers are retained on the row. Inline editor in activity history/edit/analysis and the portal session-prep activity table.

A body is at most 10,000 characters. Leading/trailing whitespace is removed. A blank string or null is treated as deletion, so the service does not retain empty note rows.

Entry points

Surface Location Function
Mobile family view-as home Baby private-note card Read/edit the selected baby's note.
Mobile activity history/edit Private coach note editor Read/edit the selected activity note.
Mobile analysis/tracking Activity edit sheet Use the same activity-note editor for a log opened from analysis/history.
Coach portal session prep Baby note above the report Keep preparation context for the selected baby.
Coach portal activity report Private coach note column Open/save one note per activity row.

Create, update and delete

  1. Opening an editor loads the current note or returns note: null.
  2. The draft stays local until Save.
  3. Saving non-empty text creates the note if absent or updates the existing note.
  4. Saving blank/null deletes the existing note and returns note: null.
  5. Baby-note cards cannot be collapsed while dirty or saving. Their collapsed preference is stored locally under the coach user identifier.
  6. Portal family/baby switching asks for confirmation when the selected baby note has unsaved edits.
  7. Activity note editors expose compact open/edit/cancel/save states so every row does not render a large text area at once.

Optimistic concurrency

Every write can include expectedUpdatedAt:

  1. For an existing note, the client sends the timestamp it loaded.
  2. For a new note, the client sends null to assert that no note exists.
  3. If the durable state no longer matches, the API returns HTTP 409 with privateNoteMutationConflict.
  4. The UI keeps the coach's draft and reports the conflict rather than overwriting the other tab/device.
  5. Successful updates force updatedAt to move forward by at least one millisecond, even when writes occur within the same clock tick.

Omitting expectedUpdatedAt remains a compatibility last-write-wins path. Current editors provide it and should continue to do so.

Batch activity-note loading

POST /coach/families/:familyId/activity-private-notes/query accepts 1–100 activity identifiers. The platform:

  1. verifies the coach/family scope first;
  2. validates that every requested activity belongs to that family;
  3. returns only notes belonging to the current coach and organization; and
  4. does not return placeholders for activities with no note.

Clients that need more than 100 must chunk their requests. The current portal session-prep loader does not: a report containing more than 100 activities triggers a non-fatal note-load warning and shows the report without those activity notes. See Feature 18.

Access lifecycle

Private-note access requires all of the following at request time:

  1. a genuine coach actor, not ownerViewAsCoach;
  2. the active assignment matching coach and family;
  3. assignment canViewLogs;
  4. active organization membership;
  5. active/trialing organization and coach subscription access; and
  6. a support entitlement that allows family-record access.

Paused support allows record access and therefore private notes. Expired/revoked/canceled/inactive-billing support does not. The note may remain stored for legitimate retention/audit purposes, but it is not retrievable through the coach endpoint after access ends.

Privacy boundary

Consumer/output Private-note body included?
Family mobile/API No. There is no family private-note route or field.
Another assigned/team coach No. Rows are keyed and queried by the creating coach.
Owner view-as-coach No. Synthetic owner sessions are explicitly denied.
Coach dashboard/practice analytics No. Analytics services do not load private-note tables.
Generated Download PDF coach-review report No. Its activity text reads type details and family note only.
Live coach portal session-prep report Yes, for the genuine coach. It is an editable coach-only column.
Browser Print of that live report Currently yes. Print CSS does not hide the private-note column.
Do not give a browser-printed session-prep page to a family or third party without reviewing it. Use the generated Download PDF for the current private-note-free export, or remove/redact the column before printing.

The browser-print behavior is a current implementation caveat, not a relaxation of the API privacy model.

Audit behavior

Create, update and delete write coachPrivateNote.created, .updated or .deleted events. Audit metadata identifies note ID, target type, baby/activity, family and organization context. The note body is intentionally not copied into audit metadata.

Platform API contract

Method and path Role
GET /coach/families/:familyId/babies/:babyId/private-note Return the current coach's baby note or null.
PUT /coach/families/:familyId/babies/:babyId/private-note Create/update/delete with { body, expectedUpdatedAt? }.
POST /coach/families/:familyId/activity-private-notes/query Return current coach's notes for 1–100 authorized activity IDs.
PUT /coach/families/:familyId/activities/:activityId/private-note Create/update/delete one activity note.

Validation and user-visible states

State Expected behavior
Note loading Keep an editor disabled/loading; do not show another target's prior draft.
No note Start with an empty draft and expectedUpdatedAt: null.
Saved Update local note/timestamp and show concise confirmation.
Blank saved Delete, return null and close/reset the editor appropriately.
Conflict Keep the draft and ask the coach to reload/reconcile rather than silently overwrite.
Dirty baby note Disable minimize and confirm before changing family/baby.
Private-note side-load failure Keep the underlying family/report data usable and show a dedicated warning.
Access expired Deny without returning whether a note exists.

Acceptance checklist

  1. Baby and activity uniqueness scopes prevent duplicate durable notes for the same coach target.
  2. Body validation enforces 10,000 characters and blank save deletes.
  3. Current editors send expectedUpdatedAt and a stale save returns 409 without losing the draft.
  4. Baby/activity identifiers must belong to the authorized family.
  5. Family users, other coaches and owner view-as cannot read or mutate note bodies.
  6. Expired or revoked record access denies notes even from a saved route.
  7. Audit events never copy the note body.
  8. Analytics and generated PDF exclude note bodies.
  9. Browser print is recognized as currently capable of including the visible private-note column.
  10. Batch callers respect the 100-activity maximum or fail non-fatally.

Source evidence

Coach portal

  • admin-web/src/routes/CoachBabyPrivateNotePanel.tsx
  • admin-web/src/routes/ActivityPrivateNoteCell.tsx
  • admin-web/src/routes/SessionPrepPanel.tsx
  • admin-web/src/routes/SessionPrepCoachReport.tsx
  • admin-web/src/styles.css

Mobile web

  • mobile-web/src/components/CoachPrivateNotes.tsx
  • mobile-web/src/components/ActivityHistoryEditSheet.tsx
  • mobile-web/src/routes/FamilyDashboard.tsx
  • mobile-web/src/routes/ActivityTrackingScreen.tsx
  • mobile-web/src/routes/AnalysisScreen.tsx

Platform and contracts

  • platform/apps/api/src/routes/coach-private-note-routes.ts
  • platform/apps/api/src/services/coach-private-note-service.ts
  • platform/packages/shared/src/coach-private-notes.ts
  • platform/packages/shared/src/enums.ts