Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

01 — Product Overview (Biometric Module)

StudyLyon — multi-tenant ERP / School Management API. This package designs the Biometric module client (Flutter admin console, forward-looking spec) against the implemented NestJS backend. All endpoints, DTO fields, schemas, queues, and permissions are derived directly from src/modules/biometric/**, src/modules/attendance/**, src/infrastructure/bullmq/**, src/modules/rbac/permissions.constants.ts, and the authoritative blueprint (studylyon-blueprint/04-Modules/Biometric.md). No feature is invented; gaps are flagged in Assumptions & Open Questions.


1. Purpose

Biometric is StudyLyon's device-integration layer for attendance capture (studylyon-blueprint/04-Modules/Biometric.md:3). Hardware fingerprint/QR devices at the school gate produce raw punches; the Biometric module ingests them as immutable raw events (biometric_logs) and the Attendance module derives queryable attendance records from them (RELATIONSHIPS.md:95-103).

Today the backend implements only the ingest half of that vision: one endpoint (POST /biometric/ingest) that persists a raw log. Everything else — device registration, sync, enrollment, verification, attendance derivation — is (planned) per the blueprint.

ResponsibilityStatusSource
Ingest raw punch logs (immutable)✅ realbiometric.controller.ts:14-18
Store device registry (biometric_devices)✅ schema + repo (no CRUD API yet)biometric-device.schema.ts:13-32
Register / manage biometric devices🚧 plannedblueprint 04-Modules/Biometric.md:13
Poll / sync device punches (biometric-sync queue)🚧 queue + scheduler exist; worker stubqueue.constants.ts:7, scheduler.service.ts:70-76
Map employee codes → student/staff🚧 planned (employeeCode field)blueprint COLLECTIONS.md:1878-1879
Trigger attendance derivation (BiometricImported)🚧 planned eventblueprint EVENTS.md:18
Template enrollment / verify / match🚧 planned — no schema, no endpointblueprint Biometric.md:13-19
Verify device health🚧 plannedblueprint Biometric.md:19

2. Business goals

GoalMeasure
Attendance marking latency < 1 s (PRD)PRODUCT_REQUIREMENTS_DOCUMENT.md:136
Zero human double-entry at the gateraw punch → derived attendance, no clerk retyping
Audit-grade attendance evidencelogs are insert-only, never updated (biometric-log.schema.ts:7, blueprint COLLECTIONS.md:1866)
Immutable forensic recordraw payload preserved for replay (rawData, biometric-log.schema.ts:21-22)
Operational resiliencesync failures retried via BullMQ; exhausted → DLQ (blueprint Biometric.md:58)
1-year retention boundbiometric_logs TTL + archive (blueprint DATA_RETENTION.md:25)

3. User goals

  • School admin / ops: add a gate device once, see sync status, resolve offline devices, trust that every punch lands in attendance.
  • Office clerk (device operator): enroll a student's fingerprint on a device, watch the enrollment confirm, verify a disputed check-in.
  • Teacher: know a student scanned in before class starts (biometric-fed attendance).
  • Parent (planned): see the child's biometric check-in silently reflected in the daily attendance record.
  • Platform admin: cross-tenant device fleet health, vendor-SDK risk tracking.

4. Stakeholders

Institution admins, office clerks, teachers, students/parents (passive), device-vendor support, platform operator, audit/compliance board, QA + design + engineering.

5. Why this exists

School gate attendance is the highest-frequency, highest-trust data point in a school day. Manual marking is error-prone and unverifiable; biometric devices make the punch tamper-evident. The PRD makes device capture a first-class requirement (FR-ATT-02, PRODUCT_REQUIREMENTS_DOCUMENT.md:87) and the acceptance criteria demand that "biometric capture maps to a verified student record" (ACCEPTANCE_CRITERIA.md:39).

6. Dependencies

DependencyRoleSource
Attendance moduleconsumes BiometricImported → derived records; AttendanceSource.BIOMETRICblueprint Biometric.md:47; attendance.schema.ts:18
Students modulestudentId ref on every log (ref: 'Student')biometric-log.schema.ts:9-10
BullMQ biometric-syncperiodic device polling (*/15 * * * *)queue.constants.ts:7; scheduler.service.ts:70-76
BullMQ attendance-processattendance derivation workerevent-queue-map.ts:14-17; attendance.worker.ts:16
Integrations module (planned)encrypted device credentials/configblueprint Biometric.md:48,59
Audit module (planned)immutable log-write trailblueprint Biometric.md:49
RBACbiometric.log.create, biometric.log.read, biometric.device.managepermissions.constants.ts:41-43
Mongo collectionsbiometric_logs, biometric_devicesbiometric.module.ts:21-24

7. Success metrics

  • Ingest P95 < 1 s; zero log drops on the happy path.
  • Punch → attendance record derived < 2 min (sync cadence 15 min) (planned).
  • ≥ 99% of daily punches reconciled against attendance.
  • Zero cross-tenant log leakage (tenant-scoped repos, BaseRepository).
  • Offline device detected and flagged within one sync cycle (planned).

8. Edge cases

  • Duplicate punch: two logs for the same student/second; logs are immutable — dedupe is the derivation layer's job (blueprint keeps raw punches; processed flag planned, COLLECTIONS.md:1888).
  • Unknown deviceId: ingest accepts any string — no device registry check today (create-biometric-log.dto.ts:9-11).
  • Unknown studentId: @IsMongoId only checks shape, not existence (create-biometric-log.dto.ts:5-7); orphan log persists.
  • Tenancy: tenantId is taken from the JWT claim by BaseRepository — but ingest never runs tenant logic of its own (see OQ-1).
  • rawData gap: schema stores rawData (biometric-log.schema.ts:21-22) but the DTO does not accept it (create-biometric-log.dto.ts:4-20) — the forensic payload cannot actually be ingested (OQ-2).
  • Employee-code mapping: blueprint field employeeCode (COLLECTIONS.md:1878-1879) is absent from the implemented schema — mapping punches to people is done by the caller today (device pushes studentId).
  • as any: biometric.service.ts:15 casts the DTO with as any — strict-TS no-explicit-any is currently off in ESLint (AGENTS.md hard rule flags this).

9. Assumptions (module)

  • PRD scope excludes native mobile apps — web-first (PRODUCT_REQUIREMENTS_DOCUMENT.md:144). The Flutter client in this package is therefore a forward-looking admin console, not the capture surface. Capture happens on vendor hardware + SDK, which is exactly why the roadmap is gated: "Biometric depends on hardware vendor SDK availability" (FEATURE_ROADMAP.md:56); device integration is unchecked on the roadmap (:26).
  • No template storage exists anywhere. The implemented module stores no fingerprints, hashes, or templates — only punch metadata (studentId, deviceId, timestamp). Enrollment/verify/match are (planned) and their storage format is an open product decision (OQ-3).
  • The biometric-sync worker is a stub. The queue is real (queue.constants.ts:7), registered (bullmq.module.ts:34), and scheduled (scheduler.service.ts:70-76), but no @Processor('biometric-sync') exists — jobs are enqueued but never processed (OQ-4).
  • No RBAC metadata on the ingest endpoint — any authenticated user may call it (no @Permissions(...), OQ-5).
  • AttendanceSource.BIOMETRIC exists but nothing sets it (attendance.schema.ts:18); no code path links a biometric log to a mark() call.
  • Coaching mode: blueprint plans session-based (not daily) check-in for coaching tenants (IMPLEMENTATION_PLAN.md:777).
  • Permissions: blueprint names biometric.read/biometric.sync (Biometric.md:66-68); the implemented constants instead declare biometric.log.read and no sync perm (permissions.constants.ts:41-43).

10. Open questions (module-level; global ledger in 00-shared/12)

#ItemImpact
OQ-1ingest casts dto as any and never reads TenantContextService; tenant scoping happens implicitly in logRepo.create. Is an explicit tenant guard needed?Log integrity, cross-tenant audits
OQ-2rawData is in the schema but not the DTO — ingest the forensic payload now or drop the field?Forensic/replay promise (Biometric.md:56)
OQ-3Template storage format (hash? encrypted blob? vendor raw?) — no schema exists.Entire enrollment/verify UX + privacy posture
OQ-4Who writes the biometric-sync worker? Jobs currently stall.Sync status UX is speculative until it lands
OQ-5POST /biometric/ingest has no permission metadata — device webhooks may need a machine-token path, not user JWTs.Auth model for devices
OQ-6Duplicate-punch / dedupe policy: derive at ingest or in attendance?Attendance correctness

11. Glossary (this module)

TermMeaning
Punchone raw device event (biometric_logs row)
Logimmutable raw event: {studentId, deviceId, timestamp, mode?, rawData?}
Devicebiometric_devices doc: {name, deviceId, model?, status, location?, config?}; status ∈ active/inactive/offline (biometric-device.schema.ts:7-11)
Syncperiodic device poll via biometric-sync queue (*/15 * * * *)
Templatethe enrolled biometric sample — planned, format undecided (OQ-3)
Attendance derivationraw logs → attendance docs via BiometricImported event (planned)