Files
paliad/docs/design-prozesskostenrechner-fristenrechner.md
m 2919e1afc4 feat: design document for Prozesskostenrechner + Fristenrechner
Comprehensive design for two interactive tools:
- Prozesskostenrechner: DE (LG/OLG/BGH/BPatG), UPC, and EPA cost estimates
- Fristenrechner: Patent deadline calculator with holiday adjustment

Covers UI layout, data models, API contracts, calculation logic,
fee tables (GKG/RVG/PatKostG/UPC/EPA), deadline rules for all
proceeding types, and phased implementation plan.

Key differentiator: EPA proceedings coverage (not in KanzlAI).
2026-04-14 17:12:16 +02:00

36 KiB
Raw Permalink Blame History

Design: Prozesskostenrechner + Fristenrechner

Author: cronus (inventor) Date: 2026-04-14 Task: t-patholo-006 Status: Design complete — ready for implementation


1. Executive Summary

Two interactive calculator tools for patholo.de, tailored for HL patent lawyers:

  1. Prozesskostenrechner — Estimates litigation costs across DE courts, UPC, and EPA proceedings
  2. Fristenrechner — Calculates patent-related deadlines with holiday/weekend adjustment

Both tools follow patholo's existing architecture (SSR page shell via Bun/TSX, client-side JS for interactivity, Go API for calculation logic) and extend it with a new /tools/ section.

Key differentiator vs KanzlAI: patholo adds EPA proceeding costs and deadlines — directly relevant for HL's patent prosecution practice, which KanzlAI doesn't cover.


2. Architecture

Existing Pattern

patholo uses a three-layer architecture:

[Bun/TSX build] → static HTML pages (dist/*.html)
[Client JS]     → bundled per page (dist/assets/*.js), POSTs to Go API
[Go backend]    → serves pages + API endpoints, Supabase auth middleware

How Calculators Fit

Each calculator gets:

  • One TSX page (SSR shell with form structure and empty result containers)
  • One client JS bundle (handles form interaction, calls API, renders results)
  • Go API endpoints (pure calculation logic, returns JSON)

This matches the login page pattern (login.tsx + client/login.ts + POST /api/login).

New Files

frontend/
  src/
    kostenrechner.tsx              # SSR page shell
    fristenrechner.tsx             # SSR page shell
    client/
      kostenrechner.ts             # Client-side form logic + API calls
      fristenrechner.ts            # Client-side form logic + API calls

internal/
  handlers/
    kostenrechner.go               # API endpoint + page serving
    fristenrechner.go              # API endpoint + page serving
  calc/
    fees.go                        # GKG/RVG/PatKostG step-based fee calculation
    fee_tables.go                  # Fee schedule data (brackets, factors, UPC/EPA fees)
    deadlines.go                   # Deadline calculation + holiday adjustment
    deadline_rules.go              # Proceeding types + rule definitions
    holidays.go                    # German federal holidays (Easter algorithm)

Routes

GET  /tools/kostenrechner          → protected, serves dist/kostenrechner.html
POST /api/tools/kostenrechner      → protected, JSON calculation
GET  /tools/fristenrechner         → protected, serves dist/fristenrechner.html
POST /api/tools/fristenrechner     → protected, JSON calculation

Build Changes

frontend/build.ts adds two new entrypoints and two new page renders:

// New client bundles
entrypoints: [
  "src/client/login.ts",
  "src/client/kostenrechner.ts",
  "src/client/fristenrechner.ts",
]

// New page renders
Bun.write(join(DIST, "kostenrechner.html"), renderKostenrechner());
Bun.write(join(DIST, "fristenrechner.html"), renderFristenrechner());

3. Prozesskostenrechner

3.1 Scope

Three proceeding families, covering what HL patent lawyers encounter daily:

Family Instances Fee Basis
DE Verletzung LG → OLG → BGH (NZB) → BGH (Revision) GKG + RVG
DE Nichtigkeit BPatG → BGH (Nichtigkeitsberufung) PatKostG/GKG + RVG
UPC UPC 1. Instanz → UPC Berufung Fixed + value-based
EPA Einspruch → Beschwerde Fixed fees

3.2 UI Layout

Two-column layout on desktop (stacks on mobile):

┌─────────────────────────────────────────────────────────┐
│ Header: patholo + nav                                   │
├─────────────────────────────────────────────────────────┤
│ Page Title: Prozesskostenrechner                        │
│ Subtitle:   Patent Litigation Cost Calculator           │
├──────────────────────────────┬──────────────────────────┤
│ LEFT PANEL (inputs)          │ RIGHT PANEL (results)    │
│                              │ [sticky on scroll]       │
│ ┌──────────────────────────┐ │                          │
│ │ Streitwert               │ │ ┌──────────────────────┐ │
│ │ [slider + input field]   │ │ │ Gesamtkosten         │ │
│ │ Presets: 500k 1M 5M 10M │ │ │ EUR XX.XXX,XX        │ │
│ └──────────────────────────┘ │ │ (highlighted, large)  │ │
│                              │ └──────────────────────┘ │
│ ┌──────────────────────────┐ │                          │
│ │ MwSt: [19% ▼]           │ │ ┌──────────────────────┐ │
│ └──────────────────────────┘ │ │ Per-Instance Breakdown│ │
│                              │ │                      │ │
│ ── DE Verletzungsverfahren ──│ │ LG:     EUR XX.XXX   │ │
│ ☑ LG  [details ▼]           │ │  Gericht: EUR X.XXX  │ │
│ ☑ OLG [details ▼]           │ │  RA:      EUR X.XXX  │ │
│ ☐ BGH NZB                   │ │  PA:      EUR X.XXX  │ │
│ ☐ BGH Revision               │ │                      │ │
│                              │ │ OLG:    EUR XX.XXX   │ │
│ ── DE Nichtigkeitsverfahren ─│ │  ...                  │ │
│ ☐ BPatG                     │ │                      │ │
│ ☐ BGH Nichtigkeit           │ │ UPC 1:  EUR XX.XXX   │ │
│                              │ │  Fixed:  EUR X.XXX   │ │
│ ── UPC ──────────────────────│ │  Value:  EUR X.XXX   │ │
│ ☐ UPC 1. Instanz            │ │  Recov.: EUR X.XXX   │ │
│ ☐ UPC Berufung               │ │                      │ │
│                              │ │ EPA:    EUR X.XXX    │ │
│ ── EPA ──────────────────────│ │  ...                  │ │
│ ☐ Einspruch                  │ └──────────────────────┘ │
│ ☐ Beschwerde                 │                          │
│                              │ [Drucken / Print]        │
├──────────────────────────────┴──────────────────────────┤
│ Footer                                                  │
└─────────────────────────────────────────────────────────┘

Instance Detail Expansion (when user clicks ▼ on an enabled instance):

☑ LG (Verletzung 1. Instanz)           [▼ expanded]
  ┌────────────────────────────────────────────┐
  │ Gebührenordnung: [Aktuell (2025) ▼]       │
  │ Rechtsanwälte:   [1 ▼]                    │
  │ Patentanwälte:   [1 ▼]                    │
  │ Mandanten:       [1 ▼]                    │
  │ Mündl. Verhandlung: [☑ Ja]                │
  └────────────────────────────────────────────┘

3.3 Calculation Logic

3.3.1 GKG/RVG Base Fee (Step-Based Accumulator)

The fee schedules use brackets with step sizes. Algorithm:

func ComputeBaseFee(streitwert float64, isRVG bool, version string) float64 {
    brackets := FeeSchedules[version]
    remaining := streitwert
    fee := 0.0
    lowerBound := 0.0

    for _, b := range brackets {
        upperBound, stepSize, gkgInc, rvgInc := b[0], b[1], b[2], b[3]
        increment := gkgInc
        if isRVG { increment = rvgInc }

        bracketSize := upperBound - lowerBound
        if upperBound == math.Inf(1) { bracketSize = remaining }
        portion := math.Min(remaining, bracketSize)
        if portion <= 0 { break }

        if lowerBound == 0 {
            // First bracket: minimum = one increment
            fee += increment
            stepsAfterFirst := math.Max(0, math.Ceil((portion - stepSize) / stepSize))
            fee += stepsAfterFirst * increment
        } else {
            steps := math.Ceil(portion / stepSize)
            fee += steps * increment
        }

        remaining -= portion
        lowerBound = upperBound
        if remaining <= 0 { break }
    }
    return fee
}

3.3.2 Court Fees

courtFee = courtFeeFactor × ComputeBaseFee(streitwert, false, version)

Factors per instance:

  • LG: 3.0× GKG
  • OLG: 4.0× GKG
  • BGH NZB: 2.0× GKG
  • BGH Revision: 5.0× GKG
  • BPatG: 4.5× PatKostG (same brackets as GKG)
  • BGH Nichtigkeit: 6.0× GKG

3.3.3 Attorney Fees (per attorney)

baseFee     = ComputeBaseFee(streitwert, true, version)   // RVG base
vgFee       = vgFactor × baseFee                          // Verfahrensgebühr
erhöhung    = min((numClients - 1) × 0.3, 2.0) × baseFee // Erhöhungsgebühr
tgFee       = oralHearing ? tgFactor × baseFee : 0        // Terminsgebühr
pauschale   = 20.00                                       // Auslagenpauschale
nettoTotal  = vgFee + erhöhung + tgFee + pauschale
mwst        = nettoTotal × vatRate
bruttoTotal = nettoTotal + mwst

VG/TG factors per instance:

Instance RA VG RA TG PA VG PA TG
LG 1.3 1.2 1.3 1.2
OLG 1.6 1.2 1.6 1.2
BGH NZB 2.3 1.2 1.6 1.2
BGH Rev 2.3 1.5 1.6 1.5
BPatG 1.3 1.2 1.3 1.2
BGH Null 1.6 1.5 1.6 1.5

3.3.4 UPC Fees

fixedFee      = UPCFixedFees[version][proceedingType]
valueBasedFee = lookupBracket(streitwert, UPCValueBrackets[version])
courtTotal    = fixedFee + valueBasedFee
smeTotal      = courtTotal × (1 - smeReduction)
recoverableCostsCeiling = lookupBracket(streitwert, UPCRecoverableTable[version])

Two fee versions:

  • Pre-2026: infringement EUR 11,000, revocation EUR 20,000, SME reduction 40%
  • 2026+: infringement EUR 14,600, revocation EUR 26,500, SME reduction 50%

Value-based brackets (19 tiers from EUR 500k to EUR 50M+). Recoverable costs ceiling (10 tiers from EUR 250k to EUR 50M+).

3.3.5 EPA Fees (patholo-specific, not in KanzlAI)

EPA proceedings use fixed official fees — no Streitwert-based calculation:

Proceeding Official Fee Notes
Einspruch (Opposition) EUR 880 Per opponent
Einspruchsbeschwerde (Appeal from Opposition) EUR 2,255 EUR 1,880 for SME
Beschwerde gegen Prüfungsentscheid EUR 2,255 Appeal against examination decision
Beschränkungsantrag (Limitation) EUR 1,175
Widerrufsantrag (Revocation by proprietor) EUR — Free

Attorney costs for EPA proceedings are not RVG-based (EPA representatives are typically Patentanwälte billing hourly). We show only the official fees, with a note that attorney costs are typically agreed on a time-spent basis.

3.4 Fee Schedule Data (2025/Aktuell)

Brackets: [upperBound, stepSize, gkgIncrement, rvgIncrement]
[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]

Additional versions (2005, 2013, 2021) available as dropdown — data from GKG Anlage 2 / RVG Anlage 2.

3.5 API Contract

Request: POST /api/tools/kostenrechner

{
  "streitwert": 1000000,
  "vatRate": 0.19,
  "instances": {
    "LG":          { "enabled": true,  "feeVersion": "Aktuell", "numAttorneys": 1, "numPatentAttorneys": 1, "numClients": 1, "oralHearing": true },
    "OLG":         { "enabled": true,  "feeVersion": "Aktuell", "numAttorneys": 1, "numPatentAttorneys": 1, "numClients": 1, "oralHearing": true },
    "BGH_NZB":     { "enabled": false },
    "BGH_REV":     { "enabled": false },
    "BPatG":       { "enabled": false },
    "BGH_NULLITY": { "enabled": false },
    "UPC_FIRST":   { "enabled": true,  "feeVersion": "2026", "isSME": false, "includeRevocation": false },
    "UPC_APPEAL":  { "enabled": false },
    "EPA_OPPOSITION":     { "enabled": false },
    "EPA_APPEAL":         { "enabled": false }
  }
}

Response:

{
  "results": [
    {
      "instance": "LG",
      "label": "LG (Verletzung 1. Instanz)",
      "courtFee": 2838.00,
      "courtFeeBase": 946.00,
      "courtFeeFactor": 3.0,
      "courtFeeBasis": "GKG",
      "attorney": {
        "baseFee": 1663.50,
        "verfahrensgebuehr": 2162.55,
        "erhoehungsgebuehr": 0,
        "terminsgebuehr": 1996.20,
        "pauschale": 20.00,
        "nettoTotal": 4178.75,
        "mwst": 793.96,
        "bruttoPerAttorney": 4972.71,
        "count": 1,
        "bruttoTotal": 4972.71
      },
      "patentAttorney": {
        "baseFee": 1663.50,
        "verfahrensgebuehr": 2162.55,
        "erhoehungsgebuehr": 0,
        "terminsgebuehr": 1996.20,
        "pauschale": 20.00,
        "nettoTotal": 4178.75,
        "mwst": 793.96,
        "bruttoPerAttorney": 4972.71,
        "count": 1,
        "bruttoTotal": 4972.71
      },
      "instanceTotal": 12783.42
    }
  ],
  "totals": {
    "courtFees": 2838.00,
    "attorneyFees": 4972.71,
    "patentAttorneyFees": 4972.71,
    "grandTotal": 12783.42
  }
}

3.6 Defaults

Sensible defaults for HL patent practice:

  • Streitwert: EUR 1,000,000 (typical DE patent infringement)
  • MwSt: 19%
  • Enabled instances: LG only (user adds more)
  • Per instance: 1 RA, 1 PA, 1 Mandant, mündliche Verhandlung: yes
  • Fee version: Aktuell (2025)

4. Fristenrechner

4.1 Scope

Proceeding types grouped by jurisdiction:

UPC Proceedings:

Code Name (DE) Name (EN)
UPC_INF Verletzungsverfahren Infringement Action
UPC_REV Nichtigkeitsklage Revocation Action
UPC_CCR Widerklage auf Nichtigkeit Counterclaim for Revocation
UPC_PI Einstweilige Maßnahmen Provisional Measures
UPC_APP Berufung Appeal

DE Court Proceedings:

Code Name (DE) Name (EN)
DE_INF Verletzungsklage (LG) Infringement (Regional Court)
DE_NULL Nichtigkeitsverfahren (BPatG) Nullity (Federal Patent Court)

EPA Proceedings (patholo-specific):

Code Name (DE) Name (EN)
EPA_OPP Einspruchsverfahren Opposition Proceedings
EPA_APP Beschwerdeverfahren Appeal Proceedings
EP_GRANT EP-Erteilungsverfahren EP Grant Procedure

4.2 UI Layout

Three-step wizard layout:

┌─────────────────────────────────────────────────────────┐
│ Header: patholo + nav                                   │
├─────────────────────────────────────────────────────────┤
│ Page Title: Fristenrechner                              │
│ Subtitle:   Patent Deadline Calculator                  │
├─────────────────────────────────────────────────────────┤
│                                                         │
│ STEP 1: Verfahrensart wählen                            │
│ ─────────────────────────────                           │
│                                                         │
│ ┌─ UPC ──────────────────────────────────────────────┐  │
│ │ [Verletzung] [Nichtigkeit] [Widerklage]            │  │
│ │ [Einstw. Maßn.] [Berufung]                         │  │
│ └────────────────────────────────────────────────────┘  │
│                                                         │
│ ┌─ Deutsche Gerichte ────────────────────────────────┐  │
│ │ [Verletzungsklage LG] [Nichtigkeitsverfahren]      │  │
│ └────────────────────────────────────────────────────┘  │
│                                                         │
│ ┌─ EPA ──────────────────────────────────────────────┐  │
│ │ [Einspruch] [Beschwerde] [EP-Erteilung]            │  │
│ └────────────────────────────────────────────────────┘  │
│                                                         │
│ ─────────────────────────────────────────────────────── │
│                                                         │
│ STEP 2: Ausgangsdatum eingeben                          │
│ ─────────────────────────────                           │
│                                                         │
│ Auslösendes Ereignis: Klageerhebung                     │
│ Datum: [2026-04-14  📅]                                 │
│                                                         │
│ [Fristen berechnen]                                     │
│                                                         │
│ ─────────────────────────────────────────────────────── │
│                                                         │
│ STEP 3: Ergebnis                                        │
│ ─────────────────                                       │
│                                                         │
│ ┌────────────────────────────────────────────────────┐  │
│ │ ● Klageerhebung              14.04.2026            │  │
│ │ │                             (Ausgangsdatum)       │  │
│ │ │                                                   │  │
│ │ ├─ Klageerwiderung           14.07.2026            │  │
│ │ │  Beklagter · 3 Monate · RoP 23                   │  │
│ │ │  ⚠ Verschoben: 12.07.2026 → 14.07.2026 (So)    │  │
│ │ │                                                   │  │
│ │ ├─ Replik                    14.09.2026            │  │
│ │ │  Kläger · 2 Monate · RoP 29b                     │  │
│ │ │                                                   │  │
│ │ ├─ Duplik                    14.10.2026            │  │
│ │ │  Beklagter · 1 Monat · RoP 29c                   │  │
│ │ │                                                   │  │
│ │ ├─ Zwischenverfahren         (vom Gericht)         │  │
│ │ │  Gericht                                          │  │
│ │ │                                                   │  │
│ │ ├─ Mündliche Verhandlung     (vom Gericht)         │  │
│ │ │  Gericht                                          │  │
│ │ │                                                   │  │
│ │ └─ Entscheidung              (vom Gericht)         │  │
│ │    Gericht                                          │  │
│ └────────────────────────────────────────────────────┘  │
│                                                         │
│ [Drucken / Print]                                       │
│                                                         │
├─────────────────────────────────────────────────────────┤
│ Footer                                                  │
└─────────────────────────────────────────────────────────┘

4.3 Deadline Rules Data

All rules hardcoded in Go (no database needed). Example structure:

type DeadlineRule struct {
    Code         string        // "inf.sod"
    Name         string        // "Klageerwiderung"
    NameEN       string        // "Statement of Defence"
    Party        string        // "defendant" | "claimant" | "court" | "both"
    Duration     int           // 3
    Unit         string        // "months" | "weeks" | "days"
    IsMandatory  bool          // true
    RuleRef      string        // "RoP 23" or "§ 82 PatG"
    Notes        string        // Optional explanation
    RelativeTo   string        // Code of parent rule (empty = root event)
}

type ProceedingType struct {
    Code    string           // "UPC_INF"
    Name    string           // "Verletzungsverfahren"
    NameEN  string           // "Infringement Action"
    Group   string           // "UPC" | "DE" | "EPA"
    Rules   []DeadlineRule
}

UPC Infringement Rules (UPC_INF)

Code Name Party Duration Rule Ref
inf.soc Klageerhebung claimant
inf.sod Klageerwiderung defendant 3 months RoP 23
inf.reply Replik claimant 2 months RoP 29b
inf.rejoin Duplik defendant 1 month RoP 29c
inf.interim Zwischenverfahren court
inf.oral Mündliche Verhandlung court
inf.decision Entscheidung court

UPC Revocation Rules (UPC_REV)

Code Name Party Duration Rule Ref
rev.app Nichtigkeitsklage claimant
rev.defence Klageerwiderung defendant 3 months
rev.reply Replik claimant 2 months
rev.rejoin Duplik defendant 2 months
rev.interim Zwischenverfahren court
rev.oral Mündliche Verhandlung court
rev.decision Entscheidung court

UPC Appeal Rules (UPC_APP)

Code Name Party Duration Rule Ref
app.notice Berufungseinlegung both 2 months RoP 220.1
app.grounds Berufungsbegründung both 2 months RoP 220.1
app.response Berufungserwiderung both 2 months
app.oral Mündliche Verhandlung court
app.decision Entscheidung court

UPC Provisional Measures (UPC_PI)

Code Name Party Duration Rule Ref
pi.app Antrag claimant
pi.response Erwiderung defendant By court order
pi.oral Mündliche Verhandlung court
pi.order Beschluss court

DE Infringement (DE_INF)

Code Name Party Duration Rule Ref
de_inf.klage Klageerhebung claimant
de_inf.erwidg Klageerwiderung defendant ~6 weeks § 276 ZPO
de_inf.replik Replik claimant ~4 weeks By court
de_inf.duplik Duplik defendant ~4 weeks By court
de_inf.termin Haupttermin court
de_inf.urteil Urteil court
de_inf.berufung Berufungsfrist both 1 month § 517 ZPO
de_inf.beruf_begr Berufungsbegründung both 2 months § 520 ZPO

DE Nullity (DE_NULL)

Code Name Party Duration Rule Ref
de_null.klage Nichtigkeitsklage claimant
de_null.erwidg Klageerwiderung defendant 2 months § 82 PatG
de_null.termin Mündliche Verhandlung court
de_null.urteil Urteil court
de_null.berufung Berufungsfrist both 1 month § 110 PatG
de_null.beruf_begr Berufungsbegründung both 1 month § 111 PatG

EPA Opposition (EPA_OPP)

Code Name Party Duration Rule Ref
epa_opp.grant Veröffentlichung der Erteilung
epa_opp.frist Einspruchsfrist both 9 months Art. 99 EPÜ
epa_opp.erwidg Erwiderung des Patentinhabers defendant 4 months R. 79(1) EPÜ
epa_opp.entsch Entscheidung court
epa_opp.beschwerde Beschwerdefrist both 2 months Art. 108 EPÜ
epa_opp.beschwerde_begr Beschwerdebegründung both 4 months Art. 108 EPÜ

EPA Appeal (EPA_APP)

Code Name Party Duration Rule Ref
epa_app.entsch Zustellung der Entscheidung
epa_app.beschwerde Beschwerdeeinlegung both 2 months Art. 108 EPÜ
epa_app.begr Beschwerdebegründung both 4 months Art. 108 EPÜ
epa_app.erwidg Erwiderung both By Board
epa_app.oral Mündliche Verhandlung court
epa_app.entsch2 Entscheidung court

EP Grant Procedure (EP_GRANT)

Code Name Party Duration Rule Ref
ep_grant.filing Anmeldung claimant
ep_grant.search Recherchenberricht court ~6 months
ep_grant.publish Veröffentlichung (A1) 18 months Art. 93 EPÜ
ep_grant.exam_req Prüfungsantrag claimant 6 months R. 70(1) EPÜ
ep_grant.r71_3 Mitteilung nach R. 71(3) court R. 71(3) EPÜ
ep_grant.approval Zustimmung + Übersetzung claimant 4 months R. 71(3) EPÜ
ep_grant.grant Erteilung (B1)

4.4 Calculation Logic

func CalculateDeadline(triggerDate time.Time, rule DeadlineRule) DeadlineResult {
    var endDate time.Time

    switch rule.Unit {
    case "days":
        endDate = triggerDate.AddDate(0, 0, rule.Duration)
    case "weeks":
        endDate = triggerDate.AddDate(0, 0, rule.Duration*7)
    case "months":
        endDate = triggerDate.AddDate(0, rule.Duration, 0)
    }

    originalDate := endDate
    adjustedDate := AdjustForNonWorkingDays(endDate)

    return DeadlineResult{
        RuleCode:     rule.Code,
        DueDate:      adjustedDate,
        OriginalDate: originalDate,
        WasAdjusted:  !adjustedDate.Equal(originalDate),
    }
}

Holiday Adjustment

German federal holidays (computed per year):

  • Neujahr (1. Jan)
  • Karfreitag (Easter - 2)
  • Ostermontag (Easter + 1)
  • Tag der Arbeit (1. Mai)
  • Christi Himmelfahrt (Easter + 39)
  • Pfingstmontag (Easter + 50)
  • Tag der Deutschen Einheit (3. Okt)
    1. Weihnachtstag (25. Dez)
    1. Weihnachtstag (26. Dez)

Easter Sunday computed via Anonymous Gregorian algorithm.

If deadline falls on weekend or holiday → move to next working day (forward up to 30 days).

4.5 API Contract

Request: POST /api/tools/fristenrechner

{
  "proceedingType": "UPC_INF",
  "triggerDate": "2026-04-14"
}

Response:

{
  "proceedingType": "UPC_INF",
  "proceedingName": "Verletzungsverfahren",
  "triggerDate": "2026-04-14",
  "deadlines": [
    {
      "code": "inf.soc",
      "name": "Klageerhebung",
      "nameEN": "Statement of Claim",
      "party": "claimant",
      "isMandatory": true,
      "ruleRef": "",
      "dueDate": "2026-04-14",
      "originalDate": "2026-04-14",
      "wasAdjusted": false,
      "isRootEvent": true
    },
    {
      "code": "inf.sod",
      "name": "Klageerwiderung",
      "nameEN": "Statement of Defence",
      "party": "defendant",
      "isMandatory": true,
      "ruleRef": "RoP 23",
      "dueDate": "2026-07-14",
      "originalDate": "2026-07-14",
      "wasAdjusted": false,
      "isRootEvent": false
    }
  ]
}

4.6 Defaults

  • No proceeding type pre-selected (user must choose)
  • Trigger date: today
  • All rules shown (no filtering)

5. Shared: Navigation Integration

The home page (index.tsx) gets a new "Werkzeuge / Tools" card section linking to both calculators:

┌─────────────┐  ┌─────────────┐
│ 🔢          │  │ 📅          │
│ Kosten-     │  │ Fristen-    │
│ rechner     │  │ rechner     │
│             │  │             │
│ Cost        │  │ Deadline    │
│ Calculator  │  │ Calculator  │
└─────────────┘  └─────────────┘

Navigation Changes

Header gets a "Werkzeuge" dropdown or direct links:

<nav>
  <a href="/">Home</a>
  <a href="/tools/kostenrechner">Kostenrechner</a>
  <a href="/tools/fristenrechner">Fristenrechner</a>
</nav>

6. Styling

Both tools reuse the existing CSS variables and patterns from global.css. New CSS classes needed:

Calculator-Specific Styles

/* Tool page layout */
.tool-page { padding: 2rem 0 4rem; }
.tool-header { margin-bottom: 2rem; }
.tool-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 2rem; }

/* Input panel */
.tool-input { /* left column */ }
.tool-results { position: sticky; top: 4.5rem; /* below header */ }

/* Streitwert slider */
.streitwert-input { /* range + number input combo */ }
.streitwert-presets { display: flex; gap: 0.5rem; }
.streitwert-preset { /* small pill button */ }

/* Instance cards */
.instance-card { border: 1px solid var(--color-border); border-radius: var(--radius); }
.instance-card.enabled { border-color: var(--color-accent); }
.instance-header { display: flex; align-items: center; gap: 0.75rem; cursor: pointer; }
.instance-details { padding: 1rem; border-top: 1px solid var(--color-border); }

/* Results panel */
.result-total { font-size: 1.75rem; font-weight: 700; color: var(--color-accent); }
.result-row { display: flex; justify-content: space-between; padding: 0.5rem 0; }
.result-section { border-bottom: 1px solid var(--color-border); padding: 1rem 0; }

/* Timeline (Fristenrechner) */
.timeline { position: relative; padding-left: 2rem; }
.timeline-item { position: relative; padding: 1rem 0; }
.timeline-dot { width: 10px; height: 10px; border-radius: 50%; background: var(--color-accent); }
.timeline-line { position: absolute; left: 4px; top: 0; bottom: 0; width: 2px; background: var(--color-border); }
.timeline-date { font-weight: 600; font-variant-numeric: tabular-nums; }
.timeline-adjusted { color: #d97706; font-size: 0.85rem; }

/* Party badges */
.party-badge { font-size: 0.75rem; padding: 0.15rem 0.5rem; border-radius: 99px; }
.party-claimant { background: #dbeafe; color: #1e40af; }
.party-defendant { background: #fef3c7; color: #92400e; }
.party-court { background: #f3e8ff; color: #6b21a8; }
.party-both { background: #e5e7eb; color: #374151; }

/* Responsive */
@media (max-width: 768px) {
    .tool-grid { grid-template-columns: 1fr; }
    .tool-results { position: static; }
}

/* Print */
@media print {
    .header, .footer, .tool-input { display: none; }
    .tool-results { position: static; }
}

7. Bilingual Approach

Same pattern as existing pages — German primary, English secondary:

<h1>Prozesskostenrechner <span class="card-en">Cost Calculator</span></h1>

All labels, section headers, and result descriptions bilingual. Calculation logic language-independent (numbers are numbers).

Instance names bilingual:

  • "LG (Verletzung 1. Instanz)" / "Regional Court (Infringement 1st Instance)"
  • "Einspruchsverfahren" / "Opposition Proceedings"

Party labels: Kläger/Claimant, Beklagter/Defendant, Gericht/Court


8. Implementation Plan

Phase 1: Backend Calculation Engine (Go)

  1. internal/calc/fee_tables.go — All fee schedule data
  2. internal/calc/fees.go — GKG/RVG/PatKostG/UPC/EPA calculations
  3. internal/calc/holidays.go — Holiday computation + adjustment
  4. internal/calc/deadline_rules.go — All proceeding types + rules
  5. internal/calc/deadlines.go — Deadline calculation logic
  6. Unit tests for all calculations

Phase 2: API Endpoints (Go)

  1. internal/handlers/kostenrechner.go — POST /api/tools/kostenrechner + page serving
  2. internal/handlers/fristenrechner.go — POST /api/tools/fristenrechner + page serving
  3. Route registration in handlers.go

Phase 3: Frontend Pages (Bun/TSX)

  1. frontend/src/kostenrechner.tsx — Page shell with form structure
  2. frontend/src/fristenrechner.tsx — Page shell with wizard structure
  3. Header.tsx — Add tool navigation links
  4. CSS additions to global.css

Phase 4: Client-Side Interactivity (TypeScript)

  1. frontend/src/client/kostenrechner.ts — Form handling, API calls, result rendering
  2. frontend/src/client/fristenrechner.ts — Wizard flow, API calls, timeline rendering
  3. frontend/build.ts — Add new entrypoints and page renders

Phase 5: Integration

  1. Home page: Add "Werkzeuge" card section
  2. Navigation: Add tool links to header
  3. Print styles
  4. Mobile testing

Estimated Complexity

  • Phase 1: Medium — port KanzlAI's algorithm, add EPA fees, write tests
  • Phase 2: Low — straightforward JSON API handlers
  • Phase 3: Low — SSR shells following existing patterns
  • Phase 4: Medium — real-time UI interaction without React
  • Phase 5: Low — minor additions to existing components

Risk: Client-Side Complexity Without React

The main challenge is building interactive UIs (sliders, collapsible panels, real-time updates) with vanilla JS. The existing login.ts only handles form submission. The calculators need:

  • Checkbox toggling with conditional UI
  • Collapsible detail sections
  • Real-time result updates on any input change
  • Streitwert slider synced with text input

Mitigation: Keep all calculation on the server (Go API). Client JS only handles form state → API call → DOM update. No client-side calculation. This keeps the JS simple and the Go code testable.

Alternative considered: Moving to a reactive framework (Preact, Solid). Rejected — would require rebuilding existing pages and changing the build pipeline. Not worth it for two tool pages. If patholo grows to 5+ interactive pages, revisit.


9. Open Questions for Head

  1. EPA fee data: The official EPA fee schedule changes periodically. Should we hardcode the current (2024/2025) fees, or add a fee version selector like DE/UPC?
  2. Security for costs (Prozesskostensicherheit): KanzlAI has this feature. Include in v1 or defer?
  3. Should the inventor implement this? I have full context on the design. Alternatively, a coder worker can pick it up from this document.

10. Reference

  • KanzlAI source: /home/m/dev/KanzlAI/ — frontend/src/lib/costs/, backend/internal/services/fee_*
  • GKG Anlage 2: Official German court fee schedule (Gerichtskostengesetz)
  • RVG Anlage 2: Official German attorney fee schedule (Rechtsanwaltsvergütungsgesetz)
  • PatKostG: Patentkostengesetz (BPatG fee basis)
  • UPC Rules of Procedure: https://www.unified-patent-court.org/en/registry/rules-of-procedure
  • EPÜ (EPC): European Patent Convention, Art. 99, 108; Rules 71, 79
  • UPC Fee Schedule: Table of Fees (pre-2026 and 2026 revision)