Yılların CRM geçmişini eski PHP panelinden yeni panele taşımak

Eski CRM verisini scriptlerle yeni panele nasıl taşıdım: deneme raporu, her kayıt için bir log satırı, sadece hatalıları yeniden gönderen çalıştırmalar ve görünür kalan kirli veri.

Bir şerit üzerinde dört kapı: deneme raporu, uygula, her satırı logla, kalanı yeniden gönder; son kapıdan geçen yeşil bir blok

Yeni CRM (müşteri kayıtlarını ve geçmişini tutan sistem) ekranları hazırdı, ama içleri boştu. Yılların müşteri geçmişi hâlâ satış ve müşteri yönetimi ekiplerinin her gün kullandığı eski bir PHP panelindeydi. Müşterilerini tanımayan yeni bir araca kimse geçmezdi.

Bu yüzden veriyi scriptlerle taşıdım: önce müşteriler, sonra notları, faturaları, kişi kayıtları ve belge bağlantılarıyla birlikte sözleşmeleri. Taşıma birkaç hafta boyunca küçük çalıştırmalarla, iki panel de kullanılırken yapıldı.

Nasıl yaptığımı, neyin bozulduğunu ve neyi farklı yapacağımı anlatıyorum.

Kısaca

  • Her kayıt yeni backend'in API'sinden geçti; eski veriyi yeni panelin doğrulama kuralları kontrol etti.
  • Her scriptin, hiçbir şey göndermeden önce rapor yazan bir deneme modu var.
  • Her kayıt için bir log satırı, yeniden çalıştırmayı ve geri almayı kesin yapıyor.
  • Kirli veri düzeltiliyor ya da yer tutucu alıyor, asla düşürülmüyor; kayıt neyin değiştiğini söylüyor.

Kısıtlar

Eski taraf, scriptlerin sadece okuyup dışarı aktarabildiği bir veritabanıydı. Sadece notlar tablosu bile tek istekte almak için fazla büyüktü, bu yüzden export (veriyi dışarı aktarma) sayfa sayfa yapıldı.

Yeni tarafta veritabanına hiç doğrudan yazmadım. Her kayıt, panelin de kullandığı yeni backend'in API'sinden (başka yazılımların veri okuyup yazdığı kapı) geçti. Bu bilinçli bir tercihti, birazdan anlatacağım.

Veri gerçek müşteri verisiydi. Ekipler taşıma sürerken eski panelde çalışmaya devam etti, yani ilk çalıştırmadan sonra da yeni satırlar gelmeye devam etti.

Karar 1: veritabanına değil, API'ye yaz

Doğrudan yeni tablolara yazmak daha hızlı olurdu. Ama backend'in kontrol ettiği her kuralı da atlamış olurdum: zorunlu alanlar, geçerli e-posta, aktif hesabı olması gereken kişiler, var olması gereken durum kodları.

Benim satırlarım bu kuralları bozsaydı, panel daha sonra bir ekranda, bir kullanıcının önünde bozulurdu. O yüzden verimi önce API reddetsin istedim.

Çok reddetti. Amaç da buydu. Her ret, aksi halde canlıda bulacağım bir kuraldı.

Bedeli şuydu: API'nin kendi fikirleri vardı. Notların, faturaların ve sözleşmelerin oluşturma tarihini ne gönderirsem göndereyim "şimdi" yapıyordu. Yıllar önce yazılmış bir not dün yazılmış gibi görünecekti.

Bu yüzden orijinal tarihi kaydın içine yazdım. Notlar köşeli parantez içinde eski tarihle başlıyor; faturalarda ve sözleşmelerde orijinal tarihi gösteren bir satır var. Sözleşmeler daha tuhaftı: başlangıç tarihi oluşturmada yok sayılıyor, güncellemede kabul ediliyordu. O yüzden sözleşmeler önce oluşturma, sonra gerçek tarihleri yazan ikinci bir güncelleme turuyla taşındı.

Her kayıt eski panelden, yeni panelin de kullandığı API kurallarından geçip yeni CRM'e ulaşıyor.

Karar 2: her scriptin dört modu var

Her import scripti dry-run (deneme), apply (uygula), update (güncelle) ya da rollback (geri al) olarak çalışıyor.

Varsayılan mod dry-run. Hiçbir şey göndermiyor. Her payload'u (her isteğin taşıdığı veri) hazırlıyor ve bir rapor yazıyor. Rapor kaç satırın gideceğini, kaçının atlanacağını söylüyor. Yeni sistemde kimseyle eşleşmeyen kişileri, karşılığı olmayan durumları ve aynı ID'yi paylaşan müşterileri listeliyor.

Her gerçek çalıştırmadan önce o raporu okudum. Kararlarımın çoğu oradan çıktı.

Apply kayıtları gönderiyor. Update, taşınmış kayıtları aynı eşleştirmeyle tazeliyor; eşleştirmede yaptığım bir düzeltme eski satırlara da ulaşabiliyor. Rollback bir çalıştırmanın oluşturduğu her şeyi siliyor.

Karar 3: her kayıt için bir log satırı

Her istek log dosyasına bir satır yazıyor: eski ID, yeni ID, HTTP durum kodu ve varsa hata.

Bu log her şeyi tekrar çalıştırılabilir yaptı. Yeniden çalıştırma önce logu okuyor ve başarılı olan her şeyi atlıyor. Rollback neyi sileceğini bu logdan biliyor. Hiçbir şey benim hafızama kalmıyor.

Karşılığını hemen gördüm. Oturumların süresi doluyor ve uzun bir çalıştırma token'ından (oturumun kimlik anahtarı) uzun yaşıyor. En büyük çalıştırmalarda istekler yarı yolda yetkisiz dönmeye başladı.

Hiçbir şey kaybolmadı. Log hangi satırların düştüğünü biliyordu ve sonraki çalıştırma sadece onları gönderdi. Sonra otomatik yeniden giriş ekledim; artık bir çalıştırma oturumunu yeniliyor ve devam ediyor.

Örnek veriyle el çizimi şema: 1. çalıştırma altı kaydı logluyor, ikisi 401 oturum süresi doldu, biri 400 geçersiz tarih hatası alıyor. 2. çalıştırma yeniden giriş yapıyor, tarihi düzeltip sadece bu üçünü tekrar gönderiyor ve 200 dönmüş üç kaydı atlıyor. Bir not geri almanın aynı logu okuduğunu söylüyor.
İki çalıştırmada log nasıl görünüyor. Örnek veri, gerçek kayıt değil.
Her çalıştırma dört kapıdan geçiyor: önce deneme raporu, sonra uygulama, sonra her kayıt için bir log satırı, en son sadece düşenleri gönderen yeniden çalıştırma.

Karar 4: önce ana kayıtlar, sonra eşleştirmeyle alt kayıtlar

Önce müşteriler taşındı. Her yeni müşteri kaydı eski paneldeki ID'sini kendi alanında tuttu.

Sonra notlar, kişiler, faturalar ve sözleşmeler geldi. Eski panelde bunlar eski müşteri ID'sine bağlıydı. Script eski ID'den yeni müşteriye bir harita kurdu ve her alt kaydı doğru müşterinin altına gönderdi. Müşterisi henüz taşınmamış bir alt kayıt atlandı ve sayıldı; asla tahminle bağlanmadı.

Müşterileri bağlamanın da kendi sorunu vardı. Bazı eski müşterilerin ana platformdaki hesabıyla bağlantısı yoktu. Bunları iki tarafı da normalleştirip isimle eşleştirdim: Türkçe harfler sade karşılıklarına çevrildi, "A.Ş." ve "Ltd." gibi şirket ekleri ve noktalama kaldırıldı.

İsimle eşleştirme yanlış pozitif üretebilir. O yüzden rapor aynı ID'ye düşen her kayıt grubunu listeledi. Bazıları gerçekti (birkaç markayı yöneten bir ajans gibi), bazıları mükerrerdi ve bir insan tek tek kontrol etti.

Her alt kayıt (not, fatura ya da kişi) eski ID'den yeni müşteriye giden haritadan geçiyor ve doğru müşterinin altına düşüyor.

Karar 5: kirli veri görünür kalır

Eski veri, ancak satır satır bakınca görebileceğiniz şekillerde dağınıktır. Kuralım basitti: kayıt düşürme, sorunu saklama. Düzeltebildiğini düzelt, neyi değiştirdiğini kaydın içine yaz.

İlk kavga tarihlerle oldu. Eski veritabanında 1111-11-11 gibi değerler vardı. Yeni veritabanı 1753'ten önceki tarihleri saklayamıyor, bu yüzden ilk çalıştırmada bir grup kişi kaydı düştü. Geçersiz tarihler artık boş gidiyor. Eski panelde "tarih yok" çoğu zaman 1 Ocak 1970 olarak yazılmıştı; onlar da boş oldu.

E-posta alanları serbest metindi. "Ad Soyad mail@sirket.com", sonunda noktalı virgül olan adresler, alan adında çift nokta ve "x" gibi değerler buldum. Script, varsa içinden geçerli adresi çıkarıyor.

Bazı kişi kayıtlarında ad, soyad ya da e-posta eksikti; backend üçünü de zorunlu tutuyor. Onları düşürmek gerçek insanları kaybetmek olurdu. Bu yüzden yer tutucu aldılar. E-posta, hiçbir zaman posta alamayan ayrılmış ".invalid" alan adını kullanıyor. Notlarında neyin eksik olduğu ve eski değerin ne olduğu yazıyor.

Kişiler ayrı bir boşluktu. Eski kayıtlardaki bazı isimlerin yeni sistemde aktif hesabı yoktu ve backend sadece aktif olanları kabul ediyor. Bu isimler müşterinin not bölümüne yazıldı; geçmiş hâlâ hesabı kimin yönettiğini söylüyor.

Örnek veriyle el çizimi tablo: 1111-11-11 tarihi notsuz boş kalıyor; x e-postası yer tutucuya dönüşüyor ve not eski değeri saklıyor; eksik soyad tire oluyor ve not ekleniyor; aktif hesabı olmayan müşteri yöneticisi boş bırakılıp notta adıyla yazılıyor.
Dört tür kirli veri ve her birinin neye dönüştüğü. Örnek veri, gerçek kayıt değil.
Temiz satır API kurallarından geçiyor. Kirli satır (burada e-posta alanında sadece "x" yazıyor) durduruluyor, yer tutucu ve eski değeri saklayan bir not alıyor, sonra o da geçiyor.

Karar 6: tek müşteri modu

İlk çalıştırmalar her şeyi taşıdı. Canlıya geçtikten sonra da bir süre eski panele birkaç kayıt eklenmeye devam etti.

Tam bir yeniden çalıştırma her müşteriye dokunurdu. Bu yüzden bir çalıştırmayı tek müşteriyle sınırlayan bir seçenek ekledim. O müşterinin bekleyen satırlarını taşıyor, diğerlerine dokunmuyor.

Taşımanın geride bıraktığı hata

Alt kayıtlar müşteri ID'sine bağlıydı ve o ID panelde düzenlenebiliyor. Biri bir müşterinin ID'sini düzelttiğinde notlar, faturalar, kişiler ve sözleşmeler eski numarada kalıyordu.

Panel artık bunu yönetiyor. Müşteri ID'si değişince eski numaradaki kayıtları sayıyor, onay istiyor ve onları taşıyor. API bir notu başka müşteriye taşımaya izin vermediği için notlar yeni ID altında orijinal tarih ve yazarıyla yeniden oluşturuluyor.

Farklı ne yapardım

İlk çalıştırmadan önce backend ile bir import modu üzerinde anlaşırdım: gönderdiğim tarihleri koruyan tek bir seçenek. Özel durumlarımın yarısı "şimdi"nin etrafından dolaşmaktı.

Eski paneli belli bir tarihte dondururdum. Haftalarca iki canlı panel, ekstra çalıştırma ve ekstra soru demekti.

Belgeleri daha erken kontrol ederdim. Sözleşmeler dosyalara bağlanıyor ve eski veritabanındaki bazı dosya adlarının arkasında dosya yoktu. Bunu sözleşmeler taşındıktan sonra fark ettim, önce değil.

Sık sorulanlar

Neden veritabanına değil de API'ye yazmak?

API, yeni panelin çalıştırdığı doğrulamanın aynısını çalıştırıyor; hatalı satırlar daha sonra bir kullanıcının önünde değil, taşıma sırasında düşüyor. Bedeli, oluşturma tarihi gibi bazı alanları API'nin kendisinin yazması; bu yüzden orijinal tarihler kaydın içine yazılmak zorunda kaldı.

Bir veri taşımasını tekrar çalıştırmaya nasıl güvenli hale getirirsiniz?

Her kayıt için eski ID, yeni ID, durum ve hatayı içeren bir log satırı yazarak. Yeniden çalıştırma önce logu okuyup başarılı olanları atlıyor; geri alma da aynı logu okuyup sadece o çalıştırmanın oluşturduklarını siliyor.

Eski sistemdeki kirli veriye ne olmalı?

Kayıt düşürülmemeli. Düzeltilebilen düzeltilmeli, yeni sistemin zorunlu tuttuğu yerde açıkça sahte bir yer tutucu kullanılmalı ve eski değer bilgi taşıyorsa kaydın notuna yazılmalı.

Alt kayıtlar yeni ana kayıtlarını nasıl buluyor?

Önce ana kayıtlar taşınıyor ve her yeni ana kayıt eski ID'sini tutuyor. Sonra eski ID'den yeni ana kayda bir harita kuruluyor ve her alt kayıt doğru kaydın altına gönderiliyor. Ana kaydı taşınmamış bir alt kayıt atlanıp sayılıyor, asla tahminle bağlanmıyor.

Kapanış

Scriptler zekice değildi. Bilerek sıkıcıydı: bir deneme raporu, her kayıt için bir log satırı ve başarılı olanı atlayan bir yeniden çalıştırma. Yılların geçmişini, insanlar iki paneli de kullanırken taşımamı sağlayan buydu.

Diğer üretim işleri /tr/calismalar/ sayfasında.

Bu yazı İngilizce aslından Türkçeye çevrilmiştir.

Çözmeye değer bir problemin mi var?Birlikte çözelim

Konuşmaya başla

Full-stack ve uygulamalı AI rollerine açığım, uzaktan veya hibrit.

Rolü, ekibi ve problemi anlat.