feat(strommix): history-driven panels (residual load, dunkelflaute, neg-price, flow balance)

Aggregator route /api/strommix now reads three RustyCMS history-mode
collections in parallel — strommix_history_de, price_de_history,
crossborder_history_de — and projects derived metrics on top of the raw
upstream snapshots stored there:

- todayHourly: per-slot Last + Wind+Solar for the residual-load chart
- negPriceHoursYtd: count of YTD slots where DE-LU day-ahead < 0
- crossborderTodayGwh / netCrossborderGwhYtd / crossborderByCountryGwhYtd:
  GW × slot-hours integrated into a per-country GWh balance
- lastDunkelflaute / worstDunkelflauten: contiguous runs where
  (wind+solar)/load drops below 10 % for at least 1 h, top 5 by duration

All four are null-graceful — collections that the CMS hasn't backfilled
yet leave the corresponding panel hidden instead of breaking the widget.

Five new components in lib/components/blocks/strommix/:
- ResidualLoadChart.svelte — SVG line chart, no chart-lib dep
- CapacityFactorBars.svelte — live vs installed Wind/Wind-Off/Solar
- DunkelflauteCounter.svelte — last phase card + top-5 list
- NegPriceCounter.svelte — YTD hours + manual EinsMan compensation
- FlowBalanceTodayYtd.svelte — today + YTD saldo with per-country breakdown

Block schema additions (block-types.ts + strommix-default.json5 in
cms_content): installed_*_gw / installed_as_of for the capacity-factor
bars (BNetzA Marktstammdatenregister snapshot, manually maintained), and
einsman_costs_ytd_eur_mio / einsman_costs_as_of for the NegPrice panel
(BNetzA quarterly report figures, no API).
This commit is contained in:
Peter Meier
2026-05-07 13:06:30 +02:00
parent c4a09f03f4
commit 88514b065a
9 changed files with 1193 additions and 3 deletions
+15
View File
@@ -362,6 +362,21 @@ export interface LiveStrommixBlockData {
disclaimer_threshold_eur_mwh?: number;
/** Reference (resolved: { _slug, _type, ...page-fields } or just slug string). */
explanation_page?: string | { _slug?: string; title?: string };
// ---------------------------------------------------------------------
// Stammdaten (BNetzA Marktstammdatenregister, manuell gepflegt). Treiben
// den Live-vs-Installiert-Auslastungs-Bereich. Stand quartalsweise
// aktualisieren — die Werte bewegen sich um 13 GW pro Quartal.
// ---------------------------------------------------------------------
installed_wind_onshore_gw?: number;
installed_wind_offshore_gw?: number;
installed_solar_gw?: number;
/** Free-form Stand-Marker für die Stammdaten, z. B. "2025-Q4". */
installed_as_of?: string;
/** Optional: Hand-gepflegte EinsMan-Entschädigungssumme YTD (Mio €).
* BNetzA liefert das nur quartalsweise per PDF. Wenn nicht gesetzt,
* zeigt das Widget den Counter ohne Eurosumme. */
einsman_costs_ytd_eur_mio?: number;
einsman_costs_as_of?: string;
layout?: BlockLayout;
}