Skip to content

Conversation

@leoisadev8
Copy link
Member

Summary

  • Add critical database indexes (userId on messages) and message content validation (100KB max in bytes)
  • Implement soft delete for chats and messages to enable data recovery and prevent accidental data loss
  • Properly populate userId field in messages for query optimization
  • Use byte count instead of string length for content validation
  • Prevent resurrection of soft-deleted messages through clientMessageId lookup

Changes

  • Added userId index to messages table for better query performance
  • Added message content length validation using actual byte count (100KB max)
  • Added deletedAt field to both chats and messages tables
  • Implemented soft delete with optimized cascade for messages when parent chat is deleted
  • All queries now filter out soft-deleted records
  • userId field is properly populated during message insert/update operations
  • clientMessageId lookup now checks deletedAt to prevent resurrecting deleted messages
  • Cascade delete optimized to skip already-deleted messages

Fixes

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Greptile Overview

Greptile Summary

Implements critical database improvements including soft delete for chats/messages, content validation, and performance indexes.

Key Changes:

  • Added by_user index on messages table for userId field to optimize user-scoped queries
  • Implemented byte-based content validation (100KB max) using TextEncoder for accurate size checking
  • Added soft delete functionality with deletedAt fields on both chats and messages tables
  • Properly populates userId field in all message insert/update operations
  • Prevents resurrection of soft-deleted messages through clientMessageId lookup
  • Optimized cascade delete to skip already-deleted messages
  • All queries now filter out soft-deleted records consistently

Implementation Quality:

  • Soft delete implementation is consistent across all query and mutation handlers
  • Validation uses actual byte count rather than string length, correctly handling multi-byte characters
  • Cascade delete optimization prevents redundant database operations
  • assertOwnsChat helper properly checks for soft-deleted chats

Confidence Score: 5/5

  • This PR is safe to merge with minimal risk
  • The implementation is thorough and well-executed with proper soft delete filtering in all queries, accurate byte-based validation, and optimized cascade operations. All edge cases are handled correctly, including preventing resurrection of deleted messages.
  • No files require special attention

Important Files Changed

File Analysis

Filename Score Overview
apps/server/convex/schema.ts 5/5 Added deletedAt fields to chats and messages tables, added userId field and index to messages table, documented 100KB content limit
apps/server/convex/messages.ts 5/5 Implemented byte-based content validation (100KB), soft delete filtering in queries, userId population, and prevention of deleted message resurrection via clientMessageId
apps/server/convex/chats.ts 5/5 Implemented soft delete for chats with optimized cascade to messages, filtering deleted chats in all queries and ownership checks

Sequence Diagram

sequenceDiagram
    participant Client
    participant API
    participant DB
    
    Note over Client,DB: Chat Deletion Flow with Soft Delete
    
    Client->>API: remove(chatId, userId)
    API->>DB: get(chatId)
    DB-->>API: chat
    
    alt chat exists and user owns it
        API->>DB: patch(chatId, {deletedAt: now})
        API->>DB: query messages by_chat index
        DB-->>API: messages[]
        
        loop For each non-deleted message
            API->>DB: patch(messageId, {deletedAt: now})
        end
        
        API-->>Client: {ok: true}
    else chat not found or unauthorized
        API-->>Client: {ok: false}
    end
    
    Note over Client,DB: Query Flow with Soft Delete Filtering
    
    Client->>API: list(userId)
    API->>DB: query chats by_user index
    DB-->>API: chats[]
    API->>API: filter out deletedAt != null
    API-->>Client: active chats[]
    
    Client->>API: list messages(chatId, userId)
    API->>DB: get chat
    API->>API: check !deletedAt
    API->>DB: query messages by_chat index
    DB-->>API: messages[]
    API->>API: filter out deletedAt != null
    API-->>Client: active messages[]
    
    Note over Client,DB: Message Insert with Validation
    
    Client->>API: send(chatId, content, userId)
    API->>API: validate content <= 100KB bytes
    
    alt content valid
        API->>DB: query by_client_id
        DB-->>API: existing message
        API->>API: check !deletedAt
        
        alt not deleted or not found
            API->>DB: insert/patch message with userId
            API-->>Client: {ok: true, messageId}
        else message was deleted
            API->>DB: insert new message
            API-->>Client: {ok: true, messageId}
        end
    else content too large
        API-->>Client: Error: exceeds 100KB
    end
Loading

3 files reviewed, no comments

Edit Code Review Agent Settings | Greptile

@leoisadev8 leoisadev8 merged commit 481369d into main Nov 6, 2025
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants