22 KiB
Boilerplate-Abgleich: M19 — KWP-Integration
| Feld | Wert |
|---|---|
| Modul-ID | M19 |
| Name | KWP-Integration |
| Milestones | M089 (Sync-Programm), M090 (Heartbeat+Recovery), M091 (Warteschlange+Replay), M092 (Schema-Drift-Sentinel), M093 (Konflikt-Auflösung „KWP gewinnt"), M094 (Plantafel-Sync), M095 (Dokumenten-Archiv-Sync) |
| Block | Block 4 — USP-Säulen (Modul 19), sitzt auf M33a Apps-Engine (M008-M010) |
| Reuse-Level | medium |
Verifikations-Basis: Eigene Greps/Reads direkt in
/Users/raffaelsheikh/Documents/GitHub/boilerplate(nicht nur Inventur). Wo Inventur und Realität abweichen, ist das markiert.
Kernbefund in einem Satz
Die Boilerplate hat kein KWP-, MSSQL-, Heartbeat-, Schema-Drift- oder Windows-Sync-Code (grep über *.ts/*.prisma leer außer einem Test-Match in packages/cli). Was sie liefert, ist ein solides Querschnitt-Fundament: ein generisches Data-Sync-Datenmodell (appsEngine.prisma), eine Public-API-Runtime mit Tenant-API-Key/Webhook-Auth (apps/api), eine Cron+Queue-Worker-Runtime mit Transactional-Outbox (apps/worker), gehashte API-Keys (core.prisma), Idempotenz, Storage/Signed-URLs und Notifications. Die gesamte KWP-Fachlogik (Queue-Semantik, Mapping-Registry, Drift-Diff, Konflikt-Default „KWP gewinnt", Projektnummern-Sequenz/Reservierung) ist neu zu bauen.
Übernehmbar aus Boilerplate
| Boilerplate-Pfad | Was | Wie nutzbar |
|---|---|---|
prisma/schema/appsEngine.prisma |
App, DataConnection, AppSyncRun, AppSyncRunLog, AppSyncItem — generische Data-Sync-Engine mit Status/Mode/Metriken + Source→Destination-Mapping + Rollback-Daten |
anpassen — deckt KwpSettings (als App/DataConnection), KwpProjectQueue/Sync-Lauf (als AppSyncRun) und KwpRegistry (als AppSyncItem) teilweise ab; KWP-spezifische Felder fehlen (s.u.) |
prisma/schema/core.prisma → ApiKey + ApiKeyLog |
Gehashte Keys (keyHash/keyPrefix/keyLastFour/keyVersion/hashedAt/expires/active), @@unique([tenantId, alias]), Request-Logging |
1:1 für KwpApiKey (Token-Auth des kwpsync.exe bzw. KWP-API). Rotation/Expiry-Felder vorhanden |
prisma/schema/core.prisma → IdempotencyKey |
@@unique([scope, key]), Response-Caching, expiresAt |
1:1 für die in der Spec geforderte idempotency_key-Doppel-Push-Erkennung (Block D) |
prisma/schema/core.prisma → FileObject (+ FileUploadProgress/FileChunk) |
Storage-Metadaten (provider/bucket/key/checksum/byteSize/metadata Json) | anpassen — Basis für KwpDocument/Dokumenten-Archiv-Sync (M095); KWP-Herkunfts-Felder (direction, kwp_path, gelöscht-Badge) ergänzen |
apps/api (@toolctrl/api, Hono) + apps/api/src/route-access-inventory.ts |
Public-API-Runtime mit Auth-Klassen tenant-api-key, service-token, webhook-signature, optional-api-key-validation; apps/api/src/auth.ts (extractApiKeyFromRequest, extractBearerToken, createServicePrincipal); Error-Envelope + Request-ID |
als-vorlage / anpassen — exakt die Ingress-Schicht für /api/v1/integrations/kwp/queue/{token}/... (Pull/Push/Heartbeat). Neue Routes + Auth-Klasse für den kwpsync-Token andocken |
apps/api/src/webhooks/mailersend-signature.ts, billing/stripe-webhook-route.ts, email-sequences/provider-webhook-route.ts |
Bestehende inbound-Webhook-Handler mit Signatur-Verifikation | als-vorlage — Muster für handleWebhook (kwpsync.exe pusht Delta + Heartbeat) bzw. KWP-API-Webhook |
apps/worker (@toolctrl/worker) + apps/worker/src/jobs/*-cron.ts |
Cron+Queue-Runtime, single-instance Cron-Scheduler (Bsp. dsgvo-grace-cron.ts 24h, plugin-audit-retention nächtlich), DI-HandlerDependencies, Health/Admin-Server |
als-vorlage — für Daily-Schema-Drift-Check (M092), Heartbeat-Watchdog (M090), Rate-Limited-Replay-Worker (M091). Neuen Queue-Namen + Handler registrieren |
apps/worker/src/outbox/{dispatcher,event-router}.ts + prisma/schema/outbox.prisma |
Transactional-Outbox: Event in DB-Tx committen, Worker fan-out per Prefix-Routing (longest-prefix-wins), Exponential-Backoff-Retry, DLQ | anpassen — Push aus HiveGrid → KWP-Queue als Outbox-Event (kwp.push.* Prefix-Routing ergänzen). Garantiert „nichts geht verloren" (Spec 19.3.3) ohne eigene Queue-Mechanik |
packages/queue (@toolctrl/queue) |
BullMQ-Wrapper: enqueueJob, buildIdempotentJobId(), plan-basierte Prioritäten (resolveJobPriorityForTenant), Idempotenz |
1:1 / anpassen — Cloud-Queue-Verarbeitung + Idempotenz. Neuer Queue-Name toolctrl.kwp-sync o.ä. hinzufügen (Queue-Namen sind hartcodiert in packages/queue/src/names.ts) |
packages/foundation/src/adapters.ts |
defineAdapter()/getAdapter() + AdapterStatus = not_configured|configured|healthy|degraded|unavailable |
anpassen — die 5 Status-Werte mappen direkt auf die M33a-/Spec-Status (wartet auf Setup/aktiv/eingeschränkt/defekt/getrennt). ACHTUNG: das ist nur eine 18-Zeilen-Status-Registry, kein Sync-Connector-Framework — siehe „Lücken" |
packages/storage (@toolctrl/storage) |
S3/Scaleway-Adapter, Signed-Upload/Download-URLs, Virus-Scan (ClamAV + magic-bytes), Quarantäne | 1:1 für Dokumenten-Archiv-Sync (M095) — KWP-Dokumente in Scaleway-S3 ablegen, Signed-URLs zum Lesen/Download |
packages/marketing-outbound/src/types.ts → adapterFetch() + SSRF-Guard |
Timeout + SSRF-Allowlist (nur HTTPS, kein RFC1918/metadata) für ausgehende HTTP-Calls | als-vorlage — falls die KWP-API direkt von HiveGrid Cloud aufgerufen wird (API-Variante, s.u.), als sicherer HTTP-Egress |
packages/realtime (@toolctrl/realtime) |
SSE-Event-Serialisierung (notification.snapshot/update) |
1:1 für sichtbaren Re-Sync-Fortschritt („847/1.230 abgearbeitet") und Live-Status-Indicator |
packages/db/generated/prisma/client/models/{App,DataConnection,AppSyncRun,AppSyncRunLog,AppSyncItem}.ts |
Generierter Prisma-Client für die Apps-Engine-Modelle (bereits vorhanden) | 1:1 — Modelle sind generiert und tenant-relation-verdrahtet; sofort nutzbar |
Vorhandene Daten-Modelle (konkret, mit Pfad)
Direkt für M19 relevante, bereits existierende Prisma-Modelle:
prisma/schema/appsEngine.prismaApp(tenantId,type-Identifier,configJSON-String,isActive,installedByUserId,@@unique([tenantId, type])) → Basis für „KWP-App ist installiert" +KwpSettings.enabled_featuresDataConnection(tenantId,name(sprechender Name „Geerkens Hauptbüro KWP"),typez.B. "rest-api"/"webhook",config= verschlüsselte JSON-Credentials) → Basis fürKwpSettings/data_connection_idAppSyncRun(statuspending/running/completed/partial/failed/cancelled/reverted,executionModemanual/scheduled/webhook,itemsProcessed/Created/Updated/Failed,startedAt/completedAt,error,metadataJSON) → Basis für Sync-Lauf-Historie + M33a-Sync-VerlaufAppSyncRunLog(typeinfo/success/warning/error,message,metadata) → Klartext-Log pro Sync-Vorgang (M33a.4.2)AppSyncItem(objectType,sourceId,destinationId,action,sourceData/destinationDataJSON,status,rolledBackData/rolledBackAt,@@index([objectType, sourceId])) → Basis fürKwpRegistry-Mapping + Konflikt-Restore (M093)
prisma/schema/core.prismaApiKey+ApiKeyLog→KwpApiKey(gehasht, Rotation, Request-Logging)IdempotencyKey→ Idempotenz-Schlüssel der Push-OperationenFileObject/FileUploadProgress/FileChunk→ KwpDocument-Storage-MetadatenCredential(globaler Secret-Store,value Json) → falls Cloud-seitige Secrets nötig
prisma/schema/featureFlags.prisma→FeatureFlag/FeatureFlagFilter/FeatureFlagAudit(DoD-Pflicht „Modul ohne Deploy abschaltbar")prisma/schema/permissions.prisma→Role/Permission/RolePermission/UserRole(generisches RBAC; die 6kwp.*-Permissions sind hier zu registrieren, nicht neu zu erfinden)prisma/schema/notifications.prisma→NotificationDelivery/UserNotificationPreference/DeviceToken(Push/Email-Alerts bei broken/drift)prisma/schema/outbox.prisma→OutboxEvent(Transactional-Push-Queue)prisma/schema/workflows.prisma→Workflow/WorkflowExecution/… (M17-Engine; KWP-Triggerkwp.auftrag_pulled/kwp.push_auftragund KWP-Actions docken hier an, nicht in M19 selbst neu bauen)
Lücken / komplett neu zu bauen
Es existiert KEIN KWP-spezifischer Code. grep über das gesamte Boilerplate-Repo (kwp|KWP|mssql|MSSQL|heartbeat|schema.drift|nssm|sqlserver) liefert nur einen einzigen Treffer in packages/cli/.../doctor.test.ts (unbezogen). Konkret fehlt:
- Der komplette
kwpsync.exeWindows-Client (Block F). Nichts davon ist in der Boilerplate — kein .NET-/Go-Projekt, kein MSSQL-Treiber, kein NSSM-Wrapper, keine lokale SQLite-Queue, kein DPAPI-Verschlüsselungs-Code, kein Auto-Update. Das ist ein eigenständiges externes Programm außerhalb des Monorepos (M089). (Bei API-Variante entfällt das ganz — siehe KWP-API-Auswirkung.) defineAdapterist NICHT das Apps-Engine-Connector-Pattern. Die AGENTS.md-Tabelle (Zeile 134: „Apps-Engine-Adapter | M008-M010 |defineAdapter()") suggeriert ein fertiges Adapter-Framework. Realität:packages/foundation/src/adapters.tsist eine 18-Zeilen-Status-Registry (Mapmit key→status). Das in Spec Block I geforderte Adapter-Interface (connect/disconnect/validateConnection/syncPull/syncPush/handleWebhook+ Capabilities) existiert nicht und muss als Teil von M008-M010 (M33a) erst gebaut werden. M19 setzt darauf auf — ist also von M008-M010 blockiert (Vorbedingung steht korrekt in M089).- KWP-spezifische Datenmodelle, die
appsEngine.prismanicht abdeckt:KwpProjectNumberSequence(pro Jahr fortlaufende Auftragsnummern „2026-0042") — komplett neu, kein Sequenz-Modell vorhandenKwpProjectNumberReservation(24h-Reservierung mitexpires_at/consumed_at) — komplett neuKwpSchemaSnapshot(schema_hash,tables_metadataJSON für Diff) — komplett neuKwpErrorReport(error_kindschema_drift/connection_lost/sync_conflict/…,severity,summary_text/tech_details,acknowledged_by) — teilweise viaAppSyncRunLog, aber Tenant-Acknowledge-Flow + Severity-Filter fehlen → neuKwpSettings-Spezialfelder:kwpsync_token,kwpsync_version,kwpsync_last_heartbeat_at,polling_interval_seconds— alsApp.config/DataConnection.config-JSON ablegbar oder eigene Felder → anpassen/ergänzen
- Sync-Mechanik-Fachlogik (Block D/G/H): Cursor-basierter Delta-Pull, Rate-Limited-Replay (max 100 Ops/Min mit Fortschritt), Konflikt-Default „KWP gewinnt immer" (M093, [N14]) inkl. HiveGrid-eigene-Felder-Schutz, Optimistic-Locking mit
version_hash, Last-Known-Stand-Restore.AppSyncRun/AppSyncItemliefern die Tabellen-Hülle, aber keinerlei dieser Algorithmen. - Schema-Drift-Sentinel-Fachlogik (M092): Snapshot-Algorithmus, Hash-Vergleich, Auto-Pause, Plattform-Admin-zuerst-Benachrichtigung, Diff-Tool im Plattform-Admin (M37). Cron-Hülle vorhanden, Logik neu.
- Setup-Wizard-UI + alle Routes/View-Models/i18n (Block C). Keine
app/routes-Integration, keineui-hivegrid-Components, kein Sidebar-Eintrag „KWP-Verbindung" (in INTEGRATION-CONTRACTS §1 unter Einstellungen vorgesehen → M089-M095, aber Code existiert nicht). Subframe-Design + Adapter-Layer komplett neu. - Permissions registrieren:
kwp.read/connect/manage/manual_sync/disconnect/adminsind inpackages/entitlements/src/permissions.ts(HiveGrid-Seite) noch zu definieren; RBAC-Tabellen existieren generisch. - Plantafel-Sync (M094) und Dokumenten-Archiv-Sync (M095) Fachlogik — Storage-/File-Modelle vorhanden, Spiegelungs-Logik (Kunden-Archiv vs. Projekt-Archiv, einseitig, „in KWP gelöscht"-Badge) neu.
Empfohlenes Vorgehen (Reihenfolge)
Phase 0 — Voraussetzung außerhalb M19: Erst M008-M010 (M33a Apps-Engine) bauen — das echte Adapter-Interface (connect/syncPull/syncPush/handleWebhook + Status + Setup-Wizard-Shell). M19 ist davon hart abhängig; defineAdapter reicht NICHT.
- Daten-Layer aus Boilerplate übernehmen + KWP-Felder ergänzen:
appsEngine.prisma-Modelle als Basis nehmen (App/DataConnection/AppSyncRun/AppSyncItem),ApiKey+IdempotencyKey1:1 nutzen. Neue Modelle in eigenemprisma/schema/kwp.prisma:KwpProjectNumberSequence,KwpProjectNumberReservation,KwpSchemaSnapshot,KwpErrorReport. Forward-Only-Migration mit Inverse-SQL-Kommentar (DoD F.28). - Querschnitt 1:1 verdrahten, nicht nachbauen: Token-Auth via
ApiKey, Idempotenz viaIdempotencyKey+buildIdempotentJobId, Push-Queue via Outbox (kwp.push.*-Prefix inevent-router.ts), Notifications vianotify()(M011), Storage via@toolctrl/storage, Status-5-Werte viafoundation/adaptersAdapterStatus, Feature-Flag viaFeatureFlag. - Ingress-Schicht aus
apps/apiableiten: KWP-Queue/Heartbeat/Pull-Endpoints unter/api/v1/integrations/kwp/..., Auth-Klassetenant-api-keyausroute-access-inventory.ts, Webhook-Handler nach Vorbildmailersend-signature.ts. - Worker-Crons aus
apps/workerableiten: Heartbeat-Watchdog (M090), Daily-Schema-Drift (M092), Rate-Limited-Replay (M091) — nach Musterdsgvo-grace-cron.ts; neuen Queue-Namen inpackages/queue/src/names.tsregistrieren. - KWP-Fachlogik neu bauen (Kern-Aufwand): Mapping-Registry-Semantik auf
AppSyncItem, Konflikt-Default „KWP gewinnt" (M093) inkl. Restore ausrolledBackData, Projektnummern-Sequenz/Reservierung, Schema-Snapshot-Diff. Reine Domain-Funktionen inapp/domain/**(AGENTS.md Layer-Trennung). - UI komplett neu (Subframe → Adapter → Routes): Setup-Wizard, Status-Dashboard, Sync-Verlauf, Fehlerbericht-Liste, Konflikt-Diff-View. Sidebar-Eintrag „KWP-Verbindung" (Einstellungen-Gruppe), Breadcrumbs, i18n, Smoke-Tests, Visual-Regression — alle DoD-Punkte.
- kwpsync.exe als separates Repo/Artefakt (M089) — nur in der Sync-Programm-Variante nötig (siehe nächster Abschnitt).
KWP-API-Auswirkung (Pflicht-Abschnitt — Stand 2026-06-04, NEU/WICHTIG)
Kontext: KWP bekommt jetzt eine offizielle API-Anbindung. Der bisherige Plan (lokaler Windows-Service + NSSM + persistente lokale SQLite-Queue + Schema-Drift-Sentinel, M089-M095) war für KWP OHNE API konzipiert. Die Spec selbst hat das antizipiert (19.11.2: „Native KWP-API … würde die Architektur stark vereinfachen"). Mit API wird aus der Drei-Komponenten-Architektur eine Zwei-Komponenten-Architektur (HiveGrid Cloud ↔ KWP-API direkt), der „Kunde-vor-Ort"-Mittelteil entfällt.
(1) Was die API-Anbindung am Architektur-Plan ändert
kwpsync.exeentfällt als Mittelschicht. Statt Cloud → kwpsync.exe (Poll) → MSSQL wird es Cloud → HTTPS → KWP-API. Damit fallen weg: MSSQL-Direktzugriff, DPAPI-Config, lokale SQLite-Queue, NSSM-Service-Wrapper, Auto-Update-Mechanismus, Code-Signing.- Aus „windows_client" wird ein Standard-Connection-Type. Die Spec Block I nennt
connection_type = windows_clientals KWP-Spezialfall. Mit API wird daraus ein regulärerrest-api/oauth2-Adapter — exakt das, wasDataConnection.typeinappsEngine.prismaohnehin als Werte vorsieht ("rest-api", "oauth2", "webhook"). Damit passt KWP plötzlich nahtlos ins generische Apps-Engine-Muster statt Sonder-Pattern zu sein. - Egress statt Ingress: Statt dass kwpsync.exe in die Cloud pollt, ruft die HiveGrid Cloud die KWP-API aktiv auf. Dafür ist
packages/marketing-outbound/src/types.ts→adapterFetch()(HTTPS-only, SSRF-Allowlist, Timeout) die passende sichere HTTP-Egress-Vorlage. Pull wird zu einem normalen Cron-Job (apps/worker), Push zu einem Outbox-getriebenen API-Call. - DSGVO-Punkt verschiebt sich: Spec 19.1.2 („KWP-Zugangsdaten liegen lokal beim Kunden, niemals in der Cloud") gilt bei API-Anbindung nicht mehr 1:1 — API-Credentials liegen verschlüsselt in
DataConnection.configin der Cloud. Das ist DSGVO-konform (Plattform-Schlüssel, Pflichtenheft 33a.9.3), erfordert aber eine bewusste Neubewertung des „rohe DB-Zugriffe verlassen das Netzwerk nie"-Versprechens.
(2) Welche Milestones M089-M095 sich vereinfachen oder entfallen
| Milestone | Mit Windows-Sync (alt) | Mit KWP-API (neu) | Verdict |
|---|---|---|---|
| M089 kwpsync.exe (Win-Service+NSSM) | komplettes externes .NET/Go-Programm | — | ENTFÄLLT (ggf. Restaufwand: API-Connector-Adapter statt Programm, aber innerhalb des Monorepos) |
| M090 Heartbeat + Auto-Recovery | 5-Min-Heartbeat des Clients, 15-Min-Watchdog, Auto-Restart | API-validateConnection = einfacher Health-Probe-Call (Spec/M33a haben das ohnehin: aktiv=5min/eingeschränkt=1min/defekt=15min) |
STARK VEREINFACHT → reduziert auf den generischen M33a-Connection-Health-Check; kein Client-Recovery mehr |
| M091 Persistente Warteschlange + Replay | zwei Queues (Cloud + lokale SQLite), Rate-Limited-Replay nach Outage | nur eine Cloud-Queue (Outbox) + Rate-Limit-Replay bei KWP-API-Down | VEREINFACHT → lokale SQLite-Queue entfällt komplett; Outbox + packages/queue decken den Rest ab |
| M092 Schema-Drift-Sentinel | Daily-MSSQL-Schema-Snapshot via Client | abhängig von API-Vertrag: versionierte API → Drift wird zu API-Versions-/Contract-Check (deutlich leichter); KWP ändert MSSQL nicht mehr „still" hinter dem Rücken | VEREINFACHT bis ggf. ENTFÄLLT (bei stabiler versionierter API). Bleibt sinnvoll als API-Response-Schema-Validierung (zod) |
| M093 Konflikt „KWP gewinnt" | unverändert relevant (fachliche Regel, nicht transport-abhängig) | unverändert relevant | BLEIBT (Domain-Logik, transport-unabhängig) |
| M094 Plantafel-Sync | bidirektional via kwpsync.exe (Poll/Write MSSQL) | bidirektional via API (Webhook KWP→HiveGrid + API-Call HiveGrid→KWP) | VEREINFACHT falls KWP-API Webhooks bietet (Spec 19.11.3 „Trigger-basierter Pull" wird dann Phase-1-fähig statt Phase-2) |
| M095 Dokumenten-Archiv-Sync | KWP→HiveGrid via Client-Filezugriff | KWP→HiveGrid via API-Dokumenten-Endpoint | VEREINFACHT (kein lokaler Dateizugriff; @toolctrl/storage + API-Download) |
Netto: M089 entfällt, M090/M091/M092/M094/M095 vereinfachen sich teils erheblich, nur M093 (Konflikt-Regel) bleibt unverändert. Der Gesamt-Aufwand des Moduls sinkt deutlich, und das Reuse-Level steigt faktisch von medium Richtung medium-high, weil die generische appsEngine.prisma + apps/api/apps/worker-Fundamente bei einer API-Anbindung direkter passen als beim Windows-Client-Sonderweg.
(3) Wie Apps-Engine/Adapter (defineAdapter, plugins, plugin-sdk) statt des Sync-Programms genutzt werden
appsEngine.prismaist der richtige Boden — nicht das WASM-Plugin-System. Wichtige Abgrenzung (auch in der Inventur betont,integrations-ki.md§4 + „Wichtige Abgrenzungen"): Es gibt zwei „Apps-Engine"-Bedeutungen.packages/plugin-runtime+packages/plugin-sdk= WASM-Sandbox für Drittanbieter-Plugins (Capability-Consent, Ed25519-Signatur, Hook-Lifecycle). In Prod sind nurlog+audit-Capabilities freigeschaltet (PLUGIN_AVAILABLE_HOST_CAPABILITY_NAMES),http.outbound/db/storagesindproductionAvailable: false. → Für KWP NICHT geeignet: KWP ist ein First-Party-Connector mit DB/HTTP-Bedarf, kein sandboxed Drittanbieter-WASM-Modul. Marketplace ist ohnehin Phase 2 (33a.9.1).prisma/schema/appsEngine.prisma(App/DataConnection/AppSyncRun/AppSyncItem) = die First-Party-Data-Sync-Engine. → Das ist das richtige Fundament für eine KWP-API-App.
defineAdapter()(packages/foundation/src/adapters.ts) liefert nur Status-Registry (not_configured/configured/healthy/degraded/unavailable). Diese 5 Werte mappen sauber auf die M33a-Connection-Status. Die eigentliche Connector-Verhaltens-Schnittstelle (connect/syncPull/syncPush/validateConnection/handleWebhookaus Spec Block I) muss in M008-M010 (M33a) gebaut werden; KWP-API ist dann der erste konkrete Adapter dahinter — alsrest-api/oauth2-DataConnection.- Empfohlene Mapping-Strategie bei API-Variante:
- KWP-App =
App{ type: "kwp" }, eineDataConnection{ type: "rest-api" | "oauth2", config: <verschlüsselte API-Creds> }pro KWP-Server. - Token/Key der KWP-API =
ApiKey(gehasht) bzw. OAuth-Token inDataConnection.config. - Pull-Lauf =
AppSyncRun{ executionMode: "scheduled" }; Push-Lauf =AppSyncRun{ executionMode: "webhook"/"manual" }; Mapping HiveGrid↔KWP-Entität =AppSyncItem(sourceId/destinationId); Konflikt-Restore =AppSyncItem.rolledBackData. - Connector-Adapter als reines Domain-Modul in
app/domain/integrations/kwp/**, dasadapterFetch()für Egress nutzt; Cron/Outbox ausapps/worker.
- KWP-App =
- Konsequenz für die Planung: Vor Umsetzung von M19 muss der Plan M089-M095 gegen die API neu geschnitten werden (M089 streichen, M090-M092/M094-M095 als API-Adapter-Tasks neu fassen, M093 unverändert lassen). Die Boilerplate unterstützt die API-Variante besser als die ursprünglich geplante Windows-Client-Variante.
Reuse-Level-Begründung: medium
- Pro (warum nicht low): Komplettes Querschnitt-Fundament vorhanden — Data-Sync-Datenmodell (
appsEngine.prisma), gehashte Token (ApiKey), Idempotenz, Outbox-Push-Queue, Cron+Queue-Worker, Public-API-Auth-Schicht, Storage, Notifications, Status-Registry, Feature-Flags, RBAC. Bei API-Anbindung passt das Apps-Engine-Datenmodell sogar direkt (type: "rest-api"). - Contra (warum nicht high): Null KWP-/ERP-Fachlogik in der Boilerplate. Das in AGENTS.md angedeutete Adapter-Framework (
defineAdapter) ist nur eine Status-Map; das echte Connector-Interface (M33a Block I) existiert nicht. Alle KWP-spezifischen Modelle (Projektnummern-Sequenz/Reservierung, Schema-Snapshot, Error-Report), die gesamte Sync-/Konflikt-/Drift-Algorithmik und die komplette UI sind neu. In der Windows-Sync-Variante kommt ein komplettes externes Programm dazu (low-touch zur Boilerplate). In der API-Variante entfällt das und das Modell rutscht praktisch Richtung medium-high.