Skip to content

fix(supabase): drop wrong table cast in CRM send-email usage_count + nightly brief 2026-06-07 - #237

Closed
njrini99-code wants to merge 1 commit into
mainfrom
claude/awesome-babbage-hAbuM
Closed

fix(supabase): drop wrong table cast in CRM send-email usage_count + nightly brief 2026-06-07#237
njrini99-code wants to merge 1 commit into
mainfrom
claude/awesome-babbage-hAbuM

Conversation

@njrini99-code

Copy link
Copy Markdown
Owner

Daily Brief — 2026-06-07

24h Totals

  • Vercel runtime errors (level=error/fatal): 0
  • 5xx responses: 0
  • Cron failures: 0 (all 6 scheduled cron paths returned 200)
  • Failed deployments: 1 (preview build for Dependabot PR chore(deps): bump the production-dependencies group across 1 directory with 40 updates #229, commit 6d07386)
  • Distinct warning patterns: 2 (both pre-classified as operational diagnostics — see "Skipped" below)
  • Client-side errors POSTed to /api/log-error: 2 (payload sits in Supabase error_logs / admin_events — see "Couldn't verify" below)
  • Affected production users: Unknown — error_logs not directly queryable from this session (see below)

Top patterns (24h)

# Pattern Occ. Severity Root-cause hypothesis
1 TS build failure on src/app/api/admin/crm/send-email/route.ts:284Argument of type 'Record<string, unknown>' is not assignable to … RejectExcessProperties<…> 1 error (build-blocker on a Dependabot branch; latent on main) The SELECT chain at line 277 casts 'crm_email_templates' as 'crm_contact_log' to satisfy the typechecker. The matching .update() then carries an as Record<string, unknown> cast that fails the new postgrest-js strict-insert constraint introduced in supabase-js > 2.107. Main still builds because it pins 2.107 — but the bad cast is on the wrong table either way (different schema entirely), so it's a latent correctness footgun even before the version bump lands.
2 [insights.triggerPlayerInsightsAfterRound] philosophy gate filtered N tier-1 insight(s) (cron /api/cron/coachhelm-roster-sweep) 2 warning Informational diagnostic from the V2 engine philosophy gate. Documented in docs/daily-briefs/2026-05-27.md as "Hot but ambiguous — not safe to silence autonomously". Skipped per task rules.
3 [cron.v3.causality] unknown metric '…' on /api/cron/v3/causality-attribute 1 warning Already throttled to console.warn + one end-of-run roll-up at info severity. Registry-drift diagnostic, not a bug. Skipped per task rules.

Performance: top slow queries

Not collected — Supabase MCP could not auto-authenticate in this remote session (OAuth flow blocks on a localhost redirect that the sandbox can't reach). pg_stat_statements, admin_events, and error_logs are all behind that gate. Please run a manual db-audit if you want the perf top-N; the cron paths in the runtime log all completed in well under their 300s maxDuration budget, so nothing obviously regressed.

Deployment health

Deployment State Commit First error
dpl_2hdwVGBRQfrfa2F7rGQZT8D3jqjN ERROR 6d07386 (Dependabot PR #229 — production-dependencies group, 40 updates) Type error: Argument of type 'Record<string, unknown>' is not assignable to parameter of type 'RejectExcessProperties<{ coach_id?…contact_type?: "email" | "call" | "demo" | "meeting" | "note"… subject?…}, Record<…>>' at src/app/api/admin/crm/send-email/route.ts:284:21
dpl_BtgmhVgNzn1LQNBkJMcrX5e2DQBk (current production, commit 19fd32a) READY main

All other recent deploys are READY (Dependabot dev-dependencies group and 6 individual major-bump PRs all built clean once the production-dependencies group was split out).

Fixes applied

# File Lines Pattern addressed Diagnosis
1 src/app/api/admin/crm/send-email/route.ts 276–286 TS build failure / latent table-cast bug Replaced .from('crm_email_templates' as 'crm_contact_log') and the redundant .update(… as Record<string, unknown>) cast with calls through the existing fromUntyped() escape hatch (the documented project-wide helper for tables not in generated types). Same runtime behavior; loses the misleading cross-table cast that was silently asserting crm_email_templates rows have crm_contact_log columns; survives the strict-insert / RejectExcessProperties constraint that supabase-js > 2.107 introduces. npx tsc --noEmit is clean.

Couldn't fix / verify (handoff)

  • Supabase MCP authentication — auto-OAuth returns Host not in allowlist, so admin_events, error_logs, and pg_stat_statements were not queried this run. The 2 client-side errors POSTed to /api/log-error (18:20:02 and 19:26:31 UTC) wrote to those tables; their payloads are still readable in the Supabase dashboard but were not visible to triage. If they're high-impact, the daily brief is missing them — recommend a quick spot-check.
  • Sentry MCP authentication — same OAuth localhost-redirect problem; Sentry session replays / errors not consulted.
  • Other .from('X' as 'Y') casts still in the tree (src/app/golf/(dashboard)/dashboard/team-hub/page.tsx:84, …/hub/page.tsx:105, src/app/golf/actions/player-notifications.ts:99) — all three cast 'golf_task_assignments' as 'golf_shots'. Same anti-pattern, called out in docs/architectural-review-golfhelm-2026-02-22.md Finding 12. Not touched here to keep the PR minimal and focused on the build-blocker, but worth a follow-up sweep when someone gets to that file area.
  • NOT auto-merged — leaving for human review per task rules.

Generated by Claude Code

The SELECT for crm_email_templates.usage_count was casting the table
name as 'crm_contact_log' to suppress type-check errors. Same line
chain on the .update() then needed an 'as Record<string, unknown>'
cast on the payload. Both casts are semantically wrong (different
tables) and the update cast started failing the build under stricter
postgrest-js typing (Vercel deploy dpl_2hdwVGBRQfrfa2F7rGQZT8D3jqjN
on Dependabot PR #229).

Route both SELECT and UPDATE through the existing fromUntyped() escape
hatch — same runtime behavior, no misleading type casts, build-safe
against the next supabase-js bump.
@vercel

vercel Bot commented Jun 7, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
helmv3 Ready Ready Preview, Comment Jun 7, 2026 4:20am

Request Review

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

njrini99-code has reached the 50-review limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@coderabbitai

coderabbitai Bot commented Jun 7, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Email send endpoint refactors template usage counter increment to use fromUntyped() helper. Template usage is queried and updated in lines 273–285 through the new helper pattern instead of direct Supabase client calls.

Changes

Email template usage counter refactoring

Layer / File(s) Summary
Template usage counter increment refactoring
src/app/api/admin/crm/send-email/route.ts
Lines 273–285: Usage counter fetch and increment now use fromUntyped(supabase, 'crm_email_templates') instead of supabase.from(). Update payload simplified to { usage_count: (tpl.usage_count ?? 0) + 1 }, with .select('usage_count')...single() for the read.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes


Caution

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

  • Ignore

❌ Failed checks (1 error, 2 warnings)

Check name Status Explanation Resolution
Rls Coverage On New Tables ❌ Error Migration 20260527000000_prod_public_baseline.sql:7297-7303 creates table auth_rate_limits with ENABLE ROW LEVEL SECURITY (line 17599) but no CREATE POLICY statement. Add at least one CREATE POLICY statement for auth_rate_limits in the migration to satisfy RLS coverage requirements.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Conventional Commits ⚠️ Warning PR title starts with "nightly:" which is not a valid Conventional Commits type (must be: feat, fix, chore, docs, refactor, perf, test, ci, build, revert). Rename title to start with valid type, e.g.: "fix: production fix for email template usage count increment"
✅ Passed checks (9 passed)
Check name Status Explanation
Description check ✅ Passed The description extensively documents the daily brief findings and the specific fix applied to src/app/api/admin/crm/send-email/route.ts, directly addressing the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
No Service-Role In Client Bundles ✅ Passed Route file uses server client (anon key), in allowed path src/app/api/admin/**. No service-role key exposure.
Auth Check In Server Actions ✅ Passed PR modifies src/app/api/admin/crm/send-email/route.ts, which is not a server action file (pattern src/app//actions//*.ts). Check not applicable.
Sport-Prefixed Table Names ✅ Passed All Supabase table queries use sport-prefixed names; no unprefixed coaches, players, teams, rounds, or events tables found in TypeScript code.
No Destructive Writes ✅ Passed No DELETE+INSERT destructive patterns found. Code modifies usage count via SELECT+UPDATE only (lines 276–284).
No Edits To Historical Migrations ✅ Passed PR modifies zero files under supabase/migrations/ — only src/app/api/admin/crm/send-email/route.ts changed, so migration baseline protection rule is satisfied.
Title check ✅ Passed The pull request title follows Conventional Commits format with the required 'supabase' scope and accurately describes the main fix: replacing incorrect table casts with the fromUntyped() helper in src/app/api/admin/crm/send-email/route.ts.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/awesome-babbage-hAbuM

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/app/api/admin/crm/send-email/route.ts`:
- Around line 276-284: The current read-then-update in route handler using
fromUntyped against crm_email_templates with templateId (the tpl read and
subsequent update) causes a race; replace it with an atomic increment operation
instead of reading usage_count first—either call a DB-side RPC/function (e.g.,
increment_template_usage(template_id)) that runs UPDATE crm_email_templates SET
usage_count = COALESCE(usage_count,0)+1 WHERE id = template_id, or execute a
single atomic UPDATE query via fromUntyped to increment usage_count directly;
update the code that currently uses the tpl variable and the two-step
select+update to call the atomic updater using templateId.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: e5ea28d6-e535-4e3d-8855-8d8c12549fa2

📥 Commits

Reviewing files that changed from the base of the PR and between 19fd32a and 60f0d17.

📒 Files selected for processing (1)
  • src/app/api/admin/crm/send-email/route.ts

Comment on lines +276 to 284
const { data: tpl } = (await fromUntyped(supabase, 'crm_email_templates')
.select('usage_count')
.eq('id', templateId)
.single() as { data: { usage_count: number } | null };
.single()) as { data: { usage_count: number | null } | null };

if (tpl) {
await fromUntyped(supabase, 'crm_email_templates')
.update({ usage_count: (tpl.usage_count ?? 0) + 1 } as Record<string, unknown>)
.update({ usage_count: (tpl.usage_count ?? 0) + 1 })
.eq('id', templateId);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Race condition: usage count increment is not atomic.

src/app/api/admin/crm/send-email/route.ts:276-284

The current read-modify-write pattern can lose increments under concurrent usage. If two requests send emails with the same templateId simultaneously:

  1. Both read usage_count = N
  2. Both write usage_count = N + 1
  3. Result: count incremented by 1 instead of 2

Replace with an atomic increment to guarantee data integrity:

🔒 Proposed fix: atomic increment
     // ── Increment template usage count ──
     if (templateId && sent > 0) {
       try {
-        const { data: tpl } = (await fromUntyped(supabase, 'crm_email_templates')
-          .select('usage_count')
-          .eq('id', templateId)
-          .single()) as { data: { usage_count: number | null } | null };
-
-        if (tpl) {
-          await fromUntyped(supabase, 'crm_email_templates')
-            .update({ usage_count: (tpl.usage_count ?? 0) + 1 })
-            .eq('id', templateId);
-        }
+        // Atomic increment using RPC or raw SQL
+        await supabase.rpc('increment_template_usage', { template_id: templateId });
       } catch {
         // Non-critical — don't fail the response
       }
     }

If the RPC doesn't exist yet, add this migration:

CREATE OR REPLACE FUNCTION increment_template_usage(template_id uuid)
RETURNS void AS $$
BEGIN
  UPDATE crm_email_templates
  SET usage_count = COALESCE(usage_count, 0) + 1
  WHERE id = template_id;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/app/api/admin/crm/send-email/route.ts` around lines 276 - 284, The
current read-then-update in route handler using fromUntyped against
crm_email_templates with templateId (the tpl read and subsequent update) causes
a race; replace it with an atomic increment operation instead of reading
usage_count first—either call a DB-side RPC/function (e.g.,
increment_template_usage(template_id)) that runs UPDATE crm_email_templates SET
usage_count = COALESCE(usage_count,0)+1 WHERE id = template_id, or execute a
single atomic UPDATE query via fromUntyped to increment usage_count directly;
update the code that currently uses the tpl variable and the two-step
select+update to call the atomic updater using templateId.

@njrini99-code njrini99-code changed the title nightly: 1 production fix (2026-06-07) fix(supabase): drop wrong table cast in CRM send-email usage_count + nightly brief 2026-06-07 Jun 7, 2026
@njrini99-code

Copy link
Copy Markdown
Owner Author

Folded into #304 (feat/coachhelm-stats-roundup) — merged clean, combined gates green. Branch intact + reopenable.

@njrini99-code
njrini99-code deleted the claude/awesome-babbage-hAbuM branch June 29, 2026 12:17
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.

2 participants