JUNOHUB-test/src/app/api/stores/[storeId]/knowledge-template/route.ts
Saad Mohsin 80b53535c1 yes
2026-04-12 04:15:11 +05:00

214 lines
7.8 KiB
TypeScript

import { NextResponse } from "next/server"
import { auth } from "@/auth"
import { prisma } from "@/lib/prisma"
import { logger } from "@/lib/logger"
import {
knowledgeTemplatePutSchema,
mergeTemplateAnswers,
parseKnowledgeTemplateJson,
type KnowledgeTemplateStored,
} from "@/lib/kb/knowledgeTemplate"
import { replaceStructuredKnowledgeChunksForStore } from "@/lib/kb/structuredTemplateChunks"
import {
deleteDocumentKbForStore,
deleteFaqKbForStore,
deleteStructuredKbForStore,
} from "@/lib/kb/storeKbCleanup"
import { Prisma, type KnowledgeBaseMode } from "@prisma/client"
export async function GET(
_request: Request,
{ params }: { params: Promise<{ storeId: string }> },
) {
try {
const session = await auth()
if (!session?.user?.id) {
return NextResponse.json({ message: "Unauthorized" }, { status: 401 })
}
const { storeId } = await params
const store = await prisma.store.findFirst({
where: { id: storeId, userId: session.user.id },
select: {
id: true,
knowledgeBaseMode: true,
knowledgeTemplate: true,
},
})
if (!store) {
return NextResponse.json({ message: "Store not found" }, { status: 404 })
}
const [documentCount, faqCount, structuredChunkCount] = await Promise.all([
prisma.knowledgeDocument.count({ where: { storeId: store.id } }),
prisma.faqItem.count({ where: { storeId: store.id } }),
prisma.knowledgeChunk.count({
where: { storeId: store.id, sourceType: "STRUCTURED" },
}),
])
const normalizedTemplate = parseKnowledgeTemplateJson(store.knowledgeTemplate)
return NextResponse.json({
knowledgeBaseMode: store.knowledgeBaseMode,
knowledgeTemplate: normalizedTemplate ?? store.knowledgeTemplate,
counts: {
documents: documentCount,
faqs: faqCount,
structuredChunks: structuredChunkCount,
},
})
} catch (error) {
logger.error("GET knowledge-template error", error)
return NextResponse.json(
{ message: "Failed to load knowledge template" },
{ status: 500 },
)
}
}
export async function PUT(
request: Request,
{ params }: { params: Promise<{ storeId: string }> },
) {
try {
const session = await auth()
if (!session?.user?.id) {
return NextResponse.json({ message: "Unauthorized" }, { status: 401 })
}
const { storeId } = await params
let store = await prisma.store.findFirst({
where: { id: storeId, userId: session.user.id },
})
if (!store) {
return NextResponse.json({ message: "Store not found" }, { status: 404 })
}
const json = await request.json().catch(() => null)
const parsed = knowledgeTemplatePutSchema.safeParse(json)
if (!parsed.success) {
return NextResponse.json(
{ message: "Invalid body", issues: parsed.error.flatten() },
{ status: 400 },
)
}
const body = parsed.data
const confirm = body.confirmDestructiveSwitch === true
const docCount = await prisma.knowledgeDocument.count({
where: { storeId: store.id },
})
const faqCount = await prisma.faqItem.count({ where: { storeId: store.id } })
const structuredCount = await prisma.knowledgeChunk.count({
where: { storeId: store.id, sourceType: "STRUCTURED" },
})
const hasTemplateJson = store.knowledgeTemplate != null
if (body.knowledgeBaseMode !== undefined) {
const target = body.knowledgeBaseMode as KnowledgeBaseMode
if (target !== store.knowledgeBaseMode) {
if (target === "STRUCTURED") {
const destructive = docCount > 0 || faqCount > 0
if (destructive && !confirm) {
return NextResponse.json(
{
message:
"Switching to structured knowledge will remove uploaded documents and FAQs. Send confirmDestructiveSwitch: true to proceed.",
code: "CONFIRM_REQUIRED",
},
{ status: 400 },
)
}
if (destructive) {
await deleteDocumentKbForStore(prisma, store.id)
await deleteFaqKbForStore(prisma, store.id)
}
await prisma.store.update({
where: { id: store.id },
data: { knowledgeBaseMode: "STRUCTURED" },
})
} else if (target === "DOCUMENTS") {
const destructive = structuredCount > 0 || hasTemplateJson
if (destructive && !confirm) {
return NextResponse.json(
{
message:
"Switching to document-based knowledge will remove your structured profile and its embeddings. Send confirmDestructiveSwitch: true to proceed.",
code: "CONFIRM_REQUIRED",
},
{ status: 400 },
)
}
await deleteStructuredKbForStore(prisma, store.id)
await prisma.store.update({
where: { id: store.id },
data: {
knowledgeBaseMode: "DOCUMENTS",
knowledgeTemplate: Prisma.JsonNull,
},
})
}
}
}
store = await prisma.store.findFirstOrThrow({
where: { id: store.id, userId: session.user.id },
})
if (body.template !== undefined) {
if (store.knowledgeBaseMode === "DOCUMENTS") {
return NextResponse.json(
{
message:
"This store uses document-based knowledge. Switch to structured knowledge before editing the template.",
},
{ status: 409 },
)
}
const prev = parseKnowledgeTemplateJson(store.knowledgeTemplate)
const stored: KnowledgeTemplateStored = mergeTemplateAnswers(
prev,
body.template.answers as Record<string, string> | undefined,
)
const nextMode: KnowledgeBaseMode =
store.knowledgeBaseMode === "UNSET" ? "STRUCTURED" : store.knowledgeBaseMode
await prisma.store.update({
where: { id: store.id },
data: {
knowledgeBaseMode: nextMode,
knowledgeTemplate: stored as object,
},
})
await replaceStructuredKnowledgeChunksForStore(store.id)
}
const refreshed = await prisma.store.findFirst({
where: { id: store.id },
select: {
knowledgeBaseMode: true,
knowledgeTemplate: true,
},
})
return NextResponse.json({
success: true,
knowledgeBaseMode: refreshed?.knowledgeBaseMode,
knowledgeTemplate: parseKnowledgeTemplateJson(refreshed?.knowledgeTemplate),
})
} catch (error) {
logger.error("PUT knowledge-template error", error)
return NextResponse.json(
{ message: "Failed to save knowledge template" },
{ status: 500 },
)
}
}