İçindekiler
Çevrimdışı model
Temsilci sinyalsiz bir köyde sipariş alır, fiyatı ve kampanyayı anında görür. Bu bir önbellek değil; cihaz kendi veri kopyasını, kendi işlem kuyruğunu ve fiyat motorunun kendi kopyasını taşır.
Saha yazılımlarında “çevrimdışı destek” genelde şu anlama gelir: uygulama isteği gönderemezse ekranda bir uyarı çıkar ve temsilci sinyal arar. Rutix’te çevrimdışı varsayılan durumdur. Temsilcinin yaptığı her işlem yerel kuyruğa yazılır ve anında döner; bu yolda hiçbir adım ağı beklemez. Şebeke, işi yapan şey değil, işi sonradan taşıyan şeydir.
Cihazda ne var #
El terminalinde bir SQLite veritabanı (rutix.db) üç tablo tutar: gönderilmeyi bekleyen işlemlerin günlüğü, sunucudan inen satırların kopyası ve senkronizasyon imleci gibi birkaç değer.
Kopyadaki satırlar sütunlara açılmaz, JSON belgesi olarak saklanır. Bu bilinçli: sunucuda müşteri tablosuna bir alan eklemek, on bin el terminalinde bir şema göçü gerektirmemeli. Oturum kapatıldığında üç tablo da silinir — ortak kullanılan bir telefon, önceki temsilcinin rutunu bir sonrakine sızdırmaz.
Cihazda hangi motorlar çalışır #
Fiyatlandırma ve promosyon motorlarının TypeScript kopyaları cihazda çalışır. Bu, aynı ticari kuralların ikinci bir uygulaması demektir ve gerçek bir tehlikedir: iki uygulama anlaşamadığı an temsilci tezgâhta bir fiyat söyler, faturada başka bir fiyat çıkar. Umut etmek yerine iki koruma konuldu.
- Paylaşılan uygunluk fikstürleri. Elli bir vaka tek bir dosyada duruyor; hem .NET tarafındaki hem TypeScript tarafındaki test paketi aynı dosyayı okuyor. Referans dillerden biri değil, dosyanın kendisi. Onu fiyatlandırma (miktar kırılımı, süresi dolmuş liste, adet fiyatından koli fiyatı türetme), otuz beşi promosyon (kademeli indirim, bütçe kırpma, tekil kampanyanın diğerlerini engellemesi, kıl payı kaçan fırsat), altısı depozito. Vakalar yalnızca rakamı değil açıklamayı da sabitliyor: siparişin üstüne yazılan iz metni ve kaçan fırsat önerisi de karşılaştırılır, çünkü ikisi de karşılaştırılmadıkları sürece sessizce ayrışabiliyordu.
- Uçtan uca eşitlik kontrolü. Gerçek bir senkronizasyon çekişinden bir cihaz kopyası kurulur ve o kopyanın hesapladığı teklif sunucununkiyle karşılaştırılır. Bu kontrol ilk çalıştırmasında işini kanıtladı: çekiş, fiyat listesi satırlarını başlıkları olmadan gönderiyordu, dolayısıyla el terminali hangi listenin geçerli olduğunu ayırt edemiyor ve köşedeki bakkalı otel tarifesiyle fiyatlıyordu. Fikstürler bunu asla yakalayamazdı — açık motorlarda değil, senkronizasyon sözleşmesindeydi.
Para aritmetiği de aynı şekilde iki tarafta eşleşir: her iki motor da dört ondalık basamakta tam sayı üzerinden çalışır ve yarımı sıfırdan uzağa yuvarlar. Faturaya yazılırken iki basamağa inilir.
Bir senkronizasyon turu #
- 1
Temsilci bir işlem yapar
Ziyaret açılışı, sipariş, tahsilat, teslimat — her biri yerel kuyruğa bir satır yazar. Satır bir istemci tarafından üretilmiş kimlik ve cihazın kendi sıra numarasını taşır. Ekran hemen döner; gönderim arka planda denenir. - 2
Gönderim (push)
Bekleyen işlemler 25’lik yığınlar hâlinde gönderilir. Sunucu bunları dizideki sıraya değil, cihazın kendi sıra numarasına göre uygular — yani ziyaretin açılışı, o ziyarette alınan siparişten önce işlenir. - 3
İşlem başına cevap
Her işleme ayrı cevap verilir. Reddedilen bir sipariş, arkasında sırada bekleyen on bir ziyareti bloke etmez. Sunucu, cihazın benimsemesi gereken değerleri de geri gönderir: sipariş numarası, net tutar, indirim toplamı, risk askısı sebebi. - 4
Çekiş (pull)
Cihaz elindeki tek tam sayı imleci gönderir; sunucu o imleçten büyük her satırı döner. Yarıda kesilen bir çekişten devam etmek hiçbir şeye mal olmaz. Sayfa başına tablo başına 500 satır çekilir.
Tekrar gönderim neden güvenli #
Tünelden çıkan bir telefon, cevabını alamadığı bir yığını yeniden gönderir. İşlemin kimliği cihazda üretildiği ve (cihaz, işlem kimliği) çifti sunucuda birincil anahtar olduğu için, daha önce uygulanmış bir işlem yeniden uygulanmaz: duplicate cevabı ve ilk seferki varlığın kimliğiyle döner. Aynı para iki kez tahsil edilmez, aynı araç iki kez boşaltılmaz.
Kayıt her işlemin ardından yazılır, yığının sonunda değil — yığının ortasında kopan bir bağlantı, o ana kadar uygulananları kalıcı bırakır.
| Cevap | Anlamı | Cihaz ne yapar |
|---|---|---|
| applied | İşlem uygulandı. | Kuyruktan düşürür. |
| duplicate | Bu işlem zaten uygulanmıştı; yeniden uygulanmadı. | Uygulanmış sayar. Cevapta varlığın kimliği vardır. |
| rejected | Bir iş kuralı reddetti. Kalıcı olarak geçersiz. | Yeniden denemez. Sebebi temsilciye gösterir; temsilci gördüğünü onaylayana kadar kuyrukta kalır. |
| failed | Geçici bir sunucu sorunu. | Beklemede’ye geri alır ve bir sonraki turda yeniden dener. |
Sunucunun anladığı komutlar #
Cihazdan gelebilecek yedi işlem türü var:
| Komut | Ne yapar | Sunucunun geri verdiği değerler |
|---|---|---|
| visit.checkin | Ziyaret açılışı. | durum, coğrafi çit içinde mi, mesafe (m) |
| visit.checkout | Ziyaret kapanışı. | durum, sonuç |
| visit.skip | Ziyaret atlandı. | durum |
| order.create | Sipariş oluşturma (soğuk ya da sıcak satış). | sipariş numarası, durum, net tutar, indirim toplamı, risk askısı sebebi |
| payment.collect | Kapıda tahsilat. | durum, hangi faturaya ne kadar mahsup edildiği, mahsup edilemeyen artan |
| shipment.deliver | Teslim (tam ya da kısmi). | durum, sevkiyat durumu, teslim sayısı |
| shipment.fail | Teslim edilemedi. | durum, sevkiyat durumu, başarısız durak sayısı |
Çakışmalar #
Burada bilerek bir birleştirme algoritması yok. Sebebi üç maddede:
- İşlem verisi yalnızca eklenir. İki cihaz, yalnızca birinin oluşturduğu bir sipariş üzerinde çakışamaz.
- Ana veri sunucu otoritesindedir. Cihaz gönderileni olduğu gibi benimser. Yazma tek bir işlemde yapılır, yani yarıda kesilen bir çekiş yarım güncellenmiş bir fiyat listesi değil, bir önceki tutarlı kopyayı bırakır.
- Gerçek çakışmalar iş kararıdır. Gün ortasında başka bir ruta taşınmış bir müşteri, otomatik olarak çözülecek bir veri sorunu değildir. Bir insanın üzerinde işlem yapabileceği bir sebep koduyla reddedilir ve temsilciye gösterilir.
Cihaz kaydı #
Uygulama ilk açılışta kendine kalıcı bir kurulum kimliği üretir ve giriş yaparken gönderir. Sunucu aynı kurulum için aynı cihaz satırını döndürür — yani uygulama silinip yeniden kurulduğunda senkronizasyon imleci korunur. Aksi hâlde el terminali bütün veri kümesini mobil hat üzerinden yeniden indirirdi.
Cihaz kaydı isteğe bağlıdır: panelden giren bir kullanıcı cihaz bilgisi göndermez ve cihaz kimliği almaz. Bir cihaz engellenmişse hem gönderim hem çekiş, temsilciye yöneticisine başvurmasını söyleyen bir kodla reddedilir.
Bir çekiş ne getirir #
Sunucu, imleçten büyük satırları on beş küme hâlinde döner: müşteriler, risk profilleri, ürünler, ürün birimleri, fiyat listeleri, fiyat satırları, promosyonlar, açık faturalar, sevkiyatlar, sevkiyat durakları, sipariş satırları, rutlar, ziyaretler, siparişler ve stok seviyeleri.
Kişiye özel olanlar cihazın bağlı olduğu kullanıcıya göre daraltılır: bir şoför yalnızca kendi sevkiyatını, bir temsilci yalnızca kendi rutunu ve ziyaretlerini alır. Kapanmış faturalar hiç gönderilmez. Sipariş satırları — bir dağıtıcının şemasındaki en büyük tablo — yalnızca o şoförün kendi duraklarının arkasındaki satırlarla sınırlıdır; geri kalanının bir el terminalinde işi yoktur.
GET /sync/pull?deviceId=<cihaz>&cursor=48213&limit=500
{
"cursor": 48991,
"hasMore": false,
"serverTime": "2026-08-20T06:12:44+00:00",
"counts": { "customers": 3, "priceListItems": 118, "visits": 12 },
"changes": { "customers": [ ... ], "priceListItems": [ ... ] }
}