fix(conversations): implement soft-delete for conversation deletion
The delete conversation endpoint was a no-op — it verified ownership but never actually modified the record. Users saw conversations disappear (frontend optimistic removal) but they reappeared on refresh. Changes: - conversation.entity.ts: Add DELETED status, softDelete() and isDeleted() - conversation.service.ts: Call softDelete() + update instead of no-op - conversation-postgres.repository.ts: Exclude DELETED conversations from findByUserId() queries so they don't appear in user's list Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
b75d607e2b
commit
d083008001
|
|
@ -38,7 +38,8 @@ export class ConversationPostgresRepository
|
|||
options?: { status?: ConversationStatusType; limit?: number },
|
||||
): Promise<ConversationEntity[]> {
|
||||
const queryBuilder = this.createTenantQueryBuilder('conversation')
|
||||
.andWhere('conversation.user_id = :userId', { userId });
|
||||
.andWhere('conversation.user_id = :userId', { userId })
|
||||
.andWhere('conversation.status != :deletedStatus', { deletedStatus: 'DELETED' });
|
||||
|
||||
if (options?.status) {
|
||||
queryBuilder.andWhere('conversation.status = :status', { status: options.status });
|
||||
|
|
|
|||
|
|
@ -308,11 +308,9 @@ export class ConversationService {
|
|||
* Delete a conversation and its messages
|
||||
*/
|
||||
async deleteConversation(conversationId: string, userId: string): Promise<void> {
|
||||
// Verify user owns the conversation
|
||||
await this.getConversation(conversationId, userId);
|
||||
|
||||
// Note: In a real application, you'd want to delete messages in the repository
|
||||
// For now, we rely on database cascade or separate cleanup
|
||||
const conversation = await this.getConversation(conversationId, userId);
|
||||
conversation.softDelete();
|
||||
await this.conversationRepo.update(conversation);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ export const ConversationStatus = {
|
|||
ACTIVE: 'ACTIVE',
|
||||
ENDED: 'ENDED',
|
||||
ARCHIVED: 'ARCHIVED',
|
||||
DELETED: 'DELETED',
|
||||
} as const;
|
||||
|
||||
export type ConversationStatusType =
|
||||
|
|
@ -236,6 +237,11 @@ export class ConversationEntity {
|
|||
this.updatedAt = new Date();
|
||||
}
|
||||
|
||||
softDelete(): void {
|
||||
this.status = ConversationStatus.DELETED;
|
||||
this.updatedAt = new Date();
|
||||
}
|
||||
|
||||
isActive(): boolean {
|
||||
return this.status === ConversationStatus.ACTIVE;
|
||||
}
|
||||
|
|
@ -243,4 +249,8 @@ export class ConversationEntity {
|
|||
isEnded(): boolean {
|
||||
return this.status === ConversationStatus.ENDED;
|
||||
}
|
||||
|
||||
isDeleted(): boolean {
|
||||
return this.status === ConversationStatus.DELETED;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue