diff --git a/apps/api/src/app.ts b/apps/api/src/app.ts index 46f448a..42e86ee 100644 --- a/apps/api/src/app.ts +++ b/apps/api/src/app.ts @@ -831,6 +831,53 @@ export async function createApp( })(); } + + // Data export endpoint — user downloads all their data as JSON + app.get("/api/data/export", async (c) => { + const session = await auth.api.getSession({ headers: sessionHeaders(c.req.raw) }); + if (!session?.user) return c.json({ error: "Unauthorized" }, 401); + + const userId = session.user.id; + + const user = await prisma.user.findUnique({ + where: { id: userId }, + select: { id: true, name: true, email: true, emailVerified: true, createdAt: true, updatedAt: true }, + }); + + const bots = await prisma.bot.findMany({ + where: { userId }, + select: { id: true, name: true, createdAt: true, archivedAt: true }, + }); + + const botIds = bots.map((b) => b.id); + const runs = await prisma.run.findMany({ + where: { botId: { in: botIds } }, + select: { id: true, status: true, createdAt: true, updatedAt: true }, + }); + + const consents = await prisma.aiDataConsent.findMany({ + where: { userId }, + select: { recipientKey: true, version: true, grantedAt: true }, + }); + + const exportData = { + exportedAt: new Date().toISOString(), + user, + bots, + runs, + aiDataConsents: consents, + note: "Alle Daten werden lokal auf Ihrem Server gespeichert. Keine externen Dienste.", + }; + + const json = JSON.stringify(exportData, null, 2); + const filename = `evo-data-export-${new Date().toISOString().split("T")[0]}.json`; + + return c.newResponse(json, 200, { + "Content-Type": "application/json", + "Content-Disposition": `attachment; filename="${filename}"`, + }); + }); + app.get("/health", (c) => c.json({ ok: true,