Administration
Permissions, settings, scheduled jobs, retention and the security posture — everything an administrator owns.
Permissions
Seventeen permissions, deliberately fine-grained. The separations that matter: reading attendance does not imply changing the server connection, watching a sync does not imply starting one, running a sync does not imply creating attendance records, managing a connection does not imply being able to enter its password, and reading a row's remarks does not imply being able to write them.
| Permission | Grants |
|---|---|
| Biotime | Base access and the dashboard. Without it the module is invisible and its pages unreachable. |
| Employees & Bindings | View mirrored personnel and their match state. |
| Bind / unbind employees | Change who a BioTime employee maps to; run the bulk accept. |
| Attendance transactions | View mirrored punches. |
| Devices | View mirrored terminals. |
| Organization | View departments, positions, areas and locations. |
| Add / edit remarks | Write a free-form note on a mirrored department, position, area, location, device or employee. Reading remarks is covered by the page's own permission, and a sync never changes a note. |
| Analytics | View trends and breakdowns. |
| View sync history | Open the Sync Center and read past runs. |
| Run a sync | Start a sync. Separate from viewing, because starting one reaches an external server and consumes its rate limit. |
| Import punches into ERPat attendance | Turn mirrored punches into attendance records. Deliberately not implied by running a sync: mirroring reads a remote server, importing writes into ERPat's own payroll-facing attendance table. |
| View API logs | See the record of calls made to the BioTime server. |
| View raw API payloads | See the stored response excerpt behind a log entry. Separate, because a raw payload can hold more of the remote record than the listing shows. |
| Export mirrored data | Download attendance data. |
| Biotime settings | Open the settings page. |
| Manage connections | Add, edit and delete server connections. |
| Enter / rotate BioTime credentials | Supply or change the BioTime password. Deliberately not implied by managing connections. |
Settings
Six tabs under Biotime → Settings. Every numeric setting is clamped on save — an out-of-range value is corrected rather than stored, and read back with the same bounds.
Sync & retention
| Setting | Default | Range | Notes |
|---|---|---|---|
| Run the sync automatically | On | — | Turns the scheduled job on or off without disabling the module. |
| Overlap window (minutes) | 10 | 1–120 | How far before the last seen punch each run re-reads, so a late upload is never skipped. |
| Rows per page | 200 | 10–500 | How many records are requested per API call. |
| First-run window (days) | 30 | 1–365 | How far back the very first sync reaches. Full backfill is a separate, explicit action. |
| Maximum pages per tick | 5 | 1–50 | Work done per request. Higher is faster but each request runs longer. |
| Keep API logs for (days) | 30 | 1–365 | Pruned nightly. |
| Keep sync runs for (days) | 90 | 1–730 | Pruned nightly. |
| Keep transactions for (days) | 0 | 0–3650 | 0 means keep forever. Setting a window prunes older punches; the daily analytics rollup survives. |
Binding
| Setting | Default | Notes |
|---|---|---|
| Match employees automatically | On | Runs the matching pass as part of a sync. |
| Match on ERPat ID number | On | The primary rule: BioTime employee code against the ERPat ID number. |
| Offer name-similarity suggestions | On | Suggestions only — never applied automatically. |
| Write a canonical Kiosk enrollment row | On | Only does anything when the Kiosk module is present. Writes under a dedicated enrollment label for this connection, never the shared wildcard. |
Attendance import
Off by default, and additionally inert while the Human Resource module is switched off — the records it creates land in HR's Attendance screen, so there is nowhere for them to go without it.
| Setting | Default | Range | Notes |
|---|---|---|---|
| Create ERPat attendance from punches | Off | — | The master switch. Every other Biotime setting governs reading a remote server; this one writes into ERPat. |
| Import automatically after each sync | Off | — | When off, the import only runs when somebody starts it from the Sync Center. |
| New shift after a gap of (hours) | 6 | 1–12 | Consecutive punches more than this far apart start a new shift. Also the wait before a shift is imported — see the note below. |
| Ignore repeat taps within (seconds) | 60 | 0–600 | A second tap this soon after the first is the same arrival. 0 disables it. |
| Maximum shifts per batch | 100 | 10–500 | Work done per request. Higher finishes a backfill in fewer batches but each request runs longer. |
| Import a lone punch as an incomplete record | Off | — | Best left off. A shift with one punch has no clock-out, and ERPat treats any record without one as still open — so it blocks every later shift for that employee from importing, and the auto-clockout job closes it as "System Clockout" within hours. Measured on a real feed, switching it on cost about a quarter of the records. |
| Close a shift at its scheduled end | Off | — | When on, a shift whose last punch is at or after the day's scheduled time out is written once the grace below has passed, instead of waiting the full gap. Needs a schedule with a fixed time out: flexible schedules, rest days, no schedule, a single punch, or a last punch before the scheduled end all keep the normal gap rule. A punch arriving after the record was written still extends it in place. |
| Grace after the scheduled end (minutes) | 0 | 0–720 | How long after the scheduled time out to wait before writing the shift. 0 writes it at the scheduled end; 150 waits two and a half hours so overtime and straggler taps land in the record instead of each becoming a separate correction. Whole minutes; never lengthens the wait beyond the gap rule. |
| Import in-progress shifts before clock out | Off | — | When on, an employee's clock in and breaks appear in ERPat while they are still at work, as an incomplete record with no time out that each new punch extends until the clock out finishes it. A lone clock in is enough to open it. Only for employees on a schedule with a fixed time out, and only while their last punch is still before that time out — after it, a punch may be the clock out, so the normal rules take over. Also closes shifts at their scheduled end, exactly as the switch above does, whether or not that one is on; see the warning below for why that is a requirement rather than a convenience. |
| Auto-fix double tap on clock in | Off | — | Keeps the first punch of a shift as the time in and discards repeat taps that follow it within the window below. The punch is not deleted — it stays on the record, labelled "Double tap". |
| Clock-in window (minutes) | 15 | 1–120 | Measured from the first punch, not the previous one, so 8:00 / 8:07 / 8:12 with a 10-minute window keeps 8:12 — twelve minutes in is a plausible first break, not a fumbled badge. |
| Auto-fix double tap in breaks | Off | — | Discards a repeat tap on a break, and one made just before clocking out. The clock-out itself is always kept: somebody who taps at 17:00 and again at 17:03 left at 17:03, and without this the 17:00 tap is left behind as a break that never ends. |
| Break window (minutes) | 5 | 1–120 | Raise this carefully. Too far and genuine short breaks are erased, which pays people for time they did not work. On a real 219-shift feed, break gaps clustered at 1–5 minutes (re-taps) and again at 11–60 (real breaks), so 5 takes the first cluster and stops short of the ambiguous 6–10 band. |
Both switches are off, and you do not have to guess. While they are off the import still counts what it would have changed and reports it in the Sync Center console and the batch audit entry, without writing anything. Run a sync, read the count, then decide. To repair records imported before you switched them on, tick Re-check imported records for double taps in the Sync Center.
This is why the setting also closes shifts at their scheduled end. An open record is exactly what the HR auto-clockout job looks for: once one is older than the auto-clockout trigger — 12 hours after clock in by default — that job closes it with a time of its own. Waiting the full gap would let it reach a normal 08:00–17:00 day first and the real clock out would then be refused, so the importer finalizes at the scheduled end instead, hours ahead of it. Two cases still end with the job winning, both harmless but worth recognising: an early leaver, whose last punch falls before their scheduled time out and whose record therefore waits for the gap rule; and a clock in that never receives another punch, which is closed to a zero-length record — the same outcome as "import a lone punch", but far more common with this on.
It costs more work per batch. Every punch that arrives is one more correction, each with its own entry in the record's history. Where a whole shift clocks in at once, raise Maximum shifts per batch.
Display & advanced
| Setting | Default | Notes |
|---|---|---|
| Show capture photos | Off | Capture photos are images of employees. Opt in deliberately. |
| Show body temperature | Off | Health data. Additionally inert on cloud servers, whose feed carries no such field. |
| Dashboard range (days) | 7 | 1–90. |
| Default connection | — | Which connection the pages read when more than one exists. |
| Allow private / internal hosts | Off | On-premises servers only. See the security note below. |
Scheduled jobs
| Job | Schedule | What it does |
|---|---|---|
Biotime — incremental syncbiotime_sync |
Every 15 minutes | Mirrors new data from each active connection, resuming from the stored cursor. Does nothing when the module is off or automatic sync is disabled. When automatic attendance import is also on, the same job turns bound punches into pending attendance records. |
Biotime — retention & analytics refreshbiotime_retention |
Daily, 02:30 | Prunes API logs, sync runs and (if configured) old punches, then refreshes the daily analytics rollup. |
Security posture
Credentials
- The BioTime password is encrypted at rest with AES-256-GCM, using the key in
BIOTIME_ENCRYPTION_KEY. Access and refresh tokens are encrypted the same way. - Each encrypted value is bound to the connection row and the field it belongs to, so a stored secret copied into another row or another field simply will not decrypt.
- A credential is only stored after a real sign-in succeeds. There is no path that saves an unproven password.
- Passwords, tokens and authorization headers are stripped from every stored error message and log excerpt. API log paths are stored without their query strings.
- Repeated credential failures temporarily lock a connection. Network problems and server errors deliberately do not count toward that — otherwise one bad afternoon on the network would lock every connection.
Outbound requests
- The server address is re-resolved and re-checked before every single request, including from the scheduled job, and the connection is pinned to the approved address. A single check at setup time can be defeated by changing DNS afterwards.
- Loopback, link-local and cloud-metadata addresses are refused unconditionally.
- Allow private / internal hosts widens this to ordinary LAN ranges, applies only to the on-premises profile, and is off by default. It is a security decision, not a convenience toggle.
- Redirects are never followed, and response size is capped.
What is never collected
- Biometric templates are never mirrored. Fingerprint and face data stay on your BioTime server. Only enrollment counts are copied.
- Capture photos and body temperature default to off. Both are personal data and require a deliberate decision.
- The integration API never exposes credentials, tokens, or the raw remote record.
The integration API
Seven read-only endpoints under /api/v1/biotime/*, requiring the
biotime:read scope. Grant it in Settings → API Access like any other
scope. A token with the scope still receives a 404 on a tenant where the Biotime module is
switched off.
There is no write scope — the module is a read-only mirror, so there is nothing for a machine to contribute. Endpoint details are in Reference.
Audit trail
These actions are recorded in ERPat's audit log: creating, updating and deleting a connection; rotating a credential (the fact, never the value); running a connection test; changing settings (only the keys that actually changed); creating, changing and removing a binding; starting a sync; and importing attendance. Bulk acceptance writes one entry per batch rather than one per employee.
Attendance import writes at two levels, because they answer different questions:
| Entry | Written | Answers |
|---|---|---|
| Biotime attendance imported | Once per batch | What did this sync do? — records created, updated, skipped, failed. |
| Attendance added / updated from BioTime | Once per record | Where did this record come from? Filed against the record itself, so it appears in its Log Details history — the screen an approver is already on. |