Files
breakpilot-core/pitch-deck/lib/db.ts
Sharang Parnerkar 032df7f401
All checks were successful
Build pitch-deck / build-push-deploy (push) Successful in 1m14s
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-consent (push) Successful in 39s
CI / test-python-voice (push) Successful in 38s
CI / test-bqas (push) Successful in 29s
fix(pitch-deck): coerce pg NUMERIC to Number globally — fixes Finanzen crash
The Finanzen slide crashed on mount with "a.toFixed is not a function".
Traced to UnitEconomicsCards.tsx:59 calling ltvCacRatio.toFixed(1),
where ltvCacRatio arrives as a string.

Root cause: the cached path in /api/financial-model/compute returns raw
rows from pitch_fm_results. node-postgres returns NUMERIC / DECIMAL
columns as strings by default, so lastResult.ltv_cac_ratio (and every
other *_eur / *_pct / *_ratio field) flows through the app as a string.
Arithmetic-heavy code paths survived on accidental string-coerce (`-`,
`/`, `*`), but direct method calls like .toFixed() don't coerce, which
is why Unit Economics was the visible crash site.

Fix at the boundary: register a single types.setTypeParser(NUMERIC, …)
on the pg Pool so every query returns real numbers. All our NUMERIC
values fit well inside Number.MAX_SAFE_INTEGER, so parseFloat is safe.

One-line change, no component-level defensive coercions needed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 22:19:57 +02:00

18 lines
721 B
TypeScript

import { Pool, types } from 'pg'
// Coerce NUMERIC/DECIMAL columns to JS numbers globally. The default
// node-postgres behavior hands them back as strings, which silently breaks
// every downstream `.toFixed()` / direct-number call (seen crashing
// UnitEconomicsCards on the Finanzen slide). Our values fit comfortably in
// Number.MAX_SAFE_INTEGER, so the precision trade-off is fine.
types.setTypeParser(types.builtins.NUMERIC, (val) => (val === null ? null : parseFloat(val)))
const pool = new Pool({
connectionString: process.env.DATABASE_URL || 'postgres://breakpilot:breakpilot123@localhost:5432/breakpilot_db',
max: 20,
idleTimeoutMillis: 30000,
connectionTimeoutMillis: 10000,
})
export default pool