Split submissions into rotation vs leg paths — decided by the chain

Two leg-build members submitted the /start form thinking it was required,
polluting rotation bookkeeping. Rather than two forms, the server now
classifies every submission by on-chain truth: referrer == active
rotation sponsor -> "rotation" (Telegram says +1 direct, add to queue);
anyone else -> "leg" (correct sponsor credited, "no rotation action
needed"). The member dashboard gains its own "Just joined under this
position?" form so leg builders have a proper landing spot; /start
feedback explains each path to the submitter; admin submissions table
shows a rotation/leg chip. Verified against live data: ID 65 claiming
sponsor 36 correctly classified leg under #62.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
martbost
2026-08-14 05:39:02 -05:00
parent d9ac9c9806
commit 532cb18b68
5 changed files with 49 additions and 12 deletions
+19 -7
View File
@@ -135,17 +135,29 @@ async function handleSubmitId(req, res) {
new Promise((_, rej) => setTimeout(() => rej(new Error('timeout')), 6000))
]);
} catch (e) { onchain = null; }
subs.push({ newId, memberName, sponsorId, source: source||'(direct)', clickid, ts: new Date().toISOString(),
// the chain decides the path: rotation join (referrer = active rotation sponsor)
// vs leg join (someone's personal team build) — regardless of which page they used
const active = activeSponsor(getSponsors());
let joinPath = 'unknown';
if (onchain && onchain.registered) joinPath = (active && String(onchain.referrerId) === String(active.id)) ? 'rotation' : 'leg';
else if (onchain && !onchain.registered) joinPath = 'notfound';
subs.push({ newId, memberName, sponsorId, source: source||'(direct)', clickid, ts: new Date().toISOString(), path: joinPath,
onchain: onchain ? { registered: onchain.registered, tier: onchain.tierName, level: onchain.levelName, referrerId: onchain.referrerId, uplineId: onchain.uplineId } : undefined });
writeJson(SUBMISSIONS_FILE, subs.slice(-1000));
recordEvent('purchase', source);
firePostback(clickid, `purchase-${clickid}`, source);
const chainLine = onchain === null ? '⏳ On-chain check unavailable — verify manually in admin.'
: onchain.registered
? `✅ VERIFIED ON-CHAIN: ${onchain.tierName} tier, level ${onchain.levelName}, referred by ID ${onchain.referrerId}${String(onchain.referrerId)!==sponsorId?` ⚠ (submitted sponsor was ${sponsorId})`:''}`
: `❌ NOT FOUND ON-CHAIN — ID ${newId} has no registration on the contract yet.`;
sendTelegram(`🔔 RM Circle: NEW MEMBER CONFIRMED\nName: ${memberName}\nNew ID: ${newId}\nJoined under sponsor: ${sponsorId}\nSource: ${source||'(direct)'}\n${chainLine}\n→ Add ${memberName} (ID ${newId}) to the rotation queue.`);
return json(res, 200, { ok: true, onchain: onchain ? { registered: onchain.registered, tier: onchain.tierName, level: onchain.levelName, referrerId: onchain.referrerId } : null });
let msg;
if (joinPath === 'rotation') {
msg = `🔔 RM Circle: ROTATION JOIN CONFIRMED ✅\nName: ${memberName}\nNew ID: ${newId} (${onchain.tierName}, verified on-chain)\nJoined under rotation sponsor: #${onchain.referrerId}\nSource: ${source||'(direct)'}\n→ +1 direct for ID ${active.id}; add ${memberName} (ID ${newId}) to the rotation queue.`;
} else if (joinPath === 'leg') {
msg = `🌱 RM Circle: TEAM-BUILD JOIN (not rotation)\nName: ${memberName}\nNew ID: ${newId} (${onchain.tierName}, verified on-chain)\nActual sponsor on-chain: #${onchain.referrerId}${sponsorId!=='?'&&String(onchain.referrerId)!==sponsorId?` (form said ${sponsorId})`:''}\nSource: ${source||'(direct)'}\n→ Leg growth under #${onchain.referrerId} — no rotation action needed. Add them to the rotation queue only if they want the team effort.`;
} else if (joinPath === 'notfound') {
msg = `🔔 RM Circle: ID SUBMITTED — ❌ NOT FOUND ON-CHAIN\nName: ${memberName}\nNew ID: ${newId}\nClaimed sponsor: ${sponsorId}\nSource: ${source||'(direct)'}\n→ ID has no registration on the contract — double-check with them before any queue action.`;
} else {
msg = `🔔 RM Circle: NEW MEMBER SUBMITTED\nName: ${memberName}\nNew ID: ${newId}\nClaimed sponsor: ${sponsorId}\nSource: ${source||'(direct)'}\n⏳ On-chain check unavailable — verify manually in admin (member lookup).`;
}
sendTelegram(msg);
return json(res, 200, { ok: true, path: joinPath, onchain: onchain ? { registered: onchain.registered, tier: onchain.tierName, level: onchain.levelName, referrerId: onchain.referrerId } : null });
}
async function handleChat(req, res) {
const ip = String(req.headers['x-forwarded-for']||req.socket.remoteAddress||'').split(',')[0].trim();