Commit Graph

202 Commits

Author SHA1 Message Date
martbost c5a846bd91 Keep the notifications worth interrupting for
Splitting system messages out of the modal was right for payout receipts,
but it would have silenced two that a member genuinely loses money by
ignoring:

  - "@someone is trying to buy. Link your wallet so it pays you" — a sale
    is blocked right now, and the referral is lost permanently once it
    routes to someone else.
  - "You missed 43 POL on InstantAdPay" — a payout passed them by, and the
    message explains exactly how to stop the next one doing the same.

So the dividing line is not system-versus-human, it is "does this need you
to do something". Those two become kind 'alert' and still interrupt; the
receipts stay kind 'notice' and stay in the inbox.

The modal no longer credits an alert to a person either. It was saying "A
message from @martbost" over machine-generated text, because system mail
is sent by member 1 at ADMIN_EMAIL. Alerts now read "Action needed on your
account".

Also reclassified "X is now in your line for good" as a notice — it is
good news about a referral the member gained, with nothing at stake.

qa/messages-notice.mjs now covers both lanes: 14 checks, including that an
alert interrupts and a flood of 25 receipts does not.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-18 08:25:08 -05:00
martbost a2c77d01d1 Stop payout notices interrupting members who are earning
Marty hit this viewing daily ads: a popup after every single return to
the dashboard, each one a different payout notice.

Two causes, both fixed.

The channel was shared. "You just got paid 40.8923 POL" and "Welcome to
my line, here are your first three moves" were stored identically, as
kind 'broadcast' — the kind the sign-in modal is meant to interrupt for.
Dismissing one just promoted the next unread notice, so a backlog became
a carousel. System messages are now kind 'notice': they land in the
inbox, count toward its badge, and never pop. Only a message a person
actually wrote can interrupt.

The modal also had no memory. loadDashboard() runs on far more than
sign-in — after every ad view, campaign edit and chat close — and it
re-popped each time. It now shows at most once per page load and never
twice for the same message.

The 79 existing machine-generated rows are retagged by a migration in
ensureSchema, 15 of them unread and currently popping. Matched on
subject rather than sender on purpose: these come from member 1 at
ADMIN_EMAIL, which is also Marty's own member address, so his genuine
broadcasts sit under the same sender and must be left alone. Verified
against the live data first — "Credits returned: a counting error on our
side" and the broken-banner note are his, and stay as broadcasts.

qa/messages-notice.mjs covers it: a flood of 25 notices produces no
interruption, the human message still does, and chat stays in its own
lane. Member walk clean.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-18 08:09:50 -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 230c250c64 Earnings pane: Trace a payment card sits at the top
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 12:30:46 -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 616f328db5 Report-an-ad dialog: site dialog with no default reason (was a native prompt pre-filled with "broken")
Campaign #27 (house AdRevSplit text ad) was reported "broken" with no note while the target framed
and loaded fine; the report dialog was prompt() with 'broken' as the default value, so one stray OK
filed it. Now IAP.ask with an explicit, validated reason and an optional note; common.js tag bumped
on all pages.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 10:21:53 -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 ffacf741da Extend run / visits top-up: budget = charged + this buy (release parked credits); featured row shows days left
Hugh extended his featured link and his balance fell 1,133 -> 0: the row still carried the 1,400
parked by the old add-credits button, and reactivating it reserved that budget again. Both flat
paths now set budget to spent + accrued + cost. Featured Run column shows "N of M days left"
(Hugh: "says 14 but it's actually 7") and "M days done" after the run.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 08:19:33 -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 b7cc06b28c Overview: click a chip in Your line at a glance to open that member's Activity panel on My line
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-15 18:54:00 -05:00
martbost 0da7c796b8 Campaigns: visit packs show 'paid up front' and delivered-of-total instead of a spent bar (Michael's 3,000-credit pack looked used up)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-15 16:13:26 -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 87fa837165 Campaigns table: click sources stacked so the Clicks column stays narrow, card layout up to 900px; audit alert-day persisted, rounding-scale diffs ignored
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-15 07:31:16 -05:00
martbost a19a3fc31e Campaigns list: stacked cards on phones with the buttons at the bottom, no sideways scroll (Jim, 2026-09-15)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-15 04:37:43 -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 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 f2c155a6d2 My line: sixth grid column so the Activity button sits on the row
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-14 09:58:47 -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 32028b1e8e Video Maker: live progress bar (stage labels + ffmpeg -progress percent, queue position), page polls every 2.5s
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-14 09:04:38 -05:00
martbost d57fc40299 Toolkit: render the Spark/Circuit/Nexus sections for members below Surge too (early return skipped them); log toolkit errors
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-14 08:43:35 -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 b09e5dce8b Overview: Getting-started stepper (username, link wallet, switch on payouts, first package) with one guided button per step; soft nudge, collapsible, never a gate
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-14 05:53:02 -05:00
martbost 825d0de6c3 Header: Leaderboard link
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-14 05:40:26 -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 f7b911bab6 Badge share sheet: Massifly option (copies the post, opens the feed composer)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-13 17:23:57 -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 b9a70dba1a Sponsor chat: composer grows with the message (up to 45% of the screen) and can be dragged taller
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-13 13:41:18 -05:00
martbost 34098e5565 Watch videos: green-check done screen when the day's videos are finished, like Watch ads
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-13 08:56:13 -05:00
martbost b5eb03456c Wallet tab: Ad credits card counts earned credits too (promo credits looked like 0)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-13 07:29:24 -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 a6dcd02999 Earn: claim streak (5/7/10, 25 every 7th day), after-set prompts for verified visits and launching a campaign
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-12 17:30:02 -05:00
martbost 9d14af0898 Top menu: 'How it works' and 'Ad packages' anchor to homepage sections (#how, #packages); sections clear the sticky nav
The Ad packages link pointed at /#ladder, an id that did not exist on the homepage.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-12 16:54:55 -05:00
martbost 99f6c1f8c6 Dialogs: Cancel used the site's giant .ghost display class by mistake; use the secondary button style
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-12 16:23:39 -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
martbost a9f10f861d Wallet tab: 'Wallet connected' with a green check next to the address; explicit 'No wallet connected yet' otherwise
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-12 15:39:46 -05:00
martbost a385fbf4c2 Username is required: blocking first step on every sign-in until one is saved
showOnboard(required) has no skip and no dismiss; a suggestion from the email
prefix is prefilled (GET /api/my/username-suggest, made unique); the member
area does not render until the username exists. Welcome tour and login ad still
run once for invite arrivals afterwards. Wallet-only sessions are unaffected.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-12 15:32:42 -05:00