CodeIssuesPull RequestsActionsSecurityInsights
✨ AI
More
Settings

fix(billing+dashboard): honest peak-day figure; honest verify-email banner (refs #211) #5460

Merged⚡ AI-generatedXSccantynz wants to mergesweep/billing-bannermainopened 24d ago
ccantynzcommented 24d ago

Part of the design-sweep for the visual-audit ledger (#211). Slice: billing numbers + the email-verification banner.

Defect 1 — /billing/usage: "Peak day $0.01" beside "30-day total $0.00"

Root cause: not two rounding policies — a chart-scaling clamp leaking into display copy. buildTrendSparkline computed max = Math.max(1, ...series) so an all-zero month couldn't divide by zero when scaling the SVG, and the page then rendered that clamped value as the "Peak day" dollar figure. With zero spend: peak showed $0.01, total showed $0.00.

Fix (src/routes/billing-usage.tsx): max is now the true peak day (0 when there is no spend); the >=1 clamp survives only as an internal Y-axis denominator (scaleMax) that is never surfaced as money. Both displayed figures now derive from the same summed integer-cents series (per-event centsEstimate is already an integer, day buckets sum those integers), so total >= max(daily) holds by construction — a nonzero peak can never again coexist with a zero total.

Tests (src/__tests__/ai-cost-tracker.test.ts): new section pins the invariant — all-zero window renders peak $0.00; total >= max(daily) across several series shapes (empty, single day, multi-day, out-of-window rows); aggregateEvents upstream invariant totalCents >= max(byDay).

No Stripe/payment logic touched — presentation and the sparkline helper only.

Defect 2 — "Verify your email to keep using Gluecron."

What enforcement actually does: nothing. users.emailVerifiedAt is never read by any gate — no middleware, no route guard, no quota path. It is only set (verify-link consumption, magic-link sign-in, admin provisioning, playground) and read for banner/status display. An unverified user loses zero functionality, so "to keep using" implied a lockout that does not exist.

Fixes (src/routes/dashboard.tsx):

  • Reworded to the truth: "Verify your email — it's used for notifications and account recovery." This matches the existing /docs and /help copy ("Verified addresses receive issue, PR, and gate-run notifications"), which was already honest.
  • Banner suppressed for site admins via isSiteAdmin (src/lib/admin.ts). Why suppression over auto-verify: auto-verifying would write a false "verified at" fact into the DB that other surfaces trust (verification status page, welcome-email flow) — a new "two sources of truth" seam. Suppression is a one-condition display change with no data side effects. The check is ordered last in the && chain so the extra DB lookup only runs for unverified, undismissed users; verified users pay nothing.

Verification

  • bunx tsc --noEmit -p . — clean
  • bun test src/__tests__/ai-cost-tracker.test.ts — 30 pass, 0 fail (2 skips are the pre-existing DB-gated tests, expected without DATABASE_URL)
  • bun test src/__tests__/billing.test.ts — 15 pass, 0 fail

🤖 Generated with Claude Code

ccantynzAI Reviewcommented 24d ago

AI Triage

(no summary)

Priority: medium Risk area: mixed

Suggested labels: (no label suggestions) Suggested reviewers: (no reviewer suggestions)

Suggestions only — nothing has been applied. The PR author stays in control.

gluecron[bot]🤖 botAI Reviewcommented 24d ago

AI review unavailable

The platform's AI balance is exhausted, so AI generation is temporarily unavailable. Nothing was lost. You can queue this as a repair for the internal agent from the repository's Health page, or try again once the balance is restored. The PR is otherwise unchanged.

Cross-repo impact

See what breaks downstream if this PR merges.

Analyze →
⮌ Merged

This pull request was merged into main.

c comment · e edit title · m merge · a approve · r request changes · ? shortcuts