Admin Traffic tab: referring domains, landing pages, angles, by day
traffic.js logs public page views by referring domain (30 s buffered; page_hits table or traffic.json), coach exposes all join-page views, and /api/admin/traffic merges page views, join-page views, signups, registrations and $20+ buyers by first-touch source for 7/30/90/365-day ranges. Also: line-tree chips no longer truncate own-position labels. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -104,7 +104,8 @@ const J = {
|
||||
async addView(token, angle, ts, ref) { this.db.views.push({ token, angle, ts, ref: ref || '' }); if (this.db.views.length > 50000) this.db.views = this.db.views.slice(-40000); this.save(); },
|
||||
async addClick(campaignId, src, ts) { this.db.clicks = this.db.clicks || []; this.db.clicks.push({ campaignId, src, ts }); if (this.db.clicks.length > 50000) this.db.clicks = this.db.clicks.slice(-40000); this.save(); },
|
||||
async clicksFor(ids) { return (this.db.clicks || []).filter(c => ids.includes(c.campaignId)); },
|
||||
async views(tokens, since) { return this.db.views.filter(v => tokens.includes(v.token) && v.ts >= since); }
|
||||
async views(tokens, since) { return this.db.views.filter(v => tokens.includes(v.token) && v.ts >= since); },
|
||||
async viewsSince(since) { return this.db.views.filter(v => v.ts >= since); }
|
||||
};
|
||||
const D = {
|
||||
async lastNudge(email) { const r = await db.q('SELECT rung, ts FROM nudges WHERE email=?', [email]); return r[0] ? { rung: r[0].rung, ts: Number(r[0].ts) } : null; },
|
||||
@@ -131,6 +132,10 @@ const D = {
|
||||
if (!tokens.length) return [];
|
||||
const rows = await db.q('SELECT token, angle, ts, ref FROM join_views WHERE ts>=? AND token IN (' + tokens.map(() => '?').join(',') + ')', [since, ...tokens]);
|
||||
return rows.map(r => ({ token: r.token, angle: r.angle, ts: Number(r.ts), ref: r.ref || '' }));
|
||||
},
|
||||
async viewsSince(since) {
|
||||
const rows = await db.q('SELECT token, angle, ts, ref FROM join_views WHERE ts>=?', [since]);
|
||||
return rows.map(r => ({ token: r.token, angle: r.angle, ts: Number(r.ts), ref: r.ref || '' }));
|
||||
}
|
||||
};
|
||||
const impl = () => db.enabled() ? D : J;
|
||||
@@ -249,4 +254,5 @@ function init(opts) {
|
||||
DATA_DIR = opts.dataDir; chain = opts.chain; accounts = opts.accounts; mailer = opts.mailer;
|
||||
J.load();
|
||||
}
|
||||
module.exports = { init, RUNGS, rungFor, describe, coachView, prospects, saveProspect, removeProspect, STATUSES, recordView, linkStats, nudgeTick, recordClick, clickSources, refHost };
|
||||
async function viewsSince(since) { return impl().viewsSince(since); }
|
||||
module.exports = { init, RUNGS, rungFor, describe, coachView, prospects, saveProspect, removeProspect, STATUSES, recordView, linkStats, nudgeTick, recordClick, clickSources, refHost, viewsSince };
|
||||
|
||||
Reference in New Issue
Block a user