Lead capture pages + follow-up email sequence

- /join/<token>[?v=angle] now serves a capture page (email first, wallet
  later) with angle-matched hook copy, sponsor line, worked-example ledger,
  how-it-works, live package ladder, and per-angle og tags (og:url keeps ?v=).
  The sponsor cookie is set exactly as before; ?v= is remembered and stored
  on the account as joined_via (shown in admin Members).
- drip.js: 4-step getting-started sequence (24h/48h/96h/168h) queued when a
  free account is created with the pre-checked opt-in; ticker every 10 min;
  signed /unsubscribe link in every email; MySQL + JSON storage.
- Admin > Settings: edit the sequence as JSON, reset to defaults, send any
  step to the admin inbox; Overview shows follow-ups in flight.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
martbost
2026-09-09 06:21:01 -05:00
parent f717acad97
commit ce49dbbe4d
9 changed files with 509 additions and 20 deletions
+12
View File
@@ -173,6 +173,18 @@ async function bootstrap() {
burned_at BIGINT NULL,
INDEX (burned_tx)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4`);
// follow-up email sequence queue (one row per free account)
await q(`CREATE TABLE IF NOT EXISTS drips (
email VARCHAR(190) PRIMARY KEY,
step INT NOT NULL DEFAULT 0,
next_at BIGINT NOT NULL,
started BIGINT NOT NULL,
stopped TINYINT NOT NULL DEFAULT 0,
ref VARCHAR(64) NULL,
angle VARCHAR(20) NULL,
INDEX (stopped, next_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4`);
await alterSafe('ALTER TABLE accounts ADD COLUMN joined_via VARCHAR(20) NULL'); // ?v= angle the lead came in on
}
// one-time import: only when the tables are empty and JSON files exist