Files
breakpilot-core/pitch-deck/scripts/001_finanzplan_tables.sql
Benjamin Admin a58cd16f01 feat: Finanzplan Phase 1-4 — DB + Engine + API + Spreadsheet-UI
Phase 1: DB-Schema (12 fp_* Tabellen) + Excel-Import (332 Zeilen importiert)
Phase 2: Compute Engine (Personal, Invest, Umsatz, Material, Betrieblich, Liquiditaet, GuV)
Phase 3: API (/api/finanzplan/ — GET sheets, PUT cells, POST compute)
Phase 4: Spreadsheet-UI (FinanzplanSlide als Annex mit Tab-Leiste, editierbarem Grid, Jahres-Navigation)

Zusaetzlich:
- Gruendungsdatum verschoben: Feb→Aug 2026 (DB + Personalkosten)
- Neue Preisstaffel: Startup/<10 MA ab 3.600 EUR/Jahr (14-Tage-Test, Kreditkarte)
- Competition-Slide: Pricing-Tiers aktualisiert

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 19:26:46 +01:00

247 lines
11 KiB
SQL
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- ============================================================================
-- BreakPilot ComplAI — Finanzplan Database Schema
-- Mirrors Excel: "Breakpilot ComplAI Finanzplan.xlsm" (10 Reiter)
-- Monthly granularity: Jan 2026 Dec 2030 (60 months)
-- Values stored as JSONB: {"m1": ..., "m2": ..., "m60": ...}
-- ============================================================================
-- Scenarios (extends existing pitch_fm_scenarios)
CREATE TABLE IF NOT EXISTS fp_scenarios (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name TEXT NOT NULL DEFAULT 'Base Case',
description TEXT,
is_default BOOLEAN DEFAULT false,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- Insert default scenario
INSERT INTO fp_scenarios (name, description, is_default)
VALUES ('Base Case', 'Basisdaten aus Excel-Import', true)
ON CONFLICT DO NOTHING;
-- ============================================================================
-- KUNDEN (6 Segmente × ~20 Zeilen = ~120 Datenzeilen)
-- Each segment has: base customer count (editable) + module percentages
-- Formulas: module_count = ROUNDDOWN(base_count * percentage)
-- ============================================================================
CREATE TABLE fp_kunden (
id SERIAL PRIMARY KEY,
scenario_id UUID REFERENCES fp_scenarios(id) ON DELETE CASCADE,
segment_name TEXT NOT NULL, -- 'Care (Privat)', 'Horse (Händler)', etc.
segment_index INT NOT NULL, -- 1-6
row_label TEXT NOT NULL, -- 'Modul 1', 'Modul 2', ...
row_index INT NOT NULL, -- position within segment
percentage NUMERIC(5,3), -- multiplier (e.g. 0.9, 0.25)
formula_type TEXT, -- 'literal', 'roundup_pct', 'rounddown_pct', 'cumulative', null
is_editable BOOLEAN DEFAULT false, -- true for base inputs (Modul 1 per segment)
values JSONB NOT NULL DEFAULT '{}', -- {m1: 0, m2: 0, ... m60: 0}
excel_row INT, -- original Excel row number
sort_order INT NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- Summary rows (aggregated across all 6 segments)
CREATE TABLE fp_kunden_summary (
id SERIAL PRIMARY KEY,
scenario_id UUID REFERENCES fp_scenarios(id) ON DELETE CASCADE,
row_label TEXT NOT NULL, -- 'Modul 1', 'Modul 2', ...
row_index INT NOT NULL,
values JSONB NOT NULL DEFAULT '{}', -- computed: sum of 6 segments
excel_row INT,
sort_order INT NOT NULL
);
-- ============================================================================
-- UMSATZERLOESE (Revenue = Quantity × Price)
-- Section 1 (rows 3-23): Computed revenue per module
-- Section 2 (rows 27-46): Quantity (from Kunden)
-- Section 3 (rows 49-73): Prices (editable VK excl. MwSt.)
-- ============================================================================
CREATE TABLE fp_umsatzerloese (
id SERIAL PRIMARY KEY,
scenario_id UUID REFERENCES fp_scenarios(id) ON DELETE CASCADE,
section TEXT NOT NULL, -- 'revenue', 'quantity', 'price'
row_label TEXT NOT NULL, -- 'Modul 1', 'Modul 2', ...
row_index INT NOT NULL,
is_editable BOOLEAN DEFAULT false, -- only prices are editable
values JSONB NOT NULL DEFAULT '{}',
excel_row INT,
sort_order INT NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- ============================================================================
-- MATERIALAUFWAND (sehr einfach: nur Mac Mini + Mac Studio)
-- Cost = Quantity × Unit Cost (EK)
-- Mac Mini EK: 3.200 EUR, VK: 4.800 EUR (50% Aufschlag)
-- Mac Studio EK: 13.000 EUR, VK: 19.500 EUR (50% Aufschlag)
-- ============================================================================
CREATE TABLE fp_materialaufwand (
id SERIAL PRIMARY KEY,
scenario_id UUID REFERENCES fp_scenarios(id) ON DELETE CASCADE,
section TEXT NOT NULL, -- 'cost', 'quantity', 'unit_cost'
row_label TEXT NOT NULL,
row_index INT NOT NULL,
is_editable BOOLEAN DEFAULT false, -- only unit costs are editable
values JSONB NOT NULL DEFAULT '{}',
excel_row INT,
sort_order INT NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- ============================================================================
-- PERSONALKOSTEN (20 Positionen)
-- Structured: Name, Position, Start, End, Brutto, Raise%
-- Computed: monthly salary × AG-Sozialversicherung
-- ============================================================================
CREATE TABLE fp_personalkosten (
id SERIAL PRIMARY KEY,
scenario_id UUID REFERENCES fp_scenarios(id) ON DELETE CASCADE,
person_name TEXT NOT NULL,
person_nr TEXT, -- '001', '002', ...
position TEXT, -- 'GF', 'Vertrieb', 'Entwicklung', ...
start_date DATE,
end_date DATE, -- null = permanent
brutto_monthly NUMERIC(10,2), -- Bruttogehalt/Monat
annual_raise_pct NUMERIC(5,2) DEFAULT 3.0,
ag_sozial_pct NUMERIC(5,2) DEFAULT 20.425, -- AG-Anteil Sozialversicherung
is_editable BOOLEAN DEFAULT true,
-- Computed monthly values
values_brutto JSONB NOT NULL DEFAULT '{}', -- monthly brutto
values_sozial JSONB NOT NULL DEFAULT '{}', -- monthly AG-Sozial
values_total JSONB NOT NULL DEFAULT '{}', -- brutto + sozial
excel_row INT,
sort_order INT NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- ============================================================================
-- BETRIEBLICHE AUFWENDUNGEN (~40 Kostenposten)
-- Most are fixed monthly values (editable)
-- Some are computed (Summen, Abschreibungen)
-- ============================================================================
CREATE TABLE fp_betriebliche_aufwendungen (
id SERIAL PRIMARY KEY,
scenario_id UUID REFERENCES fp_scenarios(id) ON DELETE CASCADE,
category TEXT NOT NULL, -- 'raumkosten', 'versicherungen', 'marketing', etc.
row_label TEXT NOT NULL,
row_index INT NOT NULL,
is_editable BOOLEAN DEFAULT true,
is_sum_row BOOLEAN DEFAULT false, -- true for category subtotals
formula_desc TEXT, -- e.g. 'SUM(rows 9-18)', '=Personalkosten!Y4'
values JSONB NOT NULL DEFAULT '{}',
excel_row INT,
sort_order INT NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- ============================================================================
-- INVESTITIONEN (Anlagegüter mit AfA)
-- Each item: name, amount, purchase date, useful life, depreciation
-- ============================================================================
CREATE TABLE fp_investitionen (
id SERIAL PRIMARY KEY,
scenario_id UUID REFERENCES fp_scenarios(id) ON DELETE CASCADE,
item_name TEXT NOT NULL,
category TEXT, -- 'gwg', 'ausstattung', etc.
purchase_amount NUMERIC(12,2) NOT NULL,
purchase_date DATE,
afa_years INT, -- useful life in years
afa_end_date DATE, -- computed end date
is_editable BOOLEAN DEFAULT true,
-- Computed: monthly investment amount (in purchase month) and depreciation
values_invest JSONB NOT NULL DEFAULT '{}', -- investment amount per month
values_afa JSONB NOT NULL DEFAULT '{}', -- monthly depreciation
excel_row INT,
sort_order INT NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- ============================================================================
-- SONST. BETRIEBLICHE ERTRAEGE (6 Kategorien × 3 Zeilen)
-- ============================================================================
CREATE TABLE fp_sonst_ertraege (
id SERIAL PRIMARY KEY,
scenario_id UUID REFERENCES fp_scenarios(id) ON DELETE CASCADE,
category TEXT NOT NULL, -- '1-Interne Kostenstellen', '2-Entwicklung National', etc.
row_label TEXT,
row_index INT NOT NULL,
is_editable BOOLEAN DEFAULT true,
is_sum_row BOOLEAN DEFAULT false,
values JSONB NOT NULL DEFAULT '{}',
excel_row INT,
sort_order INT NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- ============================================================================
-- LIQUIDITAET (computed from all above)
-- ============================================================================
CREATE TABLE fp_liquiditaet (
id SERIAL PRIMARY KEY,
scenario_id UUID REFERENCES fp_scenarios(id) ON DELETE CASCADE,
row_label TEXT NOT NULL,
row_type TEXT NOT NULL, -- 'einzahlung', 'auszahlung', 'ueberschuss', 'kontostand'
is_editable BOOLEAN DEFAULT false, -- only Eigenkapital, Fremdkapital, Entnahmen editable
formula_desc TEXT,
values JSONB NOT NULL DEFAULT '{}',
excel_row INT,
sort_order INT NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- ============================================================================
-- GUV JAHRESABSCHLUSS (annual summary, 5 years)
-- ============================================================================
CREATE TABLE fp_guv (
id SERIAL PRIMARY KEY,
scenario_id UUID REFERENCES fp_scenarios(id) ON DELETE CASCADE,
row_label TEXT NOT NULL,
row_index INT NOT NULL,
is_sum_row BOOLEAN DEFAULT false,
formula_desc TEXT,
values JSONB NOT NULL DEFAULT '{}', -- {y2026: ..., y2027: ..., y2030: ...}
excel_row INT,
sort_order INT NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- ============================================================================
-- CELL OVERRIDES (for scenario-specific manual edits)
-- ============================================================================
CREATE TABLE fp_cell_overrides (
id SERIAL PRIMARY KEY,
scenario_id UUID REFERENCES fp_scenarios(id) ON DELETE CASCADE,
sheet_name TEXT NOT NULL, -- 'kunden', 'personalkosten', etc.
row_id INT NOT NULL, -- references the id in the sheet table
month_key TEXT NOT NULL, -- 'm1', 'm2', ... 'm60' or 'y2026', etc.
override_value NUMERIC,
created_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(scenario_id, sheet_name, row_id, month_key)
);
-- ============================================================================
-- INDEXES
-- ============================================================================
CREATE INDEX idx_fp_kunden_scenario ON fp_kunden(scenario_id);
CREATE INDEX idx_fp_kunden_summary_scenario ON fp_kunden_summary(scenario_id);
CREATE INDEX idx_fp_umsatz_scenario ON fp_umsatzerloese(scenario_id);
CREATE INDEX idx_fp_material_scenario ON fp_materialaufwand(scenario_id);
CREATE INDEX idx_fp_personal_scenario ON fp_personalkosten(scenario_id);
CREATE INDEX idx_fp_betrieb_scenario ON fp_betriebliche_aufwendungen(scenario_id);
CREATE INDEX idx_fp_invest_scenario ON fp_investitionen(scenario_id);
CREATE INDEX idx_fp_sonst_scenario ON fp_sonst_ertraege(scenario_id);
CREATE INDEX idx_fp_liquid_scenario ON fp_liquiditaet(scenario_id);
CREATE INDEX idx_fp_guv_scenario ON fp_guv(scenario_id);
CREATE INDEX idx_fp_overrides_lookup ON fp_cell_overrides(scenario_id, sheet_name, row_id);