İçeriğe geçDEMOBu site Briefikir tarafından geliştirilmiş bir e-ihale platformu yazılımı demosudur. Kurumunuza özel ihale sistemi için bize ulaşın →

API · webhook · mobil

Geliştirici ve API

Zarfora; web, mobil ve sunucunun aynı iş kurallarını paylaştığı bir monorepo olarak geliştirildi. Aşağıdaki sözleşme kurulumda kurumunuzun altyapısında uygulanır; bu demoda sunucu yoktur, işlemler tarayıcıdaki demo adaptörüyle çalışır.

Mimari

@zarfora/coreİhale durum makinesi · teklif cetveli (kuruş) · canlı oturum motoru · değerlendirme · hash zinciri · zod · DOM yok · vitest
@zarfora/apiApiClient · MockAdapter (olay günlüğü + BroadcastChannel) · HttpAdapter · WebSocketKanal
@zarfora/tokensTek JSON'dan CSS değişkenleri ve React Native stilleri
apps/web · apps/mobileReact 18 + Vite (prerender) · Expo / React Native (İhaleler, Detay, Canlı oturum, Tekliflerim)

Adaptör değişimi tek satırdır: demo MockAdapter yerine new HttpAdapter({ taban, jeton, kanal: new WebSocketKanal(…) }). Canlı oturum motoru saf ve belirlenimcidir; aynı girdiyle her istemcide ve sunucuda aynı sıralamayı, uzatmayı ve en iyi teklifi üretir. Ayrıntı için mobil uygulama sayfasına bakın.

OpenAPI 3.1 sözleşmesi

Para alanları kuruş cinsinden tam sayıdır; zamanlar ISO 8601. Teklif uçları yalnız şifreli zarf kabul eder.

API sözleşmesi yükleniyor… openapi.yaml

Canlı oturum kanalı

Kurulumda canlı e-eksiltme ve açık artırma olayları WebSocket üzerinden iletilir; sunucu her teklifi çekirdekteki teklifDogrula fonksiyonuyla doğrular. Demoda aynı olaylar sekmeler arasında BroadcastChannel ile taşınır.

// Gerçek zamanlı kanal (kurulum): wss://api.ornek-kurum.com/v1/canli?oturum=o-i-akis
← { "tur": "durum", "kalanMs": 312000, "siraniz": 2, "enIyi": 431250000, "uzatma": 0 }
→ { "tur": "teklif", "tutar": 429100000 }
← { "tur": "teklif", "katilimci": "İstekli C", "tutar": 429100000, "zaman": "2026-10-28T11:31:05+03:00" }
← { "tur": "uzatma", "yeniBitis": "2026-10-28T11:34:00+03:00" }
← { "tur": "bitis", "siralama": [{ "sira": 1, "katilimci": "Siz" }, { "sira": 2, "katilimci": "İstekli C" }] }

Webhook örnekleri

ihale.yayimlandi

Yeni ilan yayımlandığında (ERP'de talep kaydını güncellemek, kategori abonelerine kendi kanalınızdan duyuru göndermek için).

{
  "olay": "ihale.yayimlandi",
  "zaman": "2026-10-14T09:00:12+03:00",
  "ihaleId": "i-akis",
  "ikn": "2026/ZR-004199",
  "kategori": "ZK-32",
  "yon": "alim",
  "usul": "e-eksiltme",
  "teklifSon": "2026-10-27T14:00:00+03:00"
}
teklif.alindi

Bir zarf mühürlendiğinde. Gövde tutar İÇERMEZ; yalnız makbuz özeti ve sürüm.

{
  "olay": "teklif.alindi",
  "zaman": "2026-10-26T10:05:41+03:00",
  "ihaleId": "i-akis",
  "firmaId": "f-000",
  "surum": 2,
  "makbuz": "3b7e90c2a1f4d6e8b2c0a97f13e5d4c3b2a1908f7e6d5c4b3a291807f6e5d4c3"
}
oturum.sonuclandi

Canlı e-eksiltme ya da açık artırma bittiğinde (tutanak üretimi ve karar akışını başlatmak için).

{
  "olay": "oturum.sonuclandi",
  "zaman": "2026-10-28T11:42:05+03:00",
  "oturumId": "o-i-akis",
  "ihaleId": "i-akis",
  "tur": "eksiltme",
  "enIyi": 412850000,
  "teklifSayisi": 37,
  "uzatma": 3
}
// Webhook doğrulama (Node.js) — X-Zarfora-Imza başlığı = HMAC-SHA256(gizli, ham gövde), hex
import { createHmac, timingSafeEqual } from 'node:crypto'
export function imzaGecerli(hamGovde: Buffer, baslik: string, gizli: string) {
  const beklenen = createHmac('sha256', gizli).update(hamGovde).digest('hex')
  return beklenen.length === baslik.length && timingSafeEqual(Buffer.from(beklenen), Buffer.from(baslik))
}

e-İmza, KEP, ERP ve banka adaptörleri

Demo — gerçek bağlantı yok; kurulumda kurumun yetkisi ve sağlayıcının arayüzü üzerinden bağlanır.

// Entegrasyon noktaları — kurulumda kurumun sağlayıcısına göre uygulanır
export interface EImzaAdaptoru {
  /** İmzalanacak özet (teklif mektubu PDF'inin SHA-256'sı) → imza isteği; kullanıcı kart/mobil imza ile onaylar */
  imzaIste(ozet: string, imzalayan: { tckn?: string; ad: string }): Promise<{ istekId: string }>
  sonuc(istekId: string): Promise<{ durum: 'bekliyor' | 'imzali' | 'red'; imza?: string; sertifika?: string; zaman?: string }>
  dogrula(imza: string, ozet: string): Promise<{ gecerli: boolean; sahibi?: string }>
}
export interface KepAdaptoru {
  /** Sonuç bildirimi, itiraz kararı gibi resmî yazışmalar için kayıtlı elektronik posta */
  gonder(alici: string, konu: string, ekler: { ad: string; icerik: Uint8Array }[]): Promise<{ delilId: string }>
  delil(delilId: string): Promise<{ teslim: boolean; zaman?: string }>
}
export interface ErpAdaptoru {
  /** Satın alma talebi → ihale taslağı; ihale sonucu → sipariş/sözleşme kaydı */
  talepleriGetir(kurumId: string): Promise<{ talepNo: string; kalemler: { malzemeKodu: string; ad: string; birim: string; miktar: number }[]; butceKodu: string }[]>
  siparisOlustur(s: { ihaleId: string; tedarikciVkn: string; kalemler: { malzemeKodu: string; miktar: number; birimFiyat: number }[] }): Promise<{ siparisNo: string }>
  butceKontrol(butceKodu: string, tutar: number): Promise<{ yeterli: boolean; kalan: number }>
}
export interface TeminatAdaptoru {
  /** Banka e-teminat doğrulaması */
  dogrula(referans: string, vkn: string): Promise<{ gecerli: boolean; tutar: number; bitis?: string }>
}

Kalite

  • Çekirdek birim testleri (vitest): teklif cetveli kuruş yuvarlaması ve KDV kırılımı, iş günü ve resmî tatil, hash zinciri doğrulama ve kurcalama tespiti, canlı oturumda son dakika uzatması, geçersiz adım reddi, vekil pey, belirlenimcilik.
  • Mobil uygulama TypeScript tip denetiminden geçer; web ile aynı çekirdeği kullanır.
  • Uçtan uca akış testi: arama → ilan → soru-cevap → firma kaydı → kapalı zarf → zeyilname → zarf açılışı → karşılaştırma → iki sekmede canlı e-eksiltme → sonuç; açık artırmada vekil pey; denetim zinciri doğrulaması.