Skip to content

feat(#402): workspace pool-cap alerting + system email module - #421

Merged
ChesterSchendel merged 2 commits into
mainfrom
claude/402-pool-cap-alerting
Jul 30, 2026
Merged

feat(#402): workspace pool-cap alerting + system email module#421
ChesterSchendel merged 2 commits into
mainfrom
claude/402-pool-cap-alerting

Conversation

@ChesterSchendel

Copy link
Copy Markdown
Contributor

Closes #402.

Team workspaces had no combined-pool alert (only per-user personal-cap alerts). Adds:

  • maybeAlertPoolCrossed — fires when a Team workspace's combined monthly usage crosses 80% then 100% of the pool (percentage thresholds), once per (workspace, threshold, month), emailing the Team Lead + ops. Per-user alerts suppressed for the team tier.
  • src/lib/email.ts — shared system-email module; templates mirror the Clerk email chrome so they read as the same sender. Logo is a Gmail-safe PNG rasterized from the app SVG.
  • Admin tooling/api/admin/email-preview?type=… (browser) + /api/admin/email-test (send to an inbox).

tsc + eslint clean; verified against the real render. Templates interim (revisit at paid Clerk tier). Internal alerts → hello@drawbackwards.com.

🤖 Generated with Claude Code

Adds pool-level usage alerts for Team workspaces (the only alert before this
was per-user against a personal cap).

- email.ts (new): one place for product-sent email. sendEmail() via Resend
  (console fallback when RESEND_API_KEY unset) + templates whose chrome mirrors
  the Clerk emails (black logo PNG, white card, #111827 text, near-black button,
  #B7B8C2 divider + © footer) so it reads as the same sender. renderPoolAlert
  (lead client-facing + internal ops, 80%/100%).
- public/email/ladder-logo.png: black logo rasterized from LadderLogo.svg
  (Gmail strips SVG, so the email uses a hosted PNG).
- usage.ts: POOL_ALERT_THRESHOLDS (80%/100% as fractions of TEAM_MONTHLY_POOL);
  maybeAlertPoolCrossed (team-tier only; resolves the workspace, sums members,
  fires once per workspace/threshold/month, emails Team Lead + ops);
  maybeAlertCapCrossed now suppresses the team tier (pool alert replaces it).
- scores.ts: persistScoreEntry fires maybeAlertPoolCrossed fire-and-forget.
- admin email-preview + email-test routes for the see/refine/test loop.

/hq: features row + architecture "System email + usage alerting" note (#421).

Templates are interim — to be revisited at the paid Clerk tier.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 30, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
runladder Ready Ready Preview Jul 30, 2026 9:00pm

Request Review

…fest

The auth-gate guardrail requires every /api/admin route to be in
PROTECTED_ROUTES with an anon-rejection test. Added both new routes + their
expectAllMethodsRejectAnon() cases (both are getAdminEmail-gated, so they
reject anon with 403).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@ChesterSchendel
ChesterSchendel merged commit db563bd into main Jul 30, 2026
8 checks passed
@ChesterSchendel
ChesterSchendel deleted the claude/402-pool-cap-alerting branch July 30, 2026 21:54
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.

Add workspace pool-level cap alerting

1 participant