From 4fd323fff46a3e00609e566efbee8b5c7cf2fbb3 Mon Sep 17 00:00:00 2001 From: sravan Date: Tue, 7 Jul 2026 15:08:38 +0530 Subject: [PATCH] fix(chat): thread query returned OLDEST 300, hiding new messages past the cap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit THE disappearing-messages root cause (found via THREAD.length=300 vs 351 on server). messages.thread and threadByConversation did 'ORDER BY created_at ASC LIMIT 300' — the oldest 300. Once a DM/group passed 300 messages, every newer message was silently dropped from the fetch, so anything sent after that point 'disappeared' (persisted server-side, never returned to the client). Now: inner 'ORDER BY created_at DESC LIMIT' takes the NEWEST N, outer ASC presents them oldest-first. Cap raised 300 -> 500. Co-Authored-By: Claude Opus 4.8 --- server/repos.js | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/server/repos.js b/server/repos.js index 89f0e95..8423436 100644 --- a/server/repos.js +++ b/server/repos.js @@ -204,11 +204,15 @@ const messages = { attachmentsForDm: (teamId, a, b) => db.prepare(`SELECT at.id, at.name, at.mime, at.size, m.created_at FROM messages m JOIN attachments at ON at.id=m.attachment_id WHERE m.team_id=? AND m.conversation_id IS NULL AND ((m.sender_id=? AND m.recipient_id=?) OR (m.sender_id=? AND m.recipient_id=?)) AND m.deleted=0 ORDER BY m.created_at DESC`).all(teamId, a, b, b, a), linksForConversation: (teamId, conversationId) => db.prepare("SELECT body, created_at FROM messages WHERE team_id=? AND conversation_id=? AND deleted=0 AND body LIKE '%http%' ORDER BY created_at DESC").all(teamId, conversationId), linksForDm: (teamId, a, b) => db.prepare("SELECT body, created_at FROM messages WHERE team_id=? AND conversation_id IS NULL AND ((sender_id=? AND recipient_id=?) OR (sender_id=? AND recipient_id=?)) AND deleted=0 AND body LIKE '%http%' ORDER BY created_at DESC").all(teamId, a, b, b, a), - // Full 1:1 (DM) thread between two users (both directions), oldest first. - thread: (teamId, a, b, limit = 300) => - db.prepare(`SELECT * FROM messages WHERE team_id=? AND conversation_id IS NULL - AND ((sender_id=? AND recipient_id=?) OR (sender_id=? AND recipient_id=?)) - ORDER BY created_at ASC LIMIT ?`).all(teamId, a, b, b, a, limit), + // Full 1:1 (DM) thread between two users (both directions). Take the NEWEST `limit` messages + // (inner DESC), then present them oldest-first. The old plain "ASC LIMIT" returned the OLDEST 300 + // and silently dropped everything newer once a thread passed 300 — so new messages "disappeared". + thread: (teamId, a, b, limit = 500) => + db.prepare(`SELECT * FROM ( + SELECT * FROM messages WHERE team_id=? AND conversation_id IS NULL + AND ((sender_id=? AND recipient_id=?) OR (sender_id=? AND recipient_id=?)) + ORDER BY created_at DESC LIMIT ? + ) ORDER BY created_at ASC`).all(teamId, a, b, b, a, limit), markRead: (teamId, recipientId, senderId) => db.prepare('UPDATE messages SET read_at=? WHERE team_id=? AND conversation_id IS NULL AND recipient_id=? AND sender_id=? AND read_at IS NULL') .run(now(), teamId, recipientId, senderId), @@ -217,8 +221,10 @@ const messages = { db.prepare('SELECT * FROM messages WHERE team_id=? AND conversation_id IS NULL AND (sender_id=? OR recipient_id=?) ORDER BY created_at DESC LIMIT ?') .all(teamId, userId, userId, limit), // Group conversation helpers. - threadByConversation: (conversationId, limit = 300) => - db.prepare('SELECT * FROM messages WHERE conversation_id=? ORDER BY created_at ASC LIMIT ?').all(conversationId, limit), + threadByConversation: (conversationId, limit = 500) => + db.prepare(`SELECT * FROM ( + SELECT * FROM messages WHERE conversation_id=? ORDER BY created_at DESC LIMIT ? + ) ORDER BY created_at ASC`).all(conversationId, limit), lastInConversation: (conversationId) => db.prepare('SELECT * FROM messages WHERE conversation_id=? ORDER BY created_at DESC LIMIT 1').get(conversationId), unreadInConversation: (conversationId, userId, since) =>