Skip to main content

Overview

Baby profiles store essential information about your baby and configure how the app tracks and displays data. Each profile includes demographic information, timezone settings, measurement preferences, and more.

Schema Structure

Baby profiles are stored in the babyProfiles table:
convex/schema.ts
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"])

Core Fields

name
string
required
Baby’s name, displayed throughout the app
dob
string
required
Date of birth in ISO format (YYYY-MM-DD). Used to calculate age and age-appropriate milestones
gender
string
Optional gender value: "boy", "girl", or "other". Controls theming and pronouns throughout the app
timezone
string
required
IANA timezone (e.g., "Asia/Kolkata", "America/New_York"). Defaults to "Asia/Kolkata"
familyId
Id<'families'>
Reference to the family this profile belongs to. Required for multi-user access

Measurement Units

Customize units for different measurements:
measurementUnits: {
  volume: "ml" | "oz",      // Feed volumes
  weight: "kg" | "lb",      // Body weight
  length: "cm" | "in"       // Height measurements
}
While the schema supports measurement unit preferences, the current implementation primarily uses metric units (ml, kg, cm). Imperial unit conversion is planned for future releases.

Creating a Profile

Use the createBabyProfile mutation:
import { useMutation } from "convex/react";
import { api } from "../../convex/_generated/api";

const createProfile = useMutation(api.events.createBabyProfile);

await createProfile({
  familyId,
  name: "Emma",
  dob: "2024-01-15",
  gender: "girl",
  timezone: "America/New_York",
  measurementUnits: {
    volume: "oz",
    weight: "lb",
    length: "in"
  }
});
When a profile is created, the system automatically creates a caregiver record for the family owner.

Updating a Profile

Modify profile settings:
convex/events.ts
export const updateBabyProfile = mutation({
  args: {
    id: v.id("babyProfiles"),
    name: v.optional(v.string()),
    dob: v.optional(v.string()),
    gender: v.optional(v.string()),
    timezone: v.optional(v.string()),
    measurementUnits: v.optional(v.object({
      volume: v.optional(v.string()),
      weight: v.optional(v.string()),
      length: v.optional(v.string()),
    })),
  },
  handler: async (ctx, args) => {
    const user = await requireAuth(ctx);
    await requireBabyAccess(ctx, args.id, user._id);
    const { id, ...updates } = args;
    await ctx.db.patch(id, updates);
    return id;
  },
});

Querying Profiles

Get Active Profile

const profile = useQuery(api.events.getBabyProfile, { id: babyId });

List All Profiles

const profiles = useQuery(api.events.getBabyProfiles);
The query returns profiles from all families the user belongs to, sorted by creation date (newest first).

Gender Theming

The gender field controls visual theming throughout the app:
import { useGenderTheme } from "@/components/GenderTheme";

const genderTheme = useGenderTheme();
// Returns theme objects like:
// {
//   primary: "text-sage",
//   primaryLight: "bg-sage/10",
//   bg: "bg-sage/5",
//   border: "border-sage/20",
//   text: "text-sage"
// }
Themes available:
  • Boy: Blue tones
  • Girl: Sage green tones
  • Other/Unspecified: Neutral tones

Caregiver Management

Each baby profile can have multiple caregivers who log activities:
convex/schema.ts
caregivers: defineTable({
  babyId: v.id("babyProfiles"),
  displayName: v.string(),
  color: v.string(),
  userId: v.optional(v.string()),
  createdAt: v.string(),
})
  .index("by_babyId", ["babyId"])
  .index("by_userId", ["userId"])

Caregiver Colors

Each caregiver gets a unique color for easy visual identification:
convex/events.ts
const DEFAULT_CAREGIVER_COLORS = [
  "#7C9A82",  // Sage
  "#C4A484",  // Clay
  "#6B8CAE",  // Dusty Blue
  "#E57373",  // Coral
  "#9C7CF4",  // Purple
  "#F4B942",  // Gold
  "#4DB6AC",  // Teal
  "#7986CB",  // Periwinkle
];

Adding Caregivers

const addCaregiver = useMutation(api.events.createCaregiver);

await addCaregiver({
  babyId,
  displayName: "Grandma",
  color: "#7C9A82"
});

Listing Caregivers

const caregivers = useQuery(api.events.listCaregivers, { babyId });

Family Association

Profiles belong to families, enabling multi-user collaboration:
1

Family Created

A family record is created with an owner
2

Profile Linked

Baby profile is associated with the family via familyId
3

Access Control

All family members can access the profile and log activities

Access Control

The requireBabyAccess helper ensures users can only access profiles they have permission for:
convex/lib/auth.ts
export async function requireBabyAccess(
  ctx: QueryCtx | MutationCtx,
  babyId: Id<"babyProfiles">,
  userId: string
) {
  const profile = await ctx.db.get(babyId);
  if (!profile || !profile.familyId) {
    throw new Error("Baby profile not found");
  }

  const familyIds = await getUserFamilyIds(ctx, userId);
  if (!familyIds.includes(profile.familyId)) {
    throw new Error("Not a member of this family");
  }
}

Timezone Handling

Timezone settings affect:
  • Daily aggregate calculations
  • Reminder scheduling
  • Date boundaries for reports
  • Display of timestamps
Changing timezone after logging significant data may affect historical reports and aggregates. The app uses the profile’s current timezone for all calculations.

Age Calculation

The baby’s age is calculated from the dob field:
import { formatBabyAge } from "@/lib/time";

const age = formatBabyAge(profile.dob);
// Returns: "2 months 15 days"
Age affects:
  • Milestone suggestions
  • Growth chart percentiles
  • Feeding recommendations
  • Sleep pattern expectations

Activity Tracking

All activities are linked to a baby profile

Milestones

Age-appropriate milestone suggestions

Reminders

Profile-specific reminder rules

Weekly Digests

Profile-based analytics and insights

Build docs developers (and LLMs) love