Offline operation and catch-up¶
The device is the source of truth for when a punch happened; the server is the source of truth for who is enrolled. A punch is never lost, never duplicated, and never re-timed because it arrived late.
ADMS catch-up¶
- Per-device cursors (
attlog_stamp,operlog_stamp,attphoto_stamp,biodata_stamp) are returned in the handshake, so the device uploads only what it has not delivered. - A cursor advances in the same database transaction as the batch it covers. If the save fails, the reply is HTTP 500 and the device re-sends.
- Backlogs of thousands of lines are parsed in one pass and inserted with
bulk_create(ignore_conflicts=True)on a unique dedupe hash, in chunks ofPUNCH_BULK_CHUNK_SIZE. 2,000 punches take fewer than 60 queries. - Queued server-to-device commands wait while a device is offline and are delivered in order
on reconnect.
COMMAND_EXPIRYexpires time-sensitive types (reboot, set_time, enroll_fingerprint). User and template adds and deletes never expire unless you configure them to.
Force re-upload: POST devices/{id}/reupload-logs/ {"from": "..."}, the admin action, or
fpa_reupload_device_logs --device SN --from 2026-01-01. This resets the cursor and, with a
start date, queues DATA QUERY ATTLOG. Dedupe makes it safe.
Pull catch-up¶
Each device keeps a pull_last_record_at marker. Live capture gap-fills from the marker on
every reconnect, and --full re-imports everything safely.
Time integrity¶
punched_atis always the device's recorded time converted with the device timezone (DST ambiguity resolves to the first occurrence).received_atis stored separately.late_syncflags punches received more thanLATE_SYNC_THRESHOLDafter they happened.futureflags punches beyondreceived_at + FUTURE_PUNCH_TOLERANCE.- Clock drift is recorded whenever the device clock is known (pull mode, or firmware that sends
it). Drift beyond
CLOCK_DRIFT_WARNING_SECONDSflags punches (clock_drift), emitsdevice_clock_drift, and, withAUTO_CORRECT_DEVICE_TIME, queuesset_timeif it is withinMAX_AUTO_TIME_CORRECTION. - Offline periods across midnight, month ends or several days are handled per punch. Work dates come from the day boundary, which also supports overnight shifts.
Late punches and recomputation¶
After a batch lands, every affected (enrollee, work date) is queued for processing through
the task backend. backlog_synced fires with the device, count and date range when the batch
has at least BACKLOG_SIGNAL_THRESHOLD punches or contains late ones, so consumers can
refresh dashboards or regenerate reports.
Data safety¶
- The package never clears device logs on its own.
clear_logs/clear_dataare explicit, audited, permission-gated actions. They are refused (unsafe_operation) unless the device has reported its log count and the server holds every record since the last clear. GET devices/reconciliation/shows device count vs server count per device.- Log capacity warnings fire when stored logs reach
LOG_CAPACITY_WARNING_RATIOof capacity (reported orDEFAULT_LOG_CAPACITY). They are edge-triggered and also shown in health.
Health¶
GET /api/fingerprint/v1/health/ shows per device: online or offline, last_seen_at, offline
duration, pending commands, last punch time, pending-upload estimate, clock drift and the
capacity warning. It also totals devices, commands, unsynced enrollees and today's punches.