edtech / apps /api /src /services /kb-service.ts
CognxSafeTrack
feat: backlog P0→P3 — toast system, payments, tenant isolation, feedback handler, i18n parity
6dd9bad
import { prisma } from './prisma';
import { whatsappQueue } from './queue';
export class KBService {
static async uploadAndIndex(organizationId: string, fileBuffer: Buffer, filename: string, mimeType: string) {
const { uploadFile } = await import('./storage');
const publicUrl = await uploadFile(fileBuffer, filename, mimeType, organizationId);
await prisma.organization.update({
where: { id: organizationId },
data: { knowledgeBaseUrl: publicUrl }
});
await whatsappQueue.add('process-kb', { organizationId, url: publicUrl });
const chunkCount = await prisma.knowledgeBaseEntry.count({ where: { organizationId } });
return { publicUrl, chunkCount };
}
static async getStats(organizationId: string) {
const [chunkCount, org] = await Promise.all([
prisma.knowledgeBaseEntry.count({ where: { organizationId } }),
prisma.organization.findUnique({ where: { id: organizationId }, select: { knowledgeBaseUrl: true } })
]);
return { chunkCount, hasKnowledgeBase: !!org?.knowledgeBaseUrl, knowledgeBaseUrl: org?.knowledgeBaseUrl };
}
static async listChunks(organizationId: string, page: number, limit: number) {
const skip = (page - 1) * limit;
const [entries, total] = await Promise.all([
prisma.knowledgeBaseEntry.findMany({
where: { organizationId },
orderBy: { createdAt: 'desc' },
skip,
take: limit,
select: { id: true, content: true, metadata: true, createdAt: true }
}),
prisma.knowledgeBaseEntry.count({ where: { organizationId } })
]);
return { entries, total, page, limit };
}
static async deleteChunk(organizationId: string, entryId: string) {
const entry = await prisma.knowledgeBaseEntry.findFirst({ where: { id: entryId, organizationId } });
if (!entry) return false;
await prisma.knowledgeBaseEntry.delete({ where: { id: entryId } });
return true;
}
}