<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Architektur im Detail on dsyr.DataBridge</title><link>https://databridge.docs.dsyr.de/entwicklung/architektur/</link><description>Recent content in Architektur im Detail on dsyr.DataBridge</description><generator>Hugo</generator><language>de</language><atom:link href="https://databridge.docs.dsyr.de/entwicklung/architektur/index.xml" rel="self" type="application/rss+xml"/><item><title>Systemkontext und Prinzipien</title><link>https://databridge.docs.dsyr.de/entwicklung/architektur/systemkontext/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://databridge.docs.dsyr.de/entwicklung/architektur/systemkontext/</guid><description>&lt;h2 id="zweck"&gt;Zweck&lt;/h2&gt;&#10;&lt;p&gt;Die dsyr.DataBridge ist eine serverlose &lt;strong&gt;Datenintegrations-Bridge&lt;/strong&gt; auf Azure Functions&#10;(.NET 10, Isolated Worker). Sie synchronisiert Datensätze nahezu in Echtzeit zwischen&#10;heterogenen Geschäftssystemen, ohne diese direkt zu koppeln. Quelle und Ziel sind über&#10;&lt;strong&gt;Azure Service Bus&lt;/strong&gt; entkoppelt, Änderungen werden über Watermarks change-getrieben&#10;übertragen.&lt;/p&gt;&#10;&lt;p&gt;Die Bridge hält &lt;strong&gt;keine Fachdaten&lt;/strong&gt; dauerhaft. Sie speichert nur Konfiguration und&#10;Synchronisationsstände in Azure Table Storage; Nachrichten liegen transient im Service Bus.&lt;/p&gt;&#10;&lt;h2 id="hauptfunktionen"&gt;Hauptfunktionen&lt;/h2&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Funktion&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Beschreibung&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Change Detection&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Periodisches Pollen der Quellsysteme (Timer &lt;code&gt;GetChanges&lt;/code&gt;, optional Durable-Orchestrierung)&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Asynchrone Entkopplung&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Erkannte Änderungen landen als Nachrichten in priorisierten Queues (Low / Standard / High)&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Feld-Mapping und Transformation&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Konfigurierbare Zuordnung inkl. Typ-Coercion, Default-Werten, Option-Mapping, Lookups, Source-/Target-Operationen&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Multi-System-Konnektivität&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;D365 BC, CE/Dataverse, NAV, generische REST-APIs über OpenAPI-Spezifikation, SQL-Datenbanken (MSSQL, PostgreSQL, MySQL, Oracle)&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Idempotente Zielverarbeitung&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Upsert/Delete über Primär-, Custom- oder Filter-Keys, mehrere Schlüssel mit Rangfolge&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Aktions-Jobs&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;InvokeAction&lt;/code&gt; ruft benannte Nicht-CRUD-Endpunkte auf (OpenAPI &lt;code&gt;operationId&lt;/code&gt;, CE &lt;code&gt;OrganizationRequest&lt;/code&gt;)&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Watermarking&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Persistierter Stand pro Job, nur neue Änderungen werden übertragen&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Response-Jobs&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Rückschreiben von im Ziel erzeugten Schlüsseln in die Quelle&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Diagnose und KI-Anbindung&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;HTTP-Endpunkte (&lt;code&gt;CheckList&lt;/code&gt;, &lt;code&gt;Validate&lt;/code&gt;, &lt;code&gt;JobApi&lt;/code&gt;, &lt;code&gt;MappingApi&lt;/code&gt;) und ein read-only MCP-Server&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Selektive Telemetrie&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Gepuffertes Logging pro Invocation, Dependency-Sampling, pre-aggregierte Custom Metrics&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Fehlerresilienz&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Backoff-Retry, Transitive-Queues, Dead-Letter-Queues, Alerts&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h2 id="zielgruppen"&gt;Zielgruppen&lt;/h2&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Zielgruppe&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Nutzen&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Integrations-/ERP-Berater&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Konfigurieren Connections, Jobs und Mappings in Table Storage, ohne Code zu deployen&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Cloud-/DevOps-Engineers&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Deployen via Bicep oder Marketplace, betreiben und überwachen die Function App&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Entwickler&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Erweitern Connectoren, Resolver und Source-Operationen in &lt;code&gt;DataBridge.Core&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;KI-Assistenten&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Lesen Konfiguration und Queue-Zustand über den MCP-Server&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h2 id="architekturprinzipien"&gt;Architekturprinzipien&lt;/h2&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Prinzip&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Umsetzung&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Separation of Concerns&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Host (Trigger) ↔ Core (Logik) ↔ Connectoren (System-Anbindung) ↔ Resolver/Mapper (Transformation)&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Configuration over Code&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Connections, Jobs, Mappings, Watermarks liegen in Table Storage&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Lazy Initialization&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Services sind DI-Singletons; die Konfiguration wird einmalig und thread-sicher beim ersten Aufruf geladen&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Asynchrone Entkopplung&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Service Bus zwischen Lese- und Schreibseite; jede Nachricht wird isoliert verarbeitet&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Idempotenz&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Upsert/Delete über definierte Target-Keys&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Resilienz&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Backoff, Lock-Renewal, Transitive-Queues, Dead-Letter-Queues, &lt;code&gt;DeadLetterMover&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Erweiterbarkeit&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Source-Operation-Handler werden per Reflection registriert; Connectoren über &lt;code&gt;ConnectionTypes&lt;/code&gt; gemappt; Resolver-Registries je Connector als statische &lt;code&gt;FrozenDictionary&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Observability first&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Gepuffertes Logging, Requests und Exceptions nie gesampelt, Custom Metrics ohne Sampling&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h2 id="die-zwei-phasen"&gt;Die zwei Phasen&lt;/h2&gt;&#10;&lt;pre class="mermaid"&gt;flowchart LR&#10; SRC[&amp;#34;Quellsystem&amp;#34;] --&amp;gt;|&amp;#34;1. Erkennung (Pull)&amp;#34;| FUNC1[&amp;#34;GetChanges&amp;lt;br/&amp;gt;oder Orchestrator &amp;#43; Activity&amp;#34;]&#10; FUNC1 --&amp;gt;|&amp;#34;QueueMessage&amp;#34;| SB[(&amp;#34;Service Bus&amp;lt;br/&amp;gt;Low / Standard / High&amp;#34;)]&#10; SB --&amp;gt;|&amp;#34;2. Verarbeitung (Push)&amp;#34;| FUNC2[&amp;#34;Process*QueueItems&amp;#34;]&#10; FUNC2 --&amp;gt;|&amp;#34;Upsert / Delete / Action&amp;#34;| TGT[&amp;#34;Zielsystem&amp;#34;]&#10; FUNC1 -.-&amp;gt;|&amp;#34;Watermark&amp;#34;| WM[(&amp;#34;watermark&amp;#34;)]&#10; FUNC2 -.-&amp;gt;|&amp;#34;Response-Job / Transitive / Ignored&amp;#34;| SB&lt;/pre&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Erkennung:&lt;/strong&gt; &lt;code&gt;GetChanges&lt;/code&gt; (Timer) liest Änderungen aus den Quellsystemen und&#10;enqueued sie. Die Durable-Orchestrierung ist eine Alternative, die nur per HTTP&#10;gestartet wird und im Regelbetrieb nicht läuft.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Verarbeitung:&lt;/strong&gt; Drei Service-Bus-Trigger (je Priorität) dequeuen und schreiben ins&#10;Zielsystem.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;Diese Entkopplung erlaubt unabhängige Skalierung beider Seiten und überbrückt temporäre&#10;Ausfälle des Zielsystems. Details in &lt;a href="../datenfluesse/"&gt;Datenflüsse&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Infrastruktur (Bicep)</title><link>https://databridge.docs.dsyr.de/entwicklung/architektur/infrastruktur/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://databridge.docs.dsyr.de/entwicklung/architektur/infrastruktur/</guid><description>&lt;p&gt;Einstiegspunkt ist &lt;code&gt;bicep/main.bicep&lt;/code&gt;. Das Deployment läuft im Scope einer bestehenden&#10;Resource Group (Bicep-Default, kein explizites &lt;code&gt;targetScope&lt;/code&gt;), im Modus Incremental.&#10;Die Parameter aus Anwendersicht sind unter&#10;&lt;a href="https://databridge.docs.dsyr.de/docs/einrichtung/installation/"&gt;Installation&lt;/a&gt; beschrieben; hier geht es um den inneren&#10;Aufbau.&lt;/p&gt;&#10;&lt;h2 id="module-und-parameterfluss"&gt;Module und Parameterfluss&lt;/h2&gt;&#10;&lt;pre class="mermaid"&gt;flowchart TD&#10; MAIN[&amp;#34;main.bicep&amp;#34;]&#10;&#10; SA[&amp;#34;storageaccount.bicep&amp;#34;]&#10; AI[&amp;#34;applicationinsights.bicep&amp;#34;]&#10; ASP[&amp;#34;appserviceplan.bicep&amp;#34;]&#10; SB[&amp;#34;servicebus.bicep&amp;#34;]&#10; ALERT[&amp;#34;metricalerts.bicep&amp;lt;br/&amp;gt;if enableAlerts&amp;#34;]&#10; DASH[&amp;#34;dashboard.bicep&amp;lt;br/&amp;gt;if enableGrafanaDashboard&amp;#34;]&#10; FUNC[&amp;#34;azurefunction.bicep&amp;#34;]&#10; ROLES[&amp;#34;roleassignments.bicep&amp;lt;br/&amp;gt;if enableManagedIdentity&amp;#34;]&#10;&#10; MAIN --&amp;gt; SA &amp;amp; AI &amp;amp; ASP &amp;amp; SB &amp;amp; ALERT &amp;amp; DASH &amp;amp; FUNC &amp;amp; ROLES&#10;&#10; SA --&amp;gt;|&amp;#34;id, name&amp;#34;| FUNC&#10; AI --&amp;gt;|&amp;#34;connectionString, id&amp;#34;| FUNC&#10; AI --&amp;gt;|&amp;#34;id&amp;#34;| DASH&#10; ASP --&amp;gt;|&amp;#34;id&amp;#34;| FUNC&#10; SB --&amp;gt;|&amp;#34;authorizationRuleId, name&amp;#34;| FUNC&#10; SB --&amp;gt;|&amp;#34;id&amp;#34;| ALERT&#10; FUNC --&amp;gt;|&amp;#34;principalId&amp;#34;| ROLES&#10; SA --&amp;gt;|&amp;#34;id&amp;#34;| ROLES&#10; SB --&amp;gt;|&amp;#34;id&amp;#34;| ROLES&lt;/pre&gt;&#10;&lt;p&gt;Die Abhängigkeiten ergeben sich über Modul-Outputs, es gibt keine Zyklen. Zusätzlich legt&#10;&lt;code&gt;main.bicep&lt;/code&gt; ein leeres Tracking-Deployment für die Microsoft-Partner-Attribution an.&lt;/p&gt;</description></item><item><title>Anwendungsarchitektur</title><link>https://databridge.docs.dsyr.de/entwicklung/architektur/anwendung/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://databridge.docs.dsyr.de/entwicklung/architektur/anwendung/</guid><description>&lt;h2 id="projekte-srcdatabridgeslnx"&gt;Projekte (&lt;code&gt;src/DataBridge.slnx&lt;/code&gt;)&lt;/h2&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Projekt&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Typ&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Zweck&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;DataBridge&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Azure Functions, net10.0, isolated&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Host: Trigger, DI, Telemetrie-Bootstrap, Durable Functions, MCP-Endpunkt&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;DataBridge.Core&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Class Library&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Services, Connectoren, Resolver, Mapper, Source-Operationen, Modelle, Telemetrie&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;DataBridge.Test&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;xUnit v3 + Moq (Microsoft Testing Platform)&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Unit-Tests; Ordnerstruktur spiegelt &lt;code&gt;DataBridge.Core&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;DeadLetterMover&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Konsolenanwendung&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Requeue von Dead-Letter-Nachrichten&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h2 id="dependency-injection-programcs"&gt;Dependency Injection (&lt;code&gt;Program.cs&lt;/code&gt;)&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;FunctionsApplication.CreateBuilder(args)&lt;/code&gt; (moderner Einstiegspunkt statt &lt;code&gt;new HostBuilder()&lt;/code&gt;),&#10;mit &lt;code&gt;builder.UseMiddleware&amp;lt;InvocationContextMiddleware&amp;gt;()&lt;/code&gt;, die jede Invocation in einen&#10;&lt;code&gt;InvocationContext&lt;/code&gt; einbettet und am Ende das gepufferte Log flusht.&lt;/li&gt;&#10;&lt;li&gt;Application Insights über &lt;code&gt;AddApplicationInsightsTelemetryWorkerService&lt;/code&gt;, Adaptive&#10;Sampling &lt;strong&gt;deaktiviert&lt;/strong&gt;; &lt;code&gt;DependencySamplingProcessor&lt;/code&gt; per&#10;&lt;code&gt;AddApplicationInsightsTelemetryProcessor&lt;/code&gt;. Der Standard-AI-Logger-Provider ist auf&#10;&lt;code&gt;LogLevel.None&lt;/code&gt; gesetzt, einziger Pfad nach AI ist der &lt;code&gt;BufferingLoggerProvider&lt;/code&gt;.&lt;/li&gt;&#10;&lt;li&gt;Alle Services sind &lt;strong&gt;Singletons&lt;/strong&gt;: &lt;code&gt;MetricsService&lt;/code&gt;, &lt;code&gt;SettingsService&lt;/code&gt;, &lt;code&gt;StorageService&lt;/code&gt;,&#10;&lt;code&gt;ConnectionService&lt;/code&gt;, &lt;code&gt;MappingService&lt;/code&gt;, &lt;code&gt;JobService&lt;/code&gt;, &lt;code&gt;WatermarkService&lt;/code&gt;,&#10;&lt;code&gt;ServiceBusService&lt;/code&gt;, &lt;code&gt;ProcessQueueMessageService&lt;/code&gt;,&#10;&lt;code&gt;ProcessJobsForRetrievalInOrderService&lt;/code&gt;, &lt;code&gt;CheckListService&lt;/code&gt;, &lt;code&gt;InitializationService&lt;/code&gt;,&#10;&lt;code&gt;McpToolService&lt;/code&gt;.&lt;/li&gt;&#10;&lt;li&gt;Log-Level: Kategorien &lt;code&gt;DataBridge&lt;/code&gt; und &lt;code&gt;Function&lt;/code&gt; auf &lt;code&gt;Trace&lt;/code&gt;, der Puffer-Provider&#10;filtert auf &lt;code&gt;Debug&lt;/code&gt;.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="hostjson"&gt;&lt;code&gt;host.json&lt;/code&gt;&lt;/h2&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Bereich&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Einstellung&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Wert&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Allgemein&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;functionTimeout&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;10 min&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;AI-Sampling&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;excludedTypes&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;Request;Exception&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Durable&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;hubName&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;DurableFunctionsHub&lt;/code&gt;, Azure-Storage-Provider, Distributed Tracing V2&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Storage Queues&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;batchSize&lt;/code&gt; / &lt;code&gt;maxDequeueCount&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;1 / 5 (nur für Durable relevant)&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Service Bus&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;autoCompleteMessages&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Service Bus&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;maxConcurrentCalls&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;12&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Service Bus&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;maxAutoLockRenewalDuration&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;5 min&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h2 id="functions"&gt;Functions&lt;/h2&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Function&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Trigger&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Aufgabe&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;GetChanges&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Timer &lt;code&gt;%GetChangesTimerExpression%&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Initialisiert thread-sicher über &lt;code&gt;InitializationService&lt;/code&gt; und ruft &lt;code&gt;ProcessJobsForRetrievalInOrderService.Execute&lt;/code&gt; auf&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;ProcessStandardQueueItems&lt;/code&gt;, &lt;code&gt;ProcessHighPriorityQueueItems&lt;/code&gt;, &lt;code&gt;ProcessLowPriorityQueueItems&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Service Bus &lt;code&gt;sbqexport&lt;/code&gt;, &lt;code&gt;sbqhighexport&lt;/code&gt;, &lt;code&gt;sbqlowexport&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Verarbeiten je eine Nachricht end-to-end über &lt;code&gt;ProcessQueueMessageService.Execute&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;ExecuteJob&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;HTTP POST&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Stößt einen Job per Name über &lt;code&gt;ProcessJobsForRetrievalInOrderService.ExecuteByJobName&lt;/code&gt; an&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;ExecuteHttpRequest&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;HTTP POST&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Ad-hoc-HTTP-GET mit eigenem &lt;code&gt;HttpClient&lt;/code&gt; (NTLM oder anonym), unabhängig von den Connectoren&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;GetInfo&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;HTTP GET&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Assembly-Version&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;CheckList&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;HTTP GET&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;InitializationService.CheckAsync()&lt;/code&gt;: Mappings gegen Live-Metadaten der Systeme&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;Validate&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;HTTP GET&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Erzwingt die Initialisierung, liefert das Fehlerlog&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;GetJobs&lt;/code&gt;, &lt;code&gt;GetJobByRowKey&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;HTTP GET &lt;code&gt;job&lt;/code&gt;, &lt;code&gt;job/{rowKey}&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Geladene Job-Konfiguration&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;GetMappings&lt;/code&gt;, &lt;code&gt;GetMappingByRowKey&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;HTTP GET &lt;code&gt;mapping&lt;/code&gt;, &lt;code&gt;mapping/{name}&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Geladene Mappings, Suche per Name mit Fallback auf RowKey&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;Mcp&lt;/code&gt;, &lt;code&gt;McpGet&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;HTTP POST/GET &lt;code&gt;mcp&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;MCP-Server; GET antwortet mit 405, weil SSE-Streams nicht unterstützt werden&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;StartGetChangesOrchestration&lt;/code&gt;, &lt;code&gt;GetChangesOrchestrator&lt;/code&gt;, &lt;code&gt;GetChangesActivity&lt;/code&gt;, &lt;code&gt;JobState&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;HTTP, Orchestration, Activity, Entity&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Optionale Durable-Variante der Erkennung&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;Details zu Request und Response: &lt;a href="../api-referenz/"&gt;API-Referenz&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>API- und Nachrichten-Referenz</title><link>https://databridge.docs.dsyr.de/entwicklung/architektur/api-referenz/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://databridge.docs.dsyr.de/entwicklung/architektur/api-referenz/</guid><description>&lt;h2 id="authentifizierung"&gt;Authentifizierung&lt;/h2&gt;&#10;&lt;p&gt;Alle HTTP-Functions verwenden &lt;code&gt;AuthorizationLevel.Function&lt;/code&gt;. Der Funktionsschlüssel wird&#10;als Query-Parameter &lt;code&gt;code&lt;/code&gt; oder Header &lt;code&gt;x-functions-key&lt;/code&gt; übergeben. Es gibt keine&#10;Easy-Auth- oder Entra-Konfiguration im Deployment. Timer-, Service-Bus- und&#10;Durable-Trigger haben keinen HTTP-Endpunkt.&lt;/p&gt;&#10;&lt;p&gt;Routen ohne &lt;code&gt;Route&lt;/code&gt;-Attribut folgen der Konvention &lt;code&gt;/api/&amp;lt;FunctionName&amp;gt;&lt;/code&gt;.&lt;/p&gt;&#10;&lt;h2 id="http-endpunkte"&gt;HTTP-Endpunkte&lt;/h2&gt;&#10;&lt;h3 id="get-apigetinfo"&gt;&lt;code&gt;GET /api/GetInfo&lt;/code&gt;&lt;/h3&gt;&#10;&lt;p&gt;Liefert die Assembly-Version, keine Gesundheitsprüfung.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{ &lt;span style="color:#f92672"&gt;&amp;#34;Version&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;2.3.2026.0926&amp;#34;&lt;/span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="post-apiexecutejob"&gt;&lt;code&gt;POST /api/ExecuteJob&lt;/code&gt;&lt;/h3&gt;&#10;&lt;p&gt;Stößt einen Job aus der Tabelle &lt;code&gt;jobs&lt;/code&gt; manuell an (Erkennungsphase).&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{ &lt;span style="color:#f92672"&gt;&amp;#34;JobName&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;lt;RowKey des Jobs&amp;gt;&amp;#34;&lt;/span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Ablauf: &lt;code&gt;JobName&lt;/code&gt; prüfen → &lt;code&gt;EnsureInitializedAsync&lt;/code&gt; → &lt;code&gt;ProcessJobForRetrieval&lt;/code&gt;.&#10;Antwort &lt;code&gt;200 OK&lt;/code&gt;; Fehler propagieren als 500. Der Aufruf läuft ohne Job-Locking parallel&#10;zum Timer, siehe &lt;a href="../datenfluesse/#watermark-logik"&gt;Datenflüsse → Watermark&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Datenflüsse</title><link>https://databridge.docs.dsyr.de/entwicklung/architektur/datenfluesse/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://databridge.docs.dsyr.de/entwicklung/architektur/datenfluesse/</guid><description>&lt;p&gt;Die konzeptuelle Beschreibung steht unter &lt;a href="https://databridge.docs.dsyr.de/docs/ueberblick/wie-es-funktioniert/"&gt;Wie es funktioniert&lt;/a&gt;.&#10;Hier folgen die Abläufe auf Klassenebene.&lt;/p&gt;&#10;&lt;h2 id="erkennung-timer"&gt;Erkennung (Timer)&lt;/h2&gt;&#10;&lt;pre class="mermaid"&gt;sequenceDiagram&#10; autonumber&#10; participant Timer as GetChanges (Timer)&#10; participant Init as InitializationService&#10; participant PJ as ProcessJobsForRetrievalInOrderService&#10; participant Job as JobService&#10; participant WM as WatermarkService&#10; participant Conn as Source-Connector&#10; participant SBS as ServiceBusService&#10; participant SB as Service Bus&#10;&#10; Timer-&amp;gt;&amp;gt;Init: EnsureInitializedAsync()&#10; Note over Init: einmalig: Storage → Connections → Mappings → Jobs&#10; Timer-&amp;gt;&amp;gt;PJ: Execute()&#10; PJ-&amp;gt;&amp;gt;Job: GetJobsToRun()&#10; Note over Job,WM: GetAllWatermarks() (Bulk) für LastCronRun&#10; loop je Job nach Order&#10; PJ-&amp;gt;&amp;gt;WM: GetWatermarkByJobName(job)&#10; PJ-&amp;gt;&amp;gt;Conn: RetrieveChangesAsync(mapping, job, watermark, filter)&#10; loop seitenweise&#10; Conn--&amp;gt;&amp;gt;PJ: QueueMessage (serialisiert)&#10; PJ-&amp;gt;&amp;gt;SBS: AddMessageOrSendAsync(msg, priority)&#10; alt Batch voll (200) oder Größenlimit&#10; SBS-&amp;gt;&amp;gt;SB: SendMessagesAsync(batch)&#10; end&#10; PJ-&amp;gt;&amp;gt;PJ: lastChangeTracker = msg.ChangeTracker&#10; end&#10; PJ-&amp;gt;&amp;gt;SBS: FlushBatch()&#10; PJ-&amp;gt;&amp;gt;WM: UpdateWatermarkByJobName(newWatermark, lastCronRun)&#10; end&lt;/pre&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Die Serialisierung (Key-Aufbau → Feld-Mappings → Source-Operationen / Resolver) passiert&#10;im Connector (&lt;code&gt;ConnectorBase.Serialize&lt;/code&gt;).&lt;/li&gt;&#10;&lt;li&gt;Die Watermark wird &lt;strong&gt;erst am Ende&lt;/strong&gt; eines Jobs geschrieben. Bricht der Lauf vorher ab,&#10;wird beim nächsten Lauf erneut ab dem alten Stand gelesen; &lt;code&gt;SkipOutdatedMessages&lt;/code&gt; fängt&#10;Doppel-Nachrichten im Ziel ab.&lt;/li&gt;&#10;&lt;li&gt;Bei reinem Zeitstempel-Vorrücken ohne fachliche Änderung wird &lt;code&gt;JobActionType.TimeStamp&lt;/code&gt;&#10;verwendet.&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;MetricsService&lt;/code&gt; zählt &lt;code&gt;ChangesDetected&lt;/code&gt; je Job.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="erkennung-durable"&gt;Erkennung (Durable)&lt;/h2&gt;&#10;&lt;pre class="mermaid"&gt;sequenceDiagram&#10; autonumber&#10; participant HTTP as StartGetChangesOrchestration&#10; participant Orch as GetChangesOrchestrator&#10; participant State as JobState (Entity)&#10; participant Act as GetChangesActivity&#10; participant Conn as Source-Connector&#10; participant SBS as ServiceBusService&#10;&#10; HTTP--&amp;gt;&amp;gt;HTTP: 202 &amp;#43; InstanceId&#10; loop je Job aus GetJobsToRun&#10; Orch-&amp;gt;&amp;gt;State: InProgress(jobName)?&#10; alt in Bearbeitung&#10; Orch-&amp;gt;&amp;gt;Orch: überspringen&#10; else&#10; Orch-&amp;gt;&amp;gt;State: Add(jobName)&#10; loop do … while HasMoreRecord&#10; Orch-&amp;gt;&amp;gt;Act: CallActivity(JobActivityParam)&#10; Act-&amp;gt;&amp;gt;Conn: RetrieveChangesAsync(…, MaxBatchSize=3)&#10; Act-&amp;gt;&amp;gt;SBS: SendMessage(record, priority)&#10; Act--&amp;gt;&amp;gt;Orch: Page, Cookie, Watermark, HasMoreRecord&#10; end&#10; Orch-&amp;gt;&amp;gt;State: Remove(jobName)&#10; end&#10; end&lt;/pre&gt;&#10;&lt;p&gt;Der Durable-Pfad persistiert die Watermark nicht und ist im Timer-Betrieb nicht aktiv.&lt;/p&gt;</description></item><item><title>Abhängigkeiten</title><link>https://databridge.docs.dsyr.de/entwicklung/architektur/abhaengigkeiten/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://databridge.docs.dsyr.de/entwicklung/architektur/abhaengigkeiten/</guid><description>&lt;h2 id="plattform"&gt;Plattform&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;net10.0&lt;/code&gt; in allen Projekten, &lt;code&gt;ImplicitUsings&lt;/code&gt; und &lt;code&gt;Nullable&lt;/code&gt; aktiv.&lt;/li&gt;&#10;&lt;li&gt;Azure Functions v4, Isolated Worker, &lt;code&gt;OutputType=Exe&lt;/code&gt;.&lt;/li&gt;&#10;&lt;li&gt;Tests auf xUnit v3 mit Microsoft Testing Platform. Aufruf mit&#10;&lt;code&gt;dotnet test --project …&lt;/code&gt;; das Positionsargument funktioniert nicht mehr.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="projekte"&gt;Projekte&lt;/h2&gt;&#10;&lt;pre class="mermaid"&gt;flowchart LR&#10; HOST[&amp;#34;DataBridge (Host)&amp;#34;] --&amp;gt; CORE[&amp;#34;DataBridge.Core&amp;#34;]&#10; DLM[&amp;#34;DeadLetterMover&amp;#34;] --&amp;gt; CORE&#10; TEST[&amp;#34;DataBridge.Test&amp;#34;] --&amp;gt; CORE&#10; TEST --&amp;gt; HOST&lt;/pre&gt;&#10;&lt;h2 id="nuget-pakete"&gt;NuGet-Pakete&lt;/h2&gt;&#10;&lt;p&gt;Die Versionen werden zentral in &lt;code&gt;src/Directory.Packages.props&lt;/code&gt; gepflegt (Central Package&#10;Management); die &lt;code&gt;.csproj&lt;/code&gt;-Dateien referenzieren Pakete nur noch ohne &lt;code&gt;Version&lt;/code&gt;. Ein Update&#10;passiert also an genau einer Stelle.&lt;/p&gt;</description></item><item><title>Fähigkeiten-Katalog</title><link>https://databridge.docs.dsyr.de/entwicklung/architektur/capabilities/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://databridge.docs.dsyr.de/entwicklung/architektur/capabilities/</guid><description>&lt;h2 id="integration-und-datenfluss"&gt;Integration und Datenfluss&lt;/h2&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Fähigkeit&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Umsetzung&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Change Detection (Pull)&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;GetChanges&lt;/code&gt; → &lt;code&gt;ProcessJobsForRetrievalInOrderService&lt;/code&gt;; je Connector &lt;code&gt;RetrieveChangesAsync&lt;/code&gt; (BC/NAV &lt;code&gt;$filter&lt;/code&gt;, CE &lt;code&gt;RetrieveEntityChangesRequest&lt;/code&gt;, SQL seitenweises SELECT, OpenAPI Query-String)&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Orchestrierter Abruf&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Durable: &lt;code&gt;GetChangesOrchestrator&lt;/code&gt;, &lt;code&gt;GetChangesActivity&lt;/code&gt;, Entity &lt;code&gt;JobState&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Asynchrone Entkopplung&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Service Bus mit sieben Queues, &lt;code&gt;ServiceBusService&lt;/code&gt; mit Batch bis 200&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Priorisierte Verarbeitung&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;JobPriorityType&lt;/code&gt; → Queue; drei Trigger&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Reihenfolgensteuerung&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;Job.Order&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Idempotentes Schreiben&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;Connector.Upsert/Delete&lt;/code&gt;; &lt;code&gt;TargetKey&lt;/code&gt;/&lt;code&gt;TargetKeys&lt;/code&gt; mit &lt;code&gt;KeyRank&lt;/code&gt;, erster Treffer gewinnt&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Aktions-Jobs&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;InvokeAction&lt;/code&gt;: Job-&lt;code&gt;Action&lt;/code&gt; ohne CRUD-Bedeutung ruft einen benannten Endpunkt&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Job-eigene Pfade&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;Source&lt;/code&gt;/&lt;code&gt;Target&lt;/code&gt; am Job überschreiben &lt;code&gt;SourceTable&lt;/code&gt;/&lt;code&gt;TargetTable&lt;/code&gt; des Mappings&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Eingebettete Kinder&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;EmbedChildren&lt;/code&gt; (nur CE als Quelle)&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Response-Jobs&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;Upsert(..., responseMapping, job)&lt;/code&gt; → Response-Nachricht&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Watermarking&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;WatermarkService&lt;/code&gt; + &lt;code&gt;WatermarkValue&lt;/code&gt;; Typen &lt;code&gt;date&lt;/code&gt;, &lt;code&gt;datetime&lt;/code&gt;, &lt;code&gt;string&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h2 id="konnektivität"&gt;Konnektivität&lt;/h2&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Fähigkeit&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Umsetzung&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;D365 Business Central&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;BcConnector : HttpConnectorBase&lt;/code&gt;, OAuth2 / Basic / Managed Identity&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;D365 CE / Dataverse&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;CeConnector : ConnectorBase&lt;/code&gt;, &lt;code&gt;ServiceClient&lt;/code&gt; (Connection-String oder &lt;code&gt;url&lt;/code&gt; + Managed Identity)&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;D365 NAV&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;NavConnector : HttpConnectorBase&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;REST über OpenAPI&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;OpenApiConnector : HttpConnectorBase&lt;/code&gt;, Spec aus &lt;code&gt;openApiSpecUrl&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;MSSQL, PostgreSQL, MySQL, Oracle&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;SqlConnectorBase&amp;lt;T&amp;gt;&lt;/code&gt;, nur lesend&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Auth-Varianten HTTP&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Basic, OAuth2 Client Credentials mit &lt;code&gt;tokenUrl&lt;/code&gt;, API-Key, Managed Identity (explizit über &lt;code&gt;authmethod&lt;/code&gt;)&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Key-Vault-Bezug&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;keyVaultUrl&lt;/code&gt; in der Connection + &lt;code&gt;DefaultAzureCredential&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Schema-Metadaten&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;IConnector.GetTableNames&lt;/code&gt;, &lt;code&gt;GetTableMetadata&lt;/code&gt; für alle Connector-Typen&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Ad-hoc-HTTP&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;ExecuteHttpRequest&lt;/code&gt; (nur GET)&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h2 id="transformation-und-mapping"&gt;Transformation und Mapping&lt;/h2&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Fähigkeit&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Umsetzung&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Feld-Mapping&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;TableMapping&lt;/code&gt; + &lt;code&gt;FieldMapping&lt;/code&gt; aus &lt;code&gt;mappings&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Typ-Coercion&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;AttributeResolver&lt;/code&gt;-Familien je Systemtyp&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Metadaten-basierte Resolver-Wahl&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;TargetValueMapper&lt;/code&gt; je Connector, statische &lt;code&gt;FrozenDictionary&lt;/code&gt;-Registry mit Coverage-Tests&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Default-Werte&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Target-Operationen &lt;code&gt;DefaultValue&lt;/code&gt;, &lt;code&gt;DefaultValueIfNullOrEmpty&lt;/code&gt;, &lt;code&gt;DefaultValueMap&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Option-/Picklist-Mapping&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;OptionMapping&lt;/code&gt;, CE-Resolver für Picklist, MultiSelect, State/Status&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Lookup-Auflösung&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Source-Operation &lt;code&gt;LookupValue&lt;/code&gt; mit Cache; CE mit Batch-Pre-Caching; &lt;code&gt;DoNotCreate&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;CE-Beziehungen&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;ActivityParty&lt;/code&gt;, &lt;code&gt;LinkToRecord&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;ReadFromMessage&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Wert aus der Nachricht übernehmen&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Virtuelle Felder&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;_&lt;/code&gt;-Präfix im &lt;code&gt;SourceField&lt;/code&gt;, nie gegen Metadaten validiert&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Erweiterbarkeit&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Source-Operation-Handler per Reflection&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h2 id="konfiguration-und-steuerung"&gt;Konfiguration und Steuerung&lt;/h2&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Fähigkeit&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Umsetzung&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Konfigurationsgetriebener Betrieb&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Table Storage, &lt;code&gt;StorageService&lt;/code&gt;, &lt;code&gt;SettingsService&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Cron je Job&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;Job.Schedule&lt;/code&gt;, &lt;code&gt;NCrontab.Signed&lt;/code&gt;, sechs Felder&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Manueller Job-Start&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;ExecuteJob&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Function-Toggles&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;AzureWebJobs.&amp;lt;Name&amp;gt;.Disabled&lt;/code&gt;, Bicep &lt;code&gt;disabledFunctions&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Konfig-Diagnose&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;CheckList&lt;/code&gt;, &lt;code&gt;Validate&lt;/code&gt;, &lt;code&gt;JobApi&lt;/code&gt;, &lt;code&gt;MappingApi&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;KI-Anbindung&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;MCP-Server mit read-only Tools&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Self-Repair der Initialisierung&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;ResetInitialization&lt;/code&gt; bei Fehlern&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Quell-Filter&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;Job.Filter&lt;/code&gt; mit &lt;code&gt;{{…}}&lt;/code&gt;-Templating&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Veraltete Nachrichten überspringen&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;SkipOutdatedMessages&lt;/code&gt; → &lt;code&gt;sbqignored&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h2 id="resilienz"&gt;Resilienz&lt;/h2&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Fähigkeit&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Umsetzung&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Backoff-Retry&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;DeliveryCount² · 1000 ms&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Lock-Renewal&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Hintergrund-Task alle 30 s&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Konflikt-Isolation&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;TransitiveException&lt;/code&gt; → &lt;code&gt;sbqtransitive*&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Dead-Lettering&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;maxDeliveryCount&lt;/code&gt;, Fehler-Properties an der Nachricht&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Requeue&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;DeadLetterMover&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Kommunikationsfehler&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;GetChanges&lt;/code&gt; fängt &lt;code&gt;EndpointNotFoundException&lt;/code&gt;, &lt;code&gt;CommunicationException&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h2 id="observability"&gt;Observability&lt;/h2&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Fähigkeit&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Umsetzung&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Gepuffertes Logging&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;BufferingLoggerProvider&lt;/code&gt;, Flush pro Invocation&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Dependency-Sampling&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;DependencySamplingProcessor&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Custom Metrics&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;MetricsService&lt;/code&gt; (&lt;code&gt;ChangesDetected&lt;/code&gt;, &lt;code&gt;MessagesProcessed&lt;/code&gt;)&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Korrelation&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;InvocationContext&lt;/code&gt;, &lt;code&gt;operation_id&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Steuerung&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;TELEMETRY_CONTROL&lt;/code&gt;, drei Raten-Settings&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Alerts&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;DLQ-Stufen, Queue-Länge, Action Group&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Dashboard&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Grafana-Dashboard aus Bicep&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Version&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;GetInfo&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h2 id="infrastruktur-und-auslieferung"&gt;Infrastruktur und Auslieferung&lt;/h2&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Fähigkeit&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Umsetzung&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Infrastructure as Code&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Bicep mit Modulen und &lt;code&gt;.bicepparam&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Marketplace&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;createUiDefinition.json&lt;/code&gt;, generierte &lt;code&gt;mainTemplate.json&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Identitätsbasierter Zugriff&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;enableManagedIdentity&lt;/code&gt; + Rollen&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Serverless-Skalierung&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Y1 / EP1–EP3, &lt;code&gt;functionScaleLimit&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Run-from-Package&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;WEBSITE_RUN_FROM_PACKAGE=1&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Container&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;Dockerfile&lt;/code&gt;, &lt;code&gt;compose.yml&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Versionierung&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;Major.Minor.yyyy.MMdd&lt;/code&gt;, manueller Bump&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;CI/CD&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Azure Pipelines unter &lt;code&gt;cicd/&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Lokale Entwicklung&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="../../lokale-testumgebung/"&gt;Podman-Testumgebung&lt;/a&gt; mit DBs und HTTP-Mocks&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h2 id="qualitätssicherung"&gt;Qualitätssicherung&lt;/h2&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Fähigkeit&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Umsetzung&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Unit-Tests&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;DataBridge.Test&lt;/code&gt;, xUnit v3, Moq&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Coverage&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Microsoft Testing Platform Code Coverage&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Resolver-Vollständigkeit&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;*TargetValueMapperCoverageTests&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Dokumentation&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Hugo/Docsy unter &lt;code&gt;docs/&lt;/code&gt;, veröffentlicht per Pipeline&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;</description></item></channel></rss>