arcadia-suite-sv/server/graph/routes.ts

214 lines
7.8 KiB
TypeScript

import { Router, Request, Response } from "express";
import { insertGraphNodeSchema, insertGraphEdgeSchema, insertKnowledgeBaseSchema } from "@shared/schema";
import * as graphService from "./service";
const router = Router();
// Middleware de autenticação
router.use((req: Request, res: Response, next) => {
if (!req.isAuthenticated()) {
return res.status(401).json({ error: "Não autenticado" });
}
next();
});
const tenantId = (req: Request): number | undefined =>
(req.user as any)?.tenantId ?? undefined;
// ─── Nodes ────────────────────────────────────────────────────────────────────
router.get("/nodes", async (req: Request, res: Response) => {
try {
const type = req.query.type as string | undefined;
const limit = req.query.limit ? parseInt(req.query.limit as string) : 100;
const nodes = await graphService.getNodes(tenantId(req), type, limit);
res.json(nodes);
} catch (error: any) {
res.status(500).json({ error: error.message });
}
});
router.get("/nodes/:id", async (req: Request, res: Response) => {
try {
const node = await graphService.getNodeById(parseInt(req.params.id));
if (!node) return res.status(404).json({ error: "Nó não encontrado" });
res.json(node);
} catch (error: any) {
res.status(500).json({ error: error.message });
}
});
router.post("/nodes", async (req: Request, res: Response) => {
try {
const parsed = insertGraphNodeSchema.safeParse({
...req.body,
tenantId: tenantId(req),
});
if (!parsed.success) {
return res.status(400).json({ error: parsed.error.flatten() });
}
const node = await graphService.createNode(parsed.data);
res.status(201).json(node);
} catch (error: any) {
res.status(500).json({ error: error.message });
}
});
router.put("/nodes/:id", async (req: Request, res: Response) => {
try {
const node = await graphService.updateNode(parseInt(req.params.id), req.body);
if (!node) return res.status(404).json({ error: "Nó não encontrado" });
res.json(node);
} catch (error: any) {
res.status(500).json({ error: error.message });
}
});
router.delete("/nodes/:id", async (req: Request, res: Response) => {
try {
const deleted = await graphService.deleteNode(parseInt(req.params.id));
if (!deleted) return res.status(404).json({ error: "Nó não encontrado" });
res.json({ success: true });
} catch (error: any) {
res.status(500).json({ error: error.message });
}
});
// ─── Batch de Nodes ───────────────────────────────────────────────────────────
router.post("/nodes/batch", async (req: Request, res: Response) => {
try {
const { nodes } = req.body as { nodes: any[] };
if (!Array.isArray(nodes)) {
return res.status(400).json({ error: "Campo 'nodes' deve ser um array" });
}
const created = await Promise.all(
nodes.map((n) =>
graphService.createNode({ ...n, tenantId: tenantId(req) })
)
);
res.status(201).json(created);
} catch (error: any) {
res.status(500).json({ error: error.message });
}
});
// ─── Edges ────────────────────────────────────────────────────────────────────
router.get("/edges", async (req: Request, res: Response) => {
try {
const sourceId = req.query.sourceId ? parseInt(req.query.sourceId as string) : undefined;
const targetId = req.query.targetId ? parseInt(req.query.targetId as string) : undefined;
const edges = await graphService.getEdges(sourceId, targetId);
res.json(edges);
} catch (error: any) {
res.status(500).json({ error: error.message });
}
});
router.post("/edges", async (req: Request, res: Response) => {
try {
const parsed = insertGraphEdgeSchema.safeParse(req.body);
if (!parsed.success) {
return res.status(400).json({ error: parsed.error.flatten() });
}
const edge = await graphService.createEdge(parsed.data);
res.status(201).json(edge);
} catch (error: any) {
res.status(500).json({ error: error.message });
}
});
router.delete("/edges/:id", async (req: Request, res: Response) => {
try {
const deleted = await graphService.deleteEdge(parseInt(req.params.id));
if (!deleted) return res.status(404).json({ error: "Aresta não encontrada" });
res.json({ success: true });
} catch (error: any) {
res.status(500).json({ error: error.message });
}
});
// ─── Knowledge Base ───────────────────────────────────────────────────────────
router.get("/knowledge", async (req: Request, res: Response) => {
try {
const category = req.query.category as string | undefined;
const search = req.query.search as string | undefined;
const entries = await graphService.getKnowledgeEntries(category, search);
res.json(entries);
} catch (error: any) {
res.status(500).json({ error: error.message });
}
});
router.get("/knowledge/:id", async (req: Request, res: Response) => {
try {
const entry = await graphService.getKnowledgeEntry(parseInt(req.params.id));
if (!entry) return res.status(404).json({ error: "Entrada não encontrada" });
res.json(entry);
} catch (error: any) {
res.status(500).json({ error: error.message });
}
});
router.post("/knowledge", async (req: Request, res: Response) => {
try {
const parsed = insertKnowledgeBaseSchema.safeParse(req.body);
if (!parsed.success) {
return res.status(400).json({ error: parsed.error.flatten() });
}
const entry = await graphService.createKnowledgeEntry(parsed.data);
res.status(201).json(entry);
} catch (error: any) {
res.status(500).json({ error: error.message });
}
});
router.put("/knowledge/:id", async (req: Request, res: Response) => {
try {
const entry = await graphService.updateKnowledgeEntry(parseInt(req.params.id), req.body);
if (!entry) return res.status(404).json({ error: "Entrada não encontrada" });
res.json(entry);
} catch (error: any) {
res.status(500).json({ error: error.message });
}
});
router.delete("/knowledge/:id", async (req: Request, res: Response) => {
try {
const deleted = await graphService.deleteKnowledgeEntry(parseInt(req.params.id));
if (!deleted) return res.status(404).json({ error: "Entrada não encontrada" });
res.json({ success: true });
} catch (error: any) {
res.status(500).json({ error: error.message });
}
});
// ─── Busca Semântica ──────────────────────────────────────────────────────────
router.post("/search", async (req: Request, res: Response) => {
try {
const { query, n_results = 5 } = req.body as { query: string; n_results?: number };
if (!query) return res.status(400).json({ error: "Campo 'query' é obrigatório" });
const result = await graphService.semanticSearch(query, n_results);
res.json(result);
} catch (error: any) {
res.status(500).json({ error: error.message });
}
});
// ─── Grafo completo para visualização ────────────────────────────────────────
router.get("/visualization", async (req: Request, res: Response) => {
try {
const data = await graphService.getGraphData(tenantId(req));
res.json(data);
} catch (error: any) {
res.status(500).json({ error: error.message });
}
});
export default router;