Bir Otelin Personel Takip Paneli Raspberry Pi Üzerinde Nasıl Kuruldu? Mimari ve Kararlar
Bir otelde kart okuyuculu personel giriş-çıkış sisteminin Raspberry Pi 3 üzerinde Flask ve MariaDB ile nasıl kurulduğunu; hangi kararların neden alındığını ve nelerin yanlış çıktığını anlatan proje notu.
Bu yazı bir rehber değil, bir proje notu. Bir otelde personelin kart okutarak yaptığı giriş-çıkışları toplayıp müdürlerin ve insan kaynaklarının kullandığı bir panele dönüştürdük. Sistem şu an tek bir Raspberry Pi 3 üzerinde çalışıyor. Burada neyi neden o şekilde yaptığımızı, hangi kararlardan vazgeçtiğimizi ve hangi sorunlarla karşılaştığımızı anlatıyoruz. Marka, adres ve kişi bilgisi vermiyoruz; amaç, benzer bir küçük işletme sistemi kuracak birine gerçek bir örnek göstermek.
Başlangıç sorunu
Otelde personel, kapıdaki kart okuyucuya kartını okutuyor. Okuyucu her okutmayı bir olay olarak kaydediyor: kart numarası, tarih ve saat, giriş mi çıkış mı. Bu olaylar daha önce yalnızca bir cihazın içinde duruyor, ay sonunda dışa aktarılıp elle Excel'e çevriliyordu. Her ay aynı sorular soruluyordu: Kim kaç gün geldi? Gece vardiyasındakiler hangi güne yazıldı? Kim çıkışı okutmayı unuttu? Fazla mesai ne kadar? Bölüm müdürü yalnızca kendi bölümünün kayıtlarını görebilmeli, insan kaynakları hepsini.
Gereksinimleri kısaca şöyle yazdık:
- Kart olaylarını otomatik toplamak; elle veri girişi olmasın.
- Ham olayları vardiyalara çevirmek; gece vardiyası ve eksik çıkışı doğru ele almak.
- Bölüm bazlı yetkilendirme: müdür yalnızca kendi bölümünü görür.
- Ay sonu raporlarını düzenli bir Excel olarak indirmek.
- Bakımı bir kişinin yapabileceği kadar basit olması; sunucu maliyetinin neredeyse sıfır olması.
Mimari
Sistemi bilerek sıkıcı tuttuk. Bir otel için kimsenin ekstra bir bulut aboneliğine ya da kümeye ihtiyacı yok.
Şemadaki parçalar:
- Toplayıcı: Okuyucudan olayları periyodik olarak çeken küçük bir Python betiği. Aynı olayı iki kez almamak için her olaya kart no, zaman ve yön alanlarından bir benzersizlik anahtarı verir.
- Veritabanı: MariaDB. Ham hareketler hiç değiştirilmeden saklanır; vardiya, süre, fazla mesai gibi her şey bu ham veriden hesaplanır. Bu, projenin en önemli kararıdır ve aşağıda açıklıyoruz.
- Panel: Flask uygulaması, gunicorn arkasında, systemd servisi olarak çalışır. Şablonlar sunucu tarafında üretilir; JavaScript neredeyse yoktur. Rehberde anlattığımız Flask'i systemd servisi yapma adımlarının aynısını izledik.
- Dış erişim: Panel doğrudan internete açık değil. Cloudflare Tunnel üzerinden yayınlanıyor ve ayrıca uygulamanın kendi girişi var.
- Yedek: Gece çalışan bir yedek, veritabanı dökümünü alıp başka bir makineye kopyalıyor (MariaDB otomatik yedek).
Karar 1: Ham veriyi asla değiştirme
En başta, "kişi çıkışı okutmayı unuttu, kaydı düzeltelim" yaklaşımını cazip bulduk. Hızlı çözümdü ama tehlikeliydi: bir kayıt düzeltildiğinde orijinalin ne olduğu kaybolur, kimin neyi neden değiştirdiği bilinmez. Bunun yerine iki katman kurduk:
- Ham katman: Okuyucudan gelen olaylar, yalnızca eklenir. Silme ve güncelleme yok.
- Hesap katmanı: Vardiyalar, süreler ve raporlar her seferinde ham veriden yeniden hesaplanır. Düzeltme gerekirse ham veriye "düzeltme" olarak ayrı bir kayıt eklenir ve kimin eklediği yazılır.
Bu yaklaşımın bedeli, hesabın her sayfa açılışında yeniden yapılmasıdır. Pi 3 gibi küçük bir cihazda bu kaygı verici görünür; pratikte bir ayın verisi birkaç bin satırdır ve eşleştirme milisaniyeler sürer. Algoritmanın kendisini çalışma süresi hesaplama yazısında ayrıntılı anlattık.
Karar 2: Neden Pi, neden MariaDB?
Pi 3 seçimi bir mühendislik tutkusu değil, maliyet ve alan meselesiydi: 7/24 çalışırken yaklaşık 3-5 watt çeker, sessizdir, bir dolap rafına sığar. Bunun karşılığında iki zayıflığı kabul ettik ve onlara karşı tedbir aldık:
- SD kartın ömrü sınırlı. Günlükleri RAM'e aldık, swap'i azalttık ve veritabanının yazma ayarlarını gözden geçirdik. Ayrıntısı SD kartı ölümden kurtarmak yazısında. Asıl çözüm ise "kart bozulacak" varsayımıyla düzenli ve test edilmiş yedek almaktı.
- Elektrik kesilebilir. Küçük bir UPS ve düzgün kapanma betiği ekledik; ne kadar dayanacağını hesaplamak için UPS süre hesaplayıcıyı kullandık.
SQLite de düşünülebilirdi; tek kullanıcılı bir araç olsaydı onu seçerdik. Ancak panelle aynı anda çalışan toplayıcı ve gece yedeği için çok süreçli bir veritabanı, kilitlenme sorunlarını baştan eledi.
Karar 3: Rol ve bölüm bazlı görünürlük
Panelde üç rol var: yönetici (her şeyi görür), insan kaynakları (tüm personeli görür, ayarları değiştiremez) ve bölüm müdürü (yalnızca kendi bölümü). Bölüm filtresini her sorguda elle yazmak, bir gün birinin unutacağı bir hata kaynağı olurdu. Bu yüzden filtre tek bir yerde, veritabanı oturumu seviyesinde uygulanıyor: müdür rolüyle açılan her sorguya otomatik olarak "yalnızca kendi bölümü" koşulu ekleniyor. Yeni bir rapor yazan geliştirici bu koşulu eklemeyi unutsa bile müdür başka bölümü göremiyor. Buna ek olarak, müdürlerin açabileceği sayfalar bir izin listesiyle sınırlı; yeni eklenen her sayfa varsayılan olarak müdüre kapalı.
Bu "güvenli varsayılan" yaklaşımı, sistemin yaşadığı birkaç hatayı da erkenden yakaladı: bir kez yeni bir Excel indirme adresi izin listesine eklenmediği için müdürler "erişim yok" gördü. Sinir bozucu ama güvenli bir hataydı; tersi (yanlışlıkla herkese açık bir sayfa) çok daha kötü olurdu.
Karar 4: Basit gözlemlenebilirlik
Sistem sessizce bozulduğunda kimsenin fark etmemesi en büyük risktir: okuyucudan veri gelmeyi kesebilir ve kimse haftalarca anlamayabilir. Bu yüzden iki küçük kontrol ekledik: son kayıt belirli bir süreden eskiyse uyarı üretir; her sabah kısa bir günlük özet e-postası gelir. Teknik taraf için servis izleme ve alarm ile günlük özet e-postası yazılarına bakabilirsiniz.
Ne yanlış gitti?
- İlk sürümde zaman dilimi karışıklığı. Veritabanı UTC, panel yerel saat gösteriyordu; gece yarısı civarındaki kayıtlar bir gün kaydı. Çözüm, tüm zamanları tek bir biçimde saklayıp gösterimde çevirmek oldu.
- Çift okutma. Personel kartı iki kez okutunca ilk sürüm iki giriş saydı. Kısa aralıktaki ardışık aynı yönlü okutmaları tek saymak gerekti.
- Tanımsız kartlar. Personele atanmamış bir kart okutulduğunda sistem hata vermek yerine "bilinmeyen kart" olarak ayrı listeledi; böylece kayıp ya da ödünç verilen kartlar ortaya çıktı.
- Yedek vardı, geri yükleme denenmemişti. Bir gece yedeğinin eksik çıktığını ancak ilk geri yükleme denemesinde fark ettik. O günden sonra düzenli bir geri yükleme testi yapıyoruz.
Çıkarılan dersler
Küçük bir işletme sisteminde karmaşıklık düşmandır: tek makine, tek veritabanı, az bağımlılık. Ham veriyi koruyup her şeyi ondan hesaplamak, sonradan çıkan her yeni kuralı (gece vardiyası, tolerans, resmi tatil) sistemi baştan kurmadan eklemeyi mümkün kıldı. Güvenlik varsayılan olarak kapalı olmalı, izin verilen şeyler tek tek açılmalı. Ve yedek, ancak geri yüklendiği gün yedektir. Sonraki notlarda gece vardiyası kuralını, güvenlik katmanlarını ve KVKK tarafını ayrı ayrı anlatıyoruz.