- Week Prev/Next/Today now anchor to this Monday instead of today, so
navigation stays week-aligned
- Timesheet sync no longer pulls into the future — capped at today
while shift-fetching still covers the full displayed week
- Roster pivot skips entries that are still clocked in with no
clock-out yet, instead of showing them as 0 hours
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Sync rota and pull timesheets now operate on the 7-day view window rather
than rolling default windows — reduces API calls and allows backdating.
Cron job still uses rolling defaults via runRotaSync()/runTimesheetSync().
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- fetchTimesheetShifts: hits /api/v2/shifts, subtracts breaks, carries PENDING/APPROVED status
- syncJobs.js: shared runRotaSync/runTimesheetSync logic used by routes and cron
- Rota sync now skips dates already marked source='timesheet'
- POST /api/workforce/sync-timesheets: on-demand pull of last 7 days actual hours
- Daily 6am cron: rota sync then timesheet sync, each logged independently
- upsertWorkforceShifts now writes source per row (workforce or timesheet)
- Frontend: Pull timesheets button alongside Sync rota button
- Clock icon on timesheet cells — amber for PENDING, green for APPROVED
- Both buttons disabled while either sync is in progress
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Log workforce sync errors to backend stdout so they appear in docker logs
- Extend error flash from 5s to 15s so errors are readable
- Replace sendBeacon (POST-only) with keepalive fetch (PUT) on unload —
sendBeacon was hitting 404s on all three unload saves
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>