fix(pitch-print): cover layout, Finanzplan data source, target_date
Build pitch-deck / build-push-deploy (push) Successful in 1m34s
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 30s
CI / test-python-voice (push) Successful in 30s
CI / test-bqas (push) Successful in 28s

Three critical fixes after reviewing the rendered PDF:

Cover (was: indigo block collapsed to top, white content stacked below):
- The .print-page class in print.css forces flex-direction: column !important,
  which broke the horizontal split. Wrap the cover content in a single grid
  container — the column-flex parent then has only one child so direction is
  irrelevant. Indigo block now runs full-height on the left.
- Title reduced 88pt -> 60pt so "BreakPilot ComplAI." fits without wrapping.
- Funding amount formatter now handles sub-€1M cases (€200k vs €0.2M).

Finanzplan (was: "nicht verfügbar" on both pages 20-21):
- page.tsx was querying the legacy pitch_fm_results table which isn't populated
  by the current pipeline. The interactive deck reads from fp_* tables.
- Wire in lib/finanzplan/adapter.ts (finanzplanToFMResults) which bridges the
  live fp_* tables to FMResult[] — same source the interactive deck uses.
- Fall back to live default fp_scenario if the version snapshot's fm_scenarios
  is empty.
- adapter.ts: populate total_customers + new_customers from fp_kunden_summary
  (was hardcoded 0).

The Ask:
- target_date was rendering as raw ISO timestamp "2026-08-01T00:00:00.000Z";
  now formatted as "Aug 2026" (locale-aware).
- Hero funding amount uses same sub-€1M formatter.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Sharang Parnerkar
2026-05-20 10:01:53 +02:00
parent bb85ee2e27
commit f30ac73b79
4 changed files with 133 additions and 88 deletions
+6 -3
View File
@@ -17,18 +17,20 @@ export async function finanzplanToFMResults(pool: Pool, scenarioId?: string): Pr
}
// Load computed data
const [personalRes, liquidRes, betriebRes, umsatzRes, materialRes, investRes] = await Promise.all([
const [personalRes, liquidRes, betriebRes, umsatzRes, materialRes, investRes, kundenRes] = await Promise.all([
pool.query("SELECT * FROM fp_personalkosten WHERE scenario_id = $1 ORDER BY sort_order", [sid]),
pool.query("SELECT * FROM fp_liquiditaet WHERE scenario_id = $1 ORDER BY sort_order", [sid]),
pool.query("SELECT * FROM fp_betriebliche_aufwendungen WHERE scenario_id = $1 ORDER BY sort_order", [sid]),
pool.query("SELECT * FROM fp_umsatzerloese WHERE scenario_id = $1 AND section = 'revenue' AND row_label = 'GESAMTUMSATZ' LIMIT 1", [sid]),
pool.query("SELECT * FROM fp_materialaufwand WHERE scenario_id = $1 AND row_label = 'SUMME' LIMIT 1", [sid]),
pool.query("SELECT * FROM fp_investitionen WHERE scenario_id = $1 ORDER BY sort_order", [sid]),
pool.query("SELECT * FROM fp_kunden_summary WHERE scenario_id = $1 AND row_label = 'Bestandskunden gesamt' LIMIT 1", [sid]),
])
const personal = personalRes.rows
const liquid = liquidRes.rows
const betrieb = betriebRes.rows
const customersByMonth = (kundenRes.rows[0]?.values as MonthlyValues) || emptyMonthly()
// Helper to sum a field across personnel
function sumPersonalField(field: string): MonthlyValues {
@@ -92,9 +94,9 @@ export async function finanzplanToFMResults(pool: Pool, scenarioId?: string): Pr
month: m,
year,
month_in_year: month,
new_customers: 0,
new_customers: Math.max((customersByMonth[`m${m}`] || 0) - prevCustomers, 0),
churned_customers: 0,
total_customers: 0,
total_customers: Math.round(customersByMonth[`m${m}`] || 0),
mrr_eur: Math.round(rev / 1), // monthly
arr_eur: Math.round(rev * 12),
revenue_eur: Math.round(rev),
@@ -113,6 +115,7 @@ export async function finanzplanToFMResults(pool: Pool, scenarioId?: string): Pr
cash_balance_eur: Math.round(cash),
cumulative_revenue_eur: Math.round(cumulativeRevenue),
})
prevCustomers = customersByMonth[`m${m}`] || 0
}
// Summary