May 22, 2026
Timestamp-cleanup migrations 0018 + 0019
Database
- Migration 0018 (`a9c7d37`) — converted all 37
mode: "timestamp"columns across 23 tables fromsql\CURRENT_TIMESTAMP\`default to$defaultFn(() => new Date()). Reason: Drizzle's SQLitemode: "timestamp"parses the column as **unix seconds**, butCURRENT_TIMESTAMPwritesTEXT 'YYYY-MM-DD HH:MM:SS', which Drizzle parses to invalid Date. Symptom:Date.toISOString()throwsRangeError: Invalid time valuedeep inside hot paths (chatbot, scan list, mention rendering). Header doc onanalyticsSnapshot.computedAt` documents the trap in detail so new timestamp columns don't reintroduce it. - Migration 0019 (`aad6ff1`) — backfill bug-fix for 0018. The generated rebuild block multiplied existing values by 1000 (
strftime('%s', col) * 1000) on the false assumption Drizzle stored milliseconds. With seconds-mode, the multiplier wrote ms-shaped values into seconds columns (e.g.1748000000000instead of1748000000) — interpreted as year-58348 timestamps. Migration 0019 divides any row wherecol > 10000000000(~year 2286) by 1000. Idempotent — re-running only hits values still in ms-form. 3175 rows fixed across 25 columns. `apps/saas/app/api/cron/reset-quotas/route.ts` also updated:resetAt: sql\(unixepoch() \* 1000)\`→resetAt: new Date()` so it stops generating ms-in-seconds writes.