/opt/mawid/apps/api/src/conversations
Edit: /opt/mawid/apps/api/src/conversations/conversations.service.ts (2448B)
import { Injectable, NotFoundException } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
@Injectable()
export class ConversationsService {
constructor(private readonly prisma: PrismaService) {}
async list(clinicId: string) {
const conversations = await this.prisma.conversation.findMany({
where: { clinicId },
include: {
patient: { select: { id: true, name: true, waPhone: true, language: true } },
messages: { orderBy: { createdAt: 'desc' }, take: 1 },
},
orderBy: { lastMessageAt: { sort: 'desc', nulls: 'last' } },
take: 100,
});
return conversations.map((c) => ({
id: c.id,
patient: c.patient,
lastMessageAt: c.lastMessageAt,
lastMessage: c.messages[0]?.body ?? null,
handedOff: Boolean((c.state as { handedOff?: boolean })?.handedOff),
handoffReason: (c.state as { handoffReason?: string })?.handoffReason ?? null,
}));
}
async messages(clinicId: string, id: string) {
await this.assertExists(clinicId, id);
return this.prisma.message.findMany({
where: { conversationId: id },
orderBy: { createdAt: 'asc' },
take: 500,
select: { id: true, direction: true, type: true, body: true, createdAt: true },
});
}
/** "Take over" pauses the agent for this conversation (Phase 6 page 3). */
async setTakeover(clinicId: string, id: string, takeover: boolean, actor: string) {
const conversation = await this.assertExists(clinicId, id);
const state = (conversation.state ?? {}) as Record
;
const nextState = takeover
? { ...state, handedOff: true, handoffReason: 'owner_takeover' }
: { ...state, handedOff: false, handoffReason: undefined, agentTurnsMs: [] };
await this.prisma.conversation.update({
where: { id },
data: { state: JSON.parse(JSON.stringify(nextState)) },
});
await this.prisma.auditLog.create({
data: {
clinicId,
actor,
action: takeover ? 'conversation:takeover' : 'conversation:resume_agent',
meta: { conversationId: id },
},
});
return { id, handedOff: takeover };
}
private async assertExists(clinicId: string, id: string) {
const conversation = await this.prisma.conversation.findFirst({ where: { id, clinicId } });
if (!conversation) throw new NotFoundException('Conversation not found');
return conversation;
}
}