fix(api): close M5 frontend contract gaps

This commit is contained in:
zouantchaw
2026-03-19 10:28:13 +01:00
parent 3399dfdac7
commit 4b2ef9d843
9 changed files with 293 additions and 21 deletions

View File

@@ -81,6 +81,29 @@ All routes return the same error envelope:
}
```
## 3.1) Time handling
V2 stores operational timestamps in UTC using PostgreSQL `TIMESTAMPTZ`.
Rules:
- frontend sends UTC timestamps to backend
- backend returns ISO 8601 UTC timestamps for source-of-truth fields
- frontend converts those timestamps to local time for display
Source-of-truth timestamp fields include:
- `startsAt`
- `endsAt`
- `startTime`
- `endTime`
- `clockInAt`
- `clockOutAt`
- `createdAt`
- `updatedAt`
Helper fields like `date` are UTC-derived helpers and should not replace the raw timestamp fields.
## 4) Attendance policy and monitoring
V2 now supports an explicit attendance proof policy:

View File

@@ -23,6 +23,7 @@ Supporting docs:
- Send `Idempotency-Key` on every write route.
- Treat `order`, `shift`, `shiftRole`, and `assignment` as different objects.
- For staff shift applications, `roleId` must come from the response of `GET /staff/shifts/open`.
- Treat API timestamp fields as UTC and convert them to local time in the app.
## 2) What is implemented now
@@ -145,6 +146,8 @@ Rules:
- worker rating happens through `POST /client/coverage/reviews`
- the same endpoint also supports `markAsFavorite` to add or remove a worker from business favorites
- blocking a worker is done through the same endpoint using `markAsBlocked`
- coverage shift items now include `locationName` and `locationAddress`
- assigned worker items now include `hasReview`
- dispatch ranking order is:
1. `CORE`
2. `CERTIFIED_LOCATION`
@@ -216,6 +219,7 @@ Important:
- `GET /staff/session`
- `GET /staff/dashboard`
- `GET /staff/profile/stats`
- `GET /staff/profile-completion`
### Availability
@@ -250,6 +254,7 @@ Staff shift detail and list rules:
- assigned shifts include `clientName`, `hourlyRate`, `totalRate`, `startTime`, `endTime`
- shift detail includes `clientName`, `latitude`, `longitude`, `hourlyRate`, `totalRate`
- completed shifts include `date`, `clientName`, `startTime`, `endTime`, `hourlyRate`, `totalRate`
- `GET /staff/profile/stats` returns `totalShifts`, `averageRating`, `ratingCount`, `onTimeRate`, `noShowCount`, `cancellationCount`, `reliabilityScore`
### Clock in / clock out
@@ -266,6 +271,7 @@ Clock-in payload rules:
- send `overrideReason` only when geo override is allowed
- send `proofNonce` and `proofTimestamp` on attendance writes
- send `attestationProvider` and `attestationToken` only if the device has them
- if backend returns `ALREADY_CLOCKED_IN`, treat it as a valid retry-state signal and refresh attendance/session state
Clock-in read rules:

View File

@@ -104,6 +104,11 @@ Coverage-review request payload may also send:
If `markAsFavorite` is `true`, backend adds that worker to the business favorites list. If `markAsFavorite` is `false`, backend removes them from that list. If `markAsBlocked` is `true`, backend adds that staff member to the business-level blocked list and future apply or assign attempts are rejected until a later review sends `markAsBlocked: false`.
`GET /client/coverage` response notes:
- each shift item includes `locationName` and `locationAddress`
- each assigned worker item includes `hasReview`
Swap-review routes:
- `GET /client/coverage/swap-requests?status=OPEN`
@@ -163,6 +168,7 @@ The manager is created as an invited business membership. If `hubId` is present,
- `GET /staff/session`
- `GET /staff/dashboard`
- `GET /staff/profile/stats`
- `GET /staff/profile-completion`
- `GET /staff/availability`
- `GET /staff/clock-in/shifts/today`
@@ -218,6 +224,21 @@ Example `GET /staff/clock-in/shifts/today` item:
}
```
Example `GET /staff/profile/stats` response:
```json
{
"staffId": "uuid",
"totalShifts": 12,
"averageRating": 4.8,
"ratingCount": 7,
"onTimeRate": 91.7,
"noShowCount": 1,
"cancellationCount": 0,
"reliabilityScore": 92.3
}
```
### Staff writes
- `POST /staff/profile/setup`
@@ -296,12 +317,14 @@ These are exposed as direct unified aliases even though they are backed by `core
- `NFC_REQUIRED`
- `GEO_REQUIRED`
- `EITHER`
- all source-of-truth timestamps are UTC ISO 8601 values. Frontend should convert them to local time for display.
- For `POST /staff/clock-in` and `POST /staff/clock-out`:
- send `nfcTagId` when clocking with NFC
- send `latitude`, `longitude`, and `accuracyMeters` when clocking with geolocation
- send `proofNonce` and `proofTimestamp` for attendance-proof logging; these are most important on NFC paths
- send `attestationProvider` and `attestationToken` only when the device has a real attestation result to forward
- send `overrideReason` only when the worker is bypassing a geofence failure and the shift/hub allows overrides
- if the worker is already clocked in, backend returns `409` with code `ALREADY_CLOCKED_IN`
- `POST /staff/location-streams` is for the background tracking loop after a worker is already clocked in.
- `GET /client/coverage/incidents` is the review feed for geofence breaches, missing-location batches, and clock-in overrides.
- `GET /client/coverage/blocked-staff` is the review feed for workers currently blocked by that business.