ORVIAN’s biometric attendance is powered by an independent Python microservice —Documentation Index
Fetch the complete documentation index at: https://mintlify.com/Elian-D/ORVIAN/llms.txt
Use this file to discover all available pages before exploring further.
orvian-facial-recognition — built with FastAPI and the face_recognition library. It lives in its own repository and is deployed separately from the main Laravel application. The integration is always optional: QR wristband scanning and manual attendance work completely without it, and schools that prefer not to use biometrics can ignore this section entirely.
Architecture
ORVIAN’s facial recognition follows a privacy-first, encoding-only design:- Face encodings (128 floating-point numbers per face) are stored in Laravel’s database in the
students.face_encodingJSON column. - Photos are never persisted — not in the database, not on disk, not in logs. The microservice processes uploaded image frames entirely in memory and discards them after producing an encoding or verification result.
FacialApiClient(located atapp/Services/FacialRecognition/FacialApiClient.php) is the sole HTTP bridge between Laravel and the microservice. It handles authentication viaX-API-Keyheader, timeout management (5 s for health checks, 30 s for enroll/verify), and error propagation.FaceEncodingManager(atapp/Services/FacialRecognition/FaceEncodingManager.php) wrapsFacialApiClientwith business logic: service health checks, student enrollment persistence, and 1:N identity resolution across all active enrolled students in a school.
Microservice Endpoints
Theorvian-facial-recognition FastAPI microservice exposes three endpoints:
GET /health
Health check. Returns the service status. Used by FacialApiClient::health() with a 5-second timeout.
POST /api/v1/enroll/
Accepts a student photo as a multipart upload and returns a 128-float face encoding. Used during the enrollment flow in the Biometric Kiosk.
Request (multipart/form-data):
| Field | Type | Description |
|---|---|---|
image | File | Student photo (JPEG/PNG) |
student_id | int | ORVIAN student primary key |
school_id | int | ORVIAN school (tenant) primary key |
success is false and a message field describes the error (e.g., no face detected in frame).
POST /api/v1/verify/
Performs 1:N face identification against a batch of known encodings. Used by FaceEncodingManager::identifyStudent() at the attendance scanner.
Request (multipart/form-data):
| Field | Type | Description |
|---|---|---|
image | File | Captured frame from scanner |
school_id | int | ORVIAN school (tenant) primary key |
known_encodings | JSON string | Array of {id, name, encoding} objects for all enrolled students in the school |
matched is false (or success is false) and the attendance record is not created.
Deploying the Microservice
The microservice lives in the separateorvian-facial-recognition repository and ships with a Dockerfile for straightforward deployment.
Step 1 — Clone the repository:
8001 by default. The API_KEY environment variable sets the secret that Laravel must send via the X-API-Key header.
Step 4 — Verify the service is healthy:
.env:
Required Environment Variables
| Variable | Description | Example |
|---|---|---|
FACIAL_API_URL | Base URL of the running orvian-facial-recognition microservice | http://host.docker.internal:8001 |
FACIAL_API_KEY | Shared secret sent as X-API-Key header; must match API_KEY in the container | your-secret |
config('services.facial_api.url') and config('services.facial_api.key') in Laravel.
Student Enrollment
Enrollment is performed through the Biometric Kiosk, a dedicated Livewire interface accessible at/app/academic/biometric-kiosk. It requires the students.edit permission.
Enrollment workflow:
-
Navigate to
/app/academic/biometric-kiosk. The kiosk displays a paginated grid of all active students with enrollment status badges (enrolled/pending). -
Filter the student list by section using the section dropdown, by biometric status (
all/enrolled/pending), or by searching the student’s first or last name. - Click Enroll on a student card. A modal opens and activates the device camera. The camera supports facing-mode selection — rear camera for mobile devices (better quality in field conditions), front-facing camera for desktop workstations.
-
Capture frame — the kiosk captures the current frame from the video stream and applies mirror correction (reverting the canvas flip used for preview display) before uploading. The corrected image is sent to the microservice’s
/api/v1/enroll/endpoint. -
Encoding returned — if the microservice detects a valid face, it returns the 128-float encoding.
FaceEncodingManager::enrollStudent()calls$student->update(['face_encoding' => json_encode($result['encoding'])])to persist it. -
Status update — the student’s biometric status changes to
enrolled. The kiosk stats bar (total / enrolled / pending) refreshes automatically via Livewire computed property invalidation. -
Camera release — the camera stream is stopped automatically when the modal closes (
close-biometric-modalevent), preventing the browser from holding the device camera indefinitely.
pending.
Biometric enrollment is completely optional. Schools that prefer not to use facial recognition can rely entirely on QR wristband scanning or manual attendance — no configuration is needed to disable it. Students without a
face_encoding are simply skipped during biometric verification.Attendance Verification Flow
Once students are enrolled, theAttendanceScanner Livewire component performs real-time facial identification during the school’s attendance window:
-
Camera streaming —
AttendanceScanneractivates the device camera and streams video frames. Face detection on the client side is handled by face-api.js (served locally — see section below). face-api.js detects when a face enters the frame before triggering a capture, avoiding unnecessary server calls. - Frame capture — on face detection, the component captures the current video frame as an image and sends it to the Laravel backend via a Livewire action.
-
Laravel verification — Laravel calls
FaceEncodingManager::identifyStudent(), which:- Fetches all active students with a non-null
face_encodingfor the school. - Calls
FacialApiClient::verifyFace(), passing the frame and the full array of known encodings as a JSON-encoded multipart field. - The microservice performs 1:N comparison and returns the closest match (if any) with confidence and distance metrics.
- Fetches all active students with a non-null
-
Match → attendance recorded — on a successful match,
PlantelAttendanceServicecreates the attendance record for the identified student (with tardiness validation against the school shift schedule). Aattendance-recorded-successbrowser event fires, triggering an audio beep and a success toast with the student’s name. -
No match → error feedback — if no match is found (or the microservice returns
matched: false), anattendance-facial-errorbrowser event fires, triggering a double error beep to alert the operator. No record is created.
face-api.js Local Serving
ORVIAN serves face-api.js from the application’s ownpublic/ directory rather than a CDN:
- Main library:
public/vendor/face-api/face-api.min.js - Models directory:
public/vendor/face-api/models/
cdn.jsdelivr.net is blocked by Fortinet web filtering on most Dominican school networks. Serving the library locally ensures the attendance scanner works without any firewall exceptions or network policy changes.
When updating face-api.js, replace the files in public/vendor/face-api/ and run php artisan view:clear to bust any cached asset references.