Campaign scheduling (start/end, solo send-from), scheduled NAS push + end sweep, views-by-hour chart

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
martbost
2026-09-11 06:53:53 -05:00
parent 159e19dcdf
commit bf5371ab20
7 changed files with 49 additions and 8 deletions
+2
View File
@@ -298,6 +298,7 @@ async function boot() {
chatbot.init({ dataDir: DATA_DIR, chain });
setTimeout(() => ads.dailySweep().catch(e => console.error('sweep', e.message)), 60 * 1000);
setInterval(() => ads.dailySweep().catch(e => console.error('sweep', e.message)), 60 * 60 * 1000);
setInterval(() => ads.scheduleSweep().catch(e => console.error('schedule sweep', e.message)), 5 * 60 * 1000); // scheduled starts/ends
// follow-up email sequence: send whatever came due (every 10 min, first pass shortly after boot)
coach.init({ dataDir: DATA_DIR, chain, accounts, mailer });
burner.init({ chain, ads });
@@ -1624,6 +1625,7 @@ const server = http.createServer(async (req, res) => {
const memberId = await auth.refreshMemberId(s);
const out = { campaigns: await ads.listCampaigns(s.email), rates: ads.rates(), bannerSizes: ads.bannerSizes() };
out.clickSources = await coach.clickSources(out.campaigns.map(c => c.id));
out.hours = await ads.hoursFor(out.campaigns.map(c => c.id)); // on-site views per UTC hour, last 7 days
const pool = await ads.balances((await myMemberIds(s)).ids, s.email);
out.purchasedCredits = pool.total;
out.largestPosition = pool.best.avail; // a single campaign budget has to fit one position