SC SleepCoach guide
SleepCoach platform

Sleep tracking that replaces the morning WhatsApp reconstruction.

Parents record sleep events on a phone. Coaches review structured timelines in a web dashboard. Supabase keeps each family's records separate.

2 React apps 3 user roles 5 data tables 4 sleep event types

Verified against the repository on 1 September 2026

Two stacked application layers Parent PWA Coach dashboard Supabase backend
01
Why it exists

One useful record of the night

For parents

Log in seconds

A parent may be holding a child in a dark room. One tap should start a record, and a poor connection should not lose it.

For coaches

Stop chasing messages

Assigned client records appear in one dashboard, ready for a morning review or a weekly coaching call.

For the business

Prove the coaching loop

The MVP aims for one paying coach, two active families per coach, and at least five logged nights each week.

02
People and permissions

Three roles, three different jobs

P

Parent

Owns a child profile and its sleep logs. Uses the installable phone app.

C

Coach

Invites families, reads assigned records, and manages displayed branding.

A

Administrator

Creates coaches, changes account state, and reassigns families.

03
System picture

Two frontends, one Supabase backend

Mobile first

Parent PWA

Auth, sleep logs, history, child profile, install prompt, offline create queue.

Web only

Coach and admin dashboard

Clients, timelines, invitations, branding, coach lifecycle, reassignment.

Shared backend

Supabase

  • Authentication
  • Postgres and row-level security
  • Logo storage
  • Three Edge Functions

Ordinary records go straight from the browser to Supabase. Row-level security is the real permission boundary. Edge Functions handle account operations that need the secret service-role key.

04
Core journeys

Follow the data, not just the screens

1Coach invitesDashboard creates a seven-day link.
2Parent joinsCurrently blocked by an email-field mismatch.
3Parent logsSupabase online, IndexedDB when offline.
4Coach reviewsRLS exposes assigned family records.
01
Admin creates a coachPrivileged account creation and welcome email
  1. The admin submits name, email, and display name from the dashboard.
  2. send-welcome verifies the bearer token and requires the admin role.
  3. Supabase Auth creates a confirmed coach with a generated temporary password.
  4. The database trigger creates the profile, then the function adds branding.
  5. Resend receives a welcome message with the temporary password.
Recovery gap

Branding and email failures do not fail the request. There is no password-change screen and no rollback after a partial account creation.

Owners: CreateCoachModal.tsxsend-welcome/index.tshandle_new_user()

02
Coach invites a familySeven-day link with email and copy fallback
  1. The coach submits a family label and parent email with the session token.
  2. send-invite requires an active coach and rejects an existing profile.
  3. A matching pending invite gets a new expiry. Otherwise a token and invite row are created.
  4. The function builds /signup?token=... and asks Resend to send it.
  5. The coach receives the link even when email delivery fails, so it can be copied into WhatsApp.
Hidden delivery failure

The backend returns success after a Resend failure, and the dashboard never turns on its email-failed message.

03
Parent accepts the inviteIntended onboarding flow, currently broken
  1. The public function should validate the token, status, expiry, and password length.
  2. It should create a parent Auth user and connect the generated profile to the invite's coach.
  3. It should insert the child, mark the invite accepted, and return browser session tokens.
This flow cannot complete

The function requires an email field, but the parent form does not ask for or send one. The function also trusts a submitted email instead of binding the account to the email already stored on the invite.

Owners: AcceptInviteScreen.tsxaccept-invite/index.ts

04
Parent starts and closes a logFast path with an offline creation queue
  1. A quick-start button sends the child ID, log type, and current time to the service.
  2. The service calculates the logical sleep day and checks duplicate wake or bedtime events.
  3. It validates time order, normalizes wake records, and decides whether the log stays open.
  4. Online logs go to Supabase. Offline logs get a UUID and enter IndexedDB.
  5. Startup and the browser's online event replay queued creations one at a time.
Sleep-day rule

A night wakeup belongs to the most recent bedtime's date, even when it starts after midnight. With no bedtime, it falls back to the current date.

Offline limit

Only new log creation queues. Reads, edits, closes, and deletes still need Supabase. A lost successful response can leave one UUID stuck in the queue.

05
Coach reviews a clientAssigned profiles, one child, and a dated timeline
  1. The client overview loads parent profiles assigned to the signed-in coach.
  2. Pending invites are appended as temporary client cards.
  3. The hook runs one extra latest-log query for every accepted client.
  4. Client detail loads the first child and the selected range, seven days by default.
  5. The timeline groups events by logical sleep date and shows duration, notes, and open state.
Permission boundary

The coach screens are read-only for sleep data. Postgres RLS grants access only through the assigned parent's coach_id.

06
Admin changes coach ownershipDeactivation, reactivation, and reassignment

Deactivation sends one request to disable the coach and another to set a 30-day grace timestamp on assigned parents. Reactivation reverses both writes. Reassignment changes a parent's coach_id, which immediately changes which coach RLS allows to read the family.

Grace is display-only

The parent app and RLS do not enforce read-only access or expiry. The two admin writes are not atomic and use the administrator's browser clock.

05
Feature inventory

What exists today

Partial

Parent login

Email and password work, but the guard does not require the parent role or load the profile on every restored session.

Parent PWA
Broken

Invite signup

The form omits the email required by the public acceptance function, so onboarding stops at validation.

Parent PWA + Edge Function
Implemented

One-tap quick start

Wake, nap, bedtime, and night-wakeup buttons create a record with the current time.

Parent PWA
Missing

Manual create and edit

The router imports create and edit screens that are absent, which prevents the parent app from building.

Parent PWA
Implemented

Current-day home

Shows open and closed events, elapsed time, quick close, and total closed sleep minutes.

Parent PWA
Implemented

History

Calendar totals, 20-day list windows, day detail, and links to individual records.

Parent PWA
Implemented

Child profile

Loads the family's first child and updates name and birth date.

Parent PWA
Partial

Offline support

New records queue in IndexedDB and replay on reconnect. Other actions remain online-only.

Parent PWA
Implemented

PWA installation

Generated manifest, static asset cache, Android prompt, and manual iOS instructions.

Parent PWA
Implemented

Coach client list

Assigned parents and pending invites appear as client cards with the latest log date.

Dashboard
Implemented

Client timeline

Seven-day date range, logical-day grouping, notes, duration, and open-state display.

Dashboard
Partial

Family invitations

Link creation and resend work. Email delivery failure is hidden from the coach.

Dashboard + Edge Function
Partial

Coach branding

Name and logo paths exist. The repository does not create Storage object upload policies.

Dashboard + Parent PWA
Partial

Coach account creation

Admin flow works, but later failures do not roll back the Auth user and there is no password-change screen.

Admin + Edge Function
Implemented

Client reassignment

Admin changes coach_id; RLS then transfers coach visibility.

Admin
Partial

Coach lifecycle

Active state and grace timestamps can be changed, but the operation is split across requests.

Admin
Missing

Grace enforcement

No read-only policy, expiry task, or access cutoff uses the stored grace timestamp.

Backend + Parent PWA
Missing

Analytics and CI

No product events, metric dashboards, automated tests, or continuous integration workflow.

Operations
06
Domain model

The five records that hold the product together

01

profiles

One Auth user. Role, coach ownership, active state, and grace timestamp.

02

children

Belongs to a parent. Schema allows many, screens use the first one.

03

sleep_logs

Type, status, logical date, times, and optional notes.

04

invites

Coach, family label, email, token, status, and seven-day expiry.

05

coach_branding

One display name and optional public logo per coach.

WakePoint in time, always closed
z
NapOpen until an end time
BedtimeOne intended per sleep day
Night wakeupGrouped under latest bedtime
Business rules and where they are enforced
RuleCurrent ownerStrength
One wake per child and logical dateParent service count before insertClient only
One bedtime per child and logical dateParent service count before insertClient only
Wake has no asleep or end timeParent service normalizationClient only
Times remain in start, asleep, end orderParent service validationClient only
Parent changes only their own child and logsPostgres row-level securityDatabase
Coach reads only assigned familiesPostgres row-level securityDatabase
Invite expires after seven daysAcceptance Edge FunctionServer
Grace makes a parent read-onlyNo current ownerNot enforced
07
Acceptance register

What the product must let people do

Parent9 requirements
  • FR-P01Sign in with email and passwordPartial
  • FR-P02Create an account from a valid inviteBroken
  • FR-P03Start any of four log types quicklyReady
  • FR-P04Create a past or detailed recordMissing
  • FR-P05Edit or delete a recordMissing
  • FR-P06Close an open record in one tapPartial
  • FR-P07Review current and historical recordsReady
  • FR-P08Replay a new offline record laterPartial
  • FR-P09Use read-only access during graceMissing
Coach4 requirements
  • FR-C01Sign in and see assigned clientsReady
  • FR-C02Inspect client logs by date rangeReady
  • FR-C03Invite a parent with a shareable linkPartial
  • FR-C04Update display name and logoPartial
Admin and platform6 requirements
  • FR-A01Create a coach accountPartial
  • FR-A02Activate or deactivate one consistent account statePartial
  • FR-A03Reassign a parent between coachesReady
  • FR-S01Block unrelated tenant readsUntested
  • FR-S02Protect ownership and lifecycle fieldsFailed
  • FR-O01Observe failures and product goalsMissing
08
Trust boundaries

Security lives below the screens

01

Browser session

Supabase Auth persists email-and-password sessions. Route guards steer users, but navigation checks do not protect data.

02

Row-level security

All five public tables enable RLS. Parent and coach policies follow user ID, role metadata, child ownership, and coach assignment.

03

Service role

Edge Functions use a secret key for privileged work. It bypasses RLS and never appears in browser source.

Intended table access by role
DataParentCoachAdmin
ProfilesOwn read and broad self-updateOwn plus assigned parent readsRead and update all
ChildrenCRUD ownRead assignedRead all
Sleep logsCRUD own child's logsRead assignedRead all
InvitesNo direct accessCRUD ownRead all
BrandingRead assigned coachCRUD ownRead all
Profile policy risk

A user cannot change their role, but the broad self-update policy still permits changes to coach_id, is_active, and the grace timestamp.

Invite identity risk

The public acceptance function should use the invite's stored email. It currently expects an untrusted body email.

Open CORS

Every Edge Function responds with Access-Control-Allow-Origin: *.

Mobile installConfigured, not device-tested here
Offline dataNew records only
AccessibilityMany 44 px targets, no audit
LocalizationEnglish resource plus hardcoded text
ObservabilityConsole errors and generic UI messages
AnalyticsNot wired
09
Launch reality

Fix these before real families rely on it

  1. 01
    Repair invite acceptance

    Use the invite's stored email and make parent onboarding one recoverable operation.

    Blocks onboarding
  2. 02
    Add create and edit log screens

    The missing modules prevent the parent production build.

    Blocks build
  3. 03
    Move hard rules to a trusted boundary

    Database constraints or a transaction-owned function must protect duplicates, time order, and grace behavior.

    Data integrity
  4. 04
    Restrict profile self-updates

    Users should not be able to change coach ownership or account-lifecycle fields.

    Security
  5. 05
    Create Storage upload policies

    The public logo bucket exists, but browser upload authorization does not.

    Branding
  6. 06
    Handle partial failures

    Coach creation, parent onboarding, and deactivation can leave half-finished state.

    Reliability
  7. 07
    Test tenant isolation and offline replay

    No automated suite proves RLS, role routing, invitations, queue retries, or grace.

    Quality gate
  8. 08
    Show queue and delivery state

    Parents cannot see stuck offline items, and coaches cannot see failed invitation email.

    Recovery
  9. 09
    Add metrics with privacy rules

    The product goals have no event collection or internal health view.

    Operations
  10. 10
    Finish production operations

    Complete legal placeholders, backups, alerts, secrets, domains, and rollback steps.

    Launch
10
Engineering map

Where each part lives

React 19TypeScript 5.8Vite 8React Router 7Tailwind 4Zustand 5Supabase 2Dexie 4date-fns 4i18next
● ● ●Repository
sleep_coach_platform/
├── apps/
│   ├── parent/        installable PWA
│   └── dashboard/     coach + admin
├── packages/shared/   types + client
├── supabase/
│   ├── functions/     privileged flows
│   └── migrations/    schema + RLS
├── docs/              product reference
└── legal/             draft policies
Repository health
  • Dependency installPasses, with five high-severity advisories
  • Dashboard buildPasses, with a large JavaScript chunk warning
  • Shared type-checkPasses
  • ×
    Parent buildFails on missing log screens
  • ×
    Root buildShared workspace also lacks a build script
  • ×
    App lintBoth workspaces exit nonzero
  • Automated tests and CINot present
Parent entryapps/parent/src/main.tsx
Log rulesapps/parent/src/services/sleep-log.service.ts
Offline replayapps/parent/src/services/sync.service.ts
Dashboard routesapps/dashboard/src/routes/index.tsx
Admin lifecycleapps/dashboard/src/features/admin/AdminCoachDetailScreen.tsx
Shared contractpackages/shared/src/index.ts
Database authoritysupabase/migrations/
Privileged workflowssupabase/functions/
!
The code is ahead of its old implementation plan, but behind its product promises.

Use the checked-in source and migrations to answer "what happens now." Use the PRD to answer "what was intended." This handbook keeps the two separate.

11
Shared vocabulary

Terms used throughout the project

Sleep day
The logical date that groups a bedtime and later night wakeups.
Open log
A nap, bedtime, or night wakeup that has no end time yet.
Pending invite
A coach token that has not been used and has not failed expiry validation.
Grace period
A timestamp visible in admin UI. The current system does not enforce it.
RLS
Postgres row-level security, the main tenant-isolation mechanism.
Service role
A server-only Supabase key that bypasses RLS for privileged work.
PWA
The parent web app with an install manifest and generated service worker.
Virtual client
A pending invite displayed in the coach list before a parent profile exists.
The short version

Parents create the signal. Coaches turn it into better decisions.

The foundation is sensible: separate apps, shared contracts, and database-level tenant isolation. The next work is less glamorous and more important. Finish onboarding, enforce the rules, and prove recovery before a tired parent depends on it at 3am.

Read again from the top