feat(time-tracking): cycle 5 — Smartsheet sync scaffold
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).
This commit is contained in:
@@ -23,6 +23,7 @@ import {
|
||||
type AdminSettings,
|
||||
} from "@/actions/water-log/settings";
|
||||
import SmartsheetIntegrationCard from "@/components/admin/water-log/SmartsheetIntegrationCard";
|
||||
import TimeTrackingSmartsheetCard from "@/components/admin/time-tracking/TimeTrackingSmartsheetCard";
|
||||
|
||||
const TUXEDO_BRAND_ID = "64294306-5f42-463d-a5e8-2ad6c81a96de";
|
||||
|
||||
@@ -496,6 +497,31 @@ export default function WaterLogSettingsPage() {
|
||||
<SmartsheetIntegrationCard brandId={TUXEDO_BRAND_ID} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Time Tracking → Smartsheet (Cycle 5). Independent of the
|
||||
water-log smartsheet card above; uses its own sheet ID,
|
||||
token, column mapping, and sync queue. Sibling surface in
|
||||
this same hub view. */}
|
||||
<div className="mt-12 border-t border-[#d4d9d3] pt-10">
|
||||
<p className="text-[10px] font-mono uppercase tracking-[0.3em] text-[#8a6b3b]">
|
||||
§ 06 — Time Tracking Integrations
|
||||
</p>
|
||||
<h2
|
||||
className="mt-2 text-2xl font-medium text-[#1a4d2e]"
|
||||
style={{ fontFamily: "var(--font-display, Georgia, serif)" }}
|
||||
>
|
||||
Smartsheet (Time Tracking)
|
||||
</h2>
|
||||
<p className="mt-2 text-sm text-[#5a5d5a]">
|
||||
Push every closed clock-out from the time tracking system to a
|
||||
configured Smartsheet sheet. Same encryption + retry policy as the
|
||||
water-log smartsheet integration. Config-deferred — wire it up
|
||||
whenever the brand is ready with a sheet ID + API token.
|
||||
</p>
|
||||
<div className="mt-6">
|
||||
<TimeTrackingSmartsheetCard brandId={TUXEDO_BRAND_ID} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user