2c17171e77
Reviewed the data service against mfr_interface_description.md. The OData entity sync already follows @odata.nextLink and now inherits the MFR client's transient retry + timeout, so it is spec-aligned. Reliability/performance improvements: - MFRClient.GetFile no longer news up an HttpClient per call (socket-exhaustion risk); added GetFileAsync backed by one shared static HttpClient with per-request auth, and GetFile delegates to it. - GetInvoiceFiles_async now downloads + stores invoice PDFs in parallel (bounded concurrency 4) via Parallel.ForEachAsync instead of sequentially. - Threaded CancellationToken from the MfrSync job through UpdateIfNecessary_async/ UpdateRequested_async/GetInvoiceFiles_async and the entity-sync loops for graceful shutdown (cooperative checks between iterations). Entity-table sync is left sequential on purpose (referential ordering by updateneed). IFdsMfr sync methods gained optional CancellationToken params (default) — the web app only uses the read methods, so this stays source-compatible with Fuchs. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>