Skip to main content

Overview

Zen Nurture is built with Next.js 16, Convex for the backend, and Better Auth for authentication. This guide covers everything you need to run the app locally or deploy it to production.

Prerequisites

Before you begin, ensure you have:
  • Node.js: Version 18 or higher
  • Package Manager: pnpm (recommended), npm, or yarn
  • Convex Account: Free account at convex.dev
  • OpenAI API Key: For Mora AI assistant features (optional)

Installation

1

Clone and Install Dependencies

# Install dependencies with pnpm (recommended)
pnpm install
Zen Nurture uses pnpm v9.10.0 as specified in package.json. Using pnpm ensures consistent dependency resolution.
2

Set Up Convex

Convex is the real-time backend database for Zen Nurture.

Create a Convex Project

# Login to Convex (opens browser)
npx convex dev --once

# Or log in first
npx convex login
This will:
  1. Create a new Convex project (or link to an existing one)
  2. Generate .env.local with NEXT_PUBLIC_CONVEX_URL
  3. Deploy your Convex functions from the convex/ directory

Convex Schema

The database schema is defined in convex/schema.ts:
convex/schema.ts
import { defineSchema, defineTable } from "convex/server";
import { v } from "convex/values";

export default defineSchema({
  families: defineTable({
    name: v.string(),
    ownerId: v.string(),
    createdAt: v.string(),
  }).index("by_ownerId", ["ownerId"]),

  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()),
    photoIds: v.optional(v.array(v.string())),
    createdAt: v.string(),
  })
    .index("by_babyId_timestamp", ["babyId", "timestamp"])
    .index("by_babyId_type_timestamp", ["babyId", "type", "timestamp"]),
  
  // ... more tables
});
Convex automatically manages database migrations. When you update the schema and run npx convex dev, changes are applied automatically.
3

Configure Environment Variables

Create a .env.local file in the project root:
.env.local
# Convex (auto-generated by `npx convex dev`)
NEXT_PUBLIC_CONVEX_URL=https://your-project.convex.cloud
NEXT_PUBLIC_CONVEX_SITE_URL=https://your-project.convex.site

# Site URL (for Better Auth)
SITE_URL=http://localhost:3000

# Better Auth trusted origins (comma-separated)
BETTER_AUTH_TRUSTED_ORIGINS=http://localhost:3000,http://localhost:3001

# OpenAI (for Mora AI assistant)
OPENAI_API_KEY=sk-...

# Web Push Notifications (optional)
NEXT_PUBLIC_VAPID_PUBLIC_KEY=...
VAPID_PRIVATE_KEY=...
VAPID_SUBJECT=mailto:your-email@example.com

# Cron secret (for push notification reminders)
CRON_SECRET=your-random-secret-string

Environment Variable Details

These are automatically set when you run npx convex dev. They point to your Convex backend.
  • NEXT_PUBLIC_CONVEX_URL: The Convex deployment URL
  • NEXT_PUBLIC_CONVEX_SITE_URL: The Convex site URL for authentication
The base URL where your Next.js app is running. Better Auth uses this for authentication flows.
  • Local: http://localhost:3000
  • Production: https://yourdomain.com
Required for the Mora AI assistant feature. Get your API key from platform.openai.com.Mora uses @ai-sdk/openai with GPT-4 models to answer parenting questions and analyze your baby’s data.
Required for browser push notifications. Generate VAPID keys:
npx web-push generate-vapid-keys
This outputs a public/private key pair. Add them to .env.local.
A secret string used to authenticate cron job requests for push notification reminders.
# Generate a random secret
openssl rand -base64 32
Also add this to your Convex dashboard: Settings > Environment VariablesThe cron endpoint (/api/push/check-reminders) requires an Authorization: Bearer <CRON_SECRET> header.
Never commit .env.local to version control. Add it to your .gitignore.
4

Configure Better Auth

Better Auth is already set up in the codebase. Here’s how it’s configured:

Convex Auth Setup

convex/auth.ts
import { betterAuth } from "better-auth/minimal";
import { convex } from "@convex-dev/better-auth/plugins";

export const createAuth = (ctx: GenericCtx<DataModel>) => {
  const baseURL = process.env.SITE_URL!;
  const trustedOrigins = process.env.BETTER_AUTH_TRUSTED_ORIGINS
    ? process.env.BETTER_AUTH_TRUSTED_ORIGINS.split(",").map((s) => s.trim())
    : [baseURL, "http://localhost:3000"];

  return betterAuth({
    baseURL,
    trustedOrigins,
    database: authComponent.adapter(ctx),
    emailAndPassword: {
      enabled: true,
      requireEmailVerification: false,
    },
    plugins: [convex({ authConfig })],
  });
};

Client Auth Setup

src/lib/auth-client.ts
import { createAuthClient } from "better-auth/react";
import { convexClient } from "@convex-dev/better-auth/client/plugins";

export const authClient = createAuthClient({
  plugins: [convexClient()],
});

Auth Config

convex/auth.config.ts
import { getAuthConfigProvider } from "@convex-dev/better-auth/auth-config";
import type { AuthConfig } from "convex/server";

export default {
  providers: [getAuthConfigProvider()],
} satisfies AuthConfig;
Better Auth is integrated with Convex via the @convex-dev/better-auth package. User data is stored in Convex’s managed auth tables.
5

Run the Development Server

Now you’re ready to start the app!
# Runs both Convex dev and Next.js dev concurrently
pnpm cdev

# Or with npm
npm run cdev
The app will be available at:

Available Scripts

package.json
{
  "scripts": {
    "dev": "portless zen next dev",
    "cdev": "concurrently -n convex,next \"convex dev\" \"portless zen next dev\"",
    "build": "next build",
    "start": "next start",
    "lint": "eslint .",
    "convex": "convex dev",
    "deploy": "vercel build --prod -y && vercel deploy --prebuilt --prod -y"
  }
}
The cdev script uses concurrently to run both Convex and Next.js in a single terminal. This is the easiest way to develop.

Production Deployment

Deploy to Vercel

Zen Nurture is optimized for Vercel deployment:
# Install Vercel CLI
npm i -g vercel

# Deploy to production
pnpm deploy
This runs:
  1. vercel build --prod - Builds the Next.js app
  2. vercel deploy --prebuilt --prod - Deploys to Vercel

Convex Production Deployment

# Deploy Convex functions to production
npx convex deploy --prod
Then update your production environment variables:
  • Set NEXT_PUBLIC_CONVEX_URL to your production Convex URL
  • Set SITE_URL to your production domain
  • Add all other env vars in Vercel’s dashboard
Remember to add CRON_SECRET in both Vercel environment variables and Convex dashboard (Settings > Environment Variables).

Set Up Cron for Push Notifications

If you’re using reminders with push notifications, configure a cron job to check for due reminders:
vercel.json
{
  "crons": [{
    "path": "/api/push/check-reminders",
    "schedule": "*/5 * * * *"
  }]
}
This checks every 5 minutes for reminders that need to be sent.
The cron endpoint requires the Authorization: Bearer <CRON_SECRET> header. Vercel Cron automatically includes environment variables in requests.

Database Management

Viewing Data

Use the Convex dashboard to view and query your data:
  1. Go to dashboard.convex.dev
  2. Select your project
  3. Navigate to “Data” to browse tables
  4. Use the “Functions” tab to test queries and mutations

Backup and Export

Zen Nurture includes a built-in export feature:
// Export all data for a baby
const data = await convex.query(api.events.exportBabyData, { 
  babyId: "xyz" 
});

console.log(data);
// {
//   exportedAt: "2024-03-15T10:30:00Z",
//   profile: { ... },
//   events: [ ... ],
//   caregivers: [ ... ],
//   reminders: [ ... ]
// }
You can also export data directly from the Convex dashboard.

Troubleshooting

Problem: “Failed to connect to Convex”Solution:
  • Ensure npx convex dev is running
  • Check that NEXT_PUBLIC_CONVEX_URL is set in .env.local
  • Verify you’re logged in: npx convex login
Problem: “Unable to sign in” or CORS errorsSolution:
  • Verify SITE_URL matches your app URL
  • Add your URL to BETTER_AUTH_TRUSTED_ORIGINS
  • Check that NEXT_PUBLIC_CONVEX_SITE_URL is set correctly
  • Clear browser cookies and try again
Problem: AI assistant times out or gives errorsSolution:
  • Verify OPENAI_API_KEY is set and valid
  • Check you have API credits in your OpenAI account
  • Ensure you’re using GPT-4 (check src/app/api/mora/route.ts)
Problem: Reminders don’t trigger push notificationsSolution:
  • Verify VAPID keys are set correctly
  • Check CRON_SECRET is set in both .env.local and Convex dashboard
  • Ensure user has granted browser notification permissions
  • Test the subscription endpoint: /api/push/subscribe
Problem: TypeScript or build errorsSolution:
  • Delete node_modules and reinstall: rm -rf node_modules && pnpm install
  • Clear Next.js cache: rm -rf .next
  • Regenerate Convex types: npx convex dev --once
  • Ensure you’re using Node.js 18+

Architecture Deep Dive

Frontend Stack

  • Next.js 16: React framework with App Router
  • React 19: Latest React with concurrent features
  • TailwindCSS 4: Utility-first CSS
  • Radix UI: Accessible component primitives (dialogs, dropdowns, etc.)
  • shadcn/ui: Pre-built components using Radix
  • Recharts: Data visualization library
  • Motion: Animation library (Framer Motion successor)

Backend Stack

  • Convex: Real-time database with TypeScript functions
  • Better Auth: Authentication with email/password
  • OpenAI: AI assistant (Mora) powered by GPT-4
  • Web Push: Browser push notifications via web-push package

Key Directories

zen-nurture/
├── src/
│   ├── app/              # Next.js App Router pages
│   ├── components/       # React components
│   ├── lib/              # Utility functions, auth client
│   └── hooks/            # React hooks
├── convex/
│   ├── schema.ts         # Database schema
│   ├── auth.ts           # Better Auth setup
│   ├── events.ts         # Event CRUD operations
│   ├── families.ts       # Family management
│   └── ...               # Other backend functions
├── public/               # Static assets
└── package.json

Next Steps

Explore the Codebase

Browse convex/schema.ts for the data model and convex/events.ts for backend logic

API Reference

Learn about all available Convex queries and mutations

Customize UI

Modify components in src/components/ using Tailwind and shadcn/ui

Add Features

Extend the schema and add new event types or analytics views
Zen Nurture is open source. Feel free to fork, customize, and contribute back to the project!

Build docs developers (and LLMs) love