From 1284d2889106b088b799016a461b9aaf4c9fbeef Mon Sep 17 00:00:00 2001 From: martbost Date: Fri, 18 Sep 2026 09:08:24 -0500 Subject: [PATCH] Keep a member's link inside their own team, and stop the dashboard contradicting the admin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two faults found chasing why Terry (#840) was routing joins to #148, a position outside his team. The leg lookup only considered positions on the curated rotation list. Terry qualified the same day he joined, so his two directs (#843, #844) were too new to be on it. With no leg match the code fell straight through to the GLOBAL company rotation — sending his people to a stranger while his own directs sat on 0/2. That is the opposite of the team-first doctrine the moving link exists to serve. There is now a last-resort step inside the leg: the nearest position still needing its 2, curated or not. The curated order still wins when it applies; the global rotation is now only reached when the member's whole leg really is qualified. Second, the dashboard ignored directDefault entirely. Marty had already set Terry to direct placement in the admin, which the join page honours — but Terry's own share panel still told him his link routed to someone else. Two different answers to "where do my people land". The panel now says rotation is off and every join lands under him, and explains ?direct=0 for the exception. Also made the all-qualified case name what it is: joins go to the company rotation, placed wherever the company is filling, not inside your leg. That wording is what made #148 look like a bug rather than a fallback. Co-Authored-By: Claude Opus 5 (1M context) --- public/my.js | 15 +++++++++++---- server.js | 7 +++++++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/public/my.js b/public/my.js index 5271dfc..ea56f3b 100644 --- a/public/my.js +++ b/public/my.js @@ -794,13 +794,20 @@ const dashUrl=`https://rmcircle.team/join/${d.id}`; const directUrl=`${dashUrl}?direct=1`; const q2=d.directCount>=2, nx=d.nextInLine; + // A position on the admin's direct-placement list has its moving link switched OFF: + // /join/ behaves as ?direct=1, so every join lands under THIS position. The join + // page has always honoured that; this panel did not, and told the member their link + // routed to someone else. Two different answers about where their people land. + const dd=!!d.directDefault; // The personal QR is ALWAYS shown: /join/ self-rotates via the moving // link, so a scan is always placed correctly — even after 2/2. This is the // person-to-person flow: open your page, tap the QR, they scan, they see // your pitch page with the video and the join button. - const guidance=q2 + const guidance=dd + ?`${q2?'★ Qualified':''} Rotation is off for this position: every join through your page lands directly under you as depth, and the entry reward is yours. That is a deliberate setting on your position — ask your sponsor before changing how you promote it.` + :q2 ?(nx?`★ Qualified Your page now routes new joins to #${nx.id} (${nx.directCount||0}/2) — the team play moving down your leg automatically. Anyone who scans still lands on YOUR pitch page; placement is handled for you. A signup on your own link is always a bonus: the entry reward is yours.` - :`★ Qualified Your whole leg is qualified — your page routes new joins to the team rotation automatically.`) + :`★ Qualified Your whole leg is qualified — your page routes new joins to the company rotation, so the next join is placed wherever the company is currently filling, not inside your own leg.`) :`Share this with your 2 — anyone who scans or clicks lands on your personal pitch page (video, live proof, join button) and joins under you.`; el.innerHTML=`

${guidance}

@@ -814,9 +821,9 @@
🔀 Two ways to share
-

The link above is your Team link ${q2?'— now that you’re qualified it routes new joins to the next teammate who needs directs, building your team in order (recommended).':'— it credits you and builds your first two.'} Want new people to land under YOU as spillover instead? Use your Direct link:

+

${dd?'Rotation is switched off for this position, so the link above already places every join under you. To send someone into the team rotation instead, add ?direct=0 to it.':`The link above is your Team link ${q2?'— now that you’re qualified it routes new joins to the next teammate who needs directs, building your team in order (recommended).':'— it credits you and builds your first two.'} Want new people to land under YOU as spillover instead? Use your Direct link:`}

${esc(directUrl)}
-

Team link helps your team qualify. Direct link places every join under you (own spillover). Either way you keep the entry reward on anyone you personally bring.

+

${dd?'Either way you keep the entry reward on anyone you personally bring.':'Team link helps your team qualify. Direct link places every join under you (own spillover). Either way you keep the entry reward on anyone you personally bring.'}

`; const qr=document.getElementById('dQr');if(qr)qr.innerHTML=qrSvg(dashUrl); const qb=document.getElementById('dQrBtn'); diff --git a/server.js b/server.js index cf37916..d33d845 100644 --- a/server.js +++ b/server.js @@ -646,6 +646,13 @@ async function handleApi(req,res,pathname){ let pick=null; if(act)pick=bfs.find(n=>String(n.id)===String(act.id)&&(n.directCount||0)<2); if(!pick)pick=bfs.find(n=>participants.has(String(n.id))&&(n.directCount||0)<2); + // Last resort WITHIN the leg: the nearest position that still needs its 2, + // curated list or not. Without this, a member whose directs are too new to be + // in the rotation list had no leg pick at all and fell through to the GLOBAL + // rotation — sending their people to a stranger's position while their own + // brand-new directs sat on 0/2. That is the opposite of team-first. (Terry #840, + // qualified the same day he joined, was routing to #148; 2026-09-18.) + if(!pick)pick=bfs.find(n=>(n.directCount||0)<2); if(pick)r.nextInLine={id:pick.id,directCount:pick.directCount||0,levelName:pick.levelName}; }catch(e){} }