From 6838ab38459cd14776afafd2837845c962f17466 Mon Sep 17 00:00:00 2001 From: martbost Date: Sat, 29 Aug 2026 05:26:05 -0500 Subject: [PATCH] Member pages: send readers to the proof, not back to the same video MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Marty spotted that a member's page played the angle video and then its button sent readers to /join/?v= โ€” 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 --- server.js | 11 ++++++++++- suite-pages.js | 48 ++++++++++++++++++++++++++++++++++++++++++++++-- tgbot.js | 8 +++++++- 3 files changed, 63 insertions(+), 4 deletions(-) diff --git a/server.js b/server.js index 68ba1c1..247c6c4 100644 --- a/server.js +++ b/server.js @@ -1500,7 +1500,16 @@ chain.startIndexer(evt=>{ let text; if(evt.type==='registered')text=`๐Ÿ“ˆ TEAM BUILD: new position!\n#${evt.id} registered under #${evt.referrerId} (${evt.tierName}).`; else if(evt.type==='upgraded'){const tl=suiteTools.unlockText(evt.level,evt.levelName,getConfig());text=`๐Ÿš€ TEAM BUILD: #${evt.id} upgraded to ${evt.levelName}.${tl?`\n๐Ÿงฐ Unlocked: ${tl}.`:''}`;} - else text=`๐Ÿ’ธ TEAM BUILD: #${evt.toId} just got PAID ${evt.pol.toFixed(2)} POL${evt.kind==='upline'?` (${evt.gen?`Gen ${evt.gen} `:''}upgrade pass-up from #${evt.fromId})`:` (referral reward from #${evt.fromId})`}.${contact(evt.toId)}`; + else { + // On an upgrade pass-up, say what the BUYER unlocked. This is the exact + // moment "your level is your reach" is provable โ€” someone below climbed, + // and that is why this payment landed here. Upgrades are rare next to + // payouts, so without this the toolkit is almost never mentioned. + // Entry rewards get no tool line: nobody changed level. + const upTools = evt.kind==='upline' ? suiteTools.unlockText(0,evt.levelName,getConfig()) : ''; + text=`๐Ÿ’ธ TEAM BUILD: #${evt.toId} just got PAID ${evt.pol.toFixed(2)} POL${evt.kind==='upline'?` (${evt.gen?`Gen ${evt.gen} `:''}upgrade pass-up from #${evt.fromId})`:` (referral reward from #${evt.fromId})`}.${contact(evt.toId)}`; + if(upTools) text+=`\n๐Ÿงฐ #${evt.fromId} reached ${evt.levelName} and unlocked ${upTools}.`; + } if(evt.tx)text+=`\nhttps://polygonscan.com/tx/${evt.tx}`; sendTelegram(text); // recruiting-framed copy of the SAME event to the new-members topic diff --git a/suite-pages.js b/suite-pages.js index c5dd6d5..10b5de1 100644 --- a/suite-pages.js +++ b/suite-pages.js @@ -47,6 +47,36 @@ function list(id) { return out; } +// How many pages a position may HOLD at once, by level (index = level - 1). +// This is a different thing from the monthly BUILD quota in suite-meter: builds +// are how often you may run the writer, this is how many pages you may keep. +// They used to contradict each other โ€” an Ascensus member was allowed 3 builds +// a month but every build overwrote the same page, so they could never have +// more than one. Anyone who can build a page can now keep several, because the +// moment somebody thinks about two different audiences they want two pages. +const PAGE_LIMIT = [0, 2, 3, 5, 8, 15, 25, 50]; +function pageLimit(level) { + const lv = Math.max(1, Math.min(8, Number(level) || 1)); + return PAGE_LIMIT[lv - 1] || 0; +} + +// Slug from the headline the writer produced, so the address describes the page +// without asking the member to invent one. Falls back to the angle, then to a +// short random suffix, and always de-duplicates against what they already hold. +function slugFromTitle(id, title, angle) { + let base = slugify(title || ''); + if (base.length < 3) base = slugify(angle || 'page'); + if (!base) base = 'page'; + const taken = {}; + list(id).forEach(function (p) { if (p.slug) taken[p.slug] = 1; }); + if (!taken[base]) return base; + for (let i = 2; i < 40; i++) { + const c = slugify(base.slice(0, 20) + '-' + i); + if (!taken[c]) return c; + } + return slugify(base.slice(0, 16) + '-' + Math.floor(Date.now() / 1000).toString(36)); +} + // Angles reuse the team's existing hook videos + their landing variant. const ANGLES = { pocket: { label: 'Pocket change', video: '/v/rmc-pocket-change-b403fb2f75.mp4', poster: '/v/rmc-pocket-change-poster.jpg' }, @@ -119,6 +149,20 @@ function esc(s) { function render(rec) { const a = ANGLES[rec.angle] || ANGLES.overview; + // The button and the QR go to DIFFERENT places on purpose. + // + // `?v=` is not a normal landing page โ€” it is a SQUEEZE step that hides + // everything except the hook video and one button. A reader of this page has + // just watched that exact video, so sending them there replayed it before + // they could act. Dropping the `?v=` lands them on the full invite page + // instead: payout feed, proof, sponsor card, join button. That is the proof + // layer, and skipping straight past it to the payment screen would be too big + // a jump for someone who arrived cold from an ad. + // + // The QR keeps the angle, because a scanned code often reaches somebody who + // never saw this page โ€” off a printout or a screenshot โ€” and the hook video + // is exactly what they need first. + const joinLink = 'https://rmcircle.team/join/' + rec.id; const link = 'https://rmcircle.team/join/' + rec.id + (rec.angle && rec.angle !== 'overview' ? '?v=' + rec.angle : ''); const who = esc(rec.name || ('Member #' + rec.id)); const c = rec.copy || {}; @@ -156,7 +200,7 @@ function render(rec) { story + (bullets ? '
    ' + bullets + '
' : '') + '

' + esc(c.closing || 'Take a look and see what you think.') + '

' + - 'See how it works โ†’' + + 'Join ' + who + ' →' + '
or scan ยท ' + esc(link.replace(/^https:\/\//, '')) + '
' + '
Independent team resource shared by an individual member. Participation takes real effort and involves cryptocurrency risk, including risk of total loss. No income is guaranteed. ' + 'Disclaimers ยท How the contract works
' + @@ -166,4 +210,4 @@ function render(rec) { ''; } -module.exports = { init, load, save, remove, list, slugify, generate, render, ANGLES, parseSections }; +module.exports = { init, load, save, remove, list, slugify, slugFromTitle, pageLimit, PAGE_LIMIT, generate, render, ANGLES, parseSections }; diff --git a/tgbot.js b/tgbot.js index 4e33a10..05dc522 100644 --- a/tgbot.js +++ b/tgbot.js @@ -101,7 +101,13 @@ async function notifyEvent(evt) { const chat = memberChat(evt.toId); if (!chat) return; const kind = evt.kind === 'upline' ? `${evt.gen ? `Gen ${evt.gen} ` : ''}upgrade pass-up from #${evt.fromId}` : `referral reward from #${evt.fromId}'s entry`; - await dm(chat, `๐Ÿ’ฐ You just caught ${evt.pol.toFixed(2)} POL โ€” ${kind}.\nVerify: https://polygonscan.com/tx/${evt.tx}\n\nYour pipeline: https://rmcircle.team/my/${evt.toId}`); + // Upgrade pass-up: tell the catcher what the person below just unlocked. + // It makes the reason for the payment concrete, and it is a natural nudge + // toward their own next rung without asking for anything. + const upTools = evt.kind === 'upline' ? suiteTools.unlockText(0, evt.levelName, getConfig()) : ''; + await dm(chat, `๐Ÿ’ฐ You just caught ${evt.pol.toFixed(2)} POL โ€” ${kind}.` + + (upTools ? `\n\n#${evt.fromId} reached ${evt.levelName}, which unlocked ${upTools} for them โ€” and their climb is what put this on you.` : '') + + `\nVerify: https://polygonscan.com/tx/${evt.tx}\n\nYour pipeline: https://rmcircle.team/my/${evt.toId}`); } else if (evt.type === 'upgraded') { // Congratulate the member who upgraded, and tell them what it opened up. const chat = memberChat(evt.id);