9e6accb3df
Phase 2 of the time-tracking buildout — turns the existing clock widget
into a full payroll-ready system for Drivers / Supervisors / Admins.
Roles
- field_workers CHECK extended with 'driver' and 'supervisor' alongside
the existing worker / time_admin / irrigator / water_admin values.
Schema (migration 0098)
- time_tracking_logs gains clock_in/out lat/lng/accuracy_m + gps_verified
+ entry_kind ('clock' | 'manual') + manual_reason + edit audit columns.
- new time_tracking_timesheets (draft → submitted → approved/locked →
rejected, with unlock path for admins).
- new time_tracking_audit_log (append-only).
- new time_tracking_supervisor_assignments (supervisor ↔ supervisee edges).
- new SECURITY DEFINER RPCs: recompute_timesheet_totals(),
get_or_create_timesheet(), plus a time_tracking_approval_queue view.
Workflow + locking (src/actions/time-tracking/timesheets.ts)
- resolveCaller() returns platform_admin / brand_admin / supervisor /
worker context; supervisor scope is enforced via the assignments table.
- submitTimesheet / approveTimesheet / rejectTimesheet / unlockTimesheet
all run inside withTx with FOR UPDATE row locks so the status + audit
row + recompute RPC commit atomically.
- Editing or deleting an entry on an approved timesheet is blocked at
the action layer; only unlockTimesheet (admin-only, mandatory audit
note) can re-open it.
Manual entry (src/actions/time-tracking/entries.ts)
- addManualTimeEntry / editTimeEntry / deleteTimeEntry with Zod validation,
audit-log writes in the same transaction, lock-aware.
GPS + offline (src/actions/time-tracking/field.ts,
src/lib/offline/time-tracking-queue.ts,
src/actions/time-tracking/offline-handlers.ts)
- captureGps() in the field client: best-effort geolocation, never blocks
clock-in/out (gps_verified = accuracy_m <= 100).
- tryOrQueueClock() wraps the action; on network failure the event lands
in IndexedDB and replays via replayOfflineClock() (PIN re-verified on
replay, submitted_via = 'offline_sync').
Export (src/actions/time-tracking/export.ts +
src/app/api/time-tracking/timesheets/[id]/export/route.ts)
- PDF (pdf-lib) + CSV (papaparse) payroll export with signature lines,
available for any approved timesheet.
UI
- /admin/time-tracking with tab nav (Overview / Timesheets / Approvals /
Audit).
- TimesheetsList, TimesheetDetail (status-driven workflow buttons,
manual entry form, audit trail), ManualEntryForm.
- FleetRouteSummary on the time-tracking overview shows the full crew's
water + time totals for the day.
- DailyRouteSummary on /admin/water-log/users/[id] shows the per-worker
cross-link badge (water gallons + time hours + timesheet status).
Verification
- npx tsc --noEmit → 0 errors.
- npm run build → all 10 time-tracking routes compile.
- npm run lint → 0 errors/warnings in new files.
- Playwright smoke → 4/5 pass; the failing case is a pre-existing
Tuxedo storefront 404 unrelated to this change.
58 lines
709 B
Plaintext
58 lines
709 B
Plaintext
# Dependencies
|
|
node_modules/
|
|
.pnp
|
|
.pnp.*
|
|
|
|
# Build outputs
|
|
.next/
|
|
out/
|
|
build/
|
|
dist/
|
|
|
|
# Package files
|
|
package-lock.json
|
|
yarn.lock
|
|
pnpm-lock.yaml
|
|
|
|
# Environment variables
|
|
.env
|
|
.env.local
|
|
.env.*.local
|
|
|
|
# Logs
|
|
npm-debug.log*
|
|
yarn-debug.log*
|
|
yarn-error.log*
|
|
.pnpm-debug.log*
|
|
|
|
# Vercel
|
|
.vercel
|
|
|
|
# TypeScript
|
|
*.tsbuildinfo
|
|
next-env.d.ts
|
|
|
|
# Misc
|
|
.DS_Store
|
|
*.pem
|
|
|
|
# Supabase
|
|
supabase/.temp/
|
|
|
|
# Playwright test results (generated, not source)
|
|
test-results/
|
|
playwright-report/
|
|
tests/_artifacts/
|
|
|
|
# Local debug / smoke scripts (not part of the product)
|
|
scripts/cycle*-debug.mjs
|
|
scripts/cycle*-smoke.mjs
|
|
scripts/cycle*-smoke-session.mjs
|
|
|
|
# IDE / local config
|
|
.mcp.json
|
|
.env*
|
|
public/videos/tuxedo-hero.mp4
|
|
.neon
|
|
.worktrees/
|