Repository navigation
Mimari
Founder @dakicksoft edited this page Aug 17, 2026
·
2 revisions
| # | İlke | Anlamı |
|---|---|---|
| 1 | Modüler monolit | Türkiye'nin tüm kartlı e-ticaret hacmi tek Postgres'e sığar. Modüller yalnız *.Contracts üzerinden konuşur; sınır mimari testle (NetArchTest) zorlanır. |
| 2 | Offline-first istemci, sunucu otoritesi | Saha cihazı ağsızken kayıt kuyruklar; ama yasal işlem zamanı yalnız sunucu saatinden yazılır. Cihaz "tahsil edildi" üretemez — yalnız "tahsilat talebi" üretir. |
| 3 | Hiçbir operasyonel kayıt silinmez | Olay defterlerinde DELETE (çoğunda UPDATE de) hakkı uygulama rolünde yoktur — GRANT düzeyinde. İptal = yeni durum + yeni olay. KVKK silme bir UPDATE'tir; mali kayıt yerinde kalır. |
| 4 | İki katmanlı işyeri izolasyonu | Katman A: EF global query filter. Katman B: Postgres RLS (poyra_app rolü NOBYPASSRLS, açılışta canlı doğrulanır). RLS testleri ham SQL ile bile işyerleri arası görünmezliği kanıtlar. |
flowchart LR
subgraph Istemciler["İstemciler"]
M["İşyeri sunucusu<br/>(REST + webhook)"]
P["İşyeri personeli<br/>(tarayıcı)"]
C["Son müşteri<br/>(tarayıcı)"]
S["Saha temsilcisi<br/>(MAUI/Android)"]
end
subgraph Poyra["Poyra (modüler monolit)"]
API["Poyra.Api<br/>REST + callback + Hangfire"]
PANEL["Poyra.Panel<br/>Blazor panel"]
CO["Poyra.Checkout<br/>ödeme sayfası"]
MOD["Modules/*<br/>CQRS dispatcher üzerinden"]
CONN["Connectors/*<br/>banka & PSP adaptörleri"]
end
DB[("PostgreSQL 18<br/>RLS + append-only")]
BANK["Bankalar / PSP'ler<br/>(sanal POS, 3DS)"]
M -->|X-Api-Key| API
P --> PANEL
C --> CO
S -->|toplu senkron| API
API --> MOD
PANEL --> MOD
CO --> MOD
MOD --> DB
MOD --> CONN
CONN <--> BANK
BANK -->|"callback (tek kullanımlık belirteç)"| API
API -.->|"HMAC imzalı webhook"| M
DB -.->|LISTEN/NOTIFY| PANEL
Sık sorulan üç tasarım sorusu:
- Panel neden API'ye HTTP atmaz? Modüler monolit avantajı: Panel aynı süreçte aynı komut/sorgu yolunu (dispatcher) doğrudan çağırır — çift serileştirme ve ek gecikme yok.
- Checkout neden ayrı host? Kimliksiz, herkese açık ve saldırı yüzeyi en geniş bileşen; panelden ve API'den ayrı ölçeklenir/kapatılır.
- Kart verisi nerede? Hosted akışta hiç uğramaz (banka sayfası). Direct/token akışı için Kasa modülü: PAN AES-256-GCM zarfta, CVV asla saklanmaz.
poyra/
├─ src/
│ ├─ Poyra.SharedKernel Elle yazılmış CQRS dispatcher, TenantContext/UserContext,
│ │ IClock, TurkishText, para/giriş yardımcıları, sır şifreleme
│ ├─ Poyra.Persistence ModuleDbContext tabanı, RLS + audit interceptor'ları
│ ├─ Connectors/ Abstractions + 21 banka/PSP adaptörü
│ ├─ Modules/ 20 iş modülü — her biri kendi DbContext + migration geçmişiyle
│ ├─ Poyra.Api REST API (FastEndpoints), banka callback'leri, Hangfire, Scalar, OTel
│ ├─ Poyra.Panel İşyeri paneli (Blazor, statik SSR + interaktif adalar)
│ ├─ Poyra.Checkout Müşteriye bakan kimliksiz ödeme sayfası (açık tema)
│ ├─ Poyra.Field.Core Saha kuyruk/senkron mantığı (sade, testli kütüphane)
│ └─ Poyra.Field.App MAUI/Android saha uygulaması (ince kabuk)
├─ tests/ Unit · Architecture (modül sınırı + PCI bekçileri) · Integration
├─ docker/ + docker-compose*.yml
└─ docs/ Ürün ve entegrasyon dokümanları
1.111 test, dört katman:
- 719 birim — konnektör hash'leri, TOTP RFC 6238 vektörleri, taksit matematiği, EMV QR, yeniden tahsilat politikası ve konnektör uyum kiti.
- 37 mimari/PCI bekçisi — modül sınırı, CVV sütunu yokluğu, düz PAN taraması.
- 334 entegrasyon — gerçek PG 18 + gerçek HTTP webhook alıcısı + panel/checkout HTML doğrulaması + LISTEN/NOTIFY.
- 21 E2E — gerçek tarayıcı (Playwright): interaktif adalar, TOTP 2FA yolculuğu, tehlikeli aksiyon onayı, mobil çekmece, yazdırma stilleri.
Kapsam: satır %80,7 · dal %54,3 · metot %90. Kapsam kapısı bir hedef değil
gerileme kapısıdır: testsiz kod eklenince oran düşer ve PR kırılır.
Ayrıca Stryker.NET ile mutasyon testi elle tetiklenir (./scripts/mutasyon.sh).
Poyra — Türkiye'nin açık kaynak ödeme mühendisliği platformu · AGPL-3.0 · Güvenlik açığı için: özel bildirim