Mirrors the water-log Smartsheet pattern (migration 0093 +
src/services/smartsheet-sync.ts). End-to-end wiring is in place;
the brand fills in sheet ID + token + column mapping whenever
ready.
DB:
- 0095_time_tracking_smartsheet_sync.sql — config + sync_queue +
sync_log tables with brand-scoped RLS. Unique constraint on
(brand_id, log_id) keeps the queue idempotent against retries.
Code:
- db/schema/time-tracking.ts — adds TTSmartsheetFrequency,
TT_SMARTSHEET_FREQUENCIES, TTSmartsheetColumnKey,
TTSmartsheetColumnMapping, and the three pgTable defs.
- src/services/time-tracking-smartsheet-sync.ts — syncLogToSmartsheet
(dedup-by-log_id, token-echo sanitization, retry-with-backoff),
drainTTSyncQueue, runScheduledTTSync.
- src/actions/time-tracking/smartsheet.ts — full admin CRUD
(getTTSmartsheetConfig, saveTTSmartsheetConfig,
testTTSmartsheetConnection, getTTSmartsheetRecent,
getTTSmartsheetQueueSummary, disableTTSmartsheet).
- src/actions/time-tracking/field.ts — clockOutWorker calls the new
enqueueClockOutForSync helper in its OWN transaction (so a queue-
insert failure can never poison the clock-out commit; reviewer
caught this in cycle 2's same-style bug pattern).
- src/components/admin/time-tracking/TimeTrackingSmartsheetCard.tsx —
slim, focused card: sheet ID + token + frequency + enable +
Test Connection → column-mapping dropdowns + Recent Activity table.
- src/app/admin/water-log/settings/page.tsx — §06 section renders
the new card as a sibling of the existing water-log smartsheet
card.
Permission gate uses can_manage_settings + platform_admin (not
can_manage_water_log) — feature is a brand-level integration
setting, not water-log-specific.
Out of scope / deferred:
- /api/time-tracking/smartsheet-sync cron route. The trigger is
optional: realtime mode syncs inline; 15-min/hourly modes need the
cron. Add in a follow-up cycle when the cron infrastructure is
revisited.
- drag-and-drop column-mapping UX (current card uses plain
dropdowns).
- backfill flow (no equivalent of the water-log "backfill past N
days" feature yet).
- can_manage_time_tracking permission flag (uses
can_manage_settings as the proxy; revisit once the admin_users
schema gets a time-tracking-specific permission column).