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
+17 -1
View File
@@ -84,6 +84,7 @@
<div class="statx c-cyan"><div><div class="nv" id="ovMembers">0</div><div class="lb">On-chain members</div></div></div>
<div class="statx c-violet"><div><div class="nv" id="ovActive">0</div><div class="lb">Active campaigns</div><span class="chip flat" id="ovCampSub"></span></div></div>
<div class="statx c-amber"><div><div class="nv" id="ovReports">0</div><div class="lb">Open reports</div><span class="chip flat" id="ovBurnSub"></span></div></div>
<div class="statx"><div><div class="nv" id="ovDrips">0</div><div class="lb">Follow-ups in flight</div><span class="chip flat" id="ovDripSub"></span></div></div>
</div>
<div class="grid c2" style="margin-top:16px">
<div class="card">
@@ -200,6 +201,21 @@
</div>
<div class="pane" id="pane-settings" hidden>
<div class="card">
<div class="card-head"><h3>Follow-up emails</h3><span class="sub" id="dripSub">sent to every new free member, hours after sign-up</span></div>
<p class="small muted">Each step: <code>hours</code> after the account was created, a <code>subject</code>, and a plain-text <code>body</code>.
Placeholders: <code>{{link}}</code> the member's invite link, <code>{{sponsor}}</code>, <code>{{site}}</code>, <code>{{footer}}</code> (unsubscribe line + disclaimer, keep it).
Steps must be in increasing hours.</p>
<p><textarea id="dripJson" class="json" style="min-height:360px"></textarea></p>
<p id="dripErr" class="small" style="color:var(--bad)" hidden></p>
<p style="display:flex;gap:10px;flex-wrap:wrap;align-items:center;margin:0">
<button class="btn small" id="dripSave" type="button">Save sequence</button>
<button class="btn small sec" id="dripReset" type="button">Reset to defaults</button>
<span style="flex:1"></span>
<select id="dripTestStep" style="width:auto"></select>
<button class="btn small sec" id="dripTest" type="button">Send that step to me</button>
</p>
</div>
<div class="card">
<div class="card-head"><h3>Rates</h3><span class="sub">credit prices and rewards (JSON, merged on save)</span></div>
<p><textarea id="ratesJson" class="json"></textarea></p>
@@ -219,6 +235,6 @@
</div>
<script src="/assets/common.js?v=20260909a"></script>
<script src="/assets/admin.js?v=20260909a"></script>
<script src="/assets/admin.js?v=20260909b"></script>
</body>
</html>