Skip to main content

Geo-Fencing

Model

Each organization_unit may enable geo-fencing. When on:

unit.geo_lat, unit.geo_lon, unit.geo_radius_m

Every punch carries lat, lon, accuracy_m. The server computes haversine(unit.centre, punch) and compares to radius + min(accuracy, 50) — a 50-metre cap on accuracy inflation prevents trivial spoofing.

Policy

red_flag_policies for the GEO_VIOLATION code per unit:

  • allow_flag — the punch lands, GEO_VIOLATION attached (critical severity).
  • block400 GEO_VIOLATION_BLOCKED, punch rejected.
  • require_approval — punch lands, attendance row held in pending_approval.

Mobile UX

The Flutter client requests location permission at onboarding and verifies it on every check-in:

flowchart TD
A[Tap Check-in] --> B{Location permission?}
B -- denied --> C[Show 'enable location' banner, do nothing]
B -- granted --> D[Get high-accuracy fix, timeout 8s]
D -- fix --> E[POST /attendance/punch]
D -- no fix --> F[Save to offline buffer without lat/lon]
F --> G[Server flags LOCATION_MISSING]

Accuracy Caveats

  • Indoor lat/lon can be noisy; the app falls back to last known with a visible warning and flags LOW_ACCURACY.
  • Mocked locations are detected via Geolocator.isMocked and trigger DEVICE_MISMATCH + GEO_VIOLATION.

Operator Tools

  • SystemAdmin can draw the fence on a map in Filament.
  • A debug endpoint (GET /units/{id}/geo/preview) returns recent punches plotted relative to the fence for troubleshooting.