Skip to content

feat(chat): persist messages to database using Supabase #1831

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 3, 2025

Conversation

hoshinotsuyoshi
Copy link
Member

@hoshinotsuyoshi hoshinotsuyoshi commented May 30, 2025

Screenshots

Now each messages are persisted in messages table.

messages:
1

db:
2

Why is this change needed?

want to save the chat messages.

  • Messages are now saved to and loaded from the messages table, ensuring session history is preserved
  • Introduced designSessionId prop to Chat and SessionDetailPage components
  • Added saveMessage, loadMessages, and updateMessage service methods (client-side)
  • Implemented loading indicator while fetching past messages
  • Synced user and assistant messages with Supabase during chat flow
  • Improved error handling for persistence-related failures

What would you like reviewers to focus on?

Testing Verification

What was done

🤖 Generated by PR Agent at 9e8dd21

  • Persist chat messages to Supabase messages table
    • Added client-side message save and load logic
    • Messages are loaded on chat mount and saved on send/receive
  • Introduced designSessionId prop to Chat and SessionDetailPage
    • Enables session-specific message history
  • Improved chat UI to show loading indicator while fetching messages
  • Enhanced error handling for persistence operations

Detailed Changes

Relevant files
Enhancement
messageServiceClient.ts
Add Supabase message persistence client and utilities       

frontend/apps/app/components/Chat/services/messageServiceClient.ts

  • Added client-side service for message persistence via Supabase
  • Implemented saveMessage, loadMessages, and getCurrentUserId functions
  • Provided message-to-chat-entry conversion utility
  • Included schema validation for message operations
  • +126/-0 
    index.ts
    Export message service client functions                                   

    frontend/apps/app/components/Chat/services/index.ts

    • Exported all message service client functions for use in Chat
    +1/-0     
    Chat.tsx
    Integrate Supabase message persistence into Chat component

    frontend/apps/app/components/Chat/Chat.tsx

  • Integrated message loading and saving with Supabase
  • Added designSessionId prop for session-specific chat history
  • Loaded messages on mount and saved user/assistant messages
  • Displayed loading indicator while fetching messages
  • Updated chat state to sync with database IDs
  • +107/-24
    SessionDetailPage.tsx
    Pass designSessionId to Chat for session context                 

    frontend/apps/app/components/SessionDetailPage/SessionDetailPage.tsx

  • Added designSessionId prop and passed it to Chat
  • Updated component signature and usage accordingly
  • +11/-2   
    page.tsx
    Provide designSessionId to session detail page                     

    frontend/apps/app/app/(app)/app/(with-project-and-branch)/projects/[projectId]/sessions/[id]/page.tsx

    • Passed session ID as designSessionId prop to SessionDetailPage
    +1/-0     

    Additional Notes


    Need help?
  • Type /help how to ... in the comments thread for any questions about Qodo Merge usage.
  • Check out the documentation for more information.
  • @hoshinotsuyoshi hoshinotsuyoshi self-assigned this May 30, 2025
    Copy link

    changeset-bot bot commented May 30, 2025

    ⚠️ No Changeset found

    Latest commit: 9e8dd21

    Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

    This PR includes no changesets

    When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

    Click here to learn what changesets are, and how to add one.

    Click here if you're a maintainer who wants to add a changeset to this PR

    Copy link

    vercel bot commented May 30, 2025

    The latest updates on your projects. Learn more about Vercel for Git ↗︎

    Name Status Preview Comments Updated (UTC)
    liam-app ✅ Ready (Inspect) Visit Preview 💬 Add feedback May 30, 2025 0:21am
    liam-erd-sample ✅ Ready (Inspect) Visit Preview 💬 Add feedback May 30, 2025 0:21am
    liam-storybook ✅ Ready (Inspect) Visit Preview 💬 Add feedback May 30, 2025 0:21am
    1 Skipped Deployment
    Name Status Preview Comments Updated (UTC)
    liam-docs ⬜️ Ignored (Inspect) Visit Preview May 30, 2025 0:21am

    Copy link

    supabase bot commented May 30, 2025

    Updates to Preview Branch (sessions-new-page-save-messages) ↗︎

    Deployments Status Updated
    Database Fri, 30 May 2025 11:53:37 UTC
    Services Fri, 30 May 2025 11:53:37 UTC
    APIs Fri, 30 May 2025 11:53:37 UTC

    Tasks are run on every commit but only new migration files are pushed.
    Close and reopen this PR if you want to apply changes from existing seed or migration files.

    Tasks Status Updated
    Configurations Fri, 30 May 2025 11:53:43 UTC
    Migrations Fri, 30 May 2025 11:53:46 UTC
    Seeding Fri, 30 May 2025 11:53:46 UTC
    Edge Functions Fri, 30 May 2025 11:53:46 UTC

    View logs for this Workflow Run ↗︎.
    Learn more about Supabase for Git ↗︎.

    - Implemented saving and loading chat messages using the `messages` table
    - Introduced `designSessionId` prop to both `Chat` and `SessionDetailPage` components
    - Added `saveMessage`, `loadMessages`, and `getCurrentUserId` functions on the client side
    - Chat history is now preserved across sessions and synced with Supabase
    Copy link
    Contributor

    PR Reviewer Guide 🔍

    Here are some key observations to aid the review process:

    ⏱️ Estimated effort to review: 3 🔵🔵🔵⚪⚪
    🧪 No relevant tests
    🔒 No security concerns identified
    ⚡ Recommended focus areas for review

    Error Handling

    The loadMessages function returns empty messages array on error but saveMessage doesn't provide a consistent return value. Consider standardizing error handling across all service functions.

      console.error('Failed to load messages:', error)
      return { success: false, error: error.message }
    }
    
    return { success: true, messages: messages || [] }
    Race Condition

    There's a potential race condition when saving messages to the database and updating the UI. If multiple messages are sent quickly, the database IDs might not be correctly associated with the right messages.

    // Save user message to database
    if (designSessionId) {
      const saveResult = await saveMessage({
        designSessionId,
        content,
        role: 'user',
        userId,
      })
      if (saveResult.success && saveResult.message) {
        // Update the message with the database ID
        setMessages((prev) =>
          prev.map((msg) =>
            msg.id === userMessage.id
              ? { ...msg, dbId: saveResult.message?.id }
              : msg,
          ),
        )
      }
    }
    
    Error Handling

    The code doesn't handle database save failures gracefully. If saving a message fails, the UI continues as if it succeeded, which could lead to inconsistencies between the UI and database state.

    if (designSessionId) {
      const saveResult = await saveMessage({
        designSessionId,
        content: accumulatedContent,
        role: 'assistant',
        userId: null,
      })
      if (saveResult.success && saveResult.message) {
        aiDbId = saveResult.message.id
      }
    }
    

    Copy link
    Contributor

    PR Code Suggestions ✨

    Explore these optional code suggestions:

    CategorySuggestion                                                                                                                                    Impact
    Possible issue
    Fix auto-scrolling in chat

    The scroll effect only runs once on component mount but not when messages
    change. Update the dependency array to include the messages state variable to
    ensure the chat scrolls to the bottom whenever new messages are added.

    frontend/apps/app/components/Chat/Chat.tsx [90-93]

     // Scroll to bottom when component mounts or messages change
     useEffect(() => {
       messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' })
    -}, [])
    +}, [messages])
    • Apply / Chat
    Suggestion importance[1-10]: 8

    __

    Why: The comment indicates the effect should run when messages change, but the empty dependency array means it only runs on mount. This prevents auto-scrolling when new messages are added, which is a significant UX issue.

    Medium
    Validate required field exists

    The error handling only checks if the design session exists but doesn't validate
    if it has an organization_id. Add validation to ensure organization_id exists
    before using it to prevent potential null reference errors.

    frontend/apps/app/components/Chat/services/messageServiceClient.ts [36-46]

     // Get organization_id from design_session
     const { data: designSession, error: sessionError } = await supabase
       .from('design_sessions')
       .select('organization_id')
       .eq('id', designSessionId)
       .single()
     
     if (sessionError || !designSession) {
       console.error('Failed to get design session:', sessionError)
       return { success: false, error: 'Design session not found' }
     }
     
    +if (!designSession.organization_id) {
    +  console.error('Design session has no organization ID')
    +  return { success: false, error: 'Invalid design session: missing organization ID' }
    +}
    +
    • Apply / Chat
    Suggestion importance[1-10]: 6

    __

    Why: Adding validation for organization_id existence is good defensive programming. If the database contains null values, it could cause issues when inserting the message data.

    Low
    Learned
    best practice
    Add unmount cleanup function

    Add a cleanup function to the useEffect hook to prevent state updates if the
    component unmounts during the async operation. This prevents memory leaks and
    React warnings about updating state on unmounted components.

    frontend/apps/app/components/Chat/Chat.tsx [69-88]

     // Load existing messages on component mount
     useEffect(() => {
       if (!designSessionId) {
         return
       }
    +  let isMounted = true;
       const loadExistingMessages = async () => {
         const result = await loadMessages({ designSessionId })
    -    if (result.success && result.messages) {
    +    if (isMounted && result.success && result.messages) {
           const chatEntries = result.messages.map((msg) => ({
             ...convertMessageToChatEntry(msg),
             dbId: msg.id,
           }))
           // Keep the welcome message and add loaded messages
           setMessages((prev) => [prev[0], ...chatEntries])
         }
    -    setIsLoadingMessages(false)
    +    if (isMounted) {
    +      setIsLoadingMessages(false)
    +    }
       }
     
       loadExistingMessages()
    +  return () => {
    +    isMounted = false;
    +  };
     }, [designSessionId])

    [To ensure code accuracy, apply this suggestion manually]

    Suggestion importance[1-10]: 6

    __

    Why:
    Relevant best practice - Prevent state updates on unmounted components by using cleanup functions in useEffect hooks to avoid memory leaks and React warnings.

    Low
    • More

    Copy link
    Member

    @FunamaYukina FunamaYukina left a comment

    Choose a reason for hiding this comment

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

    I made one comment, LGTM! Thank you.✨

    Base automatically changed from sessions-new-page to main June 3, 2025 00:32
    @hoshinotsuyoshi hoshinotsuyoshi added this pull request to the merge queue Jun 3, 2025
    Merged via the queue into main with commit a5df4a2 Jun 3, 2025
    22 checks passed
    @hoshinotsuyoshi hoshinotsuyoshi deleted the sessions-new-page-save-messages branch June 3, 2025 00:38
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Projects
    None yet
    Development

    Successfully merging this pull request may close these issues.

    2 participants