/** * GET /api/profile/me/sos-insights * * Aggregierte SOS-Stats der letzten 30 Tage für Profile-Page-LyraInsightsCard * (project_profile_page_design.md §4). * * Source: rebreak.sos_sessions (existiert, schema.prisma `model SosSession`) * * Heuristik für `helpedBy`: * - breathing: SUM(breathing_count > 0 ? 1 : 0) → anzahl sessions mit min. 1 Atemübung * - game: SUM(jsonb_array_length(games_played) > 0) * - talk: SUM(messages.length > 4) → mehr als 2 user-message-cycles * * Response shape (siehe PROFILE_PAGE_DESIGN.md): * { * last30Days: { sessions, overcome, overcomeRate }, * helpedBy: { breathing, game, talk, other }, * topEmotion: string | null, * topEmotionFromUrgeLogs: boolean, * } * * Empty-State: { sessions: 0, ...everything: 0, topEmotion: null } * → Frontend rendert "noch keine SOS-Session"-EmptyState. */ import { requireUser } from "../../../utils/auth"; import { usePrisma } from "../../../utils/prisma"; const WINDOW_DAYS = 30; type Helper = "breathing" | "game" | "talk" | "other"; export default defineEventHandler(async (event) => { const user = await requireUser(event); const db = usePrisma(); const since = new Date(Date.now() - WINDOW_DAYS * 24 * 60 * 60 * 1000); const sessions = await db.sosSession.findMany({ where: { userId: user.id, startedAt: { gte: since } }, select: { breathingCount: true, gamesPlayed: true, messages: true, wasOvercome: true, }, }); let overcome = 0; const helpedBy: Record = { breathing: 0, game: 0, talk: 0, other: 0, }; for (const s of sessions) { if (s.wasOvercome) overcome++; let countedHelper = false; if (s.breathingCount > 0) { helpedBy.breathing++; countedHelper = true; } const games = Array.isArray(s.gamesPlayed) ? s.gamesPlayed : []; if (games.length > 0) { helpedBy.game++; countedHelper = true; } const msgs = Array.isArray(s.messages) ? s.messages : []; if (msgs.length > 4) { helpedBy.talk++; countedHelper = true; } if (!countedHelper) helpedBy.other++; } // topEmotion via urge_logs (letzte 30 Tage) — most-frequent emotion let topEmotion: string | null = null; try { const grouped = await db.urgeLog.groupBy({ by: ["emotion"], where: { userId: user.id, timestamp: { gte: since } }, _count: { emotion: true }, orderBy: { _count: { emotion: "desc" } }, take: 1, }); topEmotion = grouped[0]?.emotion ?? null; } catch (e) { // urge_logs query may fail on edge schemas — non-fatal console.error("[sos-insights] urge_logs query failed (non-fatal):", e); } const sessionsCount = sessions.length; const overcomeRate = sessionsCount > 0 ? Math.round((overcome / sessionsCount) * 100) / 100 : 0; return { success: true, data: { last30Days: { sessions: sessionsCount, overcome, overcomeRate, }, helpedBy, topEmotion, windowDays: WINDOW_DAYS, }, }; });