66 lines
3.2 KiB
MySQL
66 lines
3.2 KiB
MySQL
|
|
-- 990_beta_invites.sql
|
||
|
|
-- v1.0.10 polish (Cluster 3.4) — soft-launch beta cohort tracking.
|
||
|
|
--
|
||
|
|
-- Records each individual invitation sent for the v2.0.0 soft-launch
|
||
|
|
-- bêta. Tracks (a) the invite code used in the registration link,
|
||
|
|
-- (b) when the recipient redeemed it (NULL until redemption), and
|
||
|
|
-- (c) which cohort segment (creator / listener / community-member /
|
||
|
|
-- press) the recipient belongs to so the post-launch report can
|
||
|
|
-- attribute feedback by audience.
|
||
|
|
--
|
||
|
|
-- The associated email template + send script live at
|
||
|
|
-- scripts/soft-launch/send-invitations.sh and reference this table
|
||
|
|
-- via INSERT … RETURNING code.
|
||
|
|
--
|
||
|
|
-- Privacy : the email column is the only PII here ; no behavioural
|
||
|
|
-- data is stored. used_at is the redemption signal. After v2.0.0
|
||
|
|
-- public launch, run the cleanup migration in 991 (TBD) to anonymise
|
||
|
|
-- the email column for invites that haven't been redeemed in 30+ days.
|
||
|
|
|
||
|
|
CREATE TABLE IF NOT EXISTS public.beta_invites (
|
||
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
|
|
-- The invite code is what the recipient pastes into the signup
|
||
|
|
-- form. 16 random characters from a base32 alphabet (no 0/1/I/L
|
||
|
|
-- to avoid eyestrain). Generated by send-invitations.sh.
|
||
|
|
code VARCHAR(32) NOT NULL UNIQUE,
|
||
|
|
email VARCHAR(320) NOT NULL,
|
||
|
|
-- Free-text label so the cohort generator can carry whatever
|
||
|
|
-- segmentation the operator wants (e.g. "creator-vinyl-pressing",
|
||
|
|
-- "listener-jazz-mailing-list", "press-pitchfork"). Index below
|
||
|
|
-- is for the post-launch report grouping.
|
||
|
|
cohort VARCHAR(64) NOT NULL,
|
||
|
|
-- NULL until the recipient signs up. Set by the auth handler
|
||
|
|
-- when /auth/register is hit with a valid invite code.
|
||
|
|
used_at TIMESTAMPTZ,
|
||
|
|
-- Hard expiry so unredeemed invites can't accumulate forever.
|
||
|
|
-- Default 30 days from creation ; soft-launch is short-window.
|
||
|
|
expires_at TIMESTAMPTZ NOT NULL DEFAULT (NOW() + INTERVAL '30 days'),
|
||
|
|
-- Operator who sent the invite — useful when reconciling "who
|
||
|
|
-- gave their friend a code" during the audit.
|
||
|
|
sent_by UUID REFERENCES public.users(id) ON DELETE SET NULL,
|
||
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||
|
|
);
|
||
|
|
|
||
|
|
COMMENT ON TABLE public.beta_invites IS
|
||
|
|
'v2.0.0 soft-launch beta invitation tracking. v1.0.10 Cluster 3.4.';
|
||
|
|
COMMENT ON COLUMN public.beta_invites.code IS
|
||
|
|
'16-char base32 invite code (no 0/1/I/L). Pasted into signup form.';
|
||
|
|
COMMENT ON COLUMN public.beta_invites.cohort IS
|
||
|
|
'Free-text cohort label (creator-* / listener-* / press-* / etc.).';
|
||
|
|
COMMENT ON COLUMN public.beta_invites.used_at IS
|
||
|
|
'Redemption timestamp. NULL means the invite is still pending.';
|
||
|
|
|
||
|
|
-- Lookup by code (signup path) — every /auth/register call reads it.
|
||
|
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_beta_invites_code
|
||
|
|
ON public.beta_invites(code);
|
||
|
|
|
||
|
|
-- Cohort grouping for the post-launch attribution query.
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_beta_invites_cohort
|
||
|
|
ON public.beta_invites(cohort);
|
||
|
|
|
||
|
|
-- Pending-invitations sweep — cron job that expires unused invites
|
||
|
|
-- after expires_at. Partial index keeps it small.
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_beta_invites_pending_expiry
|
||
|
|
ON public.beta_invites(expires_at)
|
||
|
|
WHERE used_at IS NULL;
|