Datenmigration ins CRM: fünf Jahre Bestellhistorie, keine Dublette
Wie wir einen Import so bauen, dass man ihn zweimal laufen lassen kann – und warum ein Archiv-Flag der wichtigste Teil war
· 5 Min. · Migration, CRM, PostgreSQL, Praxisbericht
Eine Datenmigration ins CRM ist kein Kopiervorgang, sondern ein Eingriff: Im CRM eines Lebensmittelherstellers standen 3 814 Bestellungen, im Onlineshop lagen fünf Jahre Historie. Wie wir die Lücke geschlossen haben, ohne eine doppelte Kundenkarte und ohne dass ein Kunde von vor drei Jahren plötzlich Post bekam, steht hier.
Die Lücke: 3 814 von 19 686
Der Kunde führt Kontakte, Bestellungen und Kundenkommunikation in einem CRM, das wir für ihn betreiben. Der Shop liefert seine Bestellungen täglich über die REST-Schnittstelle in die PostgreSQL-Datenbank dieses CRM. Das funktionierte – aber erst ab dem Tag, an dem der Shop angeschlossen wurde. Beim Anschluss eines Shops kommt der Bestand nicht automatisch mit: Neue Bestellungen laufen ein, alte bleiben, wo sie sind.
Es störte in dem Moment, in dem der Inhaber Fragen an seine Daten stellte. Welche Produkte verkaufen sich über Jahre, welche nur in einer Saison? Welche Kunden kommen wieder, und in welchem Abstand? Auch die KI-Assistenten, die auf den CRM-Daten arbeiten, kannten nur den Ausschnitt seit dem Anschluss. Der Wunsch war klar: alles nachladen. Die Frage war, wie man das tut, ohne den laufenden Betrieb zu beschädigen.
Drei Dinge, die bei einer Datenmigration ins CRM brechen
Bevor wir eine Zeile geschrieben haben, haben wir aufgeschrieben, was schiefgehen kann. Bei Bestandsimporten in ein lebendes System sind es fast immer dieselben drei Punkte.
- Dubletten. Eine Kundin, die einmal mit einer Adresse und später mit einer anderen Schreibweise derselben E-Mail bestellt hat, taucht zweimal auf. Über fünf Jahre summiert sich das zu Karten, die niemand mehr zusammenführt.
- Geweckte Automatik. Das CRM reagiert auf neue Bestellungen: Es legt Vorgänge in der Antwortschlange an, eröffnet Verkaufschancen, löst Mailings aus. Ein Import, der für das System wie ein normaler Tag aussieht, aber die Bestellungen von fünf Jahren bringt, erzeugt ebenso viele Reaktionen – an Menschen, deren letzte Bestellung lange zurückliegt.
- Falsche Zuordnung. Der Kunde führt zwei Geschäftsbereiche: den Endkundenshop und eine Produktion für Geschäftskunden, deren Waren teilweise auch im Shop verkauft werden. Eine Bestellung gehört zum einen oder zum anderen Bereich – je nach Inhalt, nicht nach Herkunft. Wer alles auf den Shop bucht, verfälscht die Auswertung beider Bereiche.
Alle drei Punkte haben eines gemeinsam: Sie fallen nicht beim Import auf, sondern später – in einer Auswertung, in einer Beschwerde, in einer Statistik, die nicht stimmt. Deshalb haben wir sie vorab entschieden, statt sie nachträglich zu reparieren.
Derselbe Importer, derselbe Schlüssel
Die erste Entscheidung: kein Sonderskript. Es ist verlockend, für einen einmaligen Import ein schnelles Programm zu schreiben, das die Daten irgendwie hineinschiebt. Das Programm läuft einmal, wird nie wieder angefasst, und später weiß niemand mehr, welche Sonderregeln darin steckten. Stattdessen haben wir den Importer erweitert, der den Shop ohnehin täglich anbindet. Alles, was für die Historie galt, gilt seitdem auch im Alltag – und wird jeden Tag mitgetestet.
Die zweite Entscheidung: Der Import muss idempotent sein. Ein zweiter Lauf über dieselben Daten darf nichts verändern. Das klingt selbstverständlich, entscheidet aber über die Nerven aller Beteiligten. Ein Import, der nach einem Abbruch nicht neu gestartet werden kann, weil er sonst alles doppelt anlegt, zwingt zu Aufräumarbeiten in der Datenbank unter Zeitdruck. Einen idempotenten Import startet man einfach noch einmal.
Technisch heißt das: Der Schlüssel einer Bestellung ist die Bestellnummer des Shops, nicht eine intern vergebene ID. Existiert eine Bestellung mit dieser Nummer bereits, wird sie aktualisiert und nicht neu angelegt. Dasselbe Prinzip gilt für Positionen und Zahlungen. Damit ließ sich der Import in Abschnitten fahren, nach einem Fehler wieder aufnehmen und am Ende ein zweites Mal komplett laufen lassen – als Nachweis, dass er nichts mehr verändert.
Dubletten und das Archiv-Flag
Für Kontakte reicht die Bestellnummer nicht, denn ein Kunde hat viele Bestellungen. Hier ordnen wir über zwei Merkmale zu: E-Mail-Adresse und Telefonnummer, beide vor dem Vergleich normalisiert – Kleinschreibung, keine Leerzeichen, einheitliche Ländervorwahl. Findet sich ein bestehender Kontakt, wird seine Karte ergänzt statt verdoppelt. Die Reihenfolge der Prüfung ist dabei nicht beliebig: erst E-Mail, dann Telefon. Zwei Personen in einem Haushalt teilen sich eher eine Telefonnummer als ein Postfach.
Den größten Schaden hätte allerdings die Automatik angerichtet. Unsere Lösung ist unspektakulär: Jede historische Bestellung trägt die Markierung „Archiv“. Sie erscheint in der Kundenkarte, in jeder Auswertung, in jeder Suche. Aber alle Stellen im CRM, die auf eine neue Bestellung reagieren – die Antwortschlange, die Eröffnung einer Verkaufschance, der Versand einer Bestätigung –, prüfen dieses Flag und bleiben still.
Das Flag hat einen eigenen automatisierten Test, der genau diese Stellen durchspielt, und er läuft bei jeder Änderung am CRM mit. Der Grund: Eine neue Automatik, die jemand später hinzufügt, kennt die Geschichte des Imports nicht. Der Test kennt sie.
Was eine Datenmigration ins CRM am Ende beweisen muss
Nach dem Lauf standen 19 686 Bestellungen aus fünf Jahren im CRM, keine einzige Dublette, keine ausgelöste Reaktion der Automatik. Genau diese drei Aussagen hatten wir vorher als Kriterium der Abnahme festgehalten – nicht „der Import ist gelaufen“, sondern was danach in der Datenbank nachweisbar sein muss. Der Inhaber hat damit erstmals fünf Jahre Nachfrage als Datenbasis, und die KI-Assistenten arbeiten auf der ganzen Geschichte statt auf einem Ausschnitt.
Ehrlich bleibt eine Einschränkung: Die Zuordnung zum Geschäftsbereich haben wir über den Inhalt der Bestellung gelöst, und diese Regel ist eine Vereinbarung, keine Wahrheit. Ändert der Kunde sein Sortiment, muss sie nachgeführt werden. Wir haben sie deshalb an einer Stelle im Code hinterlegt und dokumentiert, statt sie über den Importer zu verteilen.
Was wir aus dem Projekt mitgenommen haben, passt in einen Satz: Ein Bestandsimport ist keine Datenübertragung, sondern ein Eingriff in ein laufendes System, und die Arbeit steckt in den Regeln, nicht im Kopieren. Wie wir solche Importe und Anbindungen planen, steht unter Prozessautomatisierung für den Mittelstand; welche Altlasten dabei sichtbar werden, beschreibt der Artikel über technische Schulden.
Weitere Beiträge
Sagen Sie uns, was am Ende da sein soll
Sie schildern die Aufgabe, wir sagen offen, ob sie zu uns passt. Passt sie nicht, nennen wir Ihnen den Grund.