Demo branch for STRABAG client acquisition. No backward compatibility constraints.
STRABAG receives electricity invoices from many Austrian providers across hundreds of sites. Their controlling team needs to:
Current Orcha ingestion treats energy invoices as generic invoices, losing domain-specific structure (meter readings, tariff categories, consumption comparisons).
All Austrian Strom invoices follow a consistent pattern:
Key identifiers: Zählpunkt (metering point ID), Netzebene (grid level), Anschlusswert/Anmeldeleistung (connection capacity), RC-KST codes (STRABAG cost centers).
Add energy-details as a sibling to line-items in structured data. Generic line items
remain for accounting (debit/credit accounts, cost centers). The energy-specific UI reads
from energy-details.
Small overlap between cost-category positions and line-items is intentional — line items carry accounting metadata, energy positions carry domain metadata (tariff rates, consumption basis).
energy-details:energy-details
{:metering-points
[{:zaehlpunkt "AT0071000902000000000002124420101"
:netzebene 5
:anschlusswert {:value 3000.0 :unit "kW"}
:tarif "BK Power Klagenfurt"
:netzbetreiber "Energie Klagenfurt GmbH"
:address "Leystraße 122, 1200 Wien"
:meters
[{:number "70275998"
:readings
[{:register "HT"
:period {:from "2025-06-01" :to "2025-06-30"}
:stand-alt 104.46
:stand-neu 116.82
:differenz 12.37
:ableseart "NBE"
:faktor 3200
:verbrauch {:value 39580.80 :unit "kWh"}}]}]}]
:consumption-summary
{:current {:value 47120.00 :unit "kWh" :days 30 :per-day 1570.67}
:prior {:value 60617.60 :unit "kWh" :days 31 :per-day 1955.41}
:delta -13497.60}
:cost-categories
[{:category "energie"
:subtotal 9457.45
:positions
[{:description "Energie"
:period {:from "2025-06-01" :to "2025-06-30"}
:basis {:value 47120.00 :unit "kWh"}
:days 30
:rate {:value 19.737 :unit "Ct/kWh"}
:amount 9300.07}]}
{:category "netz" :subtotal 5936.50 :positions [...]}
{:category "abgaben" :subtotal 2349.03 :positions [...]}]}
Design decisions:
metering-points is a vector (multi-Zählpunkt support, though samples are all single)readings per meter per register — handles HT/NT, Blindstrom, Leistungsspitze (MAX)cost-categories uses 3 standard buckets: "energie", "netz", "abgaben"rate and basis capture units — rates come in Ct/kWh, €/Jahr, €/kW, Ct/Tag, €/TagClassification: Add "energy-invoice" to invoice-subtypes. The existing classification
step already produces invoice-subtype — the LLM detects Zählpunkt, meter readings,
Energie/Netz/Abgaben structure and classifies accordingly.
Extraction: When invoice-subtype is "energy-invoice", include energy-specific
extraction instructions in the prompt. The prompt instructs the LLM to populate
energy-details alongside standard fields and line items.
Line items: Still extracted in parallel from the same cost positions. They carry accounting metadata (debit/credit accounts, cost centers) while energy-details positions carry domain metadata.
Validation: Energy-specific rules:
(stand-neu - stand-alt) × faktor = verbrauch per readingRenders when invoice-subtype = "energy-invoice" and energy-details is present.
Replaces the generic line items section.
Per metering point:
Three collapsible sections (Energie, Netz, Abgaben/Steuern):
Energy-specific validations at the top:
Generic accounting section (debit/credit accounts, cost centers, accrual) still renders
below from line-items.
New route — entry point for energy controlling. Accessible from main navigation.
4 aggregate numbers, update with filters:
Sortable, filterable table of all metering points across ingested energy invoices:
| Column | Source |
|---|---|
| Zählpunkt | energy-details.metering-points[0].zaehlpunkt |
| Standort | energy-details.metering-points[0].address or recipient address |
| Netzebene | energy-details.metering-points[0].netzebene |
| Zeitraum | Invoice billing period |
| Verbrauch (kWh) | consumption-summary.current.value |
| Kosten (€ netto) | Invoice subtotal |
| €/kWh | Computed: subtotal / consumption |
| Δ Vorperiode | consumption-summary.delta as percentage |
Data source: query across documents where invoice-subtype = 'energy-invoice', reading
from JSONB structured_data column. No separate tables.