Sistem

Arka Plan İşleri (Batch)

Batch, bankayla 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 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 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 kendi uygulamasından ya da SMS ile verilir; bu durumda banka 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 eşitler.

UndeliveredEventsPollJob

Periyodik

Banka 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 sorup toparlar — bir tür yedek güvence.

EventSubscriptionEnsureJob

Saatlik

Bankadan 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 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 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 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 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 öğ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 iletir; talimatın sıradaki taksidini çalıştırır.
undelivered-events-poll
UndeliveredEventsPollJob.PollAsync
*/10 * * * *10 dakikaBize ulaşamamış olay bildirimlerini bankadan 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 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 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 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 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 ile güvenli konuşma

mTLS

Batch, bankaya 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 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 (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). api-yos (public API) bu tipleri hiç taşımaz; bankaya yalnız batch bağlanır.

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

Geçici hata (ör. bankaya o an ulaşılamıyor)
İş kendiliğinden yeniden denenir; her denemede biraz daha uzun beklenir ki banka 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 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.