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

08 — Form Specifications (Biometric Module)

Every form field-by-field. Validation mirrors class-validator decorators exactly from src/modules/biometric/dto/create-biometric-log.dto.ts; planned forms follow the schema fields (biometric-device.schema.ts, biometric-log.schema.ts) and blueprint endpoints. Client validates inline then submits; server 400 shadows client.


1. Ingest Punch (device webhook → POST /biometric/ingest)

Real today (create-biometric-log.dto.ts, biometric.controller.ts:14-18). Not a user form — the device/agent posts it; documented here because the client may preview a manual "enter punch" path for clerks.

#FieldTypeRequiredValidation (server)Notes/UX
1studentIdtext (MongoId)@IsMongoId() (create-biometric-log.dto.ts:5-7)shape-only check; no existence check (edge, 01 §8)
2deviceIdtext@IsString() (:9-11)no registry check — any string accepted today
3timestampdatetime@IsDateString() (:13-15)device clock time; keep original punch time for derivation correctness (blueprint COLLECTIONS.md:1883)
4modetext@IsOptional() @IsString() (:17-20)free string (finger/QR/card…) — no enum server-side

Server response: created BiometricLogDocument (schema biometric-log.schema.ts:7-27). rawData is schema-only — cannot be posted today (gap, 01 OQ-2).

2. Device Register — POST /biometric/devices (planned)

Endpoint blueprint Biometric.md:26; fields from biometric-device.schema.ts:15-31.

#FieldTypeRequiredValidation (mirror)Notes/UX
1nametext@IsString()autofocus; max 48 chars (client)
2deviceIdtext@IsString()monospace hint "printed on device"; unique per tenant (:36)
3modeltext@IsOptional() @IsString()vendor model string
4locationtext@IsOptional() @IsString()"Main gate", "Library"
5statusselect– (default active)enum DeviceStatus (:7-11,24-25)segmented Active/Inactive/Offline
6configJSON@IsOptional() objectadvanced disclosure; non-secret config only (07 §8)

Errors: 409 duplicate deviceId → inline banner; 400 validation → per-field.

3. Device Edit — PATCH /biometric/devices/:id (planned)

Same fields as §2, all optional (partial update); status change to offline via "Disable" confirm dialog rather than raw edit.

4. Enrollment — device capture (planned, blocked — OQ-3)

No HTTP form fields yet; the flow is device-driven (screen 06 §5). The eventual wire payload per blueprint COLLECTIONS.md:1872-1892 + Biometric.md:57:

Planned fieldTypeMeaning
employeeCodestringvendor/user code — maps punch → studentId/userId via config
templateblob/hash (format TBD)storage format undecided — hash? encrypted blob? vendor raw? (OQ-3)
studentId / userIdMongoIdresolved identity (ref Student as in biometric-log.schema.ts:9-10)

Enrollment form (client): student search → confirm. Never renders template bytes.

5. Manual Punch Entry (clerk fallback) — (proposed)

Post-sync-clinic fallback form = §1 fields + student search picker (resolves studentId). Gated biometric.log.create (permissions.constants.ts:41); flagged "manual entry" in mode so derivation/audit can distinguish (blueprint keeps raw payload for replay, Biometric.md:56).

6. Log Filters (Log List) — (planned)

FieldTypeNotes
studentsearch chipdeep-link ?student=:id
devicedropdownfrom GET /biometric/devices
date rangedate picker presetsToday / This week / Custom
modechipsmulti-select; free strings client-side

No server filter contract yet (planned GET /biometric/logs, blueprint Biometric.md:30).


Form-level rules (all)

  • Double-submit: disabled while pending; device ingest must be idempotent-safe client side (retry sends identical body; dedupe is derivation's job — logs are immutable).
  • Optimistic: no optimistic writes for register/disable/sync (server-confirm, 00-shared/08 §4).
  • Keyboard: .next sequence, .done submits; register form 6 fields single column.
  • Error copy: from message of envelope for business 4xx (00-shared/07); codes for the rest.

Client-side error priority

  1. 400 VALIDATION → field.
  2. 401 UNAUTHENTICATED → session-expiry overlay (global).
  3. 403 FORBIDDEN → permission screen ("You don't have device access").
  4. 409 DUPLICATE_RESOURCE → inline (deviceId duplicate).
  5. 429 RATE_LIMITED → countdown (ingest is high-volume — device path should use a machine token, not user rate tiers — OQ-5).
  6. 5xx → AppErrorState.