Parent roadmap: #525
Parent epic: #535
Goal
D1 data model: notification_subscriptions + notification_log with a UNIQUE(dedup_key, channel) idempotency guard and a per-recipient rate-limit window.
Reuse
Drizzle patterns mirroring digest_subscriptions (src/db/schema.ts).
Acceptance
Migration applies; duplicate dedup_key insert is a no-op.
Testing
npm run test:ci, 97%+ coverage. Public/private output boundary preserved; deterministic where applicable.
Parent roadmap: #525
Parent epic: #535
Goal
D1 data model:
notification_subscriptions+notification_logwith aUNIQUE(dedup_key, channel)idempotency guard and a per-recipient rate-limit window.Reuse
Drizzle patterns mirroring
digest_subscriptions(src/db/schema.ts).Acceptance
Migration applies; duplicate dedup_key insert is a no-op.
Testing
npm run test:ci, 97%+ coverage. Public/private output boundary preserved; deterministic where applicable.