feat(pitch-deck): full pitch versioning with git-style history (#4)
Some checks failed
Build pitch-deck / build-and-push (push) Failing after 1m8s
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 32s
CI / test-python-voice (push) Successful in 32s
CI / test-bqas (push) Successful in 32s
CI / Deploy (push) Failing after 4s

Full pitch versioning: 12 data tables versioned as JSONB snapshots,
git-style parent chain (draft→commit→fork), per-investor assignment,
side-by-side diff engine, version-aware /api/data + /api/financial-model.

Bug fixes: FM editor [object Object] for JSONB arrays, admin scroll.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit was merged in pull request #4.
This commit is contained in:
2026-04-10 07:37:33 +00:00
parent 746daaef6d
commit 1c3cec2c06
22 changed files with 1564 additions and 42 deletions

View File

@@ -0,0 +1,191 @@
-- =========================================================
-- Pitch Deck: Core data tables + Financial Model
-- Run BEFORE 001_investor_auth.sql
-- =========================================================
-- Company info
CREATE TABLE IF NOT EXISTS pitch_company (
id SERIAL PRIMARY KEY,
name TEXT,
legal_form TEXT,
founding_date TEXT,
tagline_de TEXT,
tagline_en TEXT,
mission_de TEXT,
mission_en TEXT,
website TEXT,
hq_city TEXT
);
-- Team members
CREATE TABLE IF NOT EXISTS pitch_team (
id SERIAL PRIMARY KEY,
name TEXT,
role_de TEXT,
role_en TEXT,
bio_de TEXT,
bio_en TEXT,
equity_pct NUMERIC,
expertise TEXT[],
linkedin_url TEXT,
photo_url TEXT,
sort_order INT DEFAULT 0
);
-- Historical financials
CREATE TABLE IF NOT EXISTS pitch_financials (
id SERIAL PRIMARY KEY,
year INT,
revenue_eur BIGINT,
costs_eur BIGINT,
mrr_eur BIGINT,
burn_rate_eur BIGINT,
customers_count INT,
employees_count INT,
arr_eur BIGINT
);
-- Market segments (TAM/SAM/SOM)
CREATE TABLE IF NOT EXISTS pitch_market (
id SERIAL PRIMARY KEY,
market_segment TEXT,
label TEXT,
value_eur BIGINT,
growth_rate_pct NUMERIC,
source TEXT
);
-- Competitors
CREATE TABLE IF NOT EXISTS pitch_competitors (
id SERIAL PRIMARY KEY,
name TEXT,
customers_count INT,
pricing_range TEXT,
strengths TEXT[],
weaknesses TEXT[],
website TEXT
);
-- Feature comparison matrix
CREATE TABLE IF NOT EXISTS pitch_features (
id SERIAL PRIMARY KEY,
feature_name_de TEXT,
feature_name_en TEXT,
category TEXT,
breakpilot BOOLEAN,
proliance BOOLEAN,
dataguard BOOLEAN,
heydata BOOLEAN,
is_differentiator BOOLEAN,
sort_order INT DEFAULT 0
);
-- Milestones / timeline
CREATE TABLE IF NOT EXISTS pitch_milestones (
id SERIAL PRIMARY KEY,
milestone_date TEXT,
title_de TEXT,
title_en TEXT,
description_de TEXT,
description_en TEXT,
status TEXT,
category TEXT,
sort_order INT DEFAULT 0
);
-- Key metrics
CREATE TABLE IF NOT EXISTS pitch_metrics (
id SERIAL PRIMARY KEY,
metric_name TEXT,
label_de TEXT,
label_en TEXT,
value TEXT,
unit TEXT,
is_live BOOLEAN
);
-- Funding round
CREATE TABLE IF NOT EXISTS pitch_funding (
id SERIAL PRIMARY KEY,
round_name TEXT,
amount_eur BIGINT,
use_of_funds JSONB,
instrument TEXT,
target_date TEXT,
status TEXT
);
-- Products / tiers
CREATE TABLE IF NOT EXISTS pitch_products (
id SERIAL PRIMARY KEY,
name TEXT,
hardware TEXT,
hardware_cost_eur NUMERIC,
monthly_price_eur NUMERIC,
llm_model TEXT,
llm_size TEXT,
llm_capability_de TEXT,
llm_capability_en TEXT,
features_de TEXT[],
features_en TEXT[],
is_popular BOOLEAN,
operating_cost_eur NUMERIC,
sort_order INT DEFAULT 0
);
-- =========================================================
-- Financial Model
-- =========================================================
CREATE TABLE IF NOT EXISTS pitch_fm_scenarios (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name TEXT,
description TEXT,
is_default BOOLEAN DEFAULT false,
color TEXT DEFAULT '#6366f1',
sort_order INT DEFAULT 0
);
CREATE TABLE IF NOT EXISTS pitch_fm_assumptions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
scenario_id UUID REFERENCES pitch_fm_scenarios(id) ON DELETE CASCADE,
key TEXT,
label_de TEXT,
label_en TEXT,
value JSONB,
value_type TEXT DEFAULT 'scalar',
unit TEXT,
min_value NUMERIC,
max_value NUMERIC,
step_size NUMERIC,
category TEXT,
sort_order INT DEFAULT 0
);
CREATE TABLE IF NOT EXISTS pitch_fm_results (
id SERIAL PRIMARY KEY,
scenario_id UUID REFERENCES pitch_fm_scenarios(id) ON DELETE CASCADE,
month INT,
year INT,
month_in_year INT,
new_customers INT,
churned_customers INT,
total_customers INT,
mrr_eur NUMERIC,
arr_eur NUMERIC,
revenue_eur NUMERIC,
cogs_eur NUMERIC,
personnel_eur NUMERIC,
infra_eur NUMERIC,
marketing_eur NUMERIC,
total_costs_eur NUMERIC,
employees_count INT,
gross_margin_pct NUMERIC,
burn_rate_eur NUMERIC,
runway_months NUMERIC,
cac_eur NUMERIC,
ltv_eur NUMERIC,
ltv_cac_ratio NUMERIC,
cash_balance_eur NUMERIC,
cumulative_revenue_eur NUMERIC
);

View File

@@ -0,0 +1,36 @@
-- =========================================================
-- Pitch Deck: Version Management (Git-Style History)
-- =========================================================
-- Version metadata: each version points to its parent (git-style DAG)
CREATE TABLE IF NOT EXISTS pitch_versions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name TEXT NOT NULL,
description TEXT,
parent_id UUID REFERENCES pitch_versions(id) ON DELETE SET NULL,
status VARCHAR(20) NOT NULL DEFAULT 'draft'
CHECK (status IN ('draft', 'committed')),
created_by UUID REFERENCES pitch_admins(id) ON DELETE SET NULL,
committed_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_pitch_versions_parent ON pitch_versions(parent_id);
CREATE INDEX IF NOT EXISTS idx_pitch_versions_status ON pitch_versions(status);
-- Version content: one row per data table per version (fully materialized)
-- table_name values: company, team, financials, market, competitors, features,
-- milestones, metrics, funding, products, fm_scenarios, fm_assumptions
CREATE TABLE IF NOT EXISTS pitch_version_data (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
version_id UUID NOT NULL REFERENCES pitch_versions(id) ON DELETE CASCADE,
table_name TEXT NOT NULL,
data JSONB NOT NULL,
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_by UUID REFERENCES pitch_admins(id) ON DELETE SET NULL,
UNIQUE(version_id, table_name)
);
CREATE INDEX IF NOT EXISTS idx_pitch_version_data_version ON pitch_version_data(version_id);
-- Per-investor version assignment (NULL = use base tables)
ALTER TABLE pitch_investors
ADD COLUMN IF NOT EXISTS assigned_version_id UUID REFERENCES pitch_versions(id) ON DELETE SET NULL;