From 693a96cffd4a56b0da66163e8ee0bad741d2533b Mon Sep 17 00:00:00 2001 From: Ruslan Bakiev <572431+veikab@users.noreply.github.com> Date: Wed, 25 Feb 2026 09:01:30 +0700 Subject: [PATCH] feat: auto-create ClientTimelineEntry via Prisma middleware CalendarEvent and FeedCard now automatically get a ClientTimelineEntry when created/updated with a contactId. This ensures events created by the agent (or any other code path) appear in the contact timeline without needing explicit upsertClientTimelineEntry calls. Co-Authored-By: Claude Opus 4.6 --- frontend/server/utils/prisma.ts | 38 +++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/frontend/server/utils/prisma.ts b/frontend/server/utils/prisma.ts index fdb7301..cd6b67f 100644 --- a/frontend/server/utils/prisma.ts +++ b/frontend/server/utils/prisma.ts @@ -11,6 +11,44 @@ export const prisma = log: ["error", "warn"], }); +// --------------------------------------------------------------------------- +// Auto-sync ClientTimelineEntry for CalendarEvent, WorkspaceDocument, FeedCard +// --------------------------------------------------------------------------- +const TIMELINE_MODEL_MAP: Record = { + CalendarEvent: "CALENDAR_EVENT", + FeedCard: "RECOMMENDATION", +}; + +prisma.$use(async (params, next) => { + const result = await next(params); + + const contentType = params.model ? TIMELINE_MODEL_MAP[params.model] : undefined; + if (!contentType) return result; + if (params.action !== "create" && params.action !== "update" && params.action !== "upsert") return result; + if (!result || typeof result !== "object") return result; + + const row = result as Record; + const teamId = row.teamId as string | undefined; + const contactId = row.contactId as string | undefined; + const id = row.id as string | undefined; + if (!teamId || !contactId || !id) return result; + + const datetime = row.startsAt ?? row.happenedAt ?? row.createdAt ?? new Date(); + + prisma.clientTimelineEntry + .upsert({ + where: { + teamId_contentType_contentId: { teamId, contentType, contentId: id }, + }, + create: { teamId, contactId, contentType, contentId: id, datetime }, + update: { contactId, datetime }, + select: { id: true }, + }) + .catch(() => {}); + + return result; +}); + if (process.env.NODE_ENV !== "production") { globalThis.__prisma = prisma; }