${link(r)} — qualified, still Scintilla, sitting on ${fmt(r.earnedPol)} POL (Ascensus costs ${fmt(r.ascensusCost)}). One message: “your entry rewards already cover the upgrade that catches your team's first payments.”
${link(r)} — ${esc(r.levelName)}, needs ${esc(r.neededLevelName)} to catch ${fmt(r.atRiskPol)} POL forming under them (from ${r.fromIds.map(f=>'#'+f).join(', ')}).
`).join('')||'
Everyone leveled is ahead of their wave. 🎉
';
+ const t3=d.oneAway.map(r=>`
🎯
${link(r)} — 1/2 directs, one placement from qualifying.
${link(r)} — NOT qualified (${r.directCount}/2) with ${fmt(r.atRiskPol)} POL already forming below. Qualification is urgent for them.
`).join('');
+ out.innerHTML=
+ `
Members scanned${d.scanned}
POL at risk${fmt(d.totals.atRiskPol)}
Easy wins${d.totals.rollForwardCount}
One direct away${d.totals.oneAwayCount}
`+
+ `
Tier 1 · Easy wins — one message each
${t1}`+
+ `
Tier 2 · Money at risk — coach the upgrade
${t2}`+
+ (unq?`
Tier 2b · Money forming, not yet qualified
${unq}`:'')+
+ `
Tier 3 · One placement from qualified
${t3}`;
+ }catch(x){out.innerHTML=`
${esc(x.message)}
`}
+}
+const cr=document.getElementById('coachRefresh');if(cr)cr.addEventListener('click',loadCoaching);
+let coachAutoLoaded=false;
let incomeAutoLoaded=false;
async function loadIncome(){
const ids=(document.getElementById('incomeIds').value||'').trim();
diff --git a/public/chat.js b/public/chat.js
index 2fb5bb2..17b855d 100644
--- a/public/chat.js
+++ b/public/chat.js
@@ -49,7 +49,7 @@
{k:['tier','standard','premium tier','standard tier','premium vs standard','which tier','half','smaller payment','less than expected','why is my payment'],
a:()=>`There are two tiers. Premium is what our whole team builds at (${pol()} POL entry) — full payments. Standard costs about half and pays/earns half at every level. So if a payment ever comes in smaller than expected, it usually came from a Standard-tier position below you. Your tier is set when you join and can't be changed later (upgrading advances your level, not your tier), so always join Premium and make sure the people you bring on do too. Full breakdown: how-pay-works.`},
{k:['dashboard','my dashboard','my page','my position','my team','check my','see my','pipeline','my stats','alerts','notify me','email me','get notified'],
- a:()=>`Your Member Dashboard is at rmcircle.team/my — enter your ID to see your position, your team, your payments, your pipeline (money forming below you), and any spillover under you. You can also turn on email alerts there to be notified the moment you're paid or need to upgrade. To share, use your personal invite page: rmcircle.team/join/<your ID>.`},
+ a:()=>`Your Member Dashboard is at rmcircle.team/my — enter your ID to see your position, your team (with a depth summary showing members per generation), your payments, your pipeline (money forming below you), any spillover under you, and a Coach Your Team panel that tells you exactly who in your leg needs a nudge and what to say. You can also turn on email alerts there to be notified the moment you're paid or need to upgrade. To share, use your personal invite page: rmcircle.team/join/<your ID>.`},
{k:['level','levels','upgrade','scintilla','ascensus','fabrica','culmen','apex','fastigium','vertex','corona','8 levels'],
a:()=>`There are 8 Premium levels: Scintilla, Ascensus, Fabrica, Culmen, Apex, Fastigium, Vertex, Corona. Everyone starts at Scintilla. Upgrade as quickly as practical — ideally using earned POL — because the first two payments at each level are designed to help fund your next upgrade. Stay aware of your active downline's levels so you don't fall behind.`},
{k:['30 positions','goal','milestone','matrix','how many people','team size'],
diff --git a/public/my.html b/public/my.html
index f7b5ee3..6480aab 100644
--- a/public/my.html
+++ b/public/my.html
@@ -19,6 +19,7 @@
Your team
Your position's matrix — the rollup line on each card counts everyone underneath, all the way down. Click a position to drill into that leg. Open slots are where the next placements land.
✓ qualified (2/2 directs) · P Premium · S Standard · ⬇ everyone below that position (all generations) and the POL they've earned · ↧ spillover = placed there by upline activity; only members who join with a position's own ID count toward its 2/2
Your pipeline
Money forming below you. Each generation in your leg pays your position at exactly one level — when a member's level catches up to their depth, their next upgrade comes to you.
+
Coach your team
The fastest way to grow your own income is helping the people below you take their next step. Here's who in your team could use a nudge today — updated live from the blockchain.
Email me my alerts
Get an email the moment this position is paid, and when it needs an upgrade to catch incoming pay — so you never miss one. Opt in with your email; unsubscribe anytime.
Full generations duplicate: each one can hold twice the last. A generation pays this position at exactly one level — stay qualified and at that level to catch it.
`;
}
+ // "Coach your team" — the same triage the team admin runs, scoped to THIS
+ // position's leg: who below could use a nudge, and exactly what to tell them.
+ function renderCoach(d){
+ const card=document.getElementById('dCoachCard'),el=document.getElementById('dCoach');
+ if(!card||!el)return;
+ const c=d.coach;
+ if(!c||!c.ready||!c.scanned||((c.rollForward||[]).length+(c.atRisk||[]).length+(c.oneAway||[]).length)===0){card.style.display='none';return;}
+ const link=id=>`#${id}`;
+ const rows=[];
+ (c.rollForward||[]).forEach(r=>rows.push(`
💬
${link(r.id)} is qualified but still Scintilla with ${fmt(r.earnedPol)} POL of entry rewards — their Ascensus upgrade (${fmt(r.ascensusCost)} POL) is already covered and catches their team's first payments. Tell them!
${link(r.id)} (${esc(r.levelName)}) has ${fmt(r.atRiskPol)} POL forming below them but needs ${esc(r.neededLevelName)} to catch it — worth a heads-up before it passes them.
${link(r.id)} has ${fmt(r.atRiskPol)} POL forming below but isn't qualified yet (${r.directCount}/2) — help them find their ${r.directCount===1?'last direct':'2 directs'}.
`));
+ (c.oneAway||[]).forEach(r=>rows.push(`
🎯
${link(r.id)} is one direct away from qualifying — introduce them to one good person and their whole position activates.
Why this matters to YOU: every upgrade below you either pays your position directly or builds the depth that will. Helping them is not charity — it's your pipeline.
`;
+ card.style.display='';
+ }
// "My Next Step" — the single clearest action + the level ladder + a funded
// badge (server tells us funded true/false; it never sends the raw balance).
function renderNextStep(d){
diff --git a/server.js b/server.js
index 759b3d6..6681861 100644
--- a/server.js
+++ b/server.js
@@ -41,7 +41,7 @@ FACTS:
- SPILLOVER: when a sponsor's two matrix slots are full, the contract places new members in the next open slot further down (left to right) — possibly under someone else. Spillover fills that member's matrix and sets up future upgrade income to their position, but does NOT count toward qualification: only people who join using a member's own ID are their directs. Upgrade payments travel up the MATRIX (not who-referred-whom) and only stop at positions that are qualified (2 directs) AND already at the level being bought — otherwise the payment passes them by to the next eligible upline. Members can see their own matrix, spillover tags, and payments at https://rmcircle.team/my
- PAY FLOW (full diagram at https://rmcircle.team/how-pay-works): TWO income streams. (1) Entry rewards — when a direct joins under a member's link, that member gets the entry reward (~326 POL at Premium) and keeps it, on EVERY direct (not just the first two). (2) Upgrade payments — each person below you pays you ONCE, at the single level matching how far below you they sit: someone 1 layer down pays you at their Ascensus upgrade, 2 layers down at Fabrica, 3 at Culmen, 4 at Apex, and so on. To catch each one you must be at that level yourself AND qualified — so stay one level ahead of your team's deepest active layer. This is why a member can be "skipped" on a payment: it was reserved for the position at the matching depth, or they weren't leveled up in time.
- TIERS: Premium (the tier the whole team builds at, ${c.premiumEntryPol || 362} POL entry) pays and earns FULL amounts; Standard costs about half and pays/earns HALF at every level. A smaller-than-expected payment almost always came from a Standard-tier position below. Tier is fixed at registration and CANNOT be changed later (upgrading advances your LEVEL, not your tier). Always recommend joining Premium and having recruits do the same. Amount comparison at /how-pay-works.
-- MEMBER DASHBOARD & ALERTS: each member has a live dashboard at https://rmcircle.team/my (enter your ID) showing position, team, payments, pipeline (incoming money forming below), a team-depth summary (members per generation below you and which level's upgrade each generation pays you at), spillover tags, and qualification badges. Members can turn on opt-in EMAIL ALERTS there (notified when paid, and when they need to upgrade to catch incoming pay). A member's personal invite page to share is https://rmcircle.team/join/.
+- MEMBER DASHBOARD & ALERTS: each member has a live dashboard at https://rmcircle.team/my (enter your ID) showing position, team, payments, pipeline (incoming money forming below), a team-depth summary (members per generation below you and which level's upgrade each generation pays you at), a "Coach Your Team" panel (who in YOUR leg needs a nudge — qualified-but-not-upgraded members sitting on entry rewards, members about to miss forming payments, members one direct from qualifying), spillover tags, and qualification badges. Members can turn on opt-in EMAIL ALERTS there (notified when paid, and when they need to upgrade to catch incoming pay). A member's personal invite page to share is https://rmcircle.team/join/.
- RESILIENCE ("what if the creators disappear / owner loses keys / it falls apart over time"): the contract is autonomous and immutable — NO admin action, heartbeat, or living operator is required for joins, upgrades, matrix placement, or payouts; there is no pause switch and no expiry. Verified on-chain that the founder, development, and fee-receiver wallets are ordinary wallets (EOAs), NOT smart contracts — an ordinary wallet always accepts incoming POL even if its key is lost forever, so a dead or abandoned admin wallet cannot block any member payment (only the project's OWN uncollected fee would sit idle). The contract stores no balance (every payment is delivered in the same transaction). If the owner's key were lost, only the four limited admin powers freeze in place; members are unaffected. Details in section 6 of https://rmcircle.team/contract.
- Current team sponsor: ${a ? `ID ${a.id}${c.showSponsorName && a.name ? ` (${a.name})` : ''}, ${a.directs}/2 directs` : 'shown on the start page'}. ${waiting} placement(s) waiting. Placements rotate as positions qualify — always verify on https://rmcircle.team/start right before joining.
- Site pages: https://rmcircle.team/ (strategy overview + roadmap + live team stats), https://rmcircle.team/start (current sponsor + join steps), https://rmcircle.team/training (6 videos — team overview, wallet setup, funding, the new connect-wallet join flow on the site, the dApp backup method, how payments work — + spillover article), https://rmcircle.team/how-pay-works (the two income streams shown as a pay-flow diagram + Premium/Standard tier comparison), https://rmcircle.team/contract (plain-language security review of the verified smart contract — code can't change, no pooled funds, locked rules, honest list of operator powers), https://rmcircle.team/my (member dashboard), https://rmcircle.team/tools (for existing team members who want to promote — share-ready promo videos, copy-paste social posts, short/long email swipes, and a downloadable banner kit in every standard size; to write promos in their own voice, mybrandedvoice.com), https://rmcircle.team/disclaimer (affiliate/earnings/risk disclosures).
@@ -505,6 +505,20 @@ async function handleApi(req,res,pathname){
if(!Number.isInteger(root)||root<1||root>281474976710655)return json(res,400,{error:'Enter a numeric root ID.'});
return json(res,200,chain.getOrgShare(root));
}
+ if(req.method==='GET'&&pathname==='/api/admin/coaching'){
+ const raw=new URL(req.url,'http://x').searchParams.get('root');
+ const root=Number(raw||getConfig().orgRootId||parseOwnerIds()[0]||21);
+ if(!Number.isInteger(root)||root<1||root>281474976710655)return json(res,400,{error:'Enter a numeric root ID.'});
+ const d=chain.getCoachingScan(root,20);
+ if(d.ready){
+ // decorate with known names from the queue + submissions
+ const names={};
+ try{for(const s of getSponsors())names[String(s.id)]=s.name;}catch(e){}
+ try{for(const s of readJson(SUBMISSIONS_FILE))if(s.newId&&!names[String(s.newId)])names[String(s.newId)]=s.memberName;}catch(e){}
+ for(const list of [d.atRisk,d.rollForward,d.oneAway])for(const r of list)if(names[String(r.id)])r.name=names[String(r.id)];
+ }
+ return json(res,200,d);
+ }
if(req.method==='GET'&&pathname==='/api/admin/income'){
const raw=new URL(req.url,'http://x').searchParams.get('ids')||'';
const ids=[...new Set(raw.split(',').map(s=>parseInt(String(s).trim(),10)).filter(n=>Number.isInteger(n)&&n>0&&n<=281474976710655))].slice(0,12);