🏗️ WhatsApp Lead → CRM
Otomasyon Sistemi

Enterprise-Grade Teknik & Operasyonel Dokümantasyon Raporu
Versiyon 1.0 — Production Active
Durum ✅ Production'da Aktif
Son Güncelleme 2025
Rol Full-Stack Sistem Mimarı

📋 İÇİNDEKİLER

  1. Yönetici Özeti & Başarı Metrikleri
  2. Proje Tanımı, Kapsam & Stratejik Amaç
  3. Sistem Mimarisi & Katmanlı Tasarım
  4. Web Arayüzü & Kullanıcı Deneyimi Tasarımı
  5. Job & Queue Mekanizması — Asenkron İşlem Altyapısı
  6. Worker Engine — Sistemin Beyni
  7. CREATE vs UPDATE — Kritik Karar Mekanizması
  8. CRM Kayıt Bulma Stratejisi — Multi-Field Discovery
  9. Alan Güncelleme Kuralları — Akıllı Merge Stratejisi
  10. Tarih İşleme Mantığı — Cross-Platform Format Dönüşümü
  11. Hata Yönetimi & Self-Healing Mekanizmaları
  12. Decision Tables — Formal Karar Tabloları
  13. Flowcharts — Görsel Sistem Akışları
  14. Rule Engine Tasarımı — Ölçeklenebilir İş Kuralları Mimarisi
  15. Sonuç, Değerlendirme & Stratejik Etki Analizi
  16. EK: Hızlı Referans Kartı

📊 BÖLÜM 1: YÖNETİCİ ÖZETİ

1.1 Proje Başarı Metrikleri — Ölçülebilir Sonuçlar

Bu proje, tasarımdan üretime kadar tek elden yönetilmiş olup, aşağıdaki ölçülebilir iş sonuçlarını üretmektedir:

%0 Duplicate Oranı
%0 Veri Kaybı
%100 İzlenebilirlik
Auto Hata Kurtarma

1.2 Başarı Alanları Detay Tablosu

Başarı Alanı Durum Uygulanan Çözüm İş Etkisi
Duplicate Önleme ✅ Başarılı Unique constraint kontrolü + Create-first stratejisi CRM veri kalitesi korundu
Asenkron İşleme ✅ Başarılı Database-backed Queue + Daemon Worker mimarisi Binlerce kayıt timeout olmadan işleniyor
CRM Veri Koruması ✅ Başarılı Akıllı merge stratejisi + Conditional update kuralları Satış ekibinin kararları korundu
Tam Audit Trail ✅ Başarılı Her işlem payload + response + timestamp ile loglanıyor Tam şeffaflık ve sorun tespiti

1.3 Projenin Teknik Karmaşıklık Seviyesi

⚠️ ÖNEMLİ

Bu proje basit bir CRUD uygulaması DEĞİLDİR.

Bu sistem; CRM iş kurallarını, asenkron işlem yönetimini, veri uzlaştırma (reconciliation) mantığını ve akıllı merge stratejilerini bir arada barındıran, production-grade bir enterprise entegrasyon sistemidir.

Kapsanan Teknik Disiplinler:

🏛️ Distributed Systems Design (Queue + Worker)
🧠 Business Rule Engine Architecture
🔄 Data Reconciliation & Conflict Resolution
🛡️ Fault Tolerance & Self-Healing
📊 Full Audit Trail & Observability
🔌 Third-Party API Integration & Error Handling

🎯 BÖLÜM 2: PROJENİN GERÇEK AMACI & STRATEJİK DEĞER

2.1 Net Tanım — Problem Statement

Bu sistemin tek ana amacı:
WAPIM sisteminde günlük datalar adımında, yani WhatsApp kanalından gelen dataları DUPLICATE OLUŞTURMADAN, doğru kurallarla CREATE veya UPDATE ederek, asenkron ve izlenebilir şekilde işlemek.

İş Problemi:

WhatsApp üzerinden gelen lead verileri, CRM sistemine aktarılırken:

ProblemRisk SeviyesiSistem Çözümü
Duplicate müşteri kaydı 🔴 Kritik Create-first + CRM unique constraint
Satış verisi ezilmesi 🔴 Kritik Akıllı merge + conditional update
Timeout / veri kaybı 🟡 Yüksek Asenkron queue + persistent storage
İzlenebilirlik eksikliği 🟡 Yüksek Full audit trail + status tracking

2.2 Sistem Kimliği — Bu Sistem Ne ve Ne DEĞİL

❌ Bu Sistem Ne DEĞİL

  • ❌ Basit Excel upload aracı
  • ❌ CRM clone / yedek sistemi
  • ❌ Realtime UI dashboard
  • ❌ Basit bir script

✅ Bu Sistem Ne

  • ✅ Lead Ingestion Sistemi
  • ✅ Reconciliation Platformu
  • ✅ Asenkron İş Kuyruğu
  • ✅ Business Rule Engine

🏛️ BÖLÜM 3: SİSTEM MİMARİSİ & KATMANLI TASARIM

3.1 Mimari Büyük Resim — High-Level Architecture

┌──────────────────────────────────────────┐ │ 🖥️ WEB UI │ │ (Kullanıcı Arayüzü) │ │ Form Girişi → Preview → Process │ └───────────────────┬──────────────────────┘ │ HTTP POST ▼ ┌──────────────────────────────────────────┐ │ 📦 JOB QUEUE (Database) │ │ ┌────────────┐ ┌───────────────┐ │ │ │ jobs │◄──►│ job_items │ │ │ │ (Ana İş) │ │ (Satır Satır) │ │ │ └────────────┘ └───────────────┘ │ │ Status: NEW → RUNNING → DONE/FAILED │ └───────────────────┬──────────────────────┘ │ Polling (Daemon Loop) ▼ ┌──────────────────────────────────────────┐ │ ⚙️ WORKER (Daemon) │ │ worker.php + Supervisor │ │ ┌─────────────────────────────────┐ │ │ │ • CREATE/UPDATE karar motoru │ │ │ │ • Akıllı merge stratejisi │ │ │ │ • Multi-field phone discovery │ │ │ │ • Conditional field update │ │ │ │ • Full audit logging │ │ │ └─────────────────────────────────┘ │ └───────────────────┬──────────────────────┘ │ REST API Calls ▼ ┌──────────────────────────────────────────┐ │ 🌐 SETCRM API │ │ (Gerçek Veri Kaynağı) │ │ • createRecord() │ │ • updateRecord() │ │ • getRecordByUniqueField() │ │ • Unique constraint enforcement │ └──────────────────────────────────────────┘

3.2 Katman Sorumlulukları — Separation of Concerns

Bu mimari, Separation of Concerns prensibine sıkı sıkıya bağlıdır:

KatmanGörevSorumluluk DetayıBağımlılık
🖥️ Web UI Kullanıcıdan veri almak Form girişi, veri validasyonu, Preview görünümü, Process tetikleme Sadece Queue DB
📦 Queue DB İşleri sıraya koymak Durum takibi, kalıcılık sağlama, progress tracking Yok (passive storage)
⚙️ Worker İş mantığını çalıştırmak CREATE/UPDATE kararları, merge stratejisi, CRM iletişimi Queue DB + CRM API
🌐 CRM API Gerçek veri kaynağı Lead kaydı oluşturma/güncelleme, unique constraint kontrolü Yok (external system)

3.3 Mimari Kararların Gerekçeleri

Mimari KararAlternatifNeden Bu Seçildi
Database-backed QueueRedis / RabbitMQBasitlik + kalıcılık + mevcut altyapı
Daemon WorkerCron JobSürekli işleme + düşük latency
Create-first StrategySearch-firstCRM'nin kendi constraint'ini kullanma → daha güvenilir
SupervisorManuel restartOtomatik recovery → zero downtime

🖥️ BÖLÜM 4: WEB ARAYÜZÜ & KULLANICI DENEYİMİ TASARIMI

4.1 Kullanıcı Giriş Alanları

AlanVeri TipiAçıklamaValidasyon
📱 TelefonStringLead telefon numarasıFormat kontrolü
👤 İsimStringLead adı soyadıZorunlu alan
📢 Kampanya/UTMStringKaynak kampanya bilgisiİsteğe bağlı
🔗 RefStringReferans koduİsteğe bağlı
✍️ Created ByStringOluşturan kullanıcıOtomatik atanır

4.2 Buton Davranışları — İki Aşamalı Güvenlik Tasarımı

Sistem, yanlışlıkla CRM'e veri gönderilmesini engelleyen iki aşamalı bir güvenlik mekanizması içerir:

ButonEylemCRM'ye Dokunur mu?Güvenlik Katmanı
👁️ Preview Sadece görsel kontrol ❌ HAYIR 1. katman güvenlik
▶️ Process İşlemi başlatır, Queue'ya yazar ✅ EVET (Queue üzerinden) 2. katman tetikleme
⚠️ KRİTİK TASARIM KARARI

Preview butonu hiçbir şekilde CRM'ye dokunmaz. Tüm CRM iletişimi yalnızca Process → Queue → Worker zincirleri üzerinden gerçekleşir.

Bu sayede kullanıcı hatası kaynaklı veri bozulması sıfıra indirilmiştir.


📦 BÖLÜM 5: JOB & QUEUE MEKANİZMASI

5.1 Neden Queue Gerekli? — Problem Analizi

RiskAçıklamaOlasılıkEtki
🐌 CRM API yavaş olabilirTek bir kayıt 2-5 saniye sürebilirYüksekKullanıcı bekler
⚠️ API hata verebilirNetwork timeout, 500 error, rate limitOrtaVeri kaybı
📊 Binlerce kayıt gelebilirToplu upload senaryolarıYüksekSistem çöker
⏱️ Web request timeoutPHP/Nginx default timeout aşılırYüksekİşlem yarıda kalır
ÇÖZÜM MİMARİSİ: İşi hemen yapmaya çalışma. Kuyruğa koy, arka planda güvenle işle.
Bu pattern'in adı: Asynchronous Job Processing — enterprise sistemlerin standart yaklaşımı.

5.2 jobs Tablosu — Ana İş Kaydı

CREATE TABLE jobs (
    id          INT AUTO_INCREMENT PRIMARY KEY,
    status      ENUM('NEW', 'RUNNING', 'DONE', 'FAILED'),
    total       INT          COMMENT 'Toplam kayıt sayısı',
    done        INT DEFAULT 0 COMMENT 'İşlenen kayıt sayısı',
    created_at  DATETIME DEFAULT CURRENT_TIMESTAMP
);
AlanTipAnlamKullanım
idINTPrimary KeyUnique iş tanımlayıcı
statusENUMNEW / RUNNING / DONE / FAILEDİş durumu takibi
totalINTToplam kayıt sayısıProgress hesaplama
doneINTİşlenen kayıt sayısıProgress bar (done/total)
created_atDATETIMEOluşturulma zamanıAudit & sıralama

5.3 job_items Tablosu — Satır Bazlı İş Detayı

CREATE TABLE job_items (
    id           INT AUTO_INCREMENT PRIMARY KEY,
    job_id       INT          COMMENT 'Foreign Key → jobs',
    phone        VARCHAR(20)  COMMENT 'Telefon numarası',
    payload      JSON         COMMENT 'Lead verisi (tüm alanlar)',
    status       ENUM('PENDING','PROCESSING','CREATED','UPDATED','FAILED'),
    crm_response JSON         COMMENT 'CRM API yanıtı (audit için)',
    FOREIGN KEY (job_id) REFERENCES jobs(id)
);
AlanTipAnlamNeden Önemli
idINTPrimary KeyUnique item tanımlayıcı
job_idINTForeign Key (jobs)İş gruplaması
phoneVARCHARTelefon numarasıCRM'de arama anahtarı
payloadJSONLead verisiTam veri saklama (audit)
statusENUMİşlem durumuGranüler durum takibi
crm_responseJSONCRM yanıtıHata analizi & debugging

5.4 Status Durumları — Yaşam Döngüsü

StatusAnlamSonraki Adım
PENDINGWorker bekliyor, sıradaWorker alacak
🔄 PROCESSINGWorker aldı, işliyorCRM yanıtı bekleniyor
CREATEDCRM'de yeni kayıt oluşturulduTamamlandı
UPDATEDCRM'de mevcut kayıt güncellendiTamamlandı
FAILEDİşlenemedi, detaylı log'a yazıldıManuel inceleme

⚙️ BÖLÜM 6: WORKER ENGINE — SİSTEMİN BEYNİ

6.1 Worker Nedir?

⚙️ worker.php = DAEMON PROCESS
Bu, sistemin kalbidir. Sürekli çalışır, kuyruktaki işleri alır, CRM ile konuşur ve sonuçları kaydeder.
ÖzellikDetay
🔄 Çalışma ModuSürekli (Daemon) — durduğunda otomatik restart
🛡️ YöneticiSupervisor process manager
🔧 Crash RecoveryÇökerse Supervisor otomatik restart eder
📊 MonitoringStatus dosyası + log dosyaları

6.2 Worker Yaşam Döngüsü

┌──────────┐ │ START │ └────┬─────┘ │ ▼ ┌─────────────────────┐ ┌───►│ 1️⃣ PENDING kayıtları │ │ │ al (batch) │ │ └──────────┬──────────┘ │ │ │ ▼ │ ┌─────────────────────┐ │ │ 2️⃣ PROCESSING olarak │ │ │ işaretle (lock) │ │ └──────────┬──────────┘ │ │ │ ▼ │ ┌─────────────────────┐ │ │ 3️⃣ CRM ile konuş │ │ │ (CREATE veya │ │ │ UPDATE kararı) │ │ └──────────┬──────────┘ │ │ │ ▼ │ ┌─────────────────────┐ │ │ 4️⃣ Sonucu DB'ye yaz │ │ │ (status + response) │ │ └──────────┬──────────┘ │ │ │ ▼ │ ┌─────────────────────┐ │ │ 5️⃣ Sonraki batch'e │ │ │ geç │ │ └──────────┬──────────┘ │ │ └───────────────┘ (Sonsuz döngü)

Worker'ın Kritik Sorumlulukları:

#SorumlulukNeden Önemli
1PENDING → PROCESSING lockRace condition önleme
2CREATE-first stratejisiCRM'nin kendi duplicate kontrolünü kullanma
3Fallback to UPDATECREATE başarısız → mevcut kaydı akıllıca güncelle
4Akıllı mergeCRM verisini körlemesine ezme, birleştir
5Full audit logHer adımda ne olduğunu kaydet
6Error isolationBir kaydın hatası diğerlerini etkilemesin

🧠 BÖLÜM 7: CREATE vs UPDATE — EN KRİTİK KARAR MEKANİZMASI

7.1 Temel Kural — Create-First Strategy

🔴 KRİTİK MİMARİ KARAR

HER ZAMAN ÖNCE CREATE DENENİR

Neden Create-First?

YaklaşımAvantajDezavantajSeçim
Search-first (Önce ara) Kontrollü hissettiriyor 2+ API call, race condition riski
Create-first (Önce oluştur) Tek API call, CRM constraint'i kullanır, atomik "Fail" mesajını handle etmek gerekir ✅ SEÇİLDİ

Create-First'ün Üstünlükleri:

#AvantajAçıklama
1🚀 Daha hızlıTek API call ile sonuç (yeni kayıtlarda)
2🛡️ Daha güvenilirCRM'nin kendi unique constraint'ine güven
3⚛️ AtomikRace condition riski yok
4🔄 Graceful fallbackFail = "zaten var" → UPDATE akışına geç

7.2 CREATE Akışı

// 1. Adım: Her zaman önce CREATE dene
$createRes = $crmClient->createRecord($payload);

if ($createRes['IsOk'] === true) {
    // ✅ CREATED — Yeni kayıt başarıyla oluşturuldu
    $this->markAsCreated($jobItem, $createRes);
}

7.3 CREATE Başarısız Olursa?

CREATE Fail ≈ "Bu telefon CRM'de zaten var"

Bu bir hata DEĞİL, beklenen bir senaryodur. Sistem bu durumu graceful şekilde handle eder:

➡️ UPDATE akışı otomatik olarak başlar


🔍 BÖLÜM 8: CRM'DE KAYIT BULMA STRATEJİSİ

8.1 Kritik Teknik Zorluk

Problem: SETCRM API'si multi-field search desteklemiyor. Telefon numarası CRM'de 3 farklı alanda olabilir.
Çözüm: Sıralı (cascading) arama stratejisi tasarlandı.

CRM'de arama yalnızca FIELD ID ile yapılabilir:

GET RecordByUniqueField?customObjectId=...&id=FIELD_ID&value=PHONE

8.2 Unique Phone Fields Konfigürasyonu

// app.php — Merkezi konfigürasyon
'unique_phone_fields' => [
    'Mobile',        // Öncelik 1 — En sık kullanılan
    'Other Phone',   // Öncelik 2 — Alternatif telefon
    'Other Phone 2'  // Öncelik 3 — İkincil alternatif
]

8.3 getRecordByPhone() Mantığı — Cascading Search

Telefon Numarası: "+905321234567" │ ▼ ┌──────────────────────────────┐ │ 1️⃣ Mobile alanında ara │ └──────────────┬───────────────┘ │ ┌────┴────┐ BULDU ✅ BULAMADI │ │ 🛑 BREAK ▼ (Return) ┌──────────────────────────────┐ │ 2️⃣ Other Phone alanında ara │ └──────────────┬───────────────┘ │ ┌────┴────┐ BULDU ✅ BULAMADI │ │ 🛑 BREAK ▼ (Return) ┌──────────────────────────────┐ │ 3️⃣ Other Phone 2 alanında ara│ └──────────────┬───────────────┘ │ ┌────┴────┐ BULDU ✅ BULAMADI │ │ 🛑 BREAK ❌ NOT FOUND (Return) (Kayıt yok)

8.4 Performans & Maliyet Analizi

SenaryoSonuçAPI ÇağrısıDeğerlendirme
İlk field'da (Mobile) bulundu✅ Optimal1En iyi durum
İkinci field'da bulundu⚠️ Kabul edilebilir2Nadir durum
Üçüncü field'da bulundu⚠️ Kabul edilebilir3Çok nadir durum
Hiçbirinde bulunamadı❌ Kayıt yok3Tam tarama

🔀 BÖLÜM 9: ALAN GÜNCELLEME KURALLARI — AKILLI MERGE

9.1 Temel Felsefe

🔴 KRİTİK TASARIM İLKESİ

UPDATE ≠ "Her şeyi overwrite et"

UPDATE = "Akıllıca birleştir, CRM kararlarına saygı göster"

9.2 Interest (İlgi Alanı) — Merge Stratejisi

CRM'deki DurumYeni DeğerSonuçGerekçe
BoşVar➡️ Yeniyi yazKayıp veri yok
DoluVar (aynı)➡️ Değişiklik yokGereksiz güncelleme yapma
DoluVar (farklı)➡️ MERGE etMevcut bilgiyi koruyarak yeni ekle
HerhangiYok➡️ DokunmaYeni bilgi yoksa bozma

9.3 Source / CRMID Alanları

Koşulcrmid Gönder?source Gönder?
new_lead_source = "Organic"❌ UNSET✅ Gönder
new_lead_source = "Sales Mobile" VE source_wapim = "Sales Mobile"❌ UNSET❌ UNSET
Diğer tüm durumlar✅ Gönder✅ Gönder

9.4 Contact Owner / Pool Mantığı

DurumAksiyonGerekçe
Pool + Bugün follow-up yapılmış🔴 DOKUNMASatışçı bugün ilgilenmiş
Pool + Bugün follow-up yapılmamış✅ SET ETKimse ilgilenmemiş
Banned (Kara listede)🚫 ASLA SET ETMEİş kuralı: banned'e atama yok
💡 Bu Tasarımın İş Değeri: Sistem, CRM'deki insan kararlarını EZMİYOR, SAYGI DUYUYOR. Bir satışçı bugün bir müşteriyle görüşmüşse, otomatik sistem o müşteriyi başka birine atamaz. Bu, insan-makine işbirliğinin doğru tasarlanmasıdır.

📅 BÖLÜM 10: TARİH İŞLEME MANTIĞI

10.1 Teknik Zorluk — CRM Tarih Formatı

SETCRM, .NET platformu üzerinde çalıştığı için tarihler Microsoft .NET Date format ile gelir:

\/Date(1768770000000)\/

10.2 Çözüm — dotNetMsToDmy() Format Dönüştürücüsü

// Dönüşüm: .NET milisaniye → PHP DateTime → Türk tarih formatı
function dotNetMsToDmy($dotNetDate) {
    // \/Date(1768770000000)\/ → 1768770000000 → 19.01.2026
    preg_match('/\/Date\((\d+)\)\//', $dotNetDate, $matches);
    $timestamp = $matches[1] / 1000;
    return date('d.m.Y', $timestamp);
}

10.3 Karşılaştırma Mantığı

KontrolDetayGerekçe
KarşılaştırılanSadece GÜN (dd.mm.YYYY)İş kuralı gün bazında
SaatUmursanmıyor"Bugün yapıldı mı?" sorusu saat bazında değil
TasarımBilinçli kararOver-engineering'den kaçınıldı

🛡️ BÖLÜM 11: HATA YÖNETİMİ & SELF-HEALING

11.1 Fail Durumunda Loglanan Bilgiler

BilgiAçıklamaNeden Gerekli
📤 PayloadCRM'ye gönderilen tam veriNe gönderildiğini görmek
📥 CRM ResponseCRM'den dönen yanıtHatanın kaynağını anlamak
💬 Hata Mesajıİnsan okunabilir kısa açıklamaHızlı triage
TimestampZaman damgasıKronolojik analiz

11.2 Worker Çökmesi Senaryosu — Self-Healing

❌ Worker Çöktü (memory leak, uncaught exception, vb.) │ ▼ ┌─────────────────────────────────┐ │ 🛡️ Supervisor otomatik restart │ │ eder (saniyeler içinde) │ └──────────────┬──────────────────┘ │ ▼ ┌─────────────────────────────────┐ │ 🔄 reclaimStuckProcessing() │ │ │ │ PROCESSING ama takılı kalan │ │ kayıtlar tespit edilir │ │ │ │ Status: PROCESSING ➡️ PENDING │ │ (Yeniden işlenmeye hazır) │ └─────────────────────────────────┘
AşamaNe OlurSüreİnsan Müdahalesi
1. Worker çökerProcess sonlanırAnlık❌ Gerekmez
2. Supervisor algılarYeni worker başlatır1-5 saniye❌ Gerekmez
3. Stuck recoveryPROCESSING → PENDINGOtomatik❌ Gerekmez
4. Normal akış devamKuyruktaki işler işlenirAnlık❌ Gerekmez
💡 İş Değeri

Bu mekanizma sayesinde sistem 7/24 kesintisiz çalışır. Gece yarısı bir crash olsa bile, sabah iş başı yapıldığında tüm kayıtlar işlenmiş olur.


📊 BÖLÜM 12: DECISION TABLES

12.1 Status Field Karar Tablosu

Kural Formülü: SET = isPool AND NOT isToday

CaseisPoolisTodaySonuç (statusField)Açıklama
1✅ Evet✅ Evet❌ DOKUNMA (unset)Satışçıya saygı
2✅ Evet❌ Hayır✅ SET ETYeniden atanabilir
3❌ Hayır✅ Evet❌ DOKUNMA (unset)Pool'da değil
4❌ Hayır❌ Hayır❌ DOKUNMA (unset)Pool'da değil

Kod Karşılığı:

$shouldSetStatus = ($isPool && !$istodaylastfolowupdate);

if ($shouldSetStatus) {
    // Case 2: Pool'da ve bugün follow-up yok → Virgin Lead olarak set et
    $updatePayload[$statusFieldId] = $virginLeadId;
} else {
    // Case 1, 3, 4: Dokunma
    unset($updatePayload[$statusFieldId]);
}

12.2 CRMID ve Source Karar Tablosu

Casenew_lead_source "organic"new_lead_source & source_wapim "sales mobile"crmidsource
1❌ unset✅ gönder
2❌ unset❌ unset
3✅ gönder✅ gönder
4❌ unset❌ unset
⚠️ Kural Önceliği

"Sales mobile çifti" kuralı, "organic" kuralından daha baskındır. Case 4'te her iki koşul da sağlansa, "sales mobile" kuralı kazanır.

12.3 Interest Merge Karar Tablosu

CaseCRM interest boş mu?Yeni interest var mı?Listede var mı?Sonuç
1✅ Boş✅ VarSadece yeniyi yaz
2❌ Dolu✅ Var✅ Var (aynı)Aynı kalsın
3❌ Dolu✅ Var❌ Yok (farklı)CRM + yeni birleşsin
4* (herhangi)❌ YokDokunma

📐 BÖLÜM 13: FLOWCHARTS

13.1 Yüksek Seviye Akış — CREATE → UPDATE Fallback

┌───────────────────────────┐ │ Queue'dan item al │ │ (status = PENDING) │ └─────────────┬─────────────┘ │ ▼ ┌───────────────────────────┐ │ CREATE payload hazırla │ └─────────────┬─────────────┘ │ ▼ ┌───────────────────────────┐ │ CRM createRecord() │ └─────────────┬─────────────┘ │ ┌──────┴──────┐ │ │ ▼ ▼ ┌─────────┐ ┌─────────────┐ │ IsOk = │ │ IsOk = false│ │ true │ │ (Fail) │ └────┬────┘ └──────┬──────┘ │ │ ▼ ▼ ┌─────────┐ ┌─────────────────────────┐ │✅CREATED │ │ getRecordByPhone() │ └─────────┘ └────────────┬────────────┘ │ ┌──────┴──────┐ │ │ ▼ ▼ ┌──────────┐ ┌──────────┐ │ Bulamadı │ │ Buldu │ └────┬─────┘ └────┬─────┘ │ │ ▼ ▼ ┌──────────┐ ┌───────────────────────┐ │❌ FAILED │ │ UPDATE payload │ └──────────┘ │ hazırla (akıllı │ │ merge ile) │ └───────────┬───────────┘ │ ▼ ┌───────────────────────┐ │ CRM updateRecord() │ └───────────┬───────────┘ │ ┌──────┴──────┐ │ │ ▼ ▼ ┌──────────┐ ┌──────────┐ │✅UPDATED │ │❌ FAILED │ └──────────┘ └──────────┘

13.2 UPDATE Payload Karar Akışı

┌───────────────────────────────┐ │ foundCrmRecord alındı │ └──────────────┬────────────────┘ │ ▼ ┌───────────────────────────────┐ │ 1️⃣ Interest merge │ └──────────────┬────────────────┘ │ ▼ ┌───────────────────────────────┐ │ 2️⃣ DataStatus normalize │ └──────────────┬────────────────┘ │ ▼ ┌───────────────────────────────┐ │ 3️⃣ Owner normalize │ │ ➡️ isPool belirlenir │ └──────────────┬────────────────┘ │ ▼ ┌───────────────────────────────┐ │ 4️⃣ LastFollowUp parse │ │ ➡️ isToday belirlenir │ └──────────────┬────────────────┘ │ ▼ ┌──────────────────┐ │ isPool AND │ │ NOT isToday? │ └────────┬─────────┘ │ ┌──────┴──────┐ │ │ ▼ ▼ ┌───────┐ ┌───────┐ │ YES │ │ NO │ └───┬───┘ └───┬───┘ │ │ ▼ ▼ ┌────────┐ ┌────────┐ │ status │ │ status │ │ SET │ │ UNSET │ └───┬────┘ └───┬────┘ │ │ └─────┬────┘ │ ▼ ┌───────────────────────────────┐ │ 5️⃣ LeadSource/SourceWapim │ │ kuralları uygula │ └──────────────┬────────────────┘ │ ▼ ┌───────────────────────────────┐ │ 6️⃣ updateRecord() gönder │ └───────────────────────────────┘

🏭 BÖLÜM 14: RULE ENGINE TASARIMI

14.1 Mevcut Durum Analizi & Evrim Yol Haritası

⚠️ Mevcut Durum: if/else

  • • Bugün çalışıyor
  • • Ölçeklenmez
  • • Yeni kural = bug riski
  • • Öncelik yönetimi zor

✅ Hedef: Rule Engine

  • • Kuralları DATA gibi yönet
  • • Priority ile öncelik belirle
  • • Neden uygulandığını logla
  • • Yeni kural = 1 array elemanı

14.2 Kural Yapısı — Rule Schema

BileşenTipAçıklamaÖrnek
namestringKural adı (unique)status_never_set_when_today
priorityintegerÖncelik (yüksek = baskın)200
when(context)callableKoşul fonksiyonufn($c) => $c['isToday']
then(mutation)callableUygulama fonksiyonuunset($c['payload'][...])

14.3 Örnek Kurallar

Kural 1: status_never_set_when_today

Priority: 200 (BASKIN)
When: isToday === true (bugün follow-up yapılmışsa)
Then: statusField'ı payload'dan çıkar (dokunma)
Gerekçe: Satışçı bugün ilgilenmiş, sistematik müdahale yapma

Kural 2: status_set_for_pool_not_today

Priority: 100 (Normal)
When: isPool === true AND isToday === false
Then: statusField'ı "Virgin Lead" olarak set et
Gerekçe: Pool'da ve kimse ilgilenmemiş, yeniden atanabilir

14.4 Context Objesi

$ctx = [
    'isPool'         => $isPool,
    'isToday'        => $istodaylastfolowupdate,
    'isBanned'       => $isBanned,
    'newLeadSource'  => $currentNewLeadSource,
    'sourceWapim'    => $currentSourcewapim,
    'payload'        => $updatePayload,
];

14.5 Minimal Rule Engine İmplementasyonu

$rules = [
    [
        'name'     => 'status_never_set_when_today',
        'priority' => 200,
        'when'     => fn($c) => $c['isToday'] === true,
        'then'     => function (&$c) use ($statusFieldId) {
            unset($c['payload'][$statusFieldId]);
        }
    ],
    [
        'name'     => 'status_set_for_pool_not_today',
        'priority' => 100,
        'when'     => fn($c) => ($c['isPool'] === true && $c['isToday'] === false),
        'then'     => function (&$c) use ($statusFieldId, $virginLeadId) {
            $c['payload'][$statusFieldId] = $virginLeadId;
        }
    ],
];

14.6 Rules Runner — Kural Çalıştırma Motoru

// 1. Kuralları önceliğe göre sırala (yüksek önce = daha baskın)
usort($rules, fn($a, $b) => $b['priority'] - $a['priority']);

// 2. Kuralları sırayla değerlendir
foreach ($rules as $rule) {
    if ($rule['when']($ctx)) {
        $rule['then']($ctx);
        log("Rule '{$rule['name']}' uygulandı (priority: {$rule['priority']})");
        break; // İlk match eden kazanır
    }
}

$updatePayload = $ctx['payload'];

Rule Engine'in Sağladığı Avantajlar:

Avantajif/else YaklaşımıRule Engine
Yeni kural eklemeKod değişikliği + testArray'e eleman ekle
Öncelik yönetimiİç içe if'lerlepriority sayısı ile
Audit trailManuel log eklemeOtomatik
Bug riskiHer değişiklikte artarİzole, düşük risk
OkunabilirlikKarmaşıklaşırHer kural bağımsız

📈 BÖLÜM 15: SONUÇ, DEĞERLENDİRME & STRATEJİK ETKİ

15.1 Güçlü Yanlar — Teknik Mükemmellik Alanları

#Güçlü YanTeknik Detayİş Etkisi
1🎯 Duplicate üretmezUnique constraint + create-firstCRM veri kalitesi %100
2🛡️ CRM verisini ezmezAkıllı merge + conditional updateSatış kararları korunuyor
3AsenkronQueue-based, non-blockingTimeout yok
4📊 ÖlçeklenebilirQueue + Worker mimarisiBinlerce kayıt sorunsuz
5🔍 Audit edilebilirPayload + response + timestampTam şeffaflık
6🔄 Self-healingSupervisor + stuck recovery7/24 kesintisiz

15.2 Bilinçli Sınırlamalar — Trade-off Analizi

⚠️ Not

Bunlar "kör nokta" değil, bilinçli kabul edilen trade-off'lardır.

SınırlamaNeden VarKabul Edilebilir mi?Gelecek Planı
SETCRM multi-field search yokDış bağımlılık✅ Cascading search ile çözüldüAPI güncellemesi beklenebilir
Regex ile field parseCRM .NET formatı✅ Şimdilik yeterliAdapter pattern
Worker tek süreçBasitlik öncelikli✅ Mevcut yük için yeterliMulti-worker geçiş kolay

15.3 Sistemin Stratejik Değeri

Bu sistem:

❌ "Hızlı yazılmış bir script" DEĞİL

✅ CRM davranışlarını, satış süreçlerini ve veri bütünlüğü gereksinimlerini derinlemesine bilen bir mimar tarafından şekillendirilmiş, production-grade bir lead reconciliation sistemidir.

Kapsanan Mühendislik Disiplinleri:

🏛️ System Architecture — Katmanlı mimari
🧠 Business Logic Design — Decision tables
🔄 Data Reconciliation — Akıllı merge
🛡️ Fault Tolerance — Self-healing
📊 Observability — Full audit trail
🔌 API Integration — CRM entegrasyonu
Async Processing — Queue-based
📐 Rule Engine Design — Priority-based

15.4 Dikkat Edilmesi Gerekenler

⚠️ RiskMevcut DurumÖneriÖncelik
Kod karmaşıklığı artabilirYönetilebilir seviyedeDüzenli refactoring sprintleri🟡 Orta
Kural sayısı artabilirDecision table ile yönetiliyorRule Engine'e tam geçiş🟡 Orta
Bilgi transferi riskiBu doküman varDokümantasyonu güncel tut🔴 Yüksek

📋 EK: HIZLI REFERANS KARTI

🔄 CREATE/UPDATE Akışı:

CREATE başarılı ➡️ CREATED status ✅
CREATE başarısız ➡️ Phone ile CRM'de ara
  Kayıt bulundu ➡️ UPDATE yap (akıllı merge ile)
  Kayıt bulunamadı ➡️ FAILED log ❌

📊 Status Field Kuralı:

isPool && !isToday ➡️ Status SET (Virgin Lead)
Aksi halde ➡️ Status UNSET (dokunma)

🔌 Source/CRMID Kuralları:

Organic source ➡️ crmid UNSET, source GÖNDER
Sales Mobile çifti ➡️ crmid & source UNSET
Diğer durumlar ➡️ crmid & source GÖNDER

🔀 Interest Merge:

CRM boş + yeni var ➡️ Yeniyi yaz
CRM dolu + aynı var ➡️ Değişiklik yok
CRM dolu + farklı var ➡️ MERGE (CRM + yeni)
Yeni yok ➡️ Dokunma