Skip to content

rdone4425/baby

Repository files navigation

Relay MVP on Cloudflare

A single Cloudflare Worker that bundles:

  • Hono API at /api/*
  • React 18 + Vite SPA served from dist/client/ via the Workers Assets binding
  • D1 (SQLite) — 5 tables: families, caregivers, babies, events, shifts
  • KV for magic-link tokens, invite codes, sessions
  • Anthropic Claude Sonnet 4.6 for the AI "Today's 3 Things" summary (graceful template-only fallback when the key is missing)
  • Resend for magic-link email delivery (dev mode logs codes to the Worker console instead)

Production deploy walkthrough: DEPLOY.md.

What is this

Relay is a family operations layer for new parents — less tracking, more peace of mind. The hero feature is multi-caregiver shift handoff: when your partner or nanny hands the baby off to you, you instantly know what mattered in the last few hours, what's coming next, and what to do — without asking.

This repo is the MVP (web-only, single Worker, ~25KB of TypeScript) demonstrating the core loop end-to-end. iOS and Android apps are out of scope for this repo.

Local development

# 1. Install dependencies
pnpm install

# 2. First time only — set up the local D1 database
pnpm db:migrate:local

# 3. (Optional) Add secrets for the AI / email paths to work locally
cp .env.example .dev.vars
# edit .dev.vars: set ANTHROPIC_API_KEY and RESEND_API_KEY

# 4. Run Vite + Worker on http://localhost:5173 with HMR
pnpm dev

Stop the server with Ctrl-C. Magic-link codes are printed to the dev-server console as [relay:dev-mailer] magic code for <email>: 123456 when RESEND_API_KEY is unset.

What's implemented

PRD module MVP status
§5.1 M1 Multi-Caregiver Accounts (3 roles)
§5.2 M2 Shift / Handoff (auto + manual takeover)
§5.3 M3 Quick Logging (feed / sleep / diaper / mood)
§5.4 M4 Today's 3 Things (real Claude + fallback)
§5.5 M5 Week View ❌ deferred
§5.6 M6 Baby Profile / Settings (basic only)
§6.4 End-to-end encryption ❌ deferred
§10 COPPA / GDPR full ❌ stub policy pages
Apple IAP / Google Billing ❌ Free tier only
Real-time WebSocket sync ❌ 10s poll instead
Offline queue / >24h offline mode ❌ online-only

File map

.
├── DEPLOY.md             ← production deploy walkthrough
├── README.md             ← this file
├── package.json
├── wrangler.toml         ← Worker + asset + D1 + KV bindings
├── vite.config.ts        ← @cloudflare/vite-plugin integrates everything
├── tsconfig.json
├── tsconfig.node.json
├── drizzle.config.ts
├── migrations/
│   └── 0001_init.sql     ← 5 tables + indexes
├── src/                  ← Worker code (server-side)
│   ├── worker.ts         ← Hono entry, route mounting
│   ├── env.ts            ← Bindings type definitions
│   ├── shared.ts         ← Shared TS domain types (CaregiverRole, RelayEvent, …)
│   ├── api/
│   │   ├── auth.ts         POST /auth/request-link, /verify, /logout · GET /auth/me
│   │   ├── families.ts     POST /families, /:id/invites, /join · GET /me, /:id/caregivers
│   │   ├── caregivers.ts   PATCH /:id (role) · DELETE /:id
│   │   ├── events.ts       POST / · GET / (auto-shift trigger)
│   │   ├── shifts.ts       POST /takeover · GET /current
│   │   └── today.ts        GET / (composed snapshot + AI items)
│   ├── db/
│   │   ├── schema.ts       Drizzle table defs
│   │   ├── client.ts       drizzle(env.DB) factory
│   │   └── repos/          familyRepo / caregiverRepo / babyRepo / eventRepo / shiftRepo
│   ├── lib/
│   │   ├── id.ts           UUIDs + 6-digit codes + constant-time compare
│   │   ├── session.ts      Cookie + KV session, requireAuth middleware
│   │   ├── permissions.ts  canInvite / canChangeRoles / canRemoveOthers
│   │   ├── mailer.ts       Resend adapter + dev console fallback
│   │   ├── claude.ts       Anthropic Messages fetch (8s timeout)
│   │   ├── prompts.ts      buildTodayPrompt + parseTodayResponse + fallbackThings
│   │   └── validate.ts     Zod-validator wrapper that emits uniform error envelope
│   └── validation/
│       └── schemas.ts      All request-body Zod schemas
├── web/                  ← Vite SPA (client-side React)
│   ├── index.html
│   └── src/
│       ├── main.tsx
│       ├── App.tsx          react-router routes, auth guards
│       ├── styles.css
│       ├── api/
│       │   ├── client.ts    typed fetch wrapper with ApiError
│       │   └── auth.tsx     AuthProvider + useAuth context
│       ├── pages/
│       │   ├── Login.tsx       email → magic code
│       │   ├── VerifyCode.tsx  paste code → session
│       │   ├── Onboarding.tsx  create family + baby
│       │   ├── JoinFamily.tsx  paste 6-digit invite code
│       │   ├── Today.tsx       active caregiver + AI + quick log + events
│       │   ├── Family.tsx      members, role changes, invites
│       │   └── More.tsx        profile / privacy / subscription / help
│       └── components/
│           ├── ActiveCaregiverCard.tsx
│           ├── QuickLog.tsx
│           ├── EventList.tsx
│           └── TodaysThings.tsx
└── tests/
    └── unit/                 23 passing unit tests
        ├── id.test.ts        ← UUID + 6-digit code + safeEqual
        ├── permissions.test.ts
        └── prompts.test.ts   ← buildTodayPrompt / parser / caps gate

Scripts

Script What it does
pnpm dev Vite + Worker via @cloudflare/vite-plugin on http://localhost:5173
pnpm build TypeScript + Vite production build → dist/client/ and dist/ssr/
pnpm typecheck tsc --noEmit on both project tsconfigs
pnpm test Vitest unit + integration
pnpm db:migrate:local Apply migrations/*.sql to the local Miniflare D1
pnpm db:migrate:remote Apply migrations to the production D1
pnpm deploy pnpm build && wrangler deploy

End-to-end manual smoke test

  1. pnpm dev
  2. Open http://localhost:5173 in two browsers (or one normal + one Incognito).
  3. Browser A: sign in as parent@example.com, paste the 6-digit code from the terminal, create family Smith Family + baby Emma.
  4. Browser A: tap FamilyGenerate invite code. Copy the 6-digit code.
  5. Browser B: tap Join a family, paste the code, sign in as caregiver@example.com.
  6. Browser B: tap Feed → 4 oz → Save.
  7. Browser A: within 10 s, the active-caregiver card flips to the caregiver, and the feed appears in Recent.
  8. Browser A: tap Take over → card flips back.
  9. Log 3-4 more events. After ~1 minute, the Today's things card refreshes via Claude (or shows a fallback note if no key).
  10. Browser A (Primary): change Browser B's role to Co-Parent — the dropdown updates immediately.

About

No description, website, or topics provided.

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors