Vaka çalışmasıYayında
Masa
Türkiye’deki bağımsız kafe ve restoranlar için QR menü, masadan sipariş, mutfak ekranı, garson tableti ve işletme paneli.
- Rol
- Tek başıma — ürün, tasarımın uygulanması, backend, altyapı
- Ne zaman
- 2026
- Backend
- Full-stack
Demo başlatıcı misafir, mutfak, garson ve işletme ekranlarını tek tıkla açıyor. İşletme girişi: [email protected] / bostan-demo; test kartı 4242 4242 4242 4242. Demo mekân her gece sıfırlanıyor; kaynak kod gizli.

Kimin için
- 6–40 masalı, sahibinin işlettiği mahalle mekânları — Kuzguncuk’ta bir kahvaltıcı, bir lokanta, bir meyhane — POS sözleşmesi ya da misafirlerin indirmesi gereken bir uygulama istemiyor.
- İhtiyaçları belli: her zaman güncel bir menü (tükenen ürünler, alerjenler, turistler için dört dil), mutfağa adisyon taşımadan ulaşan siparişler, Wi-Fi gidince fiş düşürmeyen bir mutfak ekranı — ve gün sonunda bir rakam.
- Masadaki QR kodu okutup birlikte sipariş veren misafirler: kurulacak bir şey yok, üyelik yok.
Ne yaptım
- Uçtan uca tek başıma kurdum: Cloudflare Workers üzerinde Hono API, katalog ve geçmiş için D1, ve canlı salonun — sepetler, siparişler, çağrılar, hesaplar — sahibi olan, mekân başına bir SQLite tabanlı Durable Object.
- Onaylanmış bir tasarım prototipinden birebir aktarılan tek React uygulamasında dört arayüz: misafir akışı (TR/EN/DE/RU, alerjen filtresi, ortak sepet, canlı sipariş durumu, hesap bölme), mutfak ekranı, garson tableti ve işletme paneli — ayrıca bir tasarım sistemi sayfası.
- Tam bir kez teslim: her değişiklik istemcide üretilen bir işlem kimliği taşıyor, onaylanana kadar IndexedDB’deki bir giden kutusunda bekliyor ve Durable Object onu uyguladığı transaction’ın içinde tekilleştiriyor. Bir service worker mutfak ekranını çevrimdışıyken de çalışır tutuyor.
- İşletme tarafı: seçenekli ve çevirili menü editörü, basılabilir QR masa kartları ve CSV’li gün sonu raporu — ayrıca PBKDF2 ve httpOnly oturumlarla kimlik doğrulama, hız sınırları, PaymentProvider arayüzü arkasında sahte bir PSP, gece çalışan bir cron ve değişmezi kanıtlayan bir kaos testi.
Nasıl çalışıyor
1Okut
7 numaralı masadaki QR kart menüyü açıyor. Misafir dilini (TR/EN/DE/RU) seçiyor, adını yazıyor, isterse alerjenleri gizliyor.
2Sepeti birlikte kur
Her telefon seçenekleri ve mutfağa notuyla ürün ekliyor; masadaki her telefon aynı sepeti, kimin ne eklediğiyle birlikte canlı görüyor.
3Gönder
Tek dokunuş bütün masa sepetini gönderiyor. İki kişi aynı anda gönder’e basarsa tam olarak bir sipariş çıkıyor; sen okurken sepet değiştiyse, değişikliği görene kadar hiçbir şey gitmiyor.
4Mutfak → garson → masa
Fiş milisaniyeler içinde mutfak ekranına düşüyor; sayacı 8. dakikada sarıya, 15’te kırmızıya dönüyor. Aşçı fişi ilerletiyor, misafirin takip ekranı güncelleniyor, garson servise hazır olduğunu görüyor.
5Öde
Eşit, ürüne göre ya da serbest tutarla böl, bahşiş ekle ve test kartıyla öde — ya da hesabı iste, kasada öde. Masa kapanıp arşivleniyor.
Önemli kararlar
01
Canlı salonun sahibi, mekân başına bir Durable Object
Yerine: İstekler arasında kilit ya da transaction’larla ortak bir veritabanı.
Neden: Sepetler, siparişler, çağrılar ve hesaplar tek bir yazana ihtiyaç duyuyor. Durable Object her işlemi kendiliğinden sıraya koyuyor — kilit yok, dağıtık transaction yok — ve output gate sayesinde yazma kalıcı olmadan onay gitmiyor. D1 katalogu ve geçmişi tutuyor; sıcak yol onu hiç okumuyor.
02
Tam bir kez: dikkatli istemcilerle değil, işlem kimlikleriyle
Yerine: Tekrar dene ve sunucunun mükerreri fark etmesini um.
Neden: Kafe Wi-Fi’ındaki bir telefon ancak en az bir kez teslim alabiliyor. İstemcideki giden kutusu ve sunucudaki tekilleştirme kaydı bunu tam bir kez etkiye çeviriyor. Değişiklikler mümkün olduğunca sıradan bağımsız — adetler fark olarak gidiyor, mutfak işaretleri tersine çevirmiyor, değer atıyor — ve sipariş, misafirin onayladığı sepet sürümünü taşıyor.
03
Yayın için uyuyan WebSocket’ler
Yerine: Polling ya da nesneyi uyanık tutan soketler.
Neden: Telefonlar, mutfak ekranları ve garson tabletleri rol ve masaya göre etiketlenmiş soketler tutuyor. Boştaki soketler Durable Object süresi harcamıyor, ping’leri nesneyi uyandırmadan runtime yanıtlıyor. Worker’ı yalnızca /api/* çağırıyor; uygulamanın kendisi ücretsiz statik dosya olarak sunuluyor.
04
Tasarımı yaklaşık değil, birebir aktar
Yerine: Ekranları yeterince benzeyen bir UI kit’le yeniden yapmak.
Neden: Onaylanmış prototip şartnamenin kendisi: CSS’i olduğu gibi aktarıldı, ekranları React bileşenleri olarak birebir yeniden kuruldu — token’lar, mutfak fişi, masa durumları ve TR/EN/DE/RU metinler. Prototipin yalnızca ima ettiği ekranlar da aynı token ve bileşenleri kullanıyor.
Mimari
Tek bir Worker deploy’u uygulamayı, API’yi ve WebSocket’leri sunuyor; canlı salona yalnızca mekânın Durable Object’i yazıyor. Buradaki her şey benim.
Sayılar
- kaos testinde kayıp / mükerrer sipariş
- 0 / 0
- o testte bağlantı kopması — 4.336 işlem yeniden oynatıldı
- 535
- siparişten mutfak ekranına, p50 (p95 87 ms, yerel)
- 30 ms
- aylık maliyet — Cloudflare’ın ücretsiz planı
- 0 €
Teknolojiler
Backend
- Cloudflare Workers
- Durable Objects
- D1 (SQLite)
- Hono
- TypeScript
- WebSocket hibernation
- Cron Triggers
- Rate Limiting
- PBKDF2
Frontend
- React
- React Router
- Vite
- Service worker
- IndexedDB
- qrcode-generator
Kalite
- Vitest (Workers pool)
- Chaos script
- wrangler dry-run
Galeri

Çevrimdışı mutfak ekranı: işlemler kuyrukta bekliyor, bağlantı gelince senkronlanıyor — hiçbiri kaybolmuyor. 
Misafir akışı: menü, canlı sipariş durumu, hesap bölme. 
Garson tableti: salon planı, çağrılar ve hesap istekleri. 
İşletmecinin gün sonu raporu. 
Her masa için basılabilir QR masa kartları.
Uzun versiyonu ister misin — kod, pipeline, ödünleşimler?
E-posta gönder