Sistem

Arka Plan İşleri (Batch)

Batch, bankayla/kurumla konuşan tek uygulamadır. Hangfire adlı zamanlayıcıyla çalışır: kimi işleri düzenli aralıklarla, kimilerini de bir şey olduğu anda yapar. Dışarıya açık bir web servisi yoktur; bütün görevi niyet kutusundaki işleri yürütmek ve verileri güncel tutmaktır. Her işin bir hız sınırı ve yeniden deneme kuralı vardır — banka/kurum yorulmaz, iş kaybolmaz.

Nasıl çalışır? İki tetik türü var: (1) anlık — API bir niyet yazınca hemen tetiklenir; (2) periyodik — düzenli aralıklarla otomatik çalışır. Aynı işin iki kopyası aynı anda çalışmaz (eşzamanlılık kilidi).

SyncIntentConsumerJob

Sürekli + anlık

Sistemin kalbi burası. API tarafı "şu iş yapılacak" diye niyet kutusuna ne bıraktıysa, bu iş onları sırayla ele alır: ilk verileri çekmek, durumu bankayla/kurumla eşitlemek, rızayı iptal etmek. Kutuyu düzenli aralıklarla kontrol eder; ama yeni bir niyet düştüğünde beklemez, hemen işe koyulur. (Rıza açma ve yetkilendirme tamamlama ise ağırlıklı olarak senkron iç RPC ile yürür; niyet kutusu bunlarda yalnızca yedek yoldur.)

PeriodicResourceRefreshJob

Periyodik

Bağlı hesapların bakiyesini, işlem geçmişini ve kart bilgilerini kimse istemeden, arka planda kendi kendine tazeler. Amaç şu: kullanıcı uygulamayı açtığında veri zaten güncel olsun. Üç görevi (bakiye, kart, işlem) üç ayrı takvimle çalışır.

DecoupledGkdPollJob

Periyodik

Bazı onaylar bankanın/kurumun kendi uygulamasından ya da SMS ile verilir; bu durumda banka/kurum bizi geri yönlendirmez. Bu iş, onay bekleyen bağlantıları ara ara yoklar; kullanıcı onayı verir vermez rızayı tamamlar.

ConsentTimeoutSweepJob

Periyodik

Kullanıcı onay ekranına gitti ama hiç onaylamadıysa o rıza yarım kalır. Bu iş, süresi geçen rızaları bulup kapatır; askıda kalmış onayları da fark edip durumu bankayla/kurumla eşitler.

UndeliveredEventsPollJob

Periyodik

Banka/Kurum normalde olan biteni bize anında bildirir. Ama bu kanal bir ara koparsa haberler kaçabilir. Bu iş, kaçan bildirimleri belli aralıklarla bankaya/kuruma sorup toparlar — bir tür yedek güvence.

EventSubscriptionEnsureJob

Saatlik

Bankadan/Kurumdan anlık bildirim alabilmek için önce "bana haber ver" aboneliğinin kurulu olması gerekir. Bu iş her saat başı kontrol eder: abonelik var mı, güncel mi? Yoksa kurar, bozulmuşsa düzeltir.

RecurringPaymentExecutionJob

Periyodik

Düzenli ödeme talimatlarını takip eder; günü gelen taksidi bankaya/kuruma iletir. Böylece kullanıcının her ay elle ödeme yapması gerekmez.

ForwardDatedPaymentStatusSyncJob

Periyodik

İleri tarihli ödemeler için "günü geldi mi, gerçekleşti mi?" sorusunun cevabını bankadan/kurumdan alır ve kayıtları buna göre günceller.

Zamanlanmış işler (Hangfire recurring)

Hangfire panosunda (:8445/hangfire) görünen 10 kayıt. Cron ifadeleri UTC.PeriodicResourceRefreshJob üç ayrı metotla üç takvimde çalışır.

İşCronSıklıkGörevi
sync-intent-consumer
SyncIntentConsumerJob.DrainDueAsync
*/10 * * * * *10 saniyeAPI'nin niyet kutusuna bıraktığı işleri (rızayı iptal et, ilk verileri çek, durumu eşitle...) sırayla alır ve her birini ilgili işleyiciye dağıtır. Batch'i API'ye bağlayan ana köprü budur. Not: rıza oluşturma ve yetkilendirme tamamlama artık ağırlıklı olarak senkron iç RPC ile yürür; AuthorizationComplete niyet türü hâlâ vardır ama yalnızca senkron çağrı başarısız olursa devreye giren yedek yoldur.
decoupled-gkd-poll
DecoupledGkdPollJob.PollDueAsync
*/30 * * * * *30 saniyeBanka/Kurum uygulamasından ya da SMS ile verilen onayları yoklar; kullanıcı onaylamışsa akışı tamamlar. Bu yolda geri yönlendirme olmadığı için sormak bize düşer.
consent-timeout-sweep
ConsentTimeoutSweepJob.SweepAsync
*/5 * * * *5 dakikaOnay süresi dolmuş, yarım kalmış rızaları bulur ve "süresi doldu" olarak kapatır. Ortalıkta askıda rıza kalmaz.
event-subscription-ensure
EventSubscriptionEnsureJob.EnsureAsync
0 * * * *SaatlikBankadaki/Kurumdaki olay aboneliğimiz duruyor mu diye bakar; yoksa yeniden kurar. Abonelik olmazsa anlık bildirimler gelmez.
forward-dated-status-sync
ForwardDatedPaymentStatusSyncJob.ExecuteDueAsync
0 * * * *Saatlikİleri tarihli ödemelerin sonucunu (gerçekleşti mi, başarısız mı) bankadan/kurumdan öğrenip kayıtları günceller.
periodic-balance-refresh
PeriodicResourceRefreshJob.RefreshBalancesAsync
0 * * * *SaatlikBağlı hesapların bakiyelerini kendiliğinden tazeler. Sistem tetiklediği için PSU=H sayılır ve kotaya tabidir.
periodic-card-refresh
PeriodicResourceRefreshJob.RefreshCardsAsync
*/45 * * * *45 dakikaKart bilgilerini (limit, borç, işlemler) kendiliğinden tazeler (PSU=H).
periodic-transaction-refresh
PeriodicResourceRefreshJob.RefreshTransactionsAsync
0 */6 * * *6 saatte birHesapların işlem geçmişini kendiliğinden tazeler (PSU=H).
recurring-payment-execution
RecurringPaymentExecutionJob.ExecuteDueAsync
0 * * * *SaatlikGünü gelen düzenli ödemeleri bankaya/kuruma iletir; talimatın sıradaki taksidini çalıştırır.
undelivered-events-poll
UndeliveredEventsPollJob.PollAsync
*/10 * * * *10 dakikaBize ulaşamamış olay bildirimlerini bankadan/kurumdan sorup toplar. Anlık kanal koparsa devreye giren yedek güvence.
PSU-Initiated: periyodik refresh'ler H (otonom, kotalı); kullanıcı?fresh=true ile E (anlık, kotasız); banka/kurum olay bildirimi tetiklerse O.

Saati beklemeyen görev: canlı okuma (?fresh=true)

Buraya kadar anlatılanların hepsi bir takvime bağlıydı. Ama batch'in bir de saati beklemeyen görevi var. Kullanıcı "bana şu an bankadaki/kurumdaki en güncel hâli göster" dediğinde — yani isteğe ?fresh=true eklendiğinde — API periyodik tazelemeyi beklemez: batch'e doğrudan, senkron bir iç çağrı yapar (/internal/live-query). Batch o an bankaya/kuruma gider, taze veriyi çeker, veritabanına yazar ve cevabı hemen geri verir. Kullanıcı birkaç saniye bekler ama karşılığında dakikalar önceki değil, o anki veriyi görür.

Normal okuma

Veri doğrudan veritabanından gelir; çok hızlıdır. Arka plandaki periyodik işler veriyi zaten düzenli tazelediği için çoğu ekrana bu yeter.

Canlı okuma (fresh)

Kullanıcı istediği için yapılır; bankaya/kuruma o an gidilir. Kullanıcı tetiklediğinden PSU=E sayılır ve kotaya takılmaz. Biraz daha yavaş, ama en güncel.

Okuma ile yazmayı karıştırma: canlı okuma niyet kutusuna uğramaz, doğrudan senkron çağrıyla yapılır. Yazma işleri (rıza açmak, ödeme başlatmak) ise her zaman niyet kutusundan sırayla geçer. Akışın tamamı: Canlı Okuma & PSU.

Banka/Kurum ile güvenli konuşma

mTLS

Batch, bankaya/kuruma kendi istemci sertifikasını sunar; iki taraf da birbirini doğrular. Sertifikalar sadece batch'te durur; artık batch imajının içine gömülüdür (Dockerfile COPY certs/…) — eski Dokploy bind mount kaldırıldığı için dışarıdan bağlanmaz.

İmzalı gövde (JWS)

Giden isteklerin gövdesi PS256 ile imzalanır (detached JWS). Banka/Kurum yanıtları da doğrulanır; imzasız yanıt reddedilir.

Oran sınırı (kota)

Bağlantı + sorgu tipi başına sayaç (HhsQueryQuota). Anlık ve periyodik çekimler aynı sayacı paylaşır — çift sayım olmaz.

BKM'ye giden alanlar (Wire DTO)

Bankaya/Kuruma (HHS) gönderilen/gelen JSON gövdelerinin Türkçe alan adları (rizaNo,hesaplar, bakiye, yetKod...) ayrı wire DTOsınıflarında yaşar. Bu sınıflar [JsonPropertyName] ile Türkçe wire adını taşır; AutoMapper profilleri bunları İngilizce iç modele çevirir.

Konum: apps/batch/src/FinevoConnect.Yos.Batch.Infrastructure.Integration/Ohvps/Models/ — 8 aile, ~69 DTO dosyası. Serileştirme: aynı klasörün Json/ altındaki source-gen context'ler. Wire yol sabitleri ayrı: Domain/Constants/Api/OhvpsPaths.cs.
Aile (klasör)İçerik (örnek wire alanları)
Models/Accounthesap + bakiye (hesaplar, bakiye, iban, hspBlg...)
Models/Cardkart + detay + taksit + puan (kartBilgileri, ekstre...)
Models/Consentrıza (rizaNo, rizaDrm, izinBilgisi, hspBlg...)
Models/Paymentödeme emri (emrBlg, tutar, alc, gon, odmStm...)
Models/Transactionişlem geçmişi (islemBilgileri, brcAlc, ttr...)
Models/Eventolay bildirim/abonelik (olaylar, abonelikTipleri...)
Models/Tokenerişim belirteci (erisimBelirteci, yetKod...)
Models/Commonortak bloklar (katilimciBlg, kmlk, gkd, hata...)
Sızma yasağı (ADR-YOS-008): Türkçe wire alan/tip adları SADECE bu klasörde bulunur;FinevoConnect.Yos.Domain/FinevoConnect.Yos.Application/FinevoConnect.Yos.Shared içine ASLA sızmaz (mimari test — NetArchTest — bunu zorlar). FinevoConnect YÖS (public API) bu tipleri hiç taşımaz; bankaya/kuruma yalnız batch bağlanır.

Bir iş başarısız olursa?

Geçici hata (ör. bankaya/kuruma o an ulaşılamıyor)
İş kendiliğinden yeniden denenir; her denemede biraz daha uzun beklenir ki banka/kurum gereksiz yere yorulmasın (exponential backoff).
Kota doldu
İş çöpe gitmez, ertelenir. Kota penceresi yenilendiğinde kaldığı yerden tekrar denenir.
Kalıcı hata / red (ör. banka/kurum 409 döndü)
Sonuç değişmeyeceği için tekrar denemenin anlamı yoktur; ilgili kayıt "başarısız" olarak işaretlenir ve akış oraya kadar gelir.
Deneme hakkı bitti
Niyet "ölü" (dead) olarak işaretlenir ve bir insanın bakması için kenara ayrılır. Hiçbir iş sessizce kaybolmaz.