arcadiasuite/server/skills/routes.ts

118 lines
4.8 KiB
TypeScript

// server/skills/routes.ts
// CRUD + execução + histórico de skills
import { Router } from "express";
import { db } from "../../db";
import { skills, skillExecutions } from "../../shared/schema";
import { eq, and, desc } from "drizzle-orm";
import { insertSkillSchema } from "../../shared/schema";
import { skillEngine } from "./engine";
const router = Router();
// ── Listar skills do tenant ────────────────────────────────────────────────
router.get("/", async (req, res) => {
try {
const tenantId = (req as any).tenantId as number | undefined;
const where = tenantId ? eq(skills.tenantId, tenantId) : undefined;
const rows = await db.select().from(skills).where(where).orderBy(desc(skills.createdAt));
res.json(rows);
} catch (err) {
res.status(500).json({ error: "Erro ao listar skills" });
}
});
// ── Buscar skill por id ────────────────────────────────────────────────────
router.get("/:id", async (req, res) => {
try {
const [skill] = await db.select().from(skills).where(eq(skills.id, req.params.id)).limit(1);
if (!skill) return res.status(404).json({ error: "Skill não encontrada" });
res.json(skill);
} catch (err) {
res.status(500).json({ error: "Erro ao buscar skill" });
}
});
// ── Criar skill ────────────────────────────────────────────────────────────
router.post("/", async (req, res) => {
try {
const tenantId = (req as any).tenantId as number | undefined;
const parsed = insertSkillSchema.safeParse({ ...req.body, tenantId });
if (!parsed.success) return res.status(400).json({ error: parsed.error.flatten() });
const [skill] = await db.insert(skills).values(parsed.data).returning();
res.status(201).json(skill);
} catch (err: any) {
if (err?.code === "23505") return res.status(409).json({ error: "Slug já existe neste tenant" });
res.status(500).json({ error: "Erro ao criar skill" });
}
});
// ── Atualizar skill ────────────────────────────────────────────────────────
router.put("/:id", async (req, res) => {
try {
const [skill] = await db.update(skills)
.set({ ...req.body, updatedAt: new Date() })
.where(eq(skills.id, req.params.id))
.returning();
if (!skill) return res.status(404).json({ error: "Skill não encontrada" });
res.json(skill);
} catch (err) {
res.status(500).json({ error: "Erro ao atualizar skill" });
}
});
// ── Deletar (arquivar) skill ───────────────────────────────────────────────
router.delete("/:id", async (req, res) => {
try {
await db.update(skills)
.set({ status: "archived", updatedAt: new Date() })
.where(eq(skills.id, req.params.id));
res.json({ ok: true });
} catch (err) {
res.status(500).json({ error: "Erro ao arquivar skill" });
}
});
// ── Executar skill ─────────────────────────────────────────────────────────
router.post("/:id/execute", async (req, res) => {
try {
const [skill] = await db.select().from(skills).where(eq(skills.id, req.params.id)).limit(1);
if (!skill) return res.status(404).json({ error: "Skill não encontrada" });
const tenantId = (req as any).tenantId as number | undefined;
const userId = (req as any).user?.id as string | undefined;
const result = await skillEngine.execute(skill.slug, {
parameters: req.body.parameters ?? {},
triggeredBy: "manual",
triggeredByUserId: userId,
ctx: { tenantId, userId },
});
res.json(result);
} catch (err) {
res.status(500).json({ error: "Erro ao executar skill" });
}
});
// ── Histórico de execuções ─────────────────────────────────────────────────
router.get("/:id/executions", async (req, res) => {
try {
const limit = Math.min(Number(req.query.limit ?? 50), 200);
const rows = await db.select().from(skillExecutions)
.where(eq(skillExecutions.skillId, req.params.id))
.orderBy(desc(skillExecutions.startedAt))
.limit(limit);
res.json(rows);
} catch (err) {
res.status(500).json({ error: "Erro ao buscar histórico" });
}
});
export default router;
export function registerSkillRoutes(app: any): void {
app.use("/api/skills", router);
}