Files
KanzlAI-mGMT/docs/kostenrechner-plan.md
m 7c70649494 docs: add Patentprozesskostenrechner implementation plan
Comprehensive analysis of the Excel-based patent litigation cost calculator
with implementation plan for the web version:

- Fee calculation logic (GKG/RVG step-based accumulator, all multipliers)
- Exact fee schedule data for all 5 versions (extracted from Excel)
- UPC fee structure research (fixed fees, value-based brackets, recoverable costs)
- Architecture: new page at /kosten/rechner within KanzlAI-mGMT (pure frontend)
- Complete input/output specifications
- 3 bugs to fix from the Excel (VAT formula, wrong fee type, missing expert fees)
- Side-by-side DE vs UPC cost comparison data
2026-03-31 17:28:39 +02:00

515 lines
20 KiB
Markdown
Raw Permalink 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.

# Patentprozesskostenrechner — Implementation Plan
**Date:** 2026-03-31
**Source:** Analysis of `Patentprozesskostenrechner.xlsm` (c) 2021 M. Siebels
**Status:** Research complete, ready for implementation
---
## 1. Fee Calculation Logic Summary
The calculator computes costs for German patent litigation using two fee systems:
### GKG (Gerichtskostengesetz) — Court Fees
A **step-based accumulator**. The Streitwert is divided into brackets, each with a step size and per-step increment. The algorithm:
1. Start with the minimum fee (first row of the fee table)
2. For each bracket: compute `steps = ceil(portion_in_bracket / step_size)`
3. Accumulate: `fee += steps * increment`
4. Result = "einfache Gebühr" (1.0x base fee)
5. Multiply by the instance-specific factor (e.g., 3.0x for LG, 4.0x for OLG)
For Streitwert > EUR 500,000 (post-2025 schedule): `base = 4,138 + ceil((Streitwert - 500,000) / 50,000) * 210`
### RVG (Rechtsanwaltsvergütungsgesetz) — Attorney Fees
Same step-based lookup but with its own column in the fee table. Per attorney, the formula is:
```
attorney_cost = (VG_factor * base_RVG + increase_fee + TG_factor * base_RVG + Pauschale) * (1 + VAT)
```
Where:
- **VG** = Verfahrensgebühr (procedural fee): 1.3x (LG/BPatG), 1.6x (OLG/BGH nullity), 2.3x (BGH NZB/Rev for RA)
- **TG** = Terminsgebühr (hearing fee): 1.2x or 1.5x (BGH), only if hearing held
- **Increase fee** (Nr. 1008 VV RVG): `MIN((clients - 1) * 0.3, 2.0) * base_RVG` for multiple clients
- **Pauschale** = EUR 20 (Auslagenpauschale Nr. 7002 VV RVG)
### PatKostG — Patent Court Fees
BPatG nullity uses PatKostG instead of GKG for court fees (but same step-based lookup from the same table). DPMA/BPatG cancellation uses fixed fees (EUR 300 / EUR 500).
### Instance Multipliers (Complete Reference)
| Instance | Court Fee Factor | Source | Fee Basis |
|---|---|---|---|
| **LG** (infringement 1st) | 3.0x GKG | Nr. 1210 Anl. 1 GKG | GKG |
| **OLG** (infringement appeal) | 4.0x GKG | Nr. 1420 KV GKG | GKG |
| **BGH NZB** (leave to appeal) | 2.0x GKG | Nr. 1242 KV GKG | GKG |
| **BGH Revision** | 5.0x GKG | Nr. 1230 KV GKG | GKG |
| **BPatG** (nullity 1st) | 4.5x | Nr. 402 100 Anl. PatKostG | PatKostG |
| **BGH** (nullity appeal) | 6.0x GKG | Nr. 1250 KV GKG | GKG |
| **DPMA** (cancellation) | EUR 300 flat | Nr. 323 100 Anl. PatKostG | Fixed |
| **BPatG** (cancellation appeal) | EUR 500 flat | Nr. 401 100 Anl. PatKostG | Fixed |
| Instance | RA VG Factor | RA TG Factor | PA VG Factor | PA TG Factor |
|---|---|---|---|---|
| **LG** | 1.3x | 1.2x | 1.3x | 1.2x |
| **OLG** | 1.6x | 1.2x | 1.6x | 1.2x |
| **BGH NZB** | 2.3x | 1.2x | 1.6x | 1.2x |
| **BGH Revision** | 2.3x | 1.5x | 1.6x | 1.5x |
| **BPatG** (nullity) | 1.3x | 1.2x | 1.3x | 1.2x |
| **BGH** (nullity appeal) | 1.6x | 1.5x | 1.6x | 1.5x |
| **DPMA** | 1.3x | 1.2x | — | — |
| **BPatG** (cancellation) | 1.3x | 1.2x | — | — |
---
## 2. Fee Schedule Data (JSON)
Five historical versions of the fee table. Each row: `[upperBound, stepSize, gkgIncrement, rvgIncrement]`.
Each row: `[upperBound, stepSize, gkgIncrement, rvgIncrement]`. Values extracted directly from the Excel ListObjects. Note: increments are decimal (e.g., 51.5 EUR per step). The last bracket uses a very large upper bound (effectively infinity).
```json
{
"feeSchedules": {
"2005": {
"label": "GKG/RVG 2006-09-01",
"validFrom": "2006-09-01",
"brackets": [
[300, 300, 25, 25],
[1500, 300, 10, 20],
[5000, 500, 8, 28],
[10000, 1000, 15, 37],
[25000, 3000, 23, 40],
[50000, 5000, 29, 72],
[200000, 15000, 100, 77],
[500000, 30000, 150, 118],
[Infinity, 50000, 150, 150]
]
},
"2013": {
"label": "GKG/RVG 2013-08-01",
"validFrom": "2013-08-01",
"brackets": [
[500, 300, 35, 45],
[2000, 500, 18, 35],
[10000, 1000, 19, 51],
[25000, 3000, 26, 46],
[50000, 5000, 35, 75],
[200000, 15000, 120, 85],
[500000, 30000, 179, 120],
[Infinity, 50000, 180, 150]
]
},
"2021": {
"label": "GKG/RVG 2021-01-01",
"validFrom": "2021-01-01",
"brackets": [
[500, 300, 38, 49],
[2000, 500, 20, 39],
[10000, 1000, 21, 56],
[25000, 3000, 29, 52],
[50000, 5000, 38, 81],
[200000, 15000, 132, 94],
[500000, 30000, 198, 132],
[Infinity, 50000, 198, 165]
]
},
"2025": {
"label": "GKG/RVG 2025-06-01",
"validFrom": "2025-06-01",
"brackets": [
[500, 300, 40, 51.5],
[2000, 500, 21, 41.5],
[10000, 1000, 22.5, 59.5],
[25000, 3000, 30.5, 55],
[50000, 5000, 40.5, 86],
[200000, 15000, 140, 99.5],
[500000, 30000, 210, 140],
[Infinity, 50000, 210, 175]
]
},
"Aktuell": {
"label": "Aktuell (= 2025-06-01)",
"validFrom": "2025-06-01",
"aliasOf": "2025"
}
},
"constants": {
"erhoehungsfaktor": 0.3,
"erhoehungsfaktorMax": 2.0,
"auslagenpauschale": 20
}
}
```
**Notes on the data:**
- The 2005 version has 9 brackets (starts at 300, not 500). Older versions differ more than expected.
- Increments are **not integers** in the 2025 version (e.g., 51.5, 41.5, 59.5) — the implementation must handle decimal arithmetic.
- The last bracket upper bound is `1e+20` in the Excel (effectively infinity). Use `Infinity` in TypeScript or a sentinel value.
- "Aktuell" is currently identical to "2025" — implement as an alias that can diverge when fees are next updated.
### UPC Fee Data (New — Not in Excel)
```json
{
"upcFees": {
"pre2026": {
"label": "UPC (vor 2026)",
"validFrom": "2023-06-01",
"fixedFees": {
"infringement": 11000,
"counterclaim_infringement": 11000,
"non_infringement": 11000,
"license_compensation": 11000,
"determine_damages": 3000,
"revocation_standalone": 20000,
"counterclaim_revocation": 20000,
"provisional_measures": 11000
},
"valueBased": [
{ "maxValue": 500000, "fee": 0 },
{ "maxValue": 750000, "fee": 2500 },
{ "maxValue": 1000000, "fee": 4000 },
{ "maxValue": 1500000, "fee": 8000 },
{ "maxValue": 2000000, "fee": 13000 },
{ "maxValue": 3000000, "fee": 20000 },
{ "maxValue": 4000000, "fee": 26000 },
{ "maxValue": 5000000, "fee": 32000 },
{ "maxValue": 6000000, "fee": 39000 },
{ "maxValue": 7000000, "fee": 46000 },
{ "maxValue": 8000000, "fee": 52000 },
{ "maxValue": 9000000, "fee": 58000 },
{ "maxValue": 10000000, "fee": 65000 },
{ "maxValue": 15000000, "fee": 75000 },
{ "maxValue": 20000000, "fee": 100000 },
{ "maxValue": 25000000, "fee": 125000 },
{ "maxValue": 30000000, "fee": 150000 },
{ "maxValue": 50000000, "fee": 250000 },
{ "maxValue": null, "fee": 325000 }
],
"recoverableCosts": [
{ "maxValue": 250000, "ceiling": 38000 },
{ "maxValue": 500000, "ceiling": 56000 },
{ "maxValue": 1000000, "ceiling": 112000 },
{ "maxValue": 2000000, "ceiling": 200000 },
{ "maxValue": 4000000, "ceiling": 400000 },
{ "maxValue": 8000000, "ceiling": 600000 },
{ "maxValue": 16000000, "ceiling": 800000 },
{ "maxValue": 30000000, "ceiling": 1200000 },
{ "maxValue": 50000000, "ceiling": 1500000 },
{ "maxValue": null, "ceiling": 2000000 }
],
"smReduction": 0.40
},
"2026": {
"label": "UPC (ab 2026)",
"validFrom": "2026-01-01",
"fixedFees": {
"infringement": 14600,
"counterclaim_infringement": 14600,
"non_infringement": 14600,
"license_compensation": 14600,
"determine_damages": 4000,
"revocation_standalone": 26500,
"counterclaim_revocation": 26500,
"provisional_measures": 14600
},
"valueBased": "TODO: exact 2026 table not yet published in extractable form. Estimated ~32% increase on pre-2026 values. Replace with official data when available.",
"smReduction": 0.50
}
}
}
```
---
## 3. Architecture Decision
### Recommendation: New page within KanzlAI-mGMT at `/kosten/rechner`
**Reasons:**
1. **Existing infrastructure**: KanzlAI already has billing/cost infrastructure (time tracking, invoices, RVG rates). The Kostenrechner is a natural extension.
2. **Shared UI patterns**: Sidebar nav, card layout, Tailwind styling, Recharts for any comparison charts — all already established.
3. **Future integration**: Cost calculations can link to cases (attach estimated costs to a case), feed into Prozesskostensicherheit calculations, and inform billing.
4. **No auth required for core calculator**: The page can work without login (public tool for marketing), but logged-in users get case-linking and save functionality.
5. **No backend needed initially**: All fee calculations are deterministic lookups + arithmetic — pure frontend. Data lives as static JSON/TypeScript constants.
**Against standalone deployment:**
- Maintaining a separate deploy adds operational overhead for zero benefit
- Can't integrate with cases or billing later without cross-origin complexity
- Duplicates styling/build tooling
### Proposed Route Structure
```
/kosten/ — Overview page (links to sub-calculators)
/kosten/rechner — Patentprozesskostenrechner (main calculator)
/kosten/rechner/vergleich — (future) Venue comparison tool (DE vs UPC)
```
### Frontend Architecture
```
frontend/src/
app/(app)/kosten/
page.tsx — Overview
rechner/
page.tsx — Calculator page (client component)
lib/
costs/
fee-tables.ts — All fee schedule data (GKG, RVG, UPC)
calculator.ts — Pure calculation functions
types.ts — TypeScript types for inputs/outputs
components/
costs/
CostCalculator.tsx — Main calculator component
InstanceCard.tsx — Per-instance input card (LG, OLG, etc.)
CostSummary.tsx — Results display with breakdown
CostComparison.tsx — (future) Side-by-side venue comparison
```
**No backend changes needed.** All calculation logic is client-side. If we later want to save calculations to a case, we add one API endpoint.
---
## 4. All Inputs
### Global Inputs
| Input | Type | Range | Default | Description |
|---|---|---|---|---|
| `vatRate` | enum | 0%, 16%, 19% | 0% | Umsatzsteuer |
| `streitwert` | number | 50030,000,000 | 100,000 | Amount in dispute (EUR) |
| `erhoehungsStreitwert` | number | >= streitwert | = streitwert | Increased amount (for Erhoehungsgebuehr) |
| `proceedingType` | enum | infringement, nullity, cancellation, security | infringement | Which proceeding to calculate |
### Per-Instance Inputs (Infringement: LG, OLG, BGH-NZB, BGH-Rev)
| Input | Type | Default | Description |
|---|---|---|---|
| `enabled` | boolean | true (LG), false (others) | Include this instance |
| `feeVersion` | enum | "Aktuell" | Fee schedule version (2005/2013/2021/2025/Aktuell) |
| `numAttorneys` | integer >= 0 | 1 | Rechtsanwälte |
| `numPatentAttorneys` | integer >= 0 | 1 | Patentanwälte |
| `oralHearing` | boolean | true | Mündliche Verhandlung held? |
| `expertFees` | number >= 0 | 0 | Sachverständigenvergütung (EUR) |
| `terminationType` | enum | "Urteil" | How case ended (Urteil/Vergleich/Klagerücknahme/etc.) |
| `numClients` | integer >= 1 | 1 | Mandanten (for Erhöhungsgebühr) |
### Per-Instance Inputs (Nullity: BPatG, BGH)
Same structure as infringement instances.
### Per-Instance Inputs (Cancellation: DPMA, BPatG)
Same structure but no patent attorneys at DPMA level, fixed court fees.
### UPC-Specific Inputs (New)
| Input | Type | Default | Description |
|---|---|---|---|
| `actionType` | enum | "infringement" | UPC action type (affects fixed fee + value-based applicability) |
| `feeVersion` | enum | "2026" | pre-2026 or 2026 |
| `isSME` | boolean | false | Small/micro enterprise (40%/50% court fee reduction) |
| `includeAppeal` | boolean | false | Include Court of Appeal |
| `includeRevocation` | boolean | false | Include counterclaim for revocation |
---
## 5. All Outputs
### Per-Instance Breakdown
| Output | Description |
|---|---|
| Court fee (base) | e.g., "3.0x GKG = EUR 18,714" |
| Expert fees | If applicable |
| **Court subtotal** | Court fee + expert fees |
| Per-attorney cost | VG + Erhöhung + TG + Pauschale, before VAT |
| Per-attorney cost (incl. VAT) | × (1 + VAT) |
| Attorney subtotal | Per-attorney × num_attorneys |
| Patent attorney subtotal | Same calculation × num_patent_attorneys |
| **Instance total** | Court subtotal + attorney subtotal + patent attorney subtotal |
### Summary Totals (Infringement)
| Output | Description |
|---|---|
| Gesamtkosten bei Nichtzulassung | LG + OLG + BGH-NZB |
| Gesamtkosten bei Revision | LG + OLG + BGH-Rev |
### Summary Totals (Nullity)
| Output | Description |
|---|---|
| Gesamtkosten Nichtigkeitsverfahren | BPatG + BGH |
### Summary Totals (Cancellation)
| Output | Description |
|---|---|
| Gesamtkosten Löschungsverfahren | DPMA + BPatG |
### Security for Costs (Prozesskostensicherheit)
| Output | Description |
|---|---|
| 1. Instanz | 2.5x RA + increase + 2.5x PA + increase + EUR 5,000 |
| 2. Instanz | 2.8x RA + increase + 2.8x PA + increase + 4.0x court + EUR 5,000 |
| NZB | 2.3x RA + increase + 2.3x PA + increase |
| Total (incl. VAT) | Sum × (1 + VAT) |
### UPC Outputs (New)
| Output | Description |
|---|---|
| Fixed court fee | Per action type |
| Value-based fee | Per Streitwert bracket |
| Total court fees | Fixed + value-based |
| Court fees (SME) | With 40%/50% reduction |
| Recoverable costs ceiling | Per Streitwert bracket |
| Appeal court fees | If appeal enabled |
| **Total cost risk** | All court fees + recoverable costs ceiling |
### Fee Schedule Reference (Quick Lookup)
| Output | Description |
|---|---|
| Base 1.0x GKG fee | For each fee version at given Streitwert |
| Base 1.0x RVG fee | For each fee version at given Streitwert |
---
## 6. Bugs to Fix (from Excel)
### Bug 1: Prozesskostensicherheit VAT Formula (CRITICAL)
- **Location:** Excel cell C31 on Prozesskostensicherheit sheet
- **Problem:** Formula `=C30*(1-Umsatzsteuer)` subtracts VAT instead of adding it
- **Label says:** "inkl. Umsatzsteuer" (including VAT)
- **Fix:** `=C30*(1+Umsatzsteuer)` → in web version: `total * (1 + vatRate)`
- **Impact:** 32% error when VAT = 19% (EUR 35,394 vs correct EUR 51,998)
- **Why hidden:** Default VAT is 0%, so `1-0 = 1+0 = 1` — bug only manifests with non-zero VAT
### Bug 2: Prozesskostensicherheit Uses Wrong Fee Type
- **Location:** Excel cell C22 on Prozesskostensicherheit sheet
- **Problem:** `mGebuehrensatz(Streitwert, 1, SelectedVersion)` — parameter `1` selects RVG (attorney) fees
- **Should be:** `mGebuehrensatz(Streitwert, 0, SelectedVersion)` — parameter `0` selects GKG (court) fees
- **Context:** This cell calculates "4-fache Gerichts-Verfahrensgebühr (Nr. 1420 KV)" — clearly a court fee
- **Fix:** Use GKG fee schedule for court fee calculations
- **Impact:** GKG and RVG fees differ, so the result is always wrong
### Bug 3: Nichtigkeitsverfahren Missing Expert Fees in Total
- **Location:** Excel cell D24 on Nichtigkeitsverfahren sheet
- **Problem:** `=C23+C13` adds attorney total (C23) + bare court fee (C13), but C13 is only the 4.5x fee line item
- **Should be:** `=C23+C15` where C15 is the Zwischensumme (court fees + expert fees)
- **Fix:** Include expert fees subtotal in instance total
- **Impact:** Expert fees are silently dropped from the BPatG total. Consistent with Verletzungsverfahren pattern where D26 = C25 + C17 (uses Zwischensumme)
---
## 7. UPC Fee Structure (New Feature)
### How UPC Fees Differ from German Courts
| Aspect | German Courts (GKG/RVG) | UPC |
|---|---|---|
| **Court fee model** | Step-based accumulator | Fixed fee + bracket lookup |
| **Attorney fees** | RVG statutory table | Contractual (market rates) |
| **Recoverable costs** | RVG-based (predictable) | Ceiling table (much higher) |
| **Scope** | Single country | Pan-European |
| **Nullity** | Separate BPatG proceeding | Counterclaim in same action |
### UPC Court Fees: Two Components
1. **Fixed fee** — always due, depends on action type:
- Infringement: EUR 14,600 (2026) / EUR 11,000 (pre-2026)
- Revocation: EUR 26,500 (2026) / EUR 20,000 (pre-2026) — flat, no value-based component
- Appeal: same fixed fees as first instance
2. **Value-based fee** — only for infringement-type actions when Streitwert > EUR 500,000:
- 19 brackets from EUR 0 (≤500k) to EUR 325,000 (>50M) — pre-2026
- ~32% increase in 2026 (exact table pending official publication)
- Revocation actions have NO value-based fee
3. **SME reduction**: 50% (2026) / 40% (pre-2026) on all court fees
### Recoverable Costs Ceilings (Attorney Fee Caps)
Per instance, the losing party reimburses up to:
| Streitwert | Ceiling |
|---|---|
| ≤ EUR 250,000 | EUR 38,000 |
| ≤ EUR 500,000 | EUR 56,000 |
| ≤ EUR 1,000,000 | EUR 112,000 |
| ≤ EUR 2,000,000 | EUR 200,000 |
| ≤ EUR 4,000,000 | EUR 400,000 |
| ≤ EUR 8,000,000 | EUR 600,000 |
| ≤ EUR 16,000,000 | EUR 800,000 |
| ≤ EUR 30,000,000 | EUR 1,200,000 |
| ≤ EUR 50,000,000 | EUR 1,500,000 |
| > EUR 50,000,000 | EUR 2,000,000 |
Court can raise ceiling by 50% (cases ≤1M) or 25% (150M). Expert/translator fees recoverable separately on top.
### Cost Comparison (Key Insight)
At EUR 3M Streitwert (infringement, 1st instance):
| | UPC (2026) | German LG |
|---|---|---|
| Court fees | ~EUR 41,000 | EUR 43,914 |
| Recoverable attorney costs | up to EUR 400,000 | ~EUR 100,388 |
| **Total cost risk** | **~EUR 441,000** | **~EUR 144,302** |
**Key takeaway:** UPC court fees are comparable to or lower than German courts. But recoverable attorney costs are 35x higher, making total cost risk at UPC roughly 23x German courts. This is the critical information patent litigators need.
### UPC Sources
- Rule 370 RoP (court fees), Rule 152 RoP (recoverable costs), Art. 69 UPCA
- UPC Administrative Committee fee table AC/05/08072022 (pre-2026)
- UPC Administrative Committee amendment, 4 Nov 2025 (2026 changes)
- Scale of Ceilings for Recoverable Costs: D-AC/10/24042023
- Maiwald MAIinsight April 2025 (practitioner analysis with verified figures)
---
## 8. Implementation Recommendations
### Phase 1: Core Calculator (MVP)
- Implement `fee-tables.ts` with all 5 GKG/RVG schedule versions as typed constants
- Implement `calculator.ts` with pure functions: `computeBaseFee(streitwert, isRVG, version)`, per-instance calculations, totals
- Build the UI as a single `"use client"` page at `/kosten/rechner`
- Card-based layout: global inputs at top, collapsible instance cards, results summary at bottom
- Fix all 3 bugs in the implementation (don't port them from Excel)
- German language UI throughout
### Phase 2: UPC Extension
- Add UPC fee data and calculation functions (bracket lookup, not step-based)
- Add UPC section to the calculator (separate card or tab)
- Add venue comparison view: side-by-side DE vs UPC for the same Streitwert
### Phase 3: Integration
- Allow saving calculations to a case (requires one backend endpoint)
- PDF export of cost breakdown
- Wire up Verfahrensbeendigung (termination type affects fee multipliers)
### Data Extraction TODO
Before implementation begins, the exact fee table values must be extracted from the Excel file. The analysis doc describes the structure but doesn't list every cell value. The implementer should either:
1. Open the Excel and manually read the Hebesaetze sheet values, or
2. Use a Python script with `openpyxl` to extract the ListObject data programmatically
This is critical — the older fee versions (2005, 2013, 2021) have different step sizes and increments.