Commit Graph

169 Commits

Author SHA1 Message Date
martbost aab18e28ca Sign-up: hand out the device cookie on every code-request response, including guard refusals
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 14:40:54 -05:00
martbost 34c62b9d3a Anti-fraud: one account per person enforced at sign-up (device cookie + IP), flags, admin duplicate signals, suspend switch
Marty, 2026-09-16, after @megamol created megamol2/megamol3 under his own link and bought $20 on each
to fake his two qualifying buyers. fraud.js records sign-up IP/UA/browser id (iap.dev cookie set with
the code request) and last-seen on sign-in. New accounts: dup-device (browser already has an account)
and sponsor-device are refused, ip-burst (> fraudMaxSignupsPerIpDay, default 2, per 24h) is refused;
sponsor-ip and shared-ip are flagged only. Flagged/suspended accounts never count on the leaderboard
and cannot adopt from the tank; suspended accounts are signed out everywhere (auth.fromRequest
wrapper) and refused at sign-in. Admin > Members: Duplicate signals card (shared browser / IP,
flagged, suspended), flags badge, Suspend/Unsuspend; GET /api/admin/fraud; PATCH members {suspend,
reason, flags}. Telegram admin alert on every block/flag. Privacy page + chatbot prompt updated.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 14:39:13 -05:00
martbost 5641582709 Banner creatives must be images: server-side image check (extension or image/* HEAD), form hint, chatbot note
Campaign #134 (NAS ad 2806) had the member's join-page link in the image field and served a broken
banner 141 times on the network; #102 did the same with an imgbb page link. imageCheck() accepts
/uploads/ and instantadpay.com/banners files and image extensions outright, otherwise HEADs the URL
(one redirect) and requires image/*. Wired into member and house campaign creation for banners and
login-ad creatives. Form placeholder + hint point at Promo tools > Banners > Copy image URL.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 13:56:30 -05:00
martbost b811b96e33 Payments feeds: post who missed a share and who got it (on-chain pass-ups and off-chain walk-ups)
Marty, 2026-09-16: make missing a payout visible. On a TierPaid with hops>0 the PassedUp events of the
same tx name the skipped positions, with the reason and how many qualifying buyers they had; the post
says the amount and who received it instead. On a Purchase whose buyer was routed past an unactivated
sponsor (movedByTx set by sponsorSyncOnEvent), the post names the sponsor who missed the whole sale
and the upline who now owns that buyer for good. Both go to the main feed and the shared payments
topic unless the events mode is 'none'.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 13:25:31 -05:00
martbost a727ab1ce5 Payment trace: self-serve "who was paid, who was skipped and why" per purchase (Earnings tab + admin member card)
Marty, 2026-09-16, after the third "why didn't my sponsor get paid" thread of the day (livedreams / gracie25,
Morten / Terry's linked wallets). GET /api/my/trace?who=<#|username> (yourself, anyone up to 3 levels
below you, or your own 3 uplines) and GET /api/admin/trace?who= list every purchase the member was
part of, newest first: buyer, sponsor, package, then levels 1-3 with the recipient, the skipped
positions and the reason ("not qualified: had N of 2 qualifying buyers then"), the platform share, and
a verify link. Linked extra wallets are named after their owner. Earnings tab card "Trace a payment";
admin member card gets a "Payment trace" section; chatbot canned answer + AI prompt route the
question there.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 12:24:53 -05:00
martbost dffcaa113b Never hold a sale for an unactivated sponsor: walk up to the first payable upline, referral follows the money
Marty, 2026-09-16: a purchase must never wait on a sponsor who has not linked a wallet / switched on
payouts. /api/sponsor and /me now walk the site's sponsor line upward to the first upline that is
activated with payouts on (not on the no-payout list) and the buy proceeds under them; nobody
activated -> the catch position (#1). The buyer sees a one-line notice and carries on; admin gets a
heads-up. When the position is created on-chain (MemberActivated), sponsorSyncOnEvent re-points the
buyer's stored sponsor to whoever was paid (#1 included), so the referral leaves the skipped
sponsor's line for good, then sends the pointed notices: the skipped sponsor(s) are told they lost
this referral permanently and how to switch on payouts; the sponsor who was paid is told the
referral is theirs for good and to coach the one who missed it (teach-forward). Admin lookup:
GET /api/admin/sponsor-resolve?ref=. Only a transient chain error still pauses a buy.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 11:18:14 -05:00
martbost a85a198e95 Chain index keeps the full event history (was a 600-event window); one-time rescan from the deploy block
Hugh's Earnings page showed no payouts, referrals or purchases: /api/my/activity read the last 600
events and the window had moved past his Sept 9-10 activity. Ten other readers (dashboard earned
total, leaderboard, holding-tank own-buy check, admin member view, growth snapshot, P&L, burner
match) treated the same list as complete. KEEP_EVENTS 600 -> 250000; chain.rescan() rebuilds from
deployBlock without re-firing onEvent (no repeat Telegram/email), keeps real ts for known events and
estimates ts by block height for backfilled ones; runs once at boot when a filled window is found;
admin routes POST /api/admin/chain/rescan and GET /api/admin/chain/status. State file only rewritten
when events changed.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 10:36:28 -05:00
martbost 69d672665c Credit activity ledger: every earn and spend logged with a reason, listed under Campaigns
Hugh earned a 10-credit sign-in bonus, then bought a 280-credit extension; earned credits spend
first, so Earned read 0 and the bonus looked lost. There was no record a member could check.
Now every real credit movement writes a credit_log row (JSON store in file mode): welcome, sign-in
bonus with streak, daily claim, inbox reads, video watches, verified visits, milestone/leaderboard
bonuses, partner codes, admin/team grants, AI Copy Engine charges + refunds, flat buys (featured
run, extension, visit pack, more visits), login-ad days, and metered delivery rolled up per
campaign per day; on-chain purchased-credit spends are marked. GET /api/my/credits/activity;
dashboard shows the last 40 under Campaigns (also when there are no campaigns) with a link from
Earn credits. Chatbot canned answer + AI prompt updated; my.js tag bumped.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 08:41:43 -05:00
martbost 28bce75913 Featured links: Extend run (book more days) replaces Buy more views; visit packs top up by visits; campaign rows say paid up front and runs through
Hugh and Michael both added credits to a featured run expecting more days. Featured is a flat
daily buy, so the credits sat unspent until the run ended and their balance read 0 meanwhile.
Now: /api/my/campaigns/:id/extend books extra days after the current run (or from today if it
ended) and charges them at once; top-up refuses featured; a visits top-up buys more visits at the
pack rate, charged now; rows show paid up front + day count + runs through <date> / run ended;
explainer under the campaign table; chatbot canned answer + AI prompt updated; my.js v tag bumped.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 07:38:37 -05:00
martbost b1a1cbff5e Achievement badge image rendered on the server with ffmpeg (a phone canvas sent a blank card); admin re-post route
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 03:30:01 -05:00
martbost 84d9f49d4b Held purchase: nudge the sponsor automatically (email + on-site) to link a wallet and switch on payouts, once an hour at most
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-15 23:43:11 -05:00
martbost 66b3c83d3d Burner: when a campaign's pinned position is dry on-chain, settle the spend from another funded position on the same account (credits are pooled per account)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-15 12:49:16 -05:00
martbost 92e7304882 Daily growth snapshot to the Telegram payments feed and shared topic (sign-ups, purchases, POL paid, campaigns, viewing, lifetime totals); admin preview/send-now routes and settings
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-15 12:43:19 -05:00
martbost 560d758ed9 Pipeline: count linked positions' buyers on member cards, the way My line and badges do; show the main/positions split on the card
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-15 12:22:25 -05:00
martbost 02f742f90a Pipeline: sponsor follow-up board (stages from the ledger, notes/follow-ups/tags, stage messages into chat), gated by pipelineMode with a coming-soon card until launch; training cards can wait on the same switch
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-15 11:01:03 -05:00
martbost 56aa7418ad Payment and missed-payment notices also land in the on-site inbox (login pop-up + Messages card), with who bought, share in POL and dollars, and the transaction link
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-15 10:44:48 -05:00
martbost d6d771d93e Missed-payout email: tell the skipped member who bought, what they missed in POL and dollars, buyers needed, and how to close the gap
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-15 10:39:12 -05:00
martbost e03dbbffcf Audit: ignore history already refunded and campaigns older than the hourly log; login daily fee capped at remaining budget
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-15 05:45:57 -05:00
martbost 84a9063bbe Admin > Reports: counters audit (views vs delivery logs, login days charged vs shown, featured views, clicks vs views, spend vs budget), daily with Telegram alert
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-15 05:32:13 -05:00
martbost 7423347c95 Featured strip: count impressions (one per viewer per campaign per hour) so featured advertisers see views and the by-hour chart
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-15 05:21:58 -05:00
martbost f155a8cc24 Sponsor hold: a named sponsor that cannot be paid (payouts off, chain lookup failed, unknown) blocks the first purchase and activation with a message and alerts the admin, instead of silently crediting the company
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-14 21:00:27 -05:00
martbost 1533d377cc Member updates: paced + retried Sendy opt-in checks (unknowns never cached as declines), explicit recipient list for repairs, recipients recorded on the send log
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-14 14:24:27 -05:00
martbost 6e8f1ccf9d Member updates: closing text after the notes (sign-off placement)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-14 14:21:13 -05:00
martbost 14868753c0 Member updates: saved draft (loads into the admin card, Save draft button)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-14 14:11:51 -05:00
martbost 024170e7f8 Member updates: audience defaults to newsletter opt-ins (Sendy list status), explicit 'everyone' option; sendy.status()
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-14 13:47:13 -05:00
martbost 7bb956e896 Admin > Releases: email an update to members (pick notes, intro, audience, preview, test, send; opt-outs honoured; send log)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-14 13:40:01 -05:00
martbost 203ebdb4bf Dashboard payload carries lineBannerUrl so the Overview launch mark counts the banner item (was 7 of 8 vs 8 of 8 on /launch)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-14 12:17:12 -05:00
martbost 119644d688 Line at a glance + My line: every level shows who made their $20+ buy and how many qualifying buyers of their own they have (Clinton); 60s member cache for line views
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-14 11:29:10 -05:00
martbost 0a19e77e7f Badges count qualifying buyers across linked positions (never regress); line chips light on any of a member's positions; buyers tile notes linked-position buyers
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-14 10:44:36 -05:00
martbost 1fad5bdab2 No-payout positions (siteConfig.noPayoutIds, default 25): linkage only. Buy-from picker disables them, purchases from them refused, joins routed away from them and their upline chain
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-14 10:30:58 -05:00
martbost e699513636 My line: show who sponsored each person on every row, all three levels
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-14 10:15:44 -05:00
martbost 201d249738 My line: Activity drop-down on every row, all three levels (last seen, stage, ads today, campaigns, link views, line, wallet, badges, Working/Quiet); Video Maker font override for local runs
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-14 09:56:14 -05:00
martbost 9316dfc0db Toolkit: ship the rest of the ladder (Spark templates + handout, Circuit Video Maker + split tester, Nexus Leader Ops, grants, co-brand, partner code)
- Spark: one-tap banner/text campaign templates aimed at the member's link (POST /api/my/toolkit/template); printable QR handout at /handout/<username>
- Circuit: videomaker.js renders every promo video/short with the member's end card + QR via ffmpeg (Dockerfile adds ffmpeg + ttf-dejavu), hosted in Spaces; split tester compares join angles
- Nexus: Leader Ops (three-level triage, stalled flags, one-click nudges), AI team broadcast kind + Send to my team, credit grants from the leader's earned pool, co-branded join page (sponsor bio for level-3 sponsors), member-funded partner code (promo_codes.funder; redemption charges the funder) + /partners?ref=<username>
- toolkit ladder all live; chatbot updated; my.js v20260914e, site.css v20260914c, join.js/partners.js v20260914a

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-14 07:15:43 -05:00
martbost c1f58b2acf Promo toolkit by badge + AI Copy Engine at Surge: posts, DMs, follow-ups, objection replies, emails, stories in the member's name; monthly free allowance by badge (20/60/150), then ad credits per generation; admin usage view
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-14 06:42:55 -05:00
martbost 6233d112e0 Leaderboard: company account excluded from rankings. Weekly member email: credits unspent, streak, contest rank, tank, line (sponsors by default; memberWeeklyEmail=1 for everyone)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-14 05:26:23 -05:00
martbost b0ef3b3a58 Leaderboard + referral contest: /leaderboard (week/month/all, read from chain, own positions excluded), Overview card with own rank, weekly and monthly winners recorded at rollover with credit ladders granted automatically and announced to Telegram
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-14 05:22:39 -05:00
martbost b3523e9dc4 Release notes + roadmap: /whats-new page, Overview What's new card, Admin > Releases editor
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-14 04:54:43 -05:00
martbost 8e415c3cf4 Badge share sheet: public badge page with preview image (/b/<user>/<badge>), X/Facebook/Telegram/WhatsApp/LinkedIn/native share, copy link, save image
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-13 17:13:18 -05:00
martbost e63bc57a99 Badge posts: manual Post to Telegram is admin-only; members' badges still post automatically on unlock
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-13 17:09:59 -05:00
martbost 964a02a342 Achievement badges: personalised badge image auto-posted to the Telegram payments topic and main group on unlock (once per badge), Post to Telegram button, feed toast
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-13 16:55:43 -05:00
martbost 0c58b80184 Holding tank: no releasing an adoptee within 3 days of pickup, dropped adoptions count toward the two-adoption limit, releases posted to the feed and Telegram
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-13 13:50:28 -05:00
martbost 6589930945 Join page names the owner of the link it was opened with, and tells a member when they are previewing their own page
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-13 07:54:29 -05:00
martbost 6ca287042f Member labels: resolve a brand-new buyer by on-chain wallet so purchase emails name the username, not member #
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-13 07:49:08 -05:00
martbost 53f87f79ba Blog syndication: publishing an article posts it to X and Instagram through Blotato (cover via media upload, once per article, retry button, status column)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-13 07:20:47 -05:00
martbost 4efba20d4e Earn: video stops when leaving the tab/pane, 'all watched today' message, open earn tokens survive a redeploy; admin member search matches as you type, clearer old-site line; QA earn harness follows the done screen
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-13 06:46:08 -05:00
martbost 0c7f957db4 Admin: member search + drilldown card (identity, chain, credits, line, purchases, payouts, campaigns) with username/sponsor/wallet/credits/delete actions; sortable + filterable admin tables; Earn tab zero-credit button wording
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-13 06:27:07 -05:00
martbost 4caa0ef5a8 Sign-up guard: honeypot is read-only until a trusted focus and ignores browser autofill (own email); masked value logging
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-13 04:57:51 -05:00
martbost 49a98e7ee3 Blog: admin-written coaching articles, server-rendered public /blog with SEO metadata, sitemap, RSS, robots
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-12 18:42:56 -05:00
martbost 1a83f4f2ff Earn tab: progress hint shows at every stage (the claim-ready hint was unreachable); member guide /earning
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-12 17:41:13 -05:00
martbost 6395ad3a7e Dashboard: community toasts for joins, tank arrivals, adoptions, purchases, payouts and qualifications
A second, quieter toast (bottom-left, one per 4 s) shows site-wide activity from the
live feed for every signed-in member; personal payout toasts are unchanged. The server
pushes Joined (at first username, with tank flag) and Adopted events onto the feed.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-12 16:03:43 -05:00