Occurrences overview
Every check template (frequency + type) generates occurrences
— individual items a staff member completes. An occurrence has a
due_at timestamp calculated from the tenant's timezone and
the check's frequency slots.
Calendar slots
Each frequency maps to fixed local-time slots in the tenant's timezone
(set in the tenant settings, default Europe/London):
| Frequency | Slots (local time) |
|---|---|
twice_daily | 00:00 and 12:00 every day |
daily | 00:00 every day |
twice_weekly | Monday 00:00 and Thursday 00:00 |
weekly | Monday 00:00 |
twice_monthly | 1st and 15th 00:00 |
monthly | 1st 00:00 |
quarterly | Jan/Apr/Jul/Oct 1st 00:00 |
Generation (lazy, on read)
Occurrences are generated when the list endpoint is called, not by a background cron. For each active check:
- If no occurrences exist: generates the current slot only.
- If occurrences exist: generates all slots between the latest
due_atand now, including the current open slot. - Catch-up is capped at the last 14 days of slots.
- The unique index on
(check_id, due_at)prevents duplicates.
States
Every occurrence is in one of three derived states (no status column):
| Status | Derived from | Meaning |
|---|---|---|
pending | checked_at IS NULL AND skipped_at IS NULL | Needs attention |
done | checked_at IS NOT NULL | Completed by a staff member |
skipped | skipped_at IS NOT NULL | Deliberately skipped (e.g. equipment offline) |
The API response also includes an overdue boolean — true when
status === "pending" and due_at is in the past.
Validation
Completion is validated server-side by check type:
| Type | Readings |
|---|---|
simple | No readings allowed |
cold_store | One reading per every active fridge, each with fridge_id |
food | ≥1 reading, each with valid food_item_id |
washer | No readings allowed |
Permissions
- Complete / Uncomplete — any tenant member
- Skip — owner or manager only
- Create / Replace / Delete templates — owner or manager only
Daily checklist (mobile app)
The home screen shows a Daily Hygiene card with a
real-time progress bar and a task carousel. Swipe through pending
occurrences — simple checks complete in one tap; cold_store
and food checks open a temperature-reading modal with
per-unit sliders.
The Daily Checklist screen (sidebar) shows the full list grouped by status: Overdue / Pending / Done / Skipped. Tap to complete or record temperatures.
- Complete — any member; simple check = one tap; cold_store/food = slider modal with corrective-action note for out-of-range readings
- Undo — any member; reverts to pending (clears completion or skip)
- Skip — owner/manager only; requires reason note
API reference
GET /v1/tenants/{tenantCode}/check-data — list occurrences
POST /v1/tenants/{tenantCode}/check-data/{id}/complete — complete (with readings)
POST /v1/tenants/{tenantCode}/check-data/{id}/uncomplete — undo completion
POST /v1/tenants/{tenantCode}/check-data/{id}/skip — skip (admin only)
All request and response bodies use snake_case keys. See the
OpenAPI reference for full schema details.