Migration (0009): notifications table with unique daily/weekly slots, is_read column, metadata JSONB for vaccine info. No more localStorage for read state — syncs across devices. API GET /api/notifications?childId=: - Generates vaccine notifications (upsert, filtered by given vaccines at query time) - log_nudge: if no feed/diaper/sleep logged today after noon IST - memory_nudge: if no photo added to memories today - garment_nudge: if wardrobe < 10 items (once per week slot) - Returns unread first, then recent read, limit 60 API PATCH /api/notifications — mark all read for family+child API PATCH /api/notifications/[id] — mark single notification read Page /notifications: - Fetches from real API (no hardcoded mock data) - Optimistic mark-read on tap, navigates to actionUrl - Colored cards per type (red=vaccine, amber=log, purple=memory, pink=garment) - Unread badge + Mark all read button in sticky header - Legend row at bottom debug-migration: added notifications table CREATE IF NOT EXISTS for hot-apply Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
38 lines
1.6 KiB
SQL
38 lines
1.6 KiB
SQL
-- Notification system — persistent, DB-backed nudges and vaccine alerts
|
|
-- Replaces the previous compute-only approach so read/unread syncs across devices.
|
|
|
|
CREATE TABLE IF NOT EXISTS notifications (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
family_id UUID NOT NULL REFERENCES families(id) ON DELETE CASCADE,
|
|
child_id UUID REFERENCES children(id) ON DELETE CASCADE,
|
|
|
|
-- Stable type codes:
|
|
-- Vaccine alerts : "vaccine_BCG", "vaccine_OPV-0", etc.
|
|
-- Daily nudges : "log_nudge", "memory_nudge"
|
|
-- Weekly nudge : "garment_nudge"
|
|
type VARCHAR(80) NOT NULL,
|
|
|
|
title TEXT NOT NULL,
|
|
message TEXT NOT NULL,
|
|
action_url TEXT,
|
|
is_read BOOLEAN NOT NULL DEFAULT false,
|
|
|
|
-- IST date this notification belongs to.
|
|
-- Nudges: today's IST date → ensures one per day per type
|
|
-- Vaccines: the vaccine due date → ensures one per vaccine (due date is fixed)
|
|
-- Garment: Monday of current IST week → ensures one per week
|
|
scheduled_for DATE NOT NULL,
|
|
|
|
-- Arbitrary extra data (e.g. { "vaccineName": "BCG" } for vaccine rows)
|
|
metadata JSONB,
|
|
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
-- One row per (family, child, type, date-slot) — prevents duplicate notifications
|
|
CREATE UNIQUE INDEX IF NOT EXISTS notifications_unique_slot
|
|
ON notifications(family_id, child_id, type, scheduled_for);
|
|
|
|
-- Fast unread count + list query
|
|
CREATE INDEX IF NOT EXISTS notifications_family_child_idx
|
|
ON notifications(family_id, child_id, is_read, created_at DESC);
|