Commit Graph

40 Commits

Author SHA1 Message Date
martbost 6ff21f76ee P&L: account for money the chain cannot explain
The P&L took revenue from AdminPaid events and holdings from eth_getBalance,
so anything else moving through a receiver was invisible. Receiver A has earned
10,871.89 POL and holds 4,561.19; nothing explained the difference, and the gap
would have widened every time Marty drew from it. "Why would I ever keep a
receiver wallet that I never take anything out of? That's stupid, so I need to
be able to account for it."

Three kinds, because three different things move through that wallet and only
one is profit. Revenue is outside income, a ClickBaitPays withdrawal paid in
POL, and counts toward profit. A draw is house profit spent on something, such
as funding RM Circle #139's Culmen to Apex upgrade; it leaves the wallet but is
not a cost of running InstantAdPay. A transfer is Marty's own capital parked in
the Tangem receiver for safekeeping, and moves the balance only: counting it as
revenue would report his savings as earnings.

The pane now states earned, plus revenue, less draws, against what is actually
held, and names any unexplained drift rather than hiding it in a balance.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-23 18:10:56 -05:00
martbost 286ac9207a Hand the sponsor to PolHunter, and put its payouts in the P&L
PolHunter now pays a bounty when a hunter brings someone who turns up and
hunts, and the person who gets it has to be the one that member actually
joined under here. The sign-in payload carries sponsorRef and the join date
across so PolHunter is never guessing from a cookie.

Its payouts are real POL from its own faucet and none of it passes through the
ad contract, so the P&L could not derive it. It now reads the figures across,
cached and fail-soft, and shows finds, bounties and matches as their own card.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-23 04:36:02 -05:00
martbost e95f9df13a Approved exceptions: people you have okayed to hold more than one account
Marty approves specific people for multiple accounts (partners, staff, a spouse on a
shared machine) and needed a way to say so without the guard fighting him.

Admin > Members > Duplicate signals now carries an "Approved exceptions" list: add an
email with a note, see who is on it and when, remove one. It sits directly under the
signals so the two are read together.

An exception can be added against the address they ALREADY have, not just the new one.
That matters because the usual case is approving a person before their second address
exists, and at sign-up time the new address is unknown to us. checkSignup now tracks
every account the sign-up collided with, and clears the block if either side is approved.

Clearing the HARD flags matters as much as clearing the block. Those flags are what
silently drop an account off the leaderboard and bar it from adopting out of the holding
tank, so an approved person would have been "allowed" in name only. They now keep both.
The account is tagged 'allowlisted' instead, so the admin sees why it went through, and
the server logs the exception by name.

Suspension still wins. An exception is permission to hold several accounts, not immunity
from being suspended for something else.

qa/fraud-allow.mjs (12 assertions) boots its own server and walks the real flow: first
account created, second blocked with the Qualified Start redirect, exception added,
second account now created, no hard flag left on it, exception visible in the admin
report, removing it blocks again, malformed address refused, endpoint admin-only.
qa/sponsor-note.mjs 5, qa/run.sh member 0 bugs.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-17 10:42:31 -05:00
martbost 8ad2e01a74 Admin: a linked wallet can no longer be misread as an active position
The member card showed the wallet address on its own, directly above "Registered:
no (payouts off)". That reads as "he is set up" when he is not, and it caused a
real misread today on @mcbit1: wallet linked, memberId 0 on chain, every sale in
his line walking up to his sponsor while the row looked healthy.

Linking a wallet is a free signature that tells the site which address is theirs.
Switching on payouts is a separate transaction that creates the position. Only the
second one makes them payable, so the two states now say so:

  Main wallet  0x30a7…5703  payouts OFF
  Registered   no  wallet linked, but payouts were never switched on, so no
               position exists. Sales in their line walk up to their sponsor and
               lock there.

and the no-wallet case says "no wallet linked yet" instead of the same text.

qa/run.sh member: 0 bugs (the 2 warnings are pre-existing and unrelated).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-17 05:03:29 -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 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 dda8c976b0 No native dialogs: Shorts report prompt -> inline reason buttons; admin drip confirms -> IAP.confirmBox
Same class of bug as the campaign #27 false report: the Shorts report was a prompt() pre-filled with
'inappropriate'. Members now tap a reason button on purpose or cancel. Script tags bumped.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 10:23:00 -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 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 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 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 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 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 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 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 0ad974ca59 Admin traffic: conversion columns (visit to signup, signup to registered, signup to buyer), stacked centered headers
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-13 07:03:04 -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 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 fc55714757 Partner promo codes: reusable codes that add free ad credits, tracked per redemption
promos.js (promo_codes + promo_redemptions, JSON fallback): create/update codes with
credits, partner, optional cap and expiry, on/off. Redeemed once per account either
from a join link ?promo=CODE (cookie, applied at signup) or the Overview box
'Have a promo code?' (/api/my/promo/redeem). Admin > Traffic gets a Partner promo
codes card (create, toggle, uses, recent redemptions). Chatbot line added.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-12 10:53:17 -05:00
martbost 0cfbe67196 Admin: register the Traffic pane in the title map (the menu click was a no-op); bump script version tags
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-12 07:57:43 -05:00
martbost ef088601c3 Admin Traffic tab: referring domains, landing pages, angles, by day
traffic.js logs public page views by referring domain (30 s buffered; page_hits
table or traffic.json), coach exposes all join-page views, and
/api/admin/traffic merges page views, join-page views, signups, registrations
and $20+ buyers by first-touch source for 7/30/90/365-day ranges.
Also: line-tree chips no longer truncate own-position labels.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-12 07:51:01 -05:00
martbost eae2a04dc0 Legacy bridge pages, welcome-back credits, holding-tank alerts
- /from/faucetwave and /from/tieroneads (?seg=advertiser): the squeeze page with
  brand copy and no video, sponsor cookie cleared so arrivals land in the holding
  tank, angle + a legacy:<brand> source recorded on the account.
- legacy.js: private list DATA_DIR/legacy.json (email -> brand, segment); listed
  emails get a one-time credit grant at account creation (legacyCreditsAdvertiser
  500 / legacyCreditsEarner 150, admin-editable), recorded in legacy-grants.json.
- Holding-tank alerts: dashboard payload carries who is waiting (Overview notice
  with usernames + adopt link), and a 15-minute tick posts new arrivals to the
  shared Telegram payments topic.
- Chatbot prompt lines + admin setting labels.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-12 07:25:32 -05:00
martbost 1fd61eca56 Telegram: echo payouts into a shared cross-program topic
telegramOnEvent now builds the line once per target: the existing proof feed
(telegramChatId) and a new echo target (telegramEchoChatId + telegramEchoTopicId,
telegramEchoEvents). AwardPaid events are now posted too. Echo lines carry an
InstantAdPay prefix since RM Circle shares the topic. Admin labels added.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 18:51:03 -05:00
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 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 9939c0487f Admin tables: action column keeps its width, email wraps, shorter dates; no sideways scroll needed
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 07:41:50 -05:00
martbost 6a21b4dc62 Admin tables: scroll instead of clipping the last column; Joined stays on one line
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 07:32:29 -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 55b010d8c2 Admin burner line: balance is the gas fund, not a cost; show skipped burns
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-10 08:21:15 -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 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 dc3a8e0464 Admin settings: graphical editors for follow-up emails, rates and site settings
Follow-ups: one card per email (hours, subject, body), placeholder chips,
add / reorder / remove / send-to-me. Rates: labeled fields with hints, tier
table, milestone sub-fields. Site settings: key/value rows. No more JSON.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-09 10:00:27 -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 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