11 Commits

Author SHA1 Message Date
martbost c9aa61e593 Telegram: say what qualifying actually opened, at the moment it happens
Nothing in the system marks the moment a member crosses two directs. That is
the exact point where the job changes from recruiting to climbing, and it is
where the org stalls — 53 qualified members parked at Ascensus, most of them
having treated two directs as the finish line.

The registered-event DM already goes to the referrer. When that registration
is the one that took them to exactly two, it now also tells them they are
qualified, what their next rung costs, which generation it reaches, how many
people they already have sitting there, and that the first catch is double
the rung's price.

It also names the actual failure mode rather than just linking a lesson: the
trap is spending catches instead of climbing with them. The wallet scan says
that is what is happening — 83 of 87 qualified members cannot cover their
next rung despite having earned well past it.

Wrapped so the join notice still sends if the lookup fails.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-31 05:22:28 -05:00
martbost bd42708fa4 Telegram bot: don't tell a linked member their code expired
Janie tapped a stale link code, got "That link code is expired or already
used", and immediately below it "Linked to position #34!". Both messages were
accurate — two different codes, the old one tapped first — but back to back
they read as a contradiction, and the expired message sends someone back to
the dashboard to redo something already done.

The bot now checks whether that chat is already linked before reporting a
dead code, and says so plainly: already linked to #34, nothing more to do,
here is what you can type. Only genuinely unlinked members get the
get-a-fresh-code path, and that copy now explains WHY codes die (single-use,
short-lived) and says to use the newest link.

Verified against live data: chat 652806260 -> position #34, so the link was
real and only the message was wrong.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-29 06:29:23 -05:00
martbost 6838ab3845 Member pages: send readers to the proof, not back to the same video
Marty spotted that a member's page played the angle video and then its button
sent readers to /join/<id>?v=<angle> — which is a SQUEEZE step that shows
that same video again before anything else.

His instinct was to jump straight to /join-now. That fixes the replay but
skips the proof layer: the live payout feed, the 2-4-8-16 explainer, the
toolkit line and the sponsor card all live on the full invite page. Going
from a personal story directly to "connect your wallet and send POL" is a big
jump for somebody who arrived cold from a Traffic Desk banner.

So the button now drops the ?v= and lands on the full invite page. The
existing design already gives exactly the wanted behaviour — the squeeze step
is skipped, the proof is kept, and no new parameter was needed.

The QR deliberately keeps the angle: a scanned code often reaches someone who
never saw the page, off a printout, and the hook video is what they need.

Also: payout alerts now name what an upgrade unlocked, on upgrade pass-ups
only. Marty noticed the toolkit was never mentioned — the unlock line was
wired to `upgraded` events, which are rare next to payouts. On a pass-up the
buyer below just climbed, so saying what they unlocked makes the reason for
the payment concrete. Entry rewards stay silent: nobody changed level.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-29 05:26:05 -05:00
martbost 3c21f9f615 Payout alerts highlight unlocked tools: shared suite-tools level map drives the Telegram team feed, recruiting feed, member DM on upgrade, and X posts; only announces LIVE tiers and gated behind config.suiteToolsInAlerts (off until Suite launch)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 07:59:40 -05:00
martbost ca4b5bf34f Members area: Circle Method lessons 2-10 + Video 8 gated behind position ownership
The product now has a lid. Server refuses the gated video FILES without a
wallet-verified member session (the Mini App bridge session counts, so
Telegram members see no locks). Lesson 1, every poster, and all join-funnel
and transparency videos stay public: free preview + trust engine. Training
page renders locked cards with a one-signature unlock (same SIWE flow as
Messages) and a members-unlocked badge. Chatbot: new members-area canned
answer, Method answer notes the preview, AI prompt routing rule now answers
prospects directly instead of sending locked links; bot lesson command notes
the unlock path.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 04:10:57 -05:00
martbost 29ec8e82a1 Mini App: tapping your OWN invite link previews the prospect view
Linked members were always routed to their dashboard, so a sponsor could
never see their angle page through their own t.me link. Now ref == own id ->
/join/<id>?src=miniapp-preview (+angle); a teammate's link still opens the
dashboard. links command notes the preview trick.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-23 07:16:00 -05:00
martbost f876351391 Mini App join funnel: startapp sponsor attribution + wallet-app handoff
- /app decodes startapp=<sponsorId>[_<angle>] -> unlinked visitors land on the
  sponsor squeeze page /join/<ref>?src=miniapp (linked members still go to
  their dashboard); no-invite prospects get a gold Join button -> /join-now
- tg-app.js: sync __rmcInTg flag; external links route out of the webview via
  openLink/openTelegramLink (wallet deep links reach the wallet app reliably)
- join-now.js in the webview leads with the MetaMask/Trust deep links (no
  injected wallet can exist there); ref + src survive into the wallet browser
- tgbot: links command + weekly digest include the t.me/<bot>/<short>?startapp
  Telegram-native invite once config.miniAppShortName is set (new PATCH key)
- Synced chat.js canned answer + AI prompt (prospects can join from the app)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-23 06:32:51 -05:00
martbost cd361a1eaa Telegram Mini App v1: initData auth bridge into the existing site
- POST /api/public/tg-webapp-auth: HMAC-verifies WebApp initData against the
  companion bot token (12h freshness, timing-safe), maps chat -> member via
  tg-links.json, mints a message session -> linked members land on /my/<id>
  with zero login
- /app entry page (vendored telegram-web-app.js keeps CSP script-src 'self');
  unlinked users get the one-time wallet-link instructions
- tg-app.js on all pages: no-op in browsers; inside the webview lazy-loads the
  SDK, expands, themes header/background #071421, wires native BackButton
- Bot menu button set programmatically to open /app; /start + help mention it
- Synced chat.js canned answer + AI system prompt (Mini App facts)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-23 05:56:51 -05:00
martbost 2a666d4063 Companion bot phase 2: /coach with lesson routing, /team org stats, /lesson links, weekly Rhythm digest (per-member schedule, Chicago time, delta tracking, rotating share angle) 2026-08-22 20:28:36 -05:00
martbost 1f95025587 Companion bot requires its own dedicated token (companionBotToken) - never the shared CTBRewards_Bot token; allowlist the new config key 2026-08-22 19:42:58 -05:00
martbost 6ac1bcab55 Telegram companion bot, phase 1
New tgbot.js (raw Bot API, zero deps, private-chats only so the
group feeds are untouched): wallet-verified linking via dashboard
deep-link codes, personal payout + joined-on-your-link DMs, a
message bridge that delivers site messages natively in Telegram
with reply-to-answer routing (matrix-line permissions enforced by
the existing messages.js rules), and links/msg/help commands.
Webhook self-registers; secret derived from the token. Config key
companionBotToken overrides the feed bot token when Marty creates
a dedicated bot. Dashboard Messages panel gains Connect Telegram;
chatbot + AI prompt synced.
2026-08-22 19:39:55 -05:00