feat: implement chat persistence with MongoDB
- Add full chat persistence to database (conversations and messages) - Implement MongoChatRepository with cursor-based pagination - Add getConversations/getConversation endpoints in ChatController - Save user and assistant messages in ChatService.processMessage() - Track respondedAction (confirm/reject) on proposed event messages - Load existing messages on chat screen mount - Add addMessages() bulk action and chatMessageToMessageData() helper to ChatStore - Add RespondedAction type and UpdateMessageDTO to shared types
This commit is contained in:
@@ -3,6 +3,7 @@ import {
|
||||
Conversation,
|
||||
CreateMessageDTO,
|
||||
GetMessagesOptions,
|
||||
UpdateMessageDTO,
|
||||
} from "@caldav/shared";
|
||||
import { ChatRepository } from "../../services/interfaces";
|
||||
import { ChatMessageModel, ConversationModel } from "./models";
|
||||
@@ -10,11 +11,15 @@ import { ChatMessageModel, ConversationModel } from "./models";
|
||||
export class MongoChatRepository implements ChatRepository {
|
||||
// Conversations
|
||||
async getConversationsByUser(userId: string): Promise<Conversation[]> {
|
||||
throw new Error("Not implemented");
|
||||
const conversations = await ConversationModel.find({ userId });
|
||||
return conversations.map((c) => c.toJSON() as unknown as Conversation);
|
||||
}
|
||||
|
||||
async createConversation(userId: string): Promise<Conversation> {
|
||||
throw new Error("Not implemented");
|
||||
const conversation = await ConversationModel.create({
|
||||
userId,
|
||||
});
|
||||
return conversation.toJSON() as unknown as Conversation;
|
||||
}
|
||||
|
||||
// Messages (cursor-based pagination)
|
||||
@@ -22,13 +27,44 @@ export class MongoChatRepository implements ChatRepository {
|
||||
conversationId: string,
|
||||
options?: GetMessagesOptions,
|
||||
): Promise<ChatMessage[]> {
|
||||
throw new Error("Not implemented");
|
||||
const limit = options?.limit ?? 20;
|
||||
const query: Record<string, unknown> = { conversationId };
|
||||
|
||||
// Cursor: load messages before this ID (for "load more" scrolling up)
|
||||
if (options?.before) {
|
||||
query._id = { $lt: options.before };
|
||||
}
|
||||
|
||||
// Fetch newest first, then reverse for chronological order
|
||||
const docs = await ChatMessageModel.find(query)
|
||||
.sort({ _id: -1 })
|
||||
.limit(limit);
|
||||
|
||||
return docs.reverse().map((doc) => doc.toJSON() as unknown as ChatMessage);
|
||||
}
|
||||
|
||||
async createMessage(
|
||||
conversationId: string,
|
||||
message: CreateMessageDTO,
|
||||
): Promise<ChatMessage> {
|
||||
throw new Error("Not implemented");
|
||||
const repoMessage = await ChatMessageModel.create({
|
||||
conversationId: conversationId,
|
||||
sender: message.sender,
|
||||
content: message.content,
|
||||
proposedChange: message.proposedChange,
|
||||
});
|
||||
return repoMessage.toJSON() as unknown as ChatMessage;
|
||||
}
|
||||
|
||||
async updateMessage(
|
||||
messageId: string,
|
||||
updates: UpdateMessageDTO,
|
||||
): Promise<ChatMessage | null> {
|
||||
const doc = await ChatMessageModel.findByIdAndUpdate(
|
||||
messageId,
|
||||
{ $set: updates },
|
||||
{ new: true },
|
||||
);
|
||||
return doc ? (doc.toJSON() as unknown as ChatMessage) : null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,6 +80,10 @@ const ChatMessageSchema = new Schema<
|
||||
proposedChange: {
|
||||
type: ProposedChangeSchema,
|
||||
},
|
||||
respondedAction: {
|
||||
type: String,
|
||||
enum: ["confirm", "reject"],
|
||||
},
|
||||
},
|
||||
{
|
||||
timestamps: true,
|
||||
|
||||
Reference in New Issue
Block a user