Commit Graph

153 Commits

Author SHA1 Message Date
martbost c9f7a50b30 Admin Members: show the sponsor's username, note share-code joins, flag dead sponsor links
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 09:06:13 -05:00
martbost ab306937e1 MoonPay fallback: use the working /buy/matic page (the /buy/pol slug 404s)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 09:01:17 -05:00
martbost 09dc6ed368 Dormant-lead rescue: 10-day warning, 14-day move to the holding tank, Contacted-them reset, dead sponsor links to the tank
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 08:06:40 -05:00
martbost 9709ce782d Holding tank: unsponsored free members, first-come adoption (own $20 buy required, 2 open, 7-day window, twice max), release to tank, admin view; PIF wallet-to-wallet POL gift with logging
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 07:57:44 -05:00
martbost 48dcd71290 Founding week: /launch leader checklist (8 live-read items incl. the level-3 leader play), dashboard launch-ready mark, launchAt setting
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 07:16:54 -05:00
martbost bf5371ab20 Campaign scheduling (start/end, solo send-from), scheduled NAS push + end sweep, views-by-hour chart
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 06:53:53 -05:00
martbost 159e19dcdf Sign-up code guard: honeypot, form age, per-IP + global limits, progressive icon check, burst alert
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 06:30:03 -05:00
martbost f7c840dee4 Training: Wallets and buying POL guide (/wallets), guide link on Buy packages, chatbot answers
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-10 17:20:31 -05:00
martbost 496133b99e Angle join pages are squeeze pages: hook, video, one capture card, three points; full page stays on the plain link
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-10 16:09:03 -05:00
martbost 04e42e94ff Sponsor attribution: last touch (30-day cookie), locked at account creation; 'Joining under' line at the code step; chatbot answer
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-10 15:49:40 -05:00
martbost 4487a90d16 Balances: one reservation rule (earned first) + purchased-grade credited pool
- balances(): live campaign budgets are set aside up front, earned pool first then
  purchased, so dashboard numbers never move per impression; new 'in campaigns' line
- earned pool gains a purchase_grade portion for refunds/comps: shows under Purchased
  as 'credited to you' and funds login ads (daily login charge draws on it first)
- viewing credits always spend before credited purchased money
- dashboard/donut/spend banner/earn pane/positions show purchased, credited, earned, in campaigns
- chatbot canned answer + AI prompt: the balance rule

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-10 11:16:40 -05:00
martbost 38366e0beb Credits: Welcome label shows only the welcome amount; login ads explain they spend purchased credits only
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-10 10:42:16 -05:00
martbost ecdee89be1 Traffic sources: referring domain on join-link visits and joins (per-member table), click sources per campaign (surface or outside host)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-10 10:12:13 -05:00
martbost 94910275c0 Positions policy: cap of five per account, refuse wallets registered under anything but the main member, admin members shows positions; Qualified Start card states the rule
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-10 09:42:06 -05:00
martbost 7708e602ae Catalog: 20s cache so ladder pages stop waiting on five live quotes
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-10 08:13:27 -05:00
martbost e0d4bbc2e1 Public /api/config never exposes credential-like site settings; join page spacing
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-10 08:04:19 -05:00
martbost b824711ac5 Campaigns: gold available-to-spend banner + where-your-ads-run (incl. Network Ad Space); Wallet: live POL balances; Earn credits: done-for-today mark
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-10 07:36:24 -05:00
martbost 4156b1f815 Coaching layer + tools: coach your directs (rungs, stalled, one-click nudges), automatic member nudges + weekly sponsor digest, prospects list, per-angle link stats, broadcast templates, Qualified Start calculator, Telegram proof feed, send-failed alerts, admin P&L pane, automatic credit burner (ethers), username lock, home-page comparison, printable checklist, wall link in Promo tools
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-10 07:30:16 -05:00
martbost 16a9f76f50 Training: section pills; /plays member page (three plays + Qualified Start) with the member's own link in the scripts
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-10 07:06:19 -05:00
martbost 046464b83e Linked positions (Qualified Start): extra wallets on one account, credits pooled, buy-from picker
- accounts/db: positions table + JSON store (add/list/owner/remove; main-wallet and cross-account guards)
- auth verify: asPosition links a second wallet without touching the session; position wallets can't mint a session
- /api/my/positions (chain-refreshed member ids, buyer counts, credits) + remove
- credits pooled across main + positions on /api/me, dashboard, campaigns; campaign charged to the best-funded position
- My line: own positions listed on level 1 as 'You · position N'
- Buy pane: Qualified Start card + Add a position flow + Buy-from picker with connected-wallet guard
- Wallet pane: Your positions card; chatbot answer updated

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-09 17:18:47 -05:00
martbost b86dbfd9e9 Admin: wall fallback ads editor (House ads pane) + /api/admin/wall-ads
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-09 15:45:49 -05:00
martbost 2ac6549171 Wall ownership ladder: positions 2 and 3 become the member's own at 2 / 5 qualifying buyers
- accounts.wall_offers (JSON, up to 2 offers: label, https link, banner) set from
  Profile > Your wall; upload supported; locks show the buyer threshold.
- /api/wall assembles: position 1 = own line banner; positions 2-3 = own offer
  when unlocked and set, else upline banners (only uplines with a live banner),
  else house ads. Response carries unlocked + buyerCount; wall labels show
  "this wall" / "their line" / "InstantAdPay".
- Chatbot canned answer + facts, follow-up email 7 mention the ladder.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-09 15:31:45 -05:00
martbost 26b98c65c5 Invite links answer HEAD too
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-09 11:05:02 -05:00
martbost fe217b897a QA fixes: HEAD on page routes, Shorts signed-out 401, invite-page onboarding handoff, viewer check buttons clear of the overlay close button
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-09 11:03:26 -05:00
martbost 4846af535a Earn credits: ad view dwell defaults to 10 seconds (was 5)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-09 07:58:24 -05:00
martbost c7018f6258 My line: POL earned from each person; wallet picker features non-Trust wallets first
- /api/my/line sums TierPaid events per buyer for the signed-in member; the
  downline rows show "+X POL" (what that person has paid you so far).
- AppKit featuredWalletIds: MetaMask, Phantom, SafePal, Coinbase first; Trust
  Wallet stays available under All wallets.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-09 07:47:41 -05:00
martbost 15a29af104 Follow-up sequence: 7 emails over 14 days in Marty's voice, paid-aware branches
Drafted through the Branded Voice engine (gain, logic, PAS, logic, honest
fear of loss, AIDA, gain + newsletter hand-off), checked against the contract
facts. {{paid:a|b}} resolves per reader from on-chain credits. Defaults now
live in drip-defaults.json; admin overrides still in the volume.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-09 06:37:39 -05:00
martbost ce49dbbe4d 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>
2026-09-09 06:21:01 -05:00
martbost f717acad97 Promo tools: drop the printable handouts section and /flyers page
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-09 06:12:00 -05:00
martbost f3f9662d99 Promo tools built out: posts, text-a-friend, swipes, banner kit, handouts, objections
- Social posts for X / Facebook / LinkedIn / Telegram-WhatsApp with post and
  share buttons; 5 SMS-sized Text-a-friend messages (Text it / WhatsApp /
  Telegram / Copy); email swipes short, standard, long, follow-up.
- Banner kit adds 1080x1080, 1080x1920 and 1280x720 (tools/gen-social-banners.cjs)
  with Download buttons.
- Printable half-sheet handouts at /flyers with the member's QR + invite link
  (qrlib.js, two per letter page, cut line, print-one).
- Objection handling bank: truth + ready-to-send reply per objection.
- Invite-link strip, Branded Voice CTA, pill menu covers every kit; chatbot
  canned answer + prompt facts updated. Angle links carry ?v= for the
  upcoming hook pages.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-09 05:54:18 -05:00
martbost dd2ee4b77e One way in: email sign-in only; wallet-only sessions finish setup by email
- Remove the "sign in with just your wallet" door from the sign-in card.
- A wallet-only session (no account) is walked to the email card with a
  finish-setup note; verifying the code links that wallet to the account
  and retires the wallet-only session, so member #, purchases and payouts
  stay attached and username/profile work.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-09 05:32:30 -05:00
martbost 438b1921e9 Admin portal (/admin) + free house ads; POL amounts show two decimals
- /admin: email magic-code sign-in allowlisted to ADMIN_EMAIL, 12h admin
  session (cookie iap.adm, persisted in the volume). Bearer ADMIN_PASSWORD
  API access still works. Member area shows an Admin link for that email.
- House ads: admin places banner/text/login/solo/video/featured/visits
  campaigns owned by house@instantadpay.com that cost nothing; budget is
  only a delivery cap, spend is never charged or burned.
- Admin APIs: overview, all campaigns (+pause/resume any), members
  (+re-point sponsor), reports (+resolve), pending burns, rates/site
  config get+patch, creative upload.
- fmtPol rounds to two decimals everywhere (dashboard, toasts, prices).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-09 05:15:19 -05:00
martbost b6a0729335 Name the referral in the new-referral email
The email fired at signup, before the member picked a username, so it always
said "A new member." Fire it instead when the username is first set (onboarding
/api/my/profile, empty->set transition only) so the sponsor's email names them
(@username). Removed the signup/verify triggers.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-08 16:46:59 -05:00
martbost e58de01209 Fallback unattributed joins under #1 instead of root
Members were activating with sponsorId 0 (their own root) whenever their sponsor
couldn't be resolved — dead pre-wipe links (dkain) or no link at all — so their
purchases rolled to admin instead of building the tree. Default an unresolvable
sponsor to the configured catch position (siteConfig.defaultSponsorId, default
1) in both the buy path (/api/sponsor) and the free-activation path (/api/me),
guarded so #1 itself is never self-sponsored.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-08 15:28:28 -05:00
martbost cb5c8db2c6 Never cache HTML (no-store) so wallet browsers can't serve stale pages
Trust's in-app browser was serving a cached pre-fix HTML page that pointed at
old JS, re-triggering the numeric-chainId crash even after the fix shipped.
Switch HTML from no-cache to no-store so every load fetches the current page and
its current asset versions. Versioned assets still cache for an hour.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-08 12:02:05 -05:00
martbost b7e2cf56b9 Use the account's stored sponsor at buy time, not just the cookie
/api/sponsor (which the buy flow reads to set sponsorIdIfNew) resolved ONLY the
iap.sponsor cookie. A member whose join cookie was absent at buy time (different
device, cleared cookies, return visit) resolved to 0 and activated on-chain as
their own root instead of under their real sponsor — irreversible. Prefer the
logged-in account's stored sponsorRef, cookie only as anonymous fallback,
matching /api/me.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-08 11:59:48 -05:00
martbost f53bb7db85 Sponsor notifications: new referral + referral purchase
- notifyNewReferral (was nudgeReferrer): email a member's sponsor on EVERY new
  referral, activated or not. Resolve the sponsor from the join token by member
  id, share code, or username (was code-only and skipped already-activated
  sponsors). Reworded from an activation nudge to a real "you have a new
  referral" note; keeps the payouts reminder only for un-activated sponsors.
- Purchase event now also emails the buyer's direct sponsor that their referral
  bought a package, noting whether it's a $20+ qualifying purchase.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-08 11:34:34 -05:00
martbost 873a9e5e4a Mainnet indexer fix + retire testnet copy
- chain.js: derive the chain tip as the MAX height across the RPC pool and scan
  getLogs against that same synced node. Load-balanced public RPCs (publicnode)
  intermittently answer eth_blockNumber from a replica lagging thousands of
  blocks behind, which stalled the mainnet scan (latest < lastBlock, 0 events)
  and could skip freshly-mined events. This unblocks the live ledger + the
  purchase-confirmation email (both driven by the event scan).
- disclaimer: replace the "rehearsal/testnet" section with a live-on-Polygon
  real-money notice (it's live now).
- Point the dead Amoy fallbacks (purchase email tx link, contract-page source
  link) at Polygon mainnet / the verified mainnet contract.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-08 11:20:47 -05:00
martbost 7b131dad28 Gas floor fix, chain guard, and dashboard footer
- wallet.js: fetch correct EIP-1559 fees from the network (Amoy/Polygon Bor
  enforce a ~25-30 gwei priority floor MetaMask's estimate misses) via new
  /api/gas; hard chain-guard before signing so a tx never lands on the wrong
  network; accept the wallet's usual networks in AppKit so its modal stops
  looping and drive add+switch ourselves.
- chain.js: suggestedFees() from eth_maxPriorityFeePerGas + base fee.
- Dashboard: move the Site links (Ad packages / Live ledger / The contract)
  out of the sidebar into a page footer; hide the sidebar scrollbar.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-08 10:49:34 -05:00
martbost 8958a9d145 Fix credits showing 0 + purchase confirmation email
- chain.rpc(): retry the RPC pool 3 rounds with backoff. Public Amoy nodes
  routinely return transient "Temporary internal error. Please retry" on
  eth_call; a single miss was silently surfacing as 0 credits / chainReadError
  on the dashboard even when the buy succeeded on-chain.
- emailOnEvent: send a purchase confirmation on the Purchase event — credits
  added, new ad-credit balance, POL paid, and a link to view the tx on the
  explorer. Fires server-side for every wallet and the Mini App.
- Added a third Amoy RPC (tenderly) to the volume config for read redundancy.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-08 10:26:53 -05:00
martbost 8eedfbe6e6 CSP: allow Coinbase Wallet endpoints (connect-src *.coinbase.com)
AppKit's Coinbase Wallet connector calls coinbase.com; allow it so Coinbase
Wallet works alongside the others.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-08 09:58:33 -05:00
martbost b172ef674d CSP: allow AppKit's inline bootstrap script by hash (keep no unsafe-inline)
AppKit injects one inline script; allow it via its sha256 hash rather than
opening script-src to unsafe-inline, preserving the strict policy.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-08 09:55:34 -05:00
martbost 0995293398 CSP: allow blob: images + reown font for AppKit modal
AppKit renders wallet icons from blob: URLs and uses its brand font from
fonts.reown.com; add blob: to img-src and fonts.reown.com to font-src so the
picker shows proper icons and type.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-08 09:52:19 -05:00
martbost bd4040ff4f Rebuild wallet connect on Reown AppKit (universal, all wallets, working icons)
Replaces the low-level ethereum-provider + deprecated modal (broken icons, jank)
with Reown AppKit loaded from the CDN — the standard connector every wallet
supports, with QR + mobile deep-links and a polished picker. Keeps the exact
SIWE sign-in and contract buy/activate logic, driving AppKit's EIP-1193 provider.
CSP widened for the AppKit SDK/RPC + a worker.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-08 09:48:38 -05:00
martbost 653a5e333a Amoy rehearsal: faucet points testers to the public Amoy faucet
anvil_setBalance doesn't exist on Amoy. The faucet now connects the wallet,
copies the address, and opens faucet.polygon.technology so testers fund their
own wallet with test POL (choose Polygon Amoy). Server endpoint returns the
faucet link + address instead of minting balance.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-08 08:33:46 -05:00
martbost f0e42e47bb Add WalletConnect: connect from any mobile browser (no dApp browser)
Mobile users in a normal browser hit "no wallet found" because EIP-6963 only
sees injected/extension wallets. WalletConnect fixes it: the connect picker now
offers WalletConnect (auto-selected when no injected wallet is present), which
shows a QR on desktop and opens the wallet app directly on mobile — no in-app
dApp browser, no second login. Lazy-loads the @walletconnect/ethereum-provider
UMD from jsdelivr; the result is a plain EIP-1193 provider so sign/switch/buy are
unchanged. CSP widened for the SDK + WC relay. Project id lives in site config
(public value); gated so nothing changes until it's set.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-08 07:36:07 -05:00
martbost 8d9f56f68a Newsletter opt-in: silent Sendy subscribe on join
Pre-checked "InstantAdPay newsletter" opt-in on the join screen (read by both the
email-code and password signup paths). On new-account creation only, the server
silently subscribes them to the Sendy "InstantAdPay Newsletter" list
(boolean=true, opt-out always wins). New sendy.js helper reads the API key from
SENDY_API_KEY env or DATA_DIR/sendy.key on the volume (same pattern as
sendgrid.key); subscribe is fire-and-forget and never blocks signup.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-08 07:13:50 -05:00
martbost 8ec6286ff7 Add MoonPay card on-ramp (same underpinning as RM Circle)
Signed /api/moonpay-url endpoint: public key from MOONPAY_PUBLIC_KEY env or site
config, SECRET from MOONPAY_SECRET_KEY env ONLY (never site config, since
/api/config exposes siteConfig). Wallet-prefilled signed MoonPay URL when keys
are set, else a generic buy page. "Buy POL with a card" button under the Buy
packages tiles. Zero custody: MoonPay is merchant of record; crypto goes
straight to the buyer's wallet.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-08 06:26:15 -05:00
martbost 0c803c07cb Legal pages (Terms, Privacy, Disclaimer) + always-present footer
- New /terms, /privacy, /disclaimer pages in the site style with real content
  tailored to an on-chain ad+referral platform (no income guarantee, crypto
  risk, rehearsal note, privacy of email/wallet/profile, acceptable use).
- renderNav now appends a persistent footer with legal + site links on every
  public page; member-area sidebar gets a Legal link group.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-07 09:38:08 -05:00
martbost 8e089070dc Recolor achievement badges: Surge purple, Circuit red starburst, Nexus navy
New kie.ai art per Marty's palette — Surge dark neon purple, Circuit bright red
starburst, Nexus navy-blue gradient (Spark stays mint). Full-bleed dark, ornate,
blank ribbon; ribbonY re-tuned per badge; ?v=2 cache-bust on the badge images.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-07 09:03:45 -05:00