Biometric Processor is the AI/ML microservice for the FIVUCSAS biometric identity platform. Python 3.12 on FastAPI with Clean Architecture (domain → application → infrastructure), dependency injection, and async I/O.
Scope:
- Face — enroll, verify, search, liveness, quality, demographics, landmarks, comparison (DeepFace / MediaPipe / YOLO)
- Client-computed face embedding (flag-gated) —
POST /verify-embeddingandPOST /enroll-embeddingaccept a precomputed, L2-normalized 512-d Facenet512 vector (computed in the browser; raw image never sent). The service runs ONLY the pgvector match / encrypt+persist — it skips detection, quality, liveness and the server-side Facenet512 forward pass. These paths have NO image and therefore NO liveness; a paired liveness factor (passive or the puzzle layer) is enforced upstream at the Identity Core. Default OFF (driven by Identity Coreapp.auth.client-side-embedding). - Puzzle liveness session (flag-gated) — server-issued, single-use, anti-replay liveness session:
POST /liveness/puzzle-session(create, server-randomized challenges),.../{session_id}/challenge(score traces),.../{session_id}/verdict(consume + verdict). Owner-bound (user_id + tenant_id), TTL-bounded. The browser uploads landmark/gesture traces, never frames. - Voice — enroll, verify (Resemblyzer GE2E 256-dim speaker embeddings, centroid-based; librosa pinned to 0.9.2 to avoid the numba/Python 3.12 import-time crash)
- Verification pipeline — YOLO-based document detection + TD1/TD3 MRZ parser + Tesseract TC Kimlik OCR + selfie-to-document cosine matching + server-authoritative liveness verdict
- Client-side ML observations —
client_embedding_observationstable (the legacy 128-d landmark-geometry signal, log-only per D2; never trusted for auth — distinct from the authoritative client-computed Facenet512 vector above)
Security: internal Docker network only. No public Traefik route. X-API-Key middleware on all /api/* routes. Demo UI disabled in production.
The fastest way to test the system is with the local demo:
python demo_local_fast.pyNote:
demo_local.pydoes not exist. Usedemo_local_fast.py(balanced) ordemo_local_optimized.py(CPU-optimised) — both are in the repo root.
Performance: 18-30 FPS (CPU), optimized and production-ready!
See docs/1-getting-started/ for detailed guides.
All documentation is organized in the docs/ directory:
- Getting Started - Installation, quick start, demo usage
- API Documentation - Complete API reference
- Deployment - Deployment guides and database setup
- Testing - Testing guides and test reports
- Performance - Performance analysis and optimizations
- Architecture - Design documents and architecture
- Changelog - Release history and notable changes
| Feature | Status | Description |
|---|---|---|
| Face Enrollment | ✅ Complete | Register face embeddings with quality assessment |
| Face Verification (1:1) | ✅ Complete | Verify if two faces belong to the same person |
| Face Search (1:N) | ✅ Complete | Identify a person from enrolled faces |
| Batch Processing | ✅ Complete | Process multiple enrollment/verification requests |
| Liveness Detection | ✅ Complete | Passive + Active anti-spoofing detection |
| Card Type Detection | ✅ Complete | YOLO-based document classification |
| Quality Assessment | ✅ Complete | Face image quality scoring and validation |
| Feature | Status | Description |
|---|---|---|
| Quality Feedback | ✅ Complete | Detailed quality analysis with actionable recommendations |
| Multi-Face Detection | ✅ Complete | Detect all faces in a single image |
| Demographics Analysis | ✅ Complete | Age, gender, emotion estimation via DeepFace |
| Facial Landmarks | ✅ Complete | 468-point landmark detection via MediaPipe |
| Face Comparison | ✅ Complete | Direct 1:1 comparison without enrollment |
| Similarity Matrix | ✅ Complete | NxN similarity computation with clustering |
| Embeddings Export/Import | ✅ Complete | Backup and migration of face embeddings |
| Webhooks | ✅ Complete | Event notifications with HMAC signing |
| Rate Limiting | ✅ Complete | Sliding window rate limit storage |
| Feature | Status | Description |
|---|---|---|
| Redis Rate Limiting | ✅ Complete | Distributed rate limiting with Redis backend |
| Rate Limit Middleware | ✅ Complete | Request throttling with X-RateLimit headers |
| API Key Authentication | ✅ Complete | SHA-256 hashed keys with scopes and tiers |
| Prometheus Metrics | ✅ Complete | Request counts, latencies, ML inference times |
| Structured Logging | ✅ Complete | JSON logging with request context via structlog |
- Clean Architecture: Domain-driven design with clear separation of concerns
- Dependency Injection: Fully injectable components for testability
- Multiple Face Models: Support for VGG-Face, Facenet, ArcFace, and more
- Async Processing: Non-blocking I/O for high throughput
- Configurable Thresholds: Environment-based configuration
- Comprehensive Error Handling: Domain-specific exceptions with proper HTTP mapping
The project follows Clean Architecture principles with four distinct layers:
biometric-processor/
├── app/
│ ├── main.py # FastAPI application entry point
│ ├── domain/ # Domain Layer (Business Logic)
│ │ ├── entities/ # Domain entities
│ │ │ ├── face_embedding.py
│ │ │ ├── face_detection.py
│ │ │ ├── verification_result.py
│ │ │ ├── liveness_result.py
│ │ │ ├── quality_assessment.py
│ │ │ └── card_type_result.py
│ │ ├── interfaces/ # Abstract interfaces (ports)
│ │ │ ├── face_detector.py
│ │ │ ├── embedding_extractor.py
│ │ │ ├── liveness_detector.py
│ │ │ ├── quality_assessor.py
│ │ │ ├── similarity_calculator.py
│ │ │ ├── embedding_repository.py
│ │ │ └── file_storage.py
│ │ └── exceptions/ # Domain exceptions
│ ├── application/ # Application Layer (Use Cases)
│ │ └── use_cases/
│ │ ├── enroll_face.py
│ │ ├── verify_face.py
│ │ ├── search_face.py
│ │ ├── check_liveness.py
│ │ ├── batch_process.py
│ │ └── detect_card_type.py
│ ├── infrastructure/ # Infrastructure Layer (Implementations)
│ │ ├── ml/
│ │ │ ├── detectors/ # Face detection (DeepFace)
│ │ │ ├── extractors/ # Embedding extraction (DeepFace)
│ │ │ ├── liveness/ # Liveness detection (Texture-based)
│ │ │ ├── quality/ # Quality assessment
│ │ │ ├── similarity/ # Cosine similarity
│ │ │ └── factories/ # Factory patterns
│ │ ├── persistence/ # Data repositories
│ │ │ └── repositories/ # In-memory embedding storage
│ │ └── storage/ # File storage
│ ├── api/ # API Layer (Controllers)
│ │ ├── routes/ # API endpoints
│ │ │ ├── health.py
│ │ │ ├── enrollment.py
│ │ │ ├── verification.py
│ │ │ ├── search.py
│ │ │ ├── liveness.py
│ │ │ ├── batch.py
│ │ │ └── card_type_router.py
│ │ ├── schemas/ # Pydantic request/response models
│ │ └── middleware/ # Error handling
│ └── core/ # Core Configuration
│ ├── config.py # Pydantic settings
│ └── container.py # Dependency injection container
├── tests/
│ ├── unit/ # Unit tests
│ ├── integration/ # Integration tests
│ └── e2e/ # End-to-end tests
├── requirements.txt
├── pyproject.toml
└── pytest.ini
| Category | Technology | Purpose |
|---|---|---|
| Framework | FastAPI 0.104+ | Async web framework |
| ML Library | DeepFace 0.0.79+ | Face detection & recognition |
| ML Backend | tf-keras 2.15+ | Deep learning backend |
| Computer Vision | OpenCV 4.8+ | Image processing |
| Object Detection | Ultralytics YOLO | Card type detection |
| Validation | Pydantic 2.5+ | Data validation & settings |
| Server | Uvicorn | ASGI server |
| Image Processing | Pillow 10.3+ | Image manipulation |
- Python 3.12 or higher
- pip package manager
- 4GB+ RAM (8GB recommended)
- GPU (optional, for faster inference)
- Python 3.12+
- Node.js 18+
- PostgreSQL 14+ with pgvector extension
- Redis 7+
- 4GB+ RAM (8GB recommended)
- GPU (optional, for faster inference)
git clone https://github.com/Rollingcat-Software/biometric-processor.git
cd biometric-processor# Ubuntu/Debian
sudo apt install postgresql postgresql-contrib
sudo -u postgres psql -c "CREATE EXTENSION vector;"
# macOS
brew install postgresql pgvector
# Create database
createdb biometric_db
psql biometric_db -c "CREATE EXTENSION vector;"# Ubuntu/Debian
sudo apt install redis-server
sudo systemctl start redis
# macOS
brew install redis
brew services start redispython -m venv .venv
# Linux/macOS
source .venv/bin/activate
# Windows
.venv\Scripts\activate
# Install dependencies
pip install -r requirements.txtcd demo-ui
npm install
npm run build
cd ..cp .env.example .envEdit .env with your settings (key changes for local development):
# Database (local PostgreSQL)
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/biometric_db
USE_PGVECTOR=True
# Redis (local)
REDIS_HOST=localhost
REDIS_PORT=6379
# Server
API_HOST=0.0.0.0
API_PORT=8001# Development mode (with auto-reload)
python -m uvicorn app.main:app --reload --host 0.0.0.0 --port 8001
# Production mode
python -m uvicorn app.main:app --host 0.0.0.0 --port 8001 --workers 4The application will be available at: http://localhost:8001
- Frontend UI:
http://localhost:8001 - API Documentation:
http://localhost:8001/docs - ReDoc:
http://localhost:8001/redoc
The application is optimized for Platform-as-a-Service deployment with managed PostgreSQL and Redis.
-
Install Railway CLI
npm install -g @railway/cli
-
Login and Initialize
railway login railway init
-
Add Services in Railway Dashboard
- PostgreSQL (with pgvector)
- Redis
-
Deploy
railway up
Railway will automatically:
- Build the frontend (
npm run buildin demo-ui) - Install Python dependencies
- Start the server using
Procfile - Provide
DATABASE_URLandREDIS_URLenvironment variables
-
Connect Repository
- Connect your GitHub repository to Render
- Render will detect
render.yamlautomatically
-
Auto-Provision Services Render will automatically create:
- Web service (Python)
- PostgreSQL database with pgvector
- Redis cache
-
Deploy
- Push to main branch
- Render auto-deploys using the configuration in
render.yaml
-
Install Heroku CLI
# Install from https://devcenter.heroku.com/articles/heroku-cli heroku login -
Create App and Add Services
heroku create biometric-processor heroku addons:create heroku-postgresql:mini heroku addons:create heroku-redis:mini
-
Enable pgvector Extension
heroku pg:psql CREATE EXTENSION IF NOT EXISTS vector; \q
-
Deploy
git push heroku main
PaaS platforms automatically provide:
PORT- Server port (auto-configured)DATABASE_URL- PostgreSQL connection stringREDIS_URL- Redis connection string
Additional variables to set:
ENVIRONMENT=production
LOG_FORMAT=json
USE_PGVECTOR=true
RATE_LIMIT_STORAGE=redispython -m uvicorn app.main:app --reload --host 0.0.0.0 --port 8001python -m uvicorn app.main:app --host 0.0.0.0 --port 8001 --workers 4# One-command build
chmod +x build.sh
./build.sh
# Then run
python -m uvicorn app.main:app --host 0.0.0.0 --port 8001http://localhost:8001/api/v1
| Endpoint | Method | Description |
|---|---|---|
/api/v1/health |
GET | Health check |
/api/v1/enroll |
POST | Enroll a face |
/api/v1/verify |
POST | Verify face (1:1) |
/api/v1/search |
POST | Search face (1:N) |
/api/v1/liveness |
POST | Liveness detection |
/api/v1/batch/enroll |
POST | Batch enrollment |
/api/v1/batch/verify |
POST | Batch verification |
/api/v1/card-type/detect-live |
POST | Card type detection |
| Endpoint | Method | Description |
|---|---|---|
/api/v1/quality/analyze |
POST | Detailed image quality analysis with feedback |
/api/v1/faces/detect-all |
POST | Multi-face detection in single image |
/api/v1/demographics/analyze |
POST | Age, gender, emotion estimation |
/api/v1/landmarks/detect |
POST | 468-point facial landmark detection |
/api/v1/compare |
POST | Direct 1:1 face comparison without enrollment |
/api/v1/similarity/matrix |
POST | NxN similarity matrix computation |
/api/v1/embeddings/export |
GET | Export all embeddings to JSON |
/api/v1/embeddings/import |
POST | Import embeddings from JSON |
/api/v1/webhooks/register |
POST | Register a webhook endpoint |
/api/v1/webhooks |
GET | List registered webhooks |
/api/v1/webhooks/{id} |
DELETE | Delete a webhook |
/api/v1/webhooks/{id}/test |
POST | Test webhook delivery |
GET /api/v1/healthResponse:
{
"status": "healthy",
"service": "FIVUCSAS Biometric Processor",
"version": "1.0.0"
}Enroll a face with quality assessment.
POST /api/v1/enroll
Content-Type: multipart/form-dataParameters:
| Name | Type | Required | Description |
|---|---|---|---|
file |
file | Yes | Face image (JPEG/PNG) |
user_id |
string | Yes | Unique user identifier |
tenant_id |
string | No | Tenant identifier (default: "default") |
Response:
{
"success": true,
"user_id": "user123",
"quality_score": 85.5,
"message": "Face enrolled successfully",
"embedding_dimension": 128
}Example:
curl -X POST "http://localhost:8001/api/v1/enroll" \
-F "file=@face.jpg" \
-F "user_id=user123"Verify if a face matches an enrolled user.
POST /api/v1/verify
Content-Type: multipart/form-dataParameters:
| Name | Type | Required | Description |
|---|---|---|---|
file |
file | Yes | Face image to verify |
user_id |
string | Yes | User ID to verify against |
tenant_id |
string | No | Tenant identifier |
Response:
{
"verified": true,
"confidence": 0.87,
"distance": 0.13,
"threshold": 0.6,
"message": "Face verified successfully"
}Example:
curl -X POST "http://localhost:8001/api/v1/verify" \
-F "file=@test_face.jpg" \
-F "user_id=user123"Search for matching faces among all enrolled users.
POST /api/v1/search
Content-Type: multipart/form-dataParameters:
| Name | Type | Required | Description |
|---|---|---|---|
file |
file | Yes | Face image to search |
tenant_id |
string | No | Tenant identifier |
max_results |
int | No | Maximum results (default: 5) |
Response:
{
"found": true,
"matches": [
{"user_id": "user123", "distance": 0.15, "confidence": 0.85},
{"user_id": "user456", "distance": 0.25, "confidence": 0.75}
],
"total_searched": 100,
"threshold": 0.6,
"best_match": {"user_id": "user123", "distance": 0.15, "confidence": 0.85},
"message": "Found 2 matches"
}Anti-spoofing liveness detection with configurable modes.
POST /api/v1/liveness
Content-Type: multipart/form-dataParameters:
| Name | Type | Required | Description |
|---|---|---|---|
file |
file | Yes | Face image to check |
Response:
{
"is_live": true,
"liveness_score": 85.0,
"challenge": "combined",
"challenge_completed": true,
"message": "Liveness check passed"
}Detection Modes (set via LIVENESS_MODE env var):
| Mode | Description | Best For |
|---|---|---|
passive |
Texture-based analysis | Detecting printed photos, screens |
active |
Smile/blink detection via MediaPipe | Interactive verification |
combined |
Both methods (default) | Highest accuracy |
Passive Detection Methods:
| Method | Weight | Description |
|---|---|---|
| Texture Analysis | 35% | Laplacian variance for texture variation |
| Color Distribution | 25% | HSV color naturalness analysis |
| Frequency Analysis | 25% | FFT-based frequency pattern detection |
| Moiré Detection | 15% | Gabor filter screen pattern detection |
Active Detection Methods:
| Method | Description |
|---|---|
| Eye Aspect Ratio (EAR) | Detects if eyes are open (EAR > 0.25) |
| Mouth Aspect Ratio (MAR) | Detects smile (MAR > 0.6) |
Threshold: Score ≥ 70.0 = Live (configurable via LIVENESS_THRESHOLD)
Enroll multiple faces in a single request.
POST /api/v1/batch/enroll
Content-Type: multipart/form-dataParameters:
| Name | Type | Required | Description |
|---|---|---|---|
files |
file[] | Yes | Multiple face images |
user_ids |
string | Yes | Comma-separated user IDs |
Verify multiple faces in a single request.
POST /api/v1/batch/verify
Content-Type: multipart/form-dataParameters:
| Name | Type | Required | Description |
|---|---|---|---|
files |
file[] | Yes | Multiple face images |
user_ids |
string | Yes | Comma-separated user IDs |
Detect document card type using YOLO object detection.
POST /api/v1/card-type/detect-live
Content-Type: multipart/form-dataParameters:
| Name | Type | Required | Description |
|---|---|---|---|
file |
file | Yes | Card/document image |
Response:
{
"detected": true,
"class_id": 0,
"class_name": "tc_kimlik",
"confidence": 0.95
}Supported Card Types:
| Class ID | Class Name | Description |
|---|---|---|
| 0 | tc_kimlik | Turkish ID Card |
| 1 | ehliyet | Driver's License |
| 2 | pasaport | Passport |
| 3 | ogrenci_karti | Student Card |
Detailed image quality analysis with actionable feedback.
POST /api/v1/quality/analyze
Content-Type: multipart/form-dataParameters:
| Name | Type | Required | Description |
|---|---|---|---|
file |
file | Yes | Face image to analyze |
Response:
{
"overall_score": 85.0,
"is_acceptable": true,
"metrics": {
"blur_score": 150.0,
"brightness_score": 120.0,
"face_size_score": 100.0
},
"issues": [],
"recommendations": ["Good lighting", "Face well-centered"]
}Detect all faces in a single image.
POST /api/v1/faces/detect-all
Content-Type: multipart/form-dataResponse:
{
"faces": [
{
"face_id": 0,
"bounding_box": {"x": 50, "y": 50, "width": 100, "height": 100},
"confidence": 0.95,
"quality_score": 85.0
}
],
"face_count": 1,
"processing_time_ms": 150.0
}Estimate age, gender, and emotion from a face image.
POST /api/v1/demographics/analyze
Content-Type: multipart/form-dataResponse:
{
"age": {"value": 30, "confidence": 0.9, "range_low": 25, "range_high": 35},
"gender": {"value": "male", "confidence": 0.95},
"emotion": {"dominant": "happy", "scores": {"happy": 0.8, "neutral": 0.15}}
}Detect 468 facial landmarks using MediaPipe Face Mesh.
POST /api/v1/landmarks/detect
Content-Type: multipart/form-dataResponse:
{
"landmarks": [
{"index": 0, "name": "nose_tip", "x": 100.0, "y": 100.0, "z": 0.0},
{"index": 1, "name": "left_eye", "x": 80.0, "y": 90.0, "z": 0.0}
],
"head_pose": {"pitch": 5.0, "yaw": -3.0, "roll": 1.0},
"model": "mediapipe_468"
}Compare two faces directly without enrollment.
POST /api/v1/compare
Content-Type: multipart/form-dataParameters:
| Name | Type | Required | Description |
|---|---|---|---|
file1 |
file | Yes | First face image |
file2 |
file | Yes | Second face image |
threshold |
float | No | Match threshold (default: 0.6) |
Response:
{
"is_match": true,
"similarity": 0.87,
"distance": 0.13,
"threshold": 0.6,
"face1": {"bounding_box": [50, 50, 100, 100], "confidence": 0.95},
"face2": {"bounding_box": [50, 50, 100, 100], "confidence": 0.93}
}Compute NxN similarity matrix for multiple faces.
POST /api/v1/similarity/matrix
Content-Type: multipart/form-dataParameters:
| Name | Type | Required | Description |
|---|---|---|---|
files |
file[] | Yes | Multiple face images |
labels |
string | No | Comma-separated labels |
threshold |
float | No | Clustering threshold (default: 0.6) |
Response:
{
"matrix": [[1.0, 0.85, 0.3], [0.85, 1.0, 0.25], [0.3, 0.25, 1.0]],
"labels": ["person_a", "person_a_2", "person_b"],
"clusters": [{"id": 0, "members": [0, 1], "avg_similarity": 0.85}],
"threshold": 0.6
}Export all face embeddings for backup/migration.
GET /api/v1/embeddings/export?tenant_id=defaultResponse:
{
"embeddings": [
{"user_id": "user1", "vector": [...], "quality_score": 85.0}
],
"metadata": {
"count": 100,
"tenant_id": "default",
"export_timestamp": "2024-01-01T00:00:00Z",
"checksum": "abc123"
}
}Import embeddings from JSON export.
POST /api/v1/embeddings/import
Content-Type: multipart/form-dataParameters:
| Name | Type | Required | Description |
|---|---|---|---|
file |
file | Yes | JSON export file |
mode |
string | No | merge/replace/skip_existing (default: merge) |
tenant_id |
string | No | Target tenant |
Response:
{
"imported": 95,
"skipped": 5,
"errors": []
}Register webhooks to receive event notifications.
POST /api/v1/webhooks/register
Content-Type: application/jsonRequest Body:
{
"url": "https://example.com/webhook",
"events": ["enrollment", "verification", "liveness"],
"secret": "optional_hmac_secret"
}Response:
{
"webhook_id": "wh_abc123def456",
"url": "https://example.com/webhook",
"events": ["enrollment", "verification"],
"enabled": true,
"created_at": "2024-01-01T00:00:00Z"
}Webhook Event Payload:
{
"event_type": "enrollment.success",
"timestamp": "2024-01-01T00:00:00Z",
"tenant_id": "default",
"data": {"user_id": "user123", "quality_score": 85.0}
}The service supports multiple face recognition models via DeepFace:
| Model | Embedding Size | Best For |
|---|---|---|
| Facenet (default) | 128 | Balanced accuracy/speed |
| Facenet512 | 512 | Higher accuracy (prod default) |
| VGG-Face | 2622 | High accuracy — requires ALLOW_HEAVY_ML=true (GPU) |
| ArcFace | 512 | State-of-the-art accuracy — requires ALLOW_HEAVY_ML=true (GPU) |
| GhostFaceNet | 512 | Compact high accuracy — requires ALLOW_HEAVY_ML=true (GPU) |
| OpenFace | 128 | Lightweight |
| DeepFace | 4096 | Legacy support |
| DeepID | 160 | Lightweight |
| Dlib | 128 | CPU-optimized |
| SFace | 128 | Lightweight |
Configure via FACE_RECOGNITION_MODEL environment variable.
The detection backends retinaface, yolov8, yolov11n, yolov11s, and yolov12n also require ALLOW_HEAVY_ML=true and will cause a hard boot failure on CPU-only hosts when that flag is false (the default).
| Variable | Default | Description |
|---|---|---|
APP_NAME |
FIVUCSAS Biometric Processor | Application name |
VERSION |
1.0.0 | Application version |
ENVIRONMENT |
development | Environment (development/staging/production) |
API_HOST |
0.0.0.0 | API host |
API_PORT |
8001 | API port |
FACE_DETECTION_BACKEND |
opencv | Face detector (opencv/ssd/mtcnn; retinaface/yolo* require ALLOW_HEAVY_ML=true) |
FACE_RECOGNITION_MODEL |
Facenet | Recognition model |
ALLOW_HEAVY_ML |
false | Must be true on a GPU host to use ArcFace/VGG-Face/GhostFaceNet/retinaface/yolo* |
VERIFICATION_THRESHOLD |
0.45 | Cosine-distance threshold (distance < threshold → match). Prod override: 0.4 |
LIVENESS_MODE |
combined | Liveness mode (passive/active/combined). Prod override: passive |
LIVENESS_BACKEND |
(derived from LIVENESS_MODE) | Explicit backend override. Prod override: uniface |
LIVENESS_THRESHOLD |
70.0 | Liveness score threshold (0-100) |
QUALITY_THRESHOLD |
70.0 | Quality score threshold (0-100) |
MIN_FACE_SIZE |
80 | Minimum face size in pixels |
BLUR_THRESHOLD |
100.0 | Blur detection threshold |
LOG_LEVEL |
INFO | Logging level |
FIVUCSAS_EMBEDDING_KEY |
(none) | Required in production. Fernet key for at-rest embedding encryption; container fails fast on boot if unset. |
FIVUCSAS_EMBEDDING_KEY_VERSION |
(none) | Key version integer for FIVUCSAS_EMBEDDING_KEY rotation. |
ANTISPOOF_BLOCK_ENFORCE |
true | When true, anti-spoof "block" verdicts and EAR closed-eye detection return HTTP 403. |
# Run all tests
pytest
# Run with coverage
pytest --cov=app tests/
# Run specific test file
pytest tests/unit/test_enrollment.py -v
# Run E2E tests
pytest tests/e2e/ -v# Format code
black app/ tests/
# Sort imports
isort app/ tests/
# Type checking
mypy app/
# Linting
pylint app/pip install pre-commit
pre-commit install| Modality | Enroll | Verify | Delete | Status | Notes |
|---|---|---|---|---|---|
| Face | POST /enroll | POST /verify | N/A | Working | Full DeepFace implementation |
| Voice | POST /voice/enroll | POST /voice/verify | DELETE /voice/{id} | Working | Resemblyzer 256-dim embeddings |
| Fingerprint | (removed P1.4) | (removed P1.4) | (removed P1.4) | Removed | SHA-256 placeholder was not a real biometric. Use WebAuthn (FIDO2) in identity-core-api for platform fingerprint auth. |
| Iris | N/A | N/A | N/A | Not implemented | No endpoints |
The following endpoints are implemented but not covered in the main API reference above. All are prefixed with /api/v1 unless noted.
| Endpoint | Method | Description |
|---|---|---|
/ready |
GET | Kubernetes readiness probe |
/live |
GET | Kubernetes liveness probe |
/health/detailed |
GET | Full system health with DB/Redis/ML status |
/metrics |
GET | Prometheus metrics scrape endpoint (excluded from OpenAPI schema) |
| Endpoint | Method | Description |
|---|---|---|
/flash-challenge/start |
POST | Start a flash-challenge PAD session |
/flash-challenge/respond |
POST | Submit frame response to a flash challenge |
| Endpoint | Method | Description |
|---|---|---|
/nfc/mrz |
POST | Parse MRZ from raw NFC TLV payload or image |
| Endpoint | Method | Description |
|---|---|---|
/proctoring/sessions |
POST | Create a proctoring session |
/proctoring/sessions/{id}/start |
POST | Start a session |
/proctoring/sessions/{id}/pause |
POST | Pause a session |
/proctoring/sessions/{id}/resume |
POST | Resume a session |
/proctoring/sessions/{id}/end |
POST | End a session |
/proctoring/sessions/{id} |
GET | Get session detail |
/proctoring/sessions |
GET | List sessions |
/proctoring/sessions/{id}/frames |
POST | Submit a frame for incident analysis |
| Endpoint | Method | Description |
|---|---|---|
/liveness/generate-puzzle |
POST | Generate a liveness puzzle challenge |
/liveness/verify |
POST | Submit puzzle answer |
/liveness/verify-challenge |
POST | Combined puzzle + anti-spoof challenge |
| Endpoint | Method | Description |
|---|---|---|
/verification/document-scan |
POST | YOLO document detection + classification |
/verification/data-extract |
POST | MRZ + Tesseract OCR field extraction |
/verification/face-match |
POST | Selfie-to-document cosine matching |
/verification/liveness-check |
POST | Server-authoritative liveness verdict |
/verification/pipeline/test |
POST | End-to-end pipeline smoke test |
/verification/video-interview |
POST | Upload video for verification pipeline |
| Endpoint | Method | Description |
|---|---|---|
/admin/stats |
GET | System-wide stats (face/voice enrollment counts, etc.) |
/admin/activity |
GET | Recent audit activity |
| Sprint | Feature | Status |
|---|---|---|
| Sprint 1-2 | Core API & Face Operations | Complete |
| Sprint 3 | Liveness & Batch Processing | Complete |
| Sprint 4 | PostgreSQL + pgvector | Complete |
| Sprint 5 | Docker, Redis, CI/CD | Complete |
| Sprint 6 | Fingerprint biometric processing | Removed P1.4 (SHA-256 placeholder, not a real biometric) |
| Sprint 7 | Voice biometric processing (Resemblyzer) | Complete |
| Sprint 8 | Verification pipeline (document scan, MRZ, OCR) | Complete |
This project is part of the FIVUCSAS platform developed as an Engineering Project at Marmara University.
Copyright © 2026 FIVUCSAS Team. All rights reserved.
Licensed under the MIT License.
- DeepFace by Sefik Ilkin Serengil
- Ultralytics YOLO for object detection
- FastAPI for the web framework
- Marmara University Computer Engineering Department
FIVUCSAS Team © 2026