Çok kiracılı bir biyometrik kimlik doğrulama platformu — yüz, ses, MRZ ve aktif canlılık — gömülebilir bir widget olarak paketlenmiş. Kendi kendine barındırılan, KVKK uyumlu, WebAuthn öncelikli.
Rol
Baş geliştirici — tam yığın, makine öğrenmesi ve altyapı · RollingCat Software
Tarih
Mar 2026 – Haz 2026
Yığın
Java 21
Spring Boot 3
Python
FastAPI
PostgreSQL 16
pgvector
React 18
Kotlin Multiplatform
WebAuthn
OAuth 2.0
OIDC
Flyway
Docker
Traefik
Loki + Promtail + Grafana
Problem
Biyometrik kimlik doğrulamayı benimsemek zordur çünkü onu entegre etmek genellikle ham yüz ve ses verisini işlemeyi, sahtecilik saldırılarını savuşturmayı ve katı gizlilik yasalarına uymayı gerektirir — çoğu ekibin üstlenemeyeceği bir iş. Amaç, biyometrik girişi bir siteye reCAPTCHA kadar kolay eklenebilir hâle getirmekti; üstelik entegre eden taraf biyometrik veriye hiç dokunmadan.
Kısıtlar
▸
Biyometrik veri hiçbir zaman şifresiz olarak depolanmamalı ve gömme çıkarımı hiçbir zaman halka açık internetten erişilebilir olmamalı.
▸
KVKK uyumluluğu sonradan eklenecek bir özellik değil, kesin bir gerekliliktir.
▸
Her kiracı kuruluş, veritabanı düzeyinde diğer tüm kiracılardan yalıtılmış olmalıdır.
Yaklaşım
Platform üç çalışma ekseni hâlinde ayrılır — doğruluk kaynağı olan bir Spring Boot kimlik çekirdeği, tüm biyometrik işlemeye sahip özel bir FastAPI ML yan-süreci ve ince istemciler (React web, Kotlin Multiplatform mobil ve masaüstü ile gömülebilir bir widget). Widget, tüm meydan okuma akışını reCAPTCHA'nın bir meydan okumayı sunduğu gibi sunar.
Önemli kararlar
ML yan-sürecini kimlik çekirdeğinden ayrı bir dağıtılabilir olarak ayır
Biyometrik işlemci API ile yalnızca özel bir Docker ağı üzerinden konuşur ve asla halka açık değildir. ML yığını API'ye dokunmadan yükseltilebilir ve gömme çıkarımı internetten yapısal olarak erişilemezdir.
Çok kiracılılığı bir uygulama filtresi değil, bir veritabanı meselesi yap
Her kuruluş şema düzeyinde yalıtılmıştır; dolayısıyla bir geliştiricinin eklemeyi unutabileceği bir "WHERE tenant_id = ?" koşulu yoktur. Kiracı yalıtımı bir uygulama hatasıyla atlanamaz.
Gömme şifreleme anahtarı eksik olduğunda hızlı başarısız ol
Gömmeler bekleme hâlinde Fernet ile şifrelenir ve yalnızca kosinüs benzerliği çalıştığı anda süreç içinde çözülür. Uygulama anahtar olmadan açılmayı reddeder; böylece her saklı gömmeyi geçersiz kılacak bir varsayılana sessizce geri dönemez.
Mimari
Tarayıcılar ve mobil istemciler, bir Traefik ters proxy'si üzerinden Spring Boot kimlik çekirdeğine ulaşır. Kimlik çekirdeği, pgvector'lü PostgreSQL 16'ya sahiptir ve FastAPI biyometrik işlemcisiyle halka açık internetin erişemediği özel bir Docker ağı üzerinden konuşur. Loki, Promtail ve Grafana tüm yığını gözlemler.
flowchart TB
client["Clients<br/>React web · KMP mobile/desktop · embeddable widget"]
traefik["Traefik reverse proxy"]
api["Identity Core API<br/>Spring Boot 3 · Java 21"]
db[("PostgreSQL 16<br/>+ pgvector")]
ml["Biometric Processor<br/>FastAPI · Python"]
obs["Loki · Promtail · Grafana"]
client --> traefik --> api
api --> db
api -. private docker network .-> ml
api --> obs
ml --> obs
Bir Traefik proxy'sinin arkasında üç çalışma ekseni; ML yan-süreci yalnızca özel ağdadır.
Sonuç
FIVUCSAS, gömülebilir bir widget, WebAuthn/FIDO2 passkey'leri ve ekran tekrarını ve önceden kaydedilmiş saldırıları savuşturan rastgele bir aktif canlılık meydan okumasıyla, kendi kendine barındırılan çok kiracılı bir platform olarak canlıda çalışır. Depo, üçüncü taraf güvenlik incelemesi tamamlanana dek özeldir; kaynak erişimi talep üzerine mümkündür.
Rakamlarla
55+ Flyway migrasyonları
13 users satırının ardındaki FK-kademeli tablo
3 Çalışma ekseni (API · ML · istemciler)
Fernet Bekleme hâlinde gömme şifrelemesi
SHA-256 Model teslim bütünlüğü
WebAuthn Birincil giriş faktörü
Aşağıdaki yapılandırılmış bölümler Türkçe mevcuttur; ayrıntılı anlatım İngilizce yazılmıştır. Tam Türkçe çeviri henüz mevcut değildir.
Derinlemesine
FIVUCSAS — Face and Identity Verification Using Cloud-based SaaS — began as
my senior engineering project at Marmara University and now ships under
RollingCat Software, the umbrella name I
publish some of my work under. This case study is the architecture story; for
the war stories — the three production incidents the team learned the most
from — see the companion
write-up.
The shape of the system
The core insight that shaped almost every decision was simple to state and hard
to enforce: biometric data must never sit unencrypted at rest, and the
embedding extraction process must never be reachable from the internet.
Everything else fell out of that.
That single constraint is why the ML stack lives in a separate FastAPI sidecar
on a private Docker network rather than inside the Spring Boot API. The identity
core is the authoritative source of truth for tenants, users, sessions, audit
logs, and MFA factors (TOTP, WebAuthn, NFC, biometric). The biometric processor
owns the face mesh, embedding extraction, and active-liveness puzzle scoring,
and it answers only to the API — never to a browser.
Active liveness as the differentiator
The “Biometric Puzzle” is the part I am proudest of. Instead of a single still
frame — which a printed photo or a screen replay can defeat — the widget prompts
a randomized sequence of facial actions: smile, blink, look left, look right.
The randomization is what makes a pre-recorded attack impractical: the attacker
cannot know the sequence in advance. The widget exposes this whole flow the way
reCAPTCHA exposes a challenge, so a tenant integrates against the smallest
possible surface.
Privacy and tenancy by construction
Two design choices keep the platform honest:
Schema-per-tenant isolation. Tenant boundaries are a database concern, not
an application filter. There is no shared table where a forgotten predicate
leaks one organization’s data to another.
Fail-fast configuration. The application refuses to start without the
embedding encryption key. A fail-soft default would silently invalidate every
stored embedding — exactly the kind of irreversible data corruption that is
far better to catch at boot than in production.
Operational posture
The platform is self-hosted on a Hetzner CX43 box behind Traefik, observed with
Loki + Promtail + Grafana, and backed up with pgBackRest WAL archiving for
point-in-time recovery. Security hygiene is part of the workflow, not an
afterthought: gitleaks runs in CI, GitHub secret-scanning and push-protection
are on, and every new OAuth endpoint gets a permitAll-chain grep as part of PR
review.
The source is private until a third-party security review completes. Source
access is available on request.