L1b/2: Kultur und Dateisystem plattformunabhaengig machen

Kultur - Ausgaben und Parsen haengen nicht mehr am Host:

- PdfExporter formatierte Betraege mit ToString("N2") ohne Formatanbieter,
  also CurrentCulture. Auf dem deutschen Desktop "1.234,56", in einem
  Container mit LANG=C "1,234.56" - dieselbe Zahl, fuer einen Leser eine
  andere. Fuer ein ausdruecklich pruefbares Dokument jetzt fest de-DE.
- CapitolTradesScraper.ParseDate nutzte DateOnly.TryParse ohne
  Formatanbieter. Das ist nicht theoretisch: gemessen wurde aus
  "2026-08-04" unter th-TH das Jahr 1483 (buddhistischer Kalender), unter
  fa-IR das Jahr 2647 (persischer Kalender), unter ar-SA schlug das Parsen
  ganz fehl. de-DE und en-US kommen mit ISO klar - genau deshalb faellt so
  etwas auf dem Entwicklungsrechner nie auf. Jetzt TryParseExact mit
  InvariantCulture; ein Formatwechsel der Quelle faellt damit auf, statt
  still ein falsches Datum zu erzeugen. Regressionstest ueber vier Kulturen.
- IBKRGatewayService baute den Query-Parameter mit .ToString().ToLower()
  (Tuerkisch-I) - jetzt fest "true"/"false".

PDF-Schriften: PDFsharp 6 loest auf Nicht-Windows-Plattformen nichts von
selbst auf, "Segoe UI" gibt es dort nicht - der Export waere zur Laufzeit
gescheitert. Neuer DocumentFontResolver: unter Windows bleibt die Plattform
zustaendig (unveraenderte Optik), auf Linux wird eine freie Systemschrift
gesucht (DejaVu/Liberation/Noto/FreeSans). Bewusst keine Schrift im Repo -
das erspart eine Lizenzfrage; fehlt sie, nennt die Fehlermeldung das zu
installierende Paket.

BackupWorker:
- Suchte "mysqldump.exe" in C:\Program Files\... und splittete PATH mit ';'.
  Auf Linux ist das Trennzeichen ':' - der gesamte PATH waere als ein
  Eintrag gelesen worden. Jetzt Path.PathSeparator, plattformabhaengige
  Suchpfade und zusaetzlich "mariadb-dump" (MariaDB hat mysqldump ab 10.5
  umbenannt).
- Das DB-Passwort stand als Kommandozeilenargument im Prozessbaum. Unter
  Linux ist /proc/<pid>/cmdline fuer jeden lokalen Nutzer lesbar - das waere
  eine neue Offenlegung gewesen, die es unter Windows so nicht gab. Jetzt
  ueber MYSQL_PWD, nur an den Kindprozess vererbt. Argumente einzeln statt
  als Zeichenkette (kein Quoting-Problem bei Pfaden mit Leerzeichen).

Verifiziert: 188 Tests gruen (+5), Build 0 Fehler/0 Warnungen, Core + 3
Module + Tests bauen fuer linux-x64, --smoke-ui konstruiert alle 7 Fenster.

Offen aus L1b und nach L2 verschoben: IAppPaths (Logs/Backups/settings.json/
master.key liegen neben der Binaerdatei; unter /opt ist das nicht schreibbar).
Gehoert zum Daemon, wo die Pfade tatsaechlich gebraucht werden.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Richard
2026-08-06 22:58:10 +02:00
co-authored by Claude Opus 5
parent d8273c3a1e
commit 8b9b993d1d
6 changed files with 256 additions and 38 deletions
@@ -1,3 +1,4 @@
using System.Globalization;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
@@ -121,7 +122,7 @@ public class CapitolTradesScraper
if (match.Success)
{
var total = int.Parse(match.Groups[1].Value);
var total = int.Parse(match.Groups[1].Value, CultureInfo.InvariantCulture);
_logger.Info("CT", $"GetTotalPagesAsync: {total} Seiten gefunden.");
return total;
}
@@ -326,11 +327,18 @@ public class CapitolTradesScraper
return null;
}
/// <summary>
/// Datum aus dem RSC-Stream ("2026-08-04T…"). Bewusst <c>TryParseExact</c> mit fester
/// Invariant-Kultur: <c>TryParse</c> ohne Formatanbieter hätte die Kultur des Rechners benutzt
/// und damit je nach Host anders geraten. Ändert die Quelle ihr Format, soll das <b>auffallen</b>
/// (null → Satz wird verworfen) statt still zu einem falschen Datum zu werden.
/// </summary>
private static DateOnly? ParseDate(string? s)
{
if (string.IsNullOrEmpty(s)) return null;
var datePart = s.Length > 10 ? s[..10] : s;
return DateOnly.TryParse(datePart, out var d) ? d : null;
return DateOnly.TryParseExact(datePart, "yyyy-MM-dd", CultureInfo.InvariantCulture,
DateTimeStyles.None, out var d) ? d : null;
}
private static string CapFirst(string s)