Skip to main content

Introduction

Zen Nurture’s API is built on Convex, a backend-as-a-service platform that provides real-time data synchronization, serverless functions, and built-in authentication. The API follows a type-safe, function-based architecture that makes it easy to interact with your baby tracking data.

Architecture

The Zen Nurture API is organized around key resources:
  • Families - Multi-caregiver family groups
  • Baby Profiles - Individual baby records with timezone and measurement preferences
  • Events - All tracked activities (feeds, diapers, sleep, growth, etc.)
  • Caregivers - People who care for a baby
  • Reminders - Configurable reminder rules
  • Milestones - Developmental milestone tracking
  • Photos - Media attachments for events
  • Weekly Digests - Auto-generated weekly summaries

Event Types

Zen Nurture supports comprehensive event tracking:
  • FEED_BOTTLE - Bottle feeding (formula or expressed milk)
  • FEED_BREAST - Breastfeeding sessions
  • PUMP - Pumping sessions
  • DIAPER - Diaper changes (wet, dirty, mixed, dry)
  • SLEEP - Sleep sessions with start/end times
  • GROWTH - Weight, height, head circumference measurements
  • MED_DOSE - Medication doses
  • VACCINE_DOSE - Vaccination records
  • NOTE - General notes and observations

API Patterns

Convex uses queries for reading data and mutations for writing data. All functions are type-safe and support real-time subscriptions.

Queries

Queries are read-only operations that can be subscribed to for real-time updates:
import { useQuery } from "convex/react";
import { api } from "../convex/_generated/api";

function BabyProfiles() {
  const profiles = useQuery(api.events.getBabyProfiles);
  
  return (
    <div>
      {profiles?.map(profile => (
        <div key={profile._id}>{profile.name}</div>
      ))}
    </div>
  );
}

Mutations

Mutations modify data and return after completion:
import { useMutation } from "convex/react";
import { api } from "../convex/_generated/api";

function CreateEvent() {
  const createEvent = useMutation(api.events.createEvent);
  
  const logFeed = async () => {
    await createEvent({
      babyId: "...",
      type: "FEED_BOTTLE",
      timestamp: new Date().toISOString(),
      payload: {
        amountMl: 120,
        contentType: "formula",
        formulaName: "Enfamil"
      }
    });
  };
  
  return <button onClick={logFeed}>Log Feed</button>;
}

Client Setup

Zen Nurture uses the Convex React client with Better Auth integration for authentication.
npm install convex better-auth @convex-dev/better-auth

Resource Schema

All resources follow Convex’s schema definition:
convex/schema.ts
import { defineSchema, defineTable } from "convex/server";
import { v } from "convex/values";

export default defineSchema({
  babyProfiles: defineTable({
    familyId: v.optional(v.id("families")),
    name: v.string(),
    dob: v.string(),
    gender: v.optional(v.string()),
    timezone: v.string(),
    measurementUnits: v.optional(v.object({
      volume: v.optional(v.string()),
      weight: v.optional(v.string()),
      length: v.optional(v.string()),
    })),
    createdAt: v.string(),
  })
    .index("by_createdAt", ["createdAt"])
    .index("by_familyId", ["familyId"]),

  events: defineTable({
    babyId: v.id("babyProfiles"),
    type: v.string(),
    timestamp: v.string(),
    caregiverId: v.optional(v.id("caregivers")),
    payload: v.optional(v.any()),
    source: v.optional(v.string()),
    loggedBy: v.optional(v.string()),
    loggedByName: v.optional(v.string()),
    photoIds: v.optional(v.array(v.string())),
    createdAt: v.string(),
    updatedAt: v.optional(v.string()),
  })
    .index("by_babyId_timestamp", ["babyId", "timestamp"])
    .index("by_babyId_type_timestamp", ["babyId", "type", "timestamp"])
});

Real-Time Subscriptions

One of Convex’s key features is automatic real-time updates. Any component using useQuery will automatically re-render when the underlying data changes:
const events = useQuery(api.events.listEvents, {
  babyId: selectedBaby._id,
  limit: 50
});

// Events automatically updates when new events are created

Error Handling

All mutations throw errors that can be caught:
try {
  await createEvent({ ... });
} catch (error) {
  console.error("Failed to create event:", error.message);
}
Common errors:
  • "Unauthenticated" - User is not logged in
  • "Not authorized" - User doesn’t have access to the resource
  • "Baby not found" - Invalid baby profile ID
  • "Not a member of this family" - User is not part of the family

Next Steps

Authentication

Learn about Better Auth integration and protected routes

Events API

Track feeding, diaper changes, sleep, and more

Baby Profiles

Create and manage baby profiles

Families

Multi-caregiver family management

Build docs developers (and LLMs) love