Co-Branded Pages: give Fastigium a change of kind, not a bigger number
Once every member from Ascensus up could hold several pages, the Funnel Factory's differentiator became a count — the same quantity-not-kind flaw the upper tiers had. L6 now unlocks identity instead: a member's own name, monogram and accent colour on every page they build. Below Fastigium you have a page on the team site; at Fastigium it becomes yours. Three deliberate limits. NO IMAGE UPLOADS. A logo file uploaded by a member and served from rmcircle.team is an abuse surface — whatever they upload lives on our domain. The mark is a monogram generated from their brand name instead: real identity, nothing to moderate. Same reasoning that keeps Traffic Desk creative team-only. ACCENTS ARE A CURATED SET, not a colour picker. Every option is checked against the dark ground, so nobody can pick something that makes their own page unreadable and then wonder why it converts badly. THE DISCLAIMERS ARE NOT THEIRS TO BRAND. Branding replaces the header identity only; the footer — independent team resource, no income guaranteed, cryptocurrency risk — is rendered by us and cannot be removed or restyled. Co-branding, not white-labelling. Verified in the renderer. Branding is resolved against the LIVE contract level at render time, so a position that drops below Fastigium reverts to team identity on its own rather than keeping something it no longer holds. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -31,6 +31,7 @@ const suiteLeader = require('./suite-leader');
|
||||
const suiteFounder = require('./suite-founder'); suiteFounder.init({ dataDir: DATA_DIR });
|
||||
const suiteGrants = require('./suite-grants'); suiteGrants.init({ dataDir: DATA_DIR });
|
||||
const suiteIntel = require('./suite-intel'); suiteIntel.init({ dataDir: DATA_DIR });
|
||||
const suiteBrand = require('./suite-brand'); suiteBrand.init({ dataDir: DATA_DIR });
|
||||
const tgbot = require('./tgbot');
|
||||
tgbot.init({ dataDir: DATA_DIR, chain, getConfig, messages, baseUrl: 'https://rmcircle.team' });
|
||||
const SESSION_TTL = 8 * 60 * 60 * 1000;
|
||||
@@ -709,6 +710,12 @@ async function handleApi(req,res,pathname){
|
||||
res.writeHead(302,securityHeaders({'Location':'/p/'+pid,'Cache-Control':'no-store'}));
|
||||
return res.end();
|
||||
}
|
||||
// Co-branding (L6) is resolved here, against the live contract level, so a
|
||||
// position that falls below Fastigium reverts to team identity by itself.
|
||||
try{
|
||||
const owner=await chain.memberPublic(rec.id).catch(()=>null);
|
||||
if(owner&&owner.registered){ const br=suiteBrand.forPage(rec.id,owner.level); if(br) rec.brand=br; }
|
||||
}catch(err){}
|
||||
const html=suitePages.render(rec);
|
||||
res.writeHead(200,securityHeaders({'Content-Type':'text/html; charset=utf-8','Cache-Control':'public, max-age=120'}));
|
||||
return res.end(html);
|
||||
@@ -724,6 +731,12 @@ async function handleApi(req,res,pathname){
|
||||
res.writeHead(302,securityHeaders({'Location':'/join/'+pid,'Cache-Control':'no-store'}));
|
||||
return res.end();
|
||||
}
|
||||
// Co-branding (L6) is resolved here, against the live contract level, so a
|
||||
// position that falls below Fastigium reverts to team identity by itself.
|
||||
try{
|
||||
const owner=await chain.memberPublic(rec.id).catch(()=>null);
|
||||
if(owner&&owner.registered){ const br=suiteBrand.forPage(rec.id,owner.level); if(br) rec.brand=br; }
|
||||
}catch(err){}
|
||||
const html=suitePages.render(rec);
|
||||
// Member pages must ALWAYS be viewable inside a frame — the builder previews
|
||||
// them, and members share them into contexts that embed. Never send
|
||||
@@ -1144,6 +1157,23 @@ async function handleApi(req,res,pathname){
|
||||
return fs.createReadStream(vfile).pipe(res);
|
||||
}
|
||||
|
||||
// -- Co-branded pages (level 6) -------------------------------------------
|
||||
if(pathname==='/api/public/suite-brand'){
|
||||
const e=await suiteEntitlement(req).catch(()=>({error:'Chain read hiccup - try again.',code:500}));
|
||||
if(e.error)return json(res,e.code||500,{error:e.error});
|
||||
if(!e.inOrg||!e.allowed)return json(res,403,{error:'The Circle Suite is not open for this position yet.'});
|
||||
if(Number(e.d.level)<suiteBrand.MIN_LEVEL)return json(res,403,{error:'Co-branded pages unlock at Fastigium (level 6).',minLevel:suiteBrand.MIN_LEVEL});
|
||||
if(req.method==='GET'){
|
||||
return json(res,200,{brand:suiteBrand.load(e.d.id)||suiteBrand.blank(),accents:suiteBrand.accents(),
|
||||
pages:suitePages.list(e.d.id),level:e.d.level,id:e.d.id});
|
||||
}
|
||||
if(req.method==='POST'){
|
||||
const b=await bodyJson(req)||{};
|
||||
if(b.clear){ return json(res,200,{brand:suiteBrand.clear(e.d.id),cleared:true}); }
|
||||
return json(res,200,{brand:suiteBrand.save(e.d.id,b),saved:true});
|
||||
}
|
||||
}
|
||||
|
||||
if(req.method==='POST'&&pathname==='/api/public/suite-traffic-stop'){
|
||||
const e=await suiteEntitlement(req).catch(()=>({error:'Chain read hiccup — try again.',code:500}));
|
||||
if(e.error)return json(res,e.code||500,{error:e.error});
|
||||
@@ -1471,7 +1501,7 @@ const server=http.createServer(async(req,res)=>{
|
||||
if((mj=pathname.match(/^\/join\/(\d{1,15})$/)))return serveMemberPage(req,res,path.join(PUBLIC_DIR,'join.html'),'join',mj[1]);
|
||||
}
|
||||
let file;
|
||||
if(pathname==='/')file=path.join(PUBLIC_DIR,'index.html');else if(pathname==='/app'||pathname==='/app/')file=path.join(PUBLIC_DIR,'app.html');else if(pathname==='/start'||pathname==='/start/')file=path.join(PUBLIC_DIR,'start.html');else if(pathname==='/training'||pathname==='/training/')file=path.join(PUBLIC_DIR,'training.html');else if(pathname==='/admin'||pathname==='/admin/')file=path.join(PUBLIC_DIR,'admin.html');else if(pathname==='/my'||pathname==='/my/'||/^\/my\/\d{1,15}$/.test(pathname))file=path.join(PUBLIC_DIR,'my.html');else if(pathname==='/contract'||pathname==='/contract/')file=path.join(PUBLIC_DIR,'contract.html');else if(pathname==='/disclaimer'||pathname==='/disclaimer/')file=path.join(PUBLIC_DIR,'disclaimer.html');else if(pathname==='/privacy'||pathname==='/privacy/')file=path.join(PUBLIC_DIR,'privacy.html');else if(pathname==='/refunds'||pathname==='/refunds/')file=path.join(PUBLIC_DIR,'refunds.html');else if(pathname==='/how-pay-works'||pathname==='/how-pay-works/')file=path.join(PUBLIC_DIR,'how-pay-works.html');else if(pathname==='/tools'||pathname==='/tools/')file=path.join(PUBLIC_DIR,'tools.html');else if(pathname==='/fast-start'||pathname==='/fast-start/')file=path.join(PUBLIC_DIR,'fast-start.html');else if(pathname==='/flyers'||pathname==='/flyers/')file=path.join(PUBLIC_DIR,'flyers.html');else if(pathname==='/weekly-rhythm'||pathname==='/weekly-rhythm/')file=path.join(PUBLIC_DIR,'weekly-rhythm.html');else if(pathname==='/generation-pay'||pathname==='/generation-pay/')file=path.join(PUBLIC_DIR,'generation-pay.html');else if(pathname==='/suite'||pathname==='/suite/')file=path.join(PUBLIC_DIR,'suite.html');else if(pathname==='/suite/copy'||pathname==='/suite/copy/')file=path.join(PUBLIC_DIR,'suite-copy.html');else if(pathname==='/suite/page'||pathname==='/suite/page/')file=path.join(PUBLIC_DIR,'suite-page.html');else if(pathname==='/suite/email'||pathname==='/suite/email/')file=path.join(PUBLIC_DIR,'suite-email.html');else if(pathname==='/suite/video'||pathname==='/suite/video/')file=path.join(PUBLIC_DIR,'suite-video.html');else if(pathname==='/suite/traffic'||pathname==='/suite/traffic/')file=path.join(PUBLIC_DIR,'suite-traffic.html');else if(pathname==='/suite/voice'||pathname==='/suite/voice/')file=path.join(PUBLIC_DIR,'suite-voice.html');else if(pathname==='/suite/split'||pathname==='/suite/split/')file=path.join(PUBLIC_DIR,'suite-split.html');else if(pathname==='/suite/funnel'||pathname==='/suite/funnel/')file=path.join(PUBLIC_DIR,'suite-funnel.html');else if(pathname==='/suite/leader'||pathname==='/suite/leader/')file=path.join(PUBLIC_DIR,'suite-leader.html');else if(pathname==='/suite/founder'||pathname==='/suite/founder/')file=path.join(PUBLIC_DIR,'suite-founder.html');else if(pathname==='/wallet-check'||pathname==='/wallet-check/')file=path.join(PUBLIC_DIR,'wallet-check.html');else if(pathname==='/suite/grants'||pathname==='/suite/grants/')file=path.join(PUBLIC_DIR,'suite-grants.html');else if(pathname==='/suite/intel'||pathname==='/suite/intel/')file=path.join(PUBLIC_DIR,'suite-intel.html');else if(pathname==='/direct-join'||pathname==='/direct-join/'){if(!getSession(req)){res.writeHead(302,{Location:'/admin'});return res.end();}file=path.join(ROOT,'private','direct-join.html');}else if(pathname==='/join-now'||pathname==='/join-now/'){if(!getConfig().dappFallbackPublic){res.writeHead(302,{Location:'/start'});return res.end();}file=path.join(ROOT,'private','join-now.html');}else if(/^\/join\/\d{1,15}$/.test(pathname))file=path.join(PUBLIC_DIR,'join.html');else if(pathname==='/join'||pathname==='/join/'){res.writeHead(302,{Location:'/join-now'});return res.end();}else{
|
||||
if(pathname==='/')file=path.join(PUBLIC_DIR,'index.html');else if(pathname==='/app'||pathname==='/app/')file=path.join(PUBLIC_DIR,'app.html');else if(pathname==='/start'||pathname==='/start/')file=path.join(PUBLIC_DIR,'start.html');else if(pathname==='/training'||pathname==='/training/')file=path.join(PUBLIC_DIR,'training.html');else if(pathname==='/admin'||pathname==='/admin/')file=path.join(PUBLIC_DIR,'admin.html');else if(pathname==='/my'||pathname==='/my/'||/^\/my\/\d{1,15}$/.test(pathname))file=path.join(PUBLIC_DIR,'my.html');else if(pathname==='/contract'||pathname==='/contract/')file=path.join(PUBLIC_DIR,'contract.html');else if(pathname==='/disclaimer'||pathname==='/disclaimer/')file=path.join(PUBLIC_DIR,'disclaimer.html');else if(pathname==='/privacy'||pathname==='/privacy/')file=path.join(PUBLIC_DIR,'privacy.html');else if(pathname==='/refunds'||pathname==='/refunds/')file=path.join(PUBLIC_DIR,'refunds.html');else if(pathname==='/how-pay-works'||pathname==='/how-pay-works/')file=path.join(PUBLIC_DIR,'how-pay-works.html');else if(pathname==='/tools'||pathname==='/tools/')file=path.join(PUBLIC_DIR,'tools.html');else if(pathname==='/fast-start'||pathname==='/fast-start/')file=path.join(PUBLIC_DIR,'fast-start.html');else if(pathname==='/flyers'||pathname==='/flyers/')file=path.join(PUBLIC_DIR,'flyers.html');else if(pathname==='/weekly-rhythm'||pathname==='/weekly-rhythm/')file=path.join(PUBLIC_DIR,'weekly-rhythm.html');else if(pathname==='/generation-pay'||pathname==='/generation-pay/')file=path.join(PUBLIC_DIR,'generation-pay.html');else if(pathname==='/suite'||pathname==='/suite/')file=path.join(PUBLIC_DIR,'suite.html');else if(pathname==='/suite/copy'||pathname==='/suite/copy/')file=path.join(PUBLIC_DIR,'suite-copy.html');else if(pathname==='/suite/page'||pathname==='/suite/page/')file=path.join(PUBLIC_DIR,'suite-page.html');else if(pathname==='/suite/email'||pathname==='/suite/email/')file=path.join(PUBLIC_DIR,'suite-email.html');else if(pathname==='/suite/video'||pathname==='/suite/video/')file=path.join(PUBLIC_DIR,'suite-video.html');else if(pathname==='/suite/traffic'||pathname==='/suite/traffic/')file=path.join(PUBLIC_DIR,'suite-traffic.html');else if(pathname==='/suite/voice'||pathname==='/suite/voice/')file=path.join(PUBLIC_DIR,'suite-voice.html');else if(pathname==='/suite/split'||pathname==='/suite/split/')file=path.join(PUBLIC_DIR,'suite-split.html');else if(pathname==='/suite/funnel'||pathname==='/suite/funnel/')file=path.join(PUBLIC_DIR,'suite-funnel.html');else if(pathname==='/suite/leader'||pathname==='/suite/leader/')file=path.join(PUBLIC_DIR,'suite-leader.html');else if(pathname==='/suite/founder'||pathname==='/suite/founder/')file=path.join(PUBLIC_DIR,'suite-founder.html');else if(pathname==='/wallet-check'||pathname==='/wallet-check/')file=path.join(PUBLIC_DIR,'wallet-check.html');else if(pathname==='/suite/brand'||pathname==='/suite/brand/')file=path.join(PUBLIC_DIR,'suite-brand.html');else if(pathname==='/suite/grants'||pathname==='/suite/grants/')file=path.join(PUBLIC_DIR,'suite-grants.html');else if(pathname==='/suite/intel'||pathname==='/suite/intel/')file=path.join(PUBLIC_DIR,'suite-intel.html');else if(pathname==='/direct-join'||pathname==='/direct-join/'){if(!getSession(req)){res.writeHead(302,{Location:'/admin'});return res.end();}file=path.join(ROOT,'private','direct-join.html');}else if(pathname==='/join-now'||pathname==='/join-now/'){if(!getConfig().dappFallbackPublic){res.writeHead(302,{Location:'/start'});return res.end();}file=path.join(ROOT,'private','join-now.html');}else if(/^\/join\/\d{1,15}$/.test(pathname))file=path.join(PUBLIC_DIR,'join.html');else if(pathname==='/join'||pathname==='/join/'){res.writeHead(302,{Location:'/join-now'});return res.end();}else{
|
||||
const safe=path.normalize(pathname).replace(/^([.][.][/\\])+/, '').replace(/^[/\\]+/,'');file=path.join(PUBLIC_DIR,safe);if(!file.startsWith(PUBLIC_DIR))file='';
|
||||
}
|
||||
if(file&&staticFile(req,res,file))return;return staticFile(req,res,path.join(PUBLIC_DIR,'404.html'),404);
|
||||
|
||||
Reference in New Issue
Block a user