feat(api): add /api/data/export endpoint for user data portability
feat(web): add DataTrustPanel to Shell sidebar showing local data status - 3 trust indicators: verschlüsselt, lokal gespeichert, kein Tracking - Responsive: hidden on small screens, visible on xl+ - Green checkmark with detail text for each trust point
This commit is contained in:
parent
308434a5f2
commit
89a932cdd5
@ -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) =>
|
app.get("/health", (c) =>
|
||||||
c.json({
|
c.json({
|
||||||
ok: true,
|
ok: true,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user