Skip to content

Nightly traffic digest, on by default - #242

Merged
ralyodio merged 1 commit into
masterfrom
feat/nightly-traffic-report
Sep 6, 2026
Merged

Nightly traffic digest, on by default#242
ralyodio merged 1 commit into
masterfrom
feat/nightly-traffic-report

Conversation

@ralyodio

@ralyodio ralyodio commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

The performance report already had weekly and monthly cadences, an hourly TZ-aware cron and a settings control. This adds daily to that rather than a second mechanism beside it.

What the nightly one is for is traffic, so the report gains a traffic section and the email leads with it: overall humans and bots first, then every property most to least busy with each one's bot share. The subject carries the human count, because that is the number worth seeing on a phone.

Counting is by tracker bucket — a bucket starting bot: is a crawler, everything else is a human, AI referrals included. That split only exists on tracker_daily_stats; tracker_event_daily_stats has no bucket column and its pageview counts include crawlers.

The migration makes daily the column default so a new account gets the digest without hunting for the setting. Existing rows keep whatever their owner chose: a default applies to inserts, and moving somebody from weekly to nightly would be changing a preference rather than honouring one.

Verified: tsc --noEmit clean; 2,136 tests pass, 11 of them new covering the daily due-check (including timezone and same-day dedupe), the ordering, and the empty case.

🤖 Generated with Claude Code

https://claude.ai/code/session_01WYMJH7N4d2qRct5Q5q2YWQ

The performance report already had weekly and monthly cadences, an
hourly TZ-aware cron and a settings control. This adds 'daily' to that
rather than a second mechanism beside it.

What the nightly one is for is traffic, so the report gains a traffic
section and the email leads with it: overall humans and bots first, then
every property most to least busy, with each one's bot share. The subject
carries the human count, because that is the number worth seeing on a
phone.

Counting is by tracker bucket — a bucket starting 'bot:' is a crawler and
everything else is a human, AI referrals included. That split only exists
on tracker_daily_stats; tracker_event_daily_stats has no bucket column and
its pageview counts include crawlers.

The migration makes 'daily' the column default so a new account gets the
digest without hunting for the setting. Existing rows keep whatever their
owner chose: a default applies to inserts, and moving somebody from weekly
to nightly would be changing a preference, not honouring one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WYMJH7N4d2qRct5Q5q2YWQ
@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown

ThreatCrush Security Scan

39 finding(s)

HIGH/CRITICAL: 2 | MEDIUM: 28 | LOW: 9

Severity Rule Location
HIGH tls-verification-disabled lib/onion.ts:48
HIGH secret-generic-credential lib/sp/platforms/facebook.ts:32
MEDIUM js-unescaped-html-sink app/(app)/dashboard/admin/email-broadcast/EmailBroadcastForm.tsx:125
MEDIUM js-unescaped-html-sink app/(app)/dashboard/projects/[id]/autoblog/articles/[articleId]/page.tsx:214
MEDIUM js-unescaped-html-sink app/(marketing)/blog/[slug]/page.tsx:67
MEDIUM js-unescaped-html-sink app/(marketing)/blog/[slug]/page.tsx:97
MEDIUM js-unescaped-html-sink app/(marketing)/blog/[slug]/page.tsx:104
MEDIUM js-unescaped-html-sink app/(marketing)/blog/[slug]/page.tsx:110
MEDIUM js-unescaped-html-sink app/(marketing)/recent/page.tsx:186
MEDIUM js-unescaped-html-sink app/(marketing)/recent/page.tsx:190
MEDIUM js-unescaped-html-sink app/c/[project]/[slug]/page.tsx:77
MEDIUM js-unescaped-html-sink app/c/[project]/page.tsx:57
MEDIUM js-unescaped-html-sink app/careers.js/route.ts:228
MEDIUM js-unescaped-html-sink app/careers.js/route.ts:285
MEDIUM js-unescaped-html-sink app/layout.tsx:129
MEDIUM js-open-redirect app/login/form.tsx:39
MEDIUM js-unescaped-html-sink app/r/[token]/page.tsx:176
MEDIUM js-open-redirect app/signup/form.tsx:43
MEDIUM js-open-redirect components/billing/buy-credits-modal.tsx:98
MEDIUM js-unescaped-html-sink components/json-ld.tsx:8
MEDIUM js-unescaped-html-sink components/report/markdown-view.tsx:15
MEDIUM js-unescaped-html-sink lib/careers/page-templates.ts:198
MEDIUM redos-nested-quantifier lib/emailMarkdown.ts:41
MEDIUM redos-nested-quantifier lib/emailMarkdown.ts:324
MEDIUM redos-nested-quantifier lib/lx/articleGen.ts:99
MEDIUM redos-nested-quantifier lib/tracker/agent-gate.ts:61
MEDIUM sh-remote-script-execution prober/deploy/provision.sh:30
MEDIUM sql-template-interpolation scripts/detect-slot-themes.ts:31
MEDIUM sql-template-interpolation scripts/purge-constructed-keywords.ts:163
MEDIUM sql-template-interpolation scripts/purge-offniche-keywords.ts:124
LOW secret-generic-credential app/(marketing)/docs/autoblog-webhook/page.tsx:145
LOW secret-generic-credential lib/sp/platforms/linkedin.ts:25
LOW js-dynamic-code-execution tests/careers-page-templates.test.ts:21
LOW js-dynamic-code-execution tests/careers-widget-script.test.ts:19
LOW js-dynamic-code-execution tests/careers-widget-script.test.ts:69
LOW js-dynamic-code-execution tests/contract/ad-visitor-id.test.ts:51
LOW js-dynamic-code-execution tests/contract/ad-visitor-id.test.ts:52
LOW secret-generic-credential tests/contract/posthog-integration.test.ts:13
LOW secret-generic-credential tests/lead-campaign.test.ts:16

Snippets are redacted; ThreatCrush never prints matched credential material.

@ralyodio
ralyodio merged commit 62717ad into master Sep 6, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant