Admin > Reports: counters audit (views vs delivery logs, login days charged vs shown, featured views, clicks vs views, spend vs budget), daily with Telegram alert
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -32,7 +32,8 @@ const blog = require('./blog');
|
||||
const adminMember = require('./adminmember');
|
||||
const syndicate = require('./syndicate');
|
||||
const releases = require('./releases');
|
||||
const updates = require('./updates'); // member update emails from Admin > Releases (Marty, 2026-09-14)
|
||||
const updates = require('./updates');
|
||||
const audit = require('./audit'); // counter audit: views vs delivery logs, charges vs shows (Marty, 2026-09-15) // member update emails from Admin > Releases (Marty, 2026-09-14)
|
||||
const leaderboard = require('./leaderboard');
|
||||
const toolkit = require('./toolkit');
|
||||
const videomaker = require('./videomaker'); // Circuit tool: promo videos with the member's own end card (ffmpeg in the image) // badge-gated promo toolkit + AI Copy Engine (Surge and up) (Marty, 2026-09-14) // referral contest: /leaderboard, Overview card, weekly + monthly winners (Marty, 2026-09-14) // release notes + roadmap: /whats-new, Overview card, Admin > Releases (Marty, 2026-09-14) // blog -> Blotato -> X + Instagram on publish (Marty, 2026-09-13) // admin member card: search, drilldown, edits (Marty, 2026-09-13) // admin-written coaching articles, server-rendered public /blog with SEO metadata (Marty, 2026-09-12)
|
||||
@@ -379,6 +380,8 @@ async function boot() {
|
||||
releases.init({ dataDir: DATA_DIR });
|
||||
toolkit.init({ dataDir: DATA_DIR, ads, accounts, siteConfig, coach, messages, promos, videomaker, chain });
|
||||
updates.init({ dataDir: DATA_DIR, accounts, releases, mailer, drip, sendy, adminEmail: ADMIN_EMAIL });
|
||||
audit.init({ notify: text => { const sc = siteConfig(); if (sc.telegramBotToken && sc.telegramAdminChatId) telegramSend(sc.telegramAdminChatId, text).catch(() => {}); else if (ADMIN_EMAIL && mailer.hasKey()) mailer.send(ADMIN_EMAIL, 'InstantAdPay: counter audit', text).catch(() => {}); } });
|
||||
setTimeout(() => audit.dailyTick(), 5 * 60 * 1000); setInterval(() => audit.dailyTick(), 24 * 60 * 60 * 1000);
|
||||
videomaker.init({ dataDir: DATA_DIR, spaces, accounts });
|
||||
leaderboard.init({ chain, accounts, ads, dataDir: DATA_DIR, siteConfig, pushFeed, adminEmail: ADMIN_EMAIL,
|
||||
notify: async text => { const sc = siteConfig(); if (!sc.telegramBotToken || !sc.telegramEchoChatId) return; await telegramSend(sc.telegramEchoChatId, text, sc.telegramEchoTopicId); if (String(sc.leaderboardAnnounceGeneral || '1') !== '0') await telegramSend(sc.telegramEchoChatId, text, null); } });
|
||||
@@ -2418,6 +2421,10 @@ const server = http.createServer(async (req, res) => {
|
||||
const r = await ads.adminSetStatus(m[1], m[2] === 'pause' ? 'paused' : 'active');
|
||||
return json(res, r.error ? 400 : 200, r);
|
||||
}
|
||||
if (p === '/api/admin/audit' && req.method === 'GET') { // counters reconciled against delivery logs
|
||||
if (!isAdmin(req)) return json(res, 401, { error: 'auth' });
|
||||
return json(res, 200, await audit.run());
|
||||
}
|
||||
if (p === '/api/admin/reports' && req.method === 'GET') {
|
||||
if (!isAdmin(req)) return json(res, 401, { error: 'auth' });
|
||||
return json(res, 200, { reports: await reports.list(200) });
|
||||
|
||||
Reference in New Issue
Block a user