Isı gider paylaşımında son halka şu: apartmanda oturan kişi eline bir fatura alıyor ve “bu rakam nereden çıktı?” diye soruyor.
Cevabı verecek yer bir portal. Eskisi vardı ama on yıllık bir e-ticaret altyapısının üstüne kurulmuştu ve her yeni istek onu biraz daha zorluyordu. Sıfırdan yazdım: app.brunatazenner.tr.
Ne gösteriyor
- Faturalar — kalem kalem: ısı payı, ortak alan, su, sabit gider. PDF olarak da indirilebiliyor.
- Günlük tüketim grafiği — sayaç okumaları, üstüne o günün hava sıcaklığı. İkisi yan yana olunca “kış soğuktu” cümlesi bir iddia olmaktan çıkıp grafiğe dönüşüyor.
- Bina ortalaması kıyası — sen mi çok harcadın, bina mı. Gelen soruların yarısı bu kutuyla bitiyor.
- İstek/öneri — mesajlaşmalı basit bir talep sistemi.
- Hane alt kullanıcıları — eşin, çocuğun da kendi girişiyle bakabilsin.
Bir de ayrı bir site yöneticisi paneli var: blok ve haneler, sakinlere toplu SMS, duyurular, gelen istekler.
Asıl mimari karar: PULL
Faturalar portalda üretilmiyor. CRM’de üretiliyor — dönem dönem, kendi veritabanlarında.
İki seçenek vardı:
| PUSH | PULL | |
|---|---|---|
| Nasıl | CRM fatura onaylanınca portala gönderir | Portal ihtiyaç duyunca CRM’e sorar |
| CRM’in portalı bilmesi | gerekir | gerekmez |
| Portal kapalıyken | gönderim kaybolur, kuyruk gerekir | hiçbir şey olmaz |
| Veri farklılaşması | zamanla kaçınılmaz | kaynak her zaman doğru |
PULL’u seçtim. Portal bir fatura listesine ihtiyaç duyduğunda CRM’in ucuna gidiyor, cevabı alıyor ve kendi tablosuna yazıyor (cache-aside). Bir sonraki sefer önbellekten okuyor.
Önbellek tazelenirken de “ekle” değil “sil ve yeniden yaz” yapıyor. Sebep: bir fatura CRM’de iptal edilmişse, ekleme mantığı onu portaldan asla silmez. Sakin, iptal edilmiş bir faturayı aylarca görmeye devam eder.
Taşınan kiracı problemi
En çok kafa yorduğum kısım burası ve teknik değil, etik bir problem.
Bir kiracı Mart’ta taşınıyor. Şubat faturasını görebilmeli — o dönem orada oturuyordu, parayı o ödedi. Ama Nisan faturasını görmemeli; o daire artık başkasının ve orada başkasının tüketimi var.
İki mekanizmayla çözdüm:
ilişki: kullanıcı ↔ hane
visible_from = taşınma tarihi
visible_until = çıkış tarihi ← sonrası görünmez
relation_frozen = 1 ← CRM'e artık SORMA
Görünürlük penceresi hangi dönemleri görebileceğini belirliyor. Donmuş ilişki ise daha sert bir şey: sistem o ilişki için CRM’e bir daha hiç gitmiyor, yalnız o güne kadar önbellekte olanı gösteriyor.
İkincisi olmasa, bir hata veya bir yanlış eşleşme yüzünden eski kiracı yeni kiracının verisini görebilirdi. Donmuş ilişkide bu fiziksel olarak mümkün değil — sorgu hiç yapılmıyor.
Yetkilendirmeyi “göster/gösterme” filtresi olarak kurmak yetmez. Asıl güvenli olan, veriyi hiç getirmemek. Filtreyi biri unutur; yapılmamış bir sorguyu kimse unutamaz.
Teknoloji tarafı
Hazır bir çatı kullanmadım ama her şeyi de yazmadım. Üç parça aldım, gerisini kendim yazdım:
yönlendirme : nikic/fast-route
şablon : Twig
veritabanı : PDO + ince bir sarmalayıcı
PDF : mpdf (faturayı yapısal veriden basıyor, HTML ekran görüntüsünden değil)
env : phpdotenv (sırlar web kökü dışında)
Eski veritabanı aynen kullanılıyor. Tablo adları, prefix, hatta eski parola özetleme yöntemi korundu — kullanıcılar eski şifreleriyle giriyor, ilk girişte sessizce modern özete geçiyorlar. Bir portalı yenilerken kimsenin şifresini sıfırlamak zorunda kalmamak, düşündüğünden büyük bir kazanç.
Ve bir demo modu
Portalı satış görüşmesinde göstermek gerekiyor. Gerçek bir sakinin faturasını açamazsın.
Bu yüzden /demo var: dolu bir hesap — 24 aylık tüketim, üç lokasyon, gerçekçi faturalar. Tamamı üretilmiş veri, ve demo hesabı CRM’e hiç gitmiyor (donmuş ilişki mekanizmasının ikinci kullanım alanı bu oldu).
Ne öğrendim
Bir portalın zor kısmı ekranlar değil. Zor kısım kimin neyi görebileceği — ve o soru neredeyse hiçbir zaman “rol” ile çözülmüyor. Zamanla, taşınmayla, iptalle, düzeltmeyle değişiyor.
Bu yüzden görünürlüğü bir tarih aralığı olarak modellemek, benim için bu projenin en değerli kararı oldu.