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.

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ı.
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.

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.
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.

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.
- Kısaca
- Kısıtlar
- Karar 1: veritabanına değil, API'ye yaz
- Karar 2: her scriptin dört modu var
- Karar 3: her kayıt için bir log satırı
- Karar 4: önce ana kayıtlar, sonra eşleştirmeyle alt kayıtlar
- Karar 5: kirli veri görünür kalır
- Karar 6: tek müşteri modu
- Taşımanın geride bıraktığı hata
- Farklı ne yapardım
- Sık sorulanlar
- Kapanış



Bu yazıya bırakılan notlar
Katıl
Bir yorum bırak.
Bu yazıya not eklemek için giriş yap.
Sadece adın ve avatarın kullanılır.