G5 — Age-Aware UX:
- useStageCheck hook: maps birth date → BabyStage (newborn/infant/sitter/crawler/toddler/walker)
- Time-of-day fast-log suggestion chip on home page (time × stage matrix)
- Milestones page: 25 WHO/AAP milestones, category filter, progress bar, inline date picker
- Milestones API: GET (merged definitions + achievements), POST (upsert), DELETE (un-mark)
- DB: milestone_achievements table with unique(child_id, milestone_key)
- Milestones 🌟 added to menu
G6 — Mama Affiliate Page:
- member_profiles, recommended_products, product_clicks tables
- /api/profile CRUD (GET/PUT), /api/profile/products (GET/POST/PATCH/DELETE)
- Public routes: /api/profile/[slug] and /api/profile/[slug]/click (IP hashed)
- /settings/profile: slug + bio editor, product list with ↑↓ reorder + click counts
- /m/[slug]: beautiful public page (gradient bg, product grid, Shop → click tracking)
- Settings page link to profile setup
DB migrations: 0014_milestones, 0015_affiliate.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
37 lines
1.5 KiB
SQL
37 lines
1.5 KiB
SQL
CREATE TABLE IF NOT EXISTS member_profiles (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
user_id UUID NOT NULL UNIQUE REFERENCES users(id) ON DELETE CASCADE,
|
|
family_id UUID NOT NULL REFERENCES families(id) ON DELETE CASCADE,
|
|
slug TEXT NOT NULL UNIQUE,
|
|
display_name TEXT NOT NULL,
|
|
bio TEXT,
|
|
avatar_url TEXT,
|
|
is_public BOOLEAN NOT NULL DEFAULT false,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS recommended_products (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
profile_id UUID NOT NULL REFERENCES member_profiles(id) ON DELETE CASCADE,
|
|
title TEXT NOT NULL,
|
|
description TEXT,
|
|
url TEXT NOT NULL,
|
|
image_url TEXT,
|
|
category TEXT NOT NULL DEFAULT 'general',
|
|
display_order INTEGER NOT NULL DEFAULT 0,
|
|
is_active BOOLEAN NOT NULL DEFAULT true,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS product_clicks (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
product_id UUID NOT NULL REFERENCES recommended_products(id) ON DELETE CASCADE,
|
|
clicked_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
referrer TEXT,
|
|
ip_hash TEXT
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS member_profiles_slug_idx ON member_profiles (slug);
|
|
CREATE INDEX IF NOT EXISTS recommended_products_profile_idx ON recommended_products (profile_id, display_order);
|
|
CREATE INDEX IF NOT EXISTS product_clicks_product_idx ON product_clicks (product_id, clicked_at DESC);
|