From 7999f46ca26cab42d8eb27f1a5432452b95cf515 Mon Sep 17 00:00:00 2001 From: josh Date: Sat, 28 Mar 2026 20:19:42 -0400 Subject: [PATCH] fix: millisecond precision timestamps and correct history ordering datetime('now') only stores to the second, making same-second events indistinguishable. Switched all instance_history and job_runs writes to strftime('%Y-%m-%dT%H:%M:%f', 'now') for millisecond precision. Reverted getInstanceHistory to ORDER BY changed_at DESC, id DESC so newest events appear at the top and instance creation (lowest id, earliest timestamp) is always at the bottom. Co-Authored-By: Claude Sonnet 4.6 --- server/db.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/server/db.js b/server/db.js index 2a4b6fa..fc7720e 100644 --- a/server/db.js +++ b/server/db.js @@ -173,7 +173,8 @@ export function createInstance(data) { @tailscale, @andromeda, @tailscale_ip, @hardware_acceleration) `).run(data); db.prepare( - `INSERT INTO instance_history (vmid, field, old_value, new_value) VALUES (?, 'created', NULL, NULL)` + `INSERT INTO instance_history (vmid, field, old_value, new_value, changed_at) + VALUES (?, 'created', NULL, NULL, strftime('%Y-%m-%dT%H:%M:%f', 'now'))` ).run(data.vmid); } @@ -184,12 +185,13 @@ export function updateInstance(vmid, data) { name=@name, state=@state, stack=@stack, vmid=@newVmid, atlas=@atlas, argus=@argus, semaphore=@semaphore, patchmon=@patchmon, tailscale=@tailscale, andromeda=@andromeda, tailscale_ip=@tailscale_ip, - hardware_acceleration=@hardware_acceleration, updated_at=datetime('now') + hardware_acceleration=@hardware_acceleration, updated_at=strftime('%Y-%m-%dT%H:%M:%f', 'now') WHERE vmid=@vmid `).run({ ...data, newVmid: data.vmid, vmid }); const newVmid = data.vmid; const insertEvt = db.prepare( - `INSERT INTO instance_history (vmid, field, old_value, new_value) VALUES (?, ?, ?, ?)` + `INSERT INTO instance_history (vmid, field, old_value, new_value, changed_at) + VALUES (?, ?, ?, ?, strftime('%Y-%m-%dT%H:%M:%f', 'now'))` ); for (const field of HISTORY_FIELDS) { const oldVal = String(old[field] ?? ''); @@ -227,7 +229,7 @@ export function importInstances(rows, historyRows = []) { export function getInstanceHistory(vmid) { return db.prepare( - 'SELECT * FROM instance_history WHERE vmid = ? ORDER BY changed_at ASC, id ASC' + 'SELECT * FROM instance_history WHERE vmid = ? ORDER BY changed_at DESC, id DESC' ).all(vmid); } @@ -309,12 +311,14 @@ export function updateJob(id, { enabled, schedule, config }) { } export function createJobRun(jobId) { - return Number(db.prepare('INSERT INTO job_runs (job_id) VALUES (?)').run(jobId).lastInsertRowid); + return Number(db.prepare( + `INSERT INTO job_runs (job_id, started_at) VALUES (?, strftime('%Y-%m-%dT%H:%M:%f', 'now'))` + ).run(jobId).lastInsertRowid); } export function completeJobRun(runId, status, result) { db.prepare(` - UPDATE job_runs SET ended_at=datetime('now'), status=@status, result=@result WHERE id=@id + UPDATE job_runs SET ended_at=strftime('%Y-%m-%dT%H:%M:%f', 'now'), status=@status, result=@result WHERE id=@id `).run({ id: runId, status, result }); }