import { desc, eq } from 'drizzle-orm'; import { campaign, leadHandover, deal, area } from '@cockpit/db'; import { CampaignSchemas } from '@cockpit/shared'; import { router, protectedProcedure } from '../trpc.js'; const MARKETING_AREA_SLUG = 'marketing'; export const campaignRouter = router({ list: protectedProcedure.query(async ({ ctx }) => { return ctx.db.select().from(campaign).orderBy(desc(campaign.createdAt)); }), create: protectedProcedure .input(CampaignSchemas.createCampaignInput) .mutation(async ({ ctx, input }) => { const a = ( await ctx.db.select().from(area).where(eq(area.slug, MARKETING_AREA_SLUG)).limit(1) )[0]; if (!a) throw new Error('Marketing-Area fehlt — bitte seed laufen lassen.'); const [created] = await ctx.db .insert(campaign) .values({ areaId: a.id, name: input.name, status: input.status, reach: input.reach, ownerUserId: input.ownerUserId ?? null, }) .returning(); return created; }), funnel: protectedProcedure.query(async ({ ctx }) => { // Lead-Funnel: simple Aggregation der bekannten Quellen. const campaigns = await ctx.db.select().from(campaign); const reichweite = campaigns.reduce((acc, c) => acc + c.reach, 0); const handovers = await ctx.db.select().from(leadHandover); const leads = handovers.length; const deals = await ctx.db.select().from(deal); const mql = deals.filter((d) => ['erstgespraech', 'demo', 'angebot'].includes(d.stage)).length; const uebergabe = handovers.length; // Frontend kann die Stage-Übergänge daraus rendern. return { reichweite, website: Math.round(reichweite * 0.2), // Placeholder bis ein Tracking-Feed existiert. leads, mql, uebergabe, }; }), crosslink: protectedProcedure.query(async ({ ctx }) => { const handovers = await ctx.db.select().from(leadHandover); const dealsFromHandovers = handovers.filter((h) => h.dealId !== null).length; // Won-Volumen aus Handover-bezogenen Deals dieses Quartals. const dealRows = await ctx.db.select().from(deal); const wonValue = dealRows .filter((d) => d.wonAt) .reduce((acc, d) => acc + (d.wonValueEur ?? 0), 0); return { uebergebenSeitTagen: 30, leadsUebergeben: handovers.length, dealsErzeugt: dealsFromHandovers, gewonneneEurQuartal: wonValue, }; }), });