A page per day: the whole contract, midnight to midnight

The daily snapshot outgrew Telegram. Past 1,000 members the post hit the
4,096-character limit and was rejected outright two mornings running, and
capping the lists to fit meant choosing what to throw away. Manson caught what
that cost: the level-up list was ordered by time, so the cap hid two Culmen and
thirteen Fabrica behind two dozen routine Ascensus upgrades.

/day/<date> now carries every climb, every payment with its Polygonscan link,
every new position and every recruiter, with no cap on any of it. Company-wide,
no team filter, keyed to the Central calendar day so a link posted on Monday
still shows Monday next year. Today is computed live; a finished day is written
to disk once, because the chain index only keeps a few hundred payouts and an
older day could never be rebuilt from it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
martbost
2026-09-23 05:41:31 -05:00
parent e6cdd77d17
commit 4c6fb7bed2
2 changed files with 247 additions and 0 deletions
+14
View File
@@ -4,6 +4,7 @@ const path = require('path');
const crypto = require('crypto');
const { URL } = require('url');
const chain = require('./chain');
const daysnap = require('./daysnap'); // /day/<date>: the whole contract, one Central day, kept forever
const messages = require('./messages');
const profiles = require('./profiles');
const placement = require('./placement');
@@ -1847,6 +1848,14 @@ const server=http.createServer(async(req,res)=>{
const u=new URL(req.url,`http://${req.headers.host||'localhost'}`),pathname=decodeURIComponent(u.pathname);
// /p/<id> = member Page Builder pages: dynamic HTML, so it must reach the
// API handler rather than the static-file path (which 404s it).
if(pathname==='/day'||/^\/day\/\d{4}-\d{2}-\d{2}$/.test(pathname)){
const key = pathname==='/day' ? daysnap.dayKey() : pathname.slice(5);
const r = daysnap.render(key, { polUsd: await getPolUsd() });
const fresh = key === daysnap.dayKey();
res.writeHead(r.status, securityHeaders({ 'Content-Type':'text/html; charset=utf-8',
'Cache-Control': fresh ? 'public, max-age=120' : 'public, max-age=86400' }));
return res.end(r.html);
}
if(pathname==='/health'||pathname==='/announce.ics'||pathname.startsWith('/api/')||pathname.startsWith('/tv/')||/^\/p\/\d{1,15}(\/[a-z0-9-]{1,24})?$/.test(pathname))return await handleApi(req,res,pathname);
if(req.method!=='GET'&&req.method!=='HEAD')return send(res,405,'Method Not Allowed',{'Content-Type':'text/plain; charset=utf-8'});
// Members-area gate: the Circle Method lessons 2-10 + the e-gift cash-out
@@ -1925,6 +1934,11 @@ function checkUpgradeAlerts(){
}catch(e){ console.error('upgrade alert check', e.message); }
}
setInterval(checkUpgradeAlerts, 5*60*1000).unref();
// close out finished days so the archive never depends on someone opening the page before the
// chain index's rolling payout window scrolls past that day
daysnap.init({ dataDir: DATA_DIR });
setTimeout(() => { try { daysnap.tick(); } catch (e) { console.error('daysnap', e.message); } }, 20000).unref();
setInterval(() => { try { daysnap.tick(); } catch (e) { console.error('daysnap', e.message); } }, 60 * 60 * 1000).unref();
setTimeout(checkUpgradeAlerts, 30000).unref();
chain.startIndexer(evt=>{
// Any on-chain event makes cached member views stale (the new member, the