← back to Animals

migrations/016_weekly_newsletter.sql

35 lines

-- Project: Animals — weekly newsletter unsubscribe + send tracking.
--
-- Wires the agents/animal-agent `weekly_newsletter` task:
--   1. Sunday cron picks up users with unsubscribed_at IS NULL.
--   2. Each user gets a digest (5 random breed photos + upcoming dog shows in
--      home_state + latest 3 marketplace listings near home_zip).
--   3. Email contains an "unsubscribe" link tied to a stable per-user
--      `unsubscribe_token` — clicking it sets unsubscribed_at without requiring
--      a login (per CAN-SPAM: unsubscribe must be one click, no auth).
--   4. last_newsletter_sent_at gates against double-sends if the cron tick
--      runs more than once on the same Sunday.
--
-- Token model: unlike email_verification_token (single-use, cleared after
-- click), unsubscribe_token is *stable* — the same link should keep working
-- forever, even after the user re-subscribes. Re-subscribe is a re-click
-- of the same link (or a checkbox in /me settings later).

BEGIN;

ALTER TABLE app_users
  ADD COLUMN IF NOT EXISTS unsubscribe_token        TEXT,
  ADD COLUMN IF NOT EXISTS unsubscribed_at          TIMESTAMPTZ,
  ADD COLUMN IF NOT EXISTS last_newsletter_sent_at  TIMESTAMPTZ;

-- Tokens must be unique while populated (NULL allowed for grandfathered users
-- whose token gets backfilled lazily on first send).
CREATE UNIQUE INDEX IF NOT EXISTS idx_app_users_unsubscribe_token
  ON app_users (unsubscribe_token)
  WHERE unsubscribe_token IS NOT NULL;

CREATE INDEX IF NOT EXISTS idx_app_users_last_newsletter
  ON app_users (last_newsletter_sent_at);

COMMIT;