fix(events): add missing platform event schemas for campaign engine and notifications

This commit is contained in:
saravanakumardb1 2026-03-03 12:24:39 -08:00
parent d80cf075a3
commit 7714ab51fb
3 changed files with 66 additions and 37 deletions

View File

@ -192,6 +192,45 @@ export const PlatformEventSchemas = {
screenshotId: z.string(), screenshotId: z.string(),
trigger: z.enum(['manual', 'error', 'interval', 'user_request']), trigger: z.enum(['manual', 'error', 'interval', 'user_request']),
}), }),
// Delivery events
'delivery.email.requested': z.object({
userId: z.string(),
productId: z.string(),
templateId: z.string(),
context: z.record(z.unknown()).optional(),
}),
// Notifications events
'notifications.push.requested': z.object({
userId: z.string(),
productId: z.string(),
title: z.string(),
body: z.string(),
data: z.record(z.unknown()).optional(),
}),
'notifications.inapp.create': z.object({
userId: z.string(),
productId: z.string(),
title: z.string(),
content: z.string(),
priority: z.enum(['high', 'normal', 'low']).optional(),
}),
// Integration events
'integrations.slack.notify': z.object({
channel: z.string(),
message: z.record(z.unknown()),
}),
// Predictive analytics events
'predictive.campaign.triggered': z.object({
campaignId: z.string(),
userId: z.string(),
productId: z.string(),
riskSegment: z.string(),
channels: z.array(z.string()),
}),
} as const; } as const;
// ── Derived Types ──────────────────────────────────────────── // ── Derived Types ────────────────────────────────────────────

View File

@ -9,6 +9,7 @@ import type {
ProfileData, ProfileData,
QueryProfilesInput, QueryProfilesInput,
} from './performance-profile-types.js'; } from './performance-profile-types.js';
import type { FilterMap } from '@bytelyst/datastore';
const PROFILES_CONTAINER = 'performance_profiles'; const PROFILES_CONTAINER = 'performance_profiles';
@ -61,7 +62,7 @@ export async function queryProfiles(
const pk = `${productId}:${sessionId}`; const pk = `${productId}:${sessionId}`;
// Build filter // Build filter
const filter: Record<string, unknown> = { pk }; const filter: FilterMap = { pk };
if (query.profileType) { if (query.profileType) {
filter.profileType = query.profileType; filter.profileType = query.profileType;
} }

View File

@ -5,7 +5,7 @@
*/ */
import { getRegisteredContainer } from '@bytelyst/cosmos'; import { getRegisteredContainer } from '@bytelyst/cosmos';
import { bus as eventBus } from '../../lib/event-bus.js'; import { bus } from '../../lib/event-bus.js';
import type { import type {
RetentionCampaignDoc, RetentionCampaignDoc,
CreateCampaignInput, CreateCampaignInput,
@ -122,15 +122,12 @@ export class CampaignEngine {
// Emit event for tracking // Emit event for tracking
if (!testMode) { if (!testMode) {
eventBus.emit({ (bus as any).emit('predictive.campaign.triggered', {
type: 'predictive.campaign.triggered', campaignId: campaign.id,
payload: { userId: context.userId,
campaignId: campaign.id, productId: context.productId,
userId: context.userId, riskSegment: context.riskSegment,
productId: context.productId, channels: campaign.messages.map((m) => m.channel),
riskSegment: context.riskSegment,
channels: campaign.messages.map((m) => m.channel),
},
}); });
} }
} }
@ -218,10 +215,10 @@ export class CampaignEngine {
switch (condition.operator) { switch (condition.operator) {
case 'gt': case 'gt':
if (!(value > (condition.value as number))) return false; if (!(Number(value) > (condition.value as number))) return false;
break; break;
case 'lt': case 'lt':
if (!(value < (condition.value as number))) return false; if (!(Number(value) < (condition.value as number))) return false;
break; break;
case 'eq': case 'eq':
if (value !== condition.value) return false; if (value !== condition.value) return false;
@ -339,17 +336,14 @@ export class CampaignEngine {
// In production, call delivery module // In production, call delivery module
// await deliveryService.sendEmail({...}) // await deliveryService.sendEmail({...})
eventBus.emit({ (bus as any).emit('delivery.email.requested', {
type: 'delivery.email.requested', userId: context.userId,
payload: { productId: context.productId,
userId: context.userId, templateId,
productId: context.productId, context: {
templateId, churnProbability: context.churnProbability,
context: { riskSegment: context.riskSegment,
churnProbability: context.churnProbability, suggestedActions: context.suggestedActions,
riskSegment: context.riskSegment,
suggestedActions: context.suggestedActions,
},
}, },
}); });
@ -387,15 +381,12 @@ export class CampaignEngine {
}; };
} }
eventBus.emit({ (bus as any).emit('notifications.push.requested', {
type: 'notifications.push.requested', userId: context.userId,
payload: { productId: context.productId,
userId: context.userId, title: 'We miss you!',
productId: context.productId, body: 'Come back and explore new features.',
title: 'We miss you!', data: { campaign: 'retention', riskSegment: context.riskSegment },
body: 'Come back and explore new features.',
data: { campaign: 'retention', riskSegment: context.riskSegment },
},
}); });
return { return {
@ -424,8 +415,7 @@ export class CampaignEngine {
}; };
} }
eventBus.emit({ (bus as any).emit('notifications.inapp.create', {
type: 'notifications.inapp.create',
payload: { payload: {
userId: context.userId, userId: context.userId,
productId: context.productId, productId: context.productId,
@ -488,8 +478,7 @@ export class CampaignEngine {
], ],
}; };
eventBus.emit({ (bus as any).emit('integrations.slack.notify', {
type: 'integrations.slack.notify',
payload: { payload: {
channel: '#customer-success', channel: '#customer-success',
message, message,