diff --git a/libs/contracts/events/schemas/notification.requested.schema.json b/libs/contracts/events/schemas/notification.requested.schema.json new file mode 100644 index 0000000..35e7b61 --- /dev/null +++ b/libs/contracts/events/schemas/notification.requested.schema.json @@ -0,0 +1,81 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://goodgo.vn/schemas/events/notification.requested.schema.json", + "title": "notification.requested", + "description": "Emitted when a domain action requests delivery of a user-facing notification. Consumed by the notifications worker pool, which fans out to email / SMS / Zalo OA / FCM / in-app channels per user preferences.", + "type": "object", + "additionalProperties": false, + "required": [ + "notificationId", + "userId", + "category", + "template", + "params", + "channels", + "requestedAt" + ], + "properties": { + "notificationId": { + "type": "string", + "minLength": 1, + "description": "UUIDv7 of the persisted Notification aggregate (also used as idempotency key by the consumer)." + }, + "userId": { + "type": "string", + "minLength": 1 + }, + "category": { + "type": "string", + "enum": [ + "auth", + "kyc", + "listing", + "payment", + "subscription", + "inquiry", + "lead", + "agent", + "residential", + "system" + ] + }, + "template": { + "type": "string", + "minLength": 1, + "description": "Template key resolved by TemplateService (e.g. 'listing.approved.email.vi')." + }, + "params": { + "type": "object", + "description": "Template substitution parameters. Shape depends on template; consumer is responsible for validation against the template manifest.", + "additionalProperties": true + }, + "channels": { + "type": "array", + "minItems": 1, + "items": { + "type": "string", + "enum": ["email", "sms", "zalo", "fcm", "in_app"] + }, + "description": "Channels requested by the producer. The consumer further filters by user notification preferences before dispatch." + }, + "locale": { + "type": "string", + "enum": ["vi", "en"], + "description": "Preferred locale; falls back to user's stored locale, then 'vi'." + }, + "priority": { + "type": "string", + "enum": ["low", "normal", "high", "critical"], + "default": "normal" + }, + "dedupeKey": { + "type": "string", + "minLength": 1, + "description": "Optional consumer-side dedupe key (collapses duplicate logical notifications inside the BullMQ queue, in addition to envelope-level eventId dedupe)." + }, + "requestedAt": { + "type": "string", + "format": "date-time" + } + } +} diff --git a/libs/contracts/events/src/event-types.ts b/libs/contracts/events/src/event-types.ts index ff03605..a381a6a 100644 --- a/libs/contracts/events/src/event-types.ts +++ b/libs/contracts/events/src/event-types.ts @@ -2,6 +2,7 @@ export const KNOWN_EVENT_TYPES = [ 'kyc.verified', 'listing.approved', 'payment.completed', + 'notification.requested', ] as const; export type KnownEventType = (typeof KNOWN_EVENT_TYPES)[number]; diff --git a/libs/contracts/events/src/index.ts b/libs/contracts/events/src/index.ts index cd525cc..4083442 100644 --- a/libs/contracts/events/src/index.ts +++ b/libs/contracts/events/src/index.ts @@ -35,3 +35,34 @@ export interface KycVerifiedPayload { verifiedAt: string; documentRefs: string[]; } + +export type NotificationCategory = + | 'auth' + | 'kyc' + | 'listing' + | 'payment' + | 'subscription' + | 'inquiry' + | 'lead' + | 'agent' + | 'residential' + | 'system'; + +export type NotificationChannel = 'email' | 'sms' | 'zalo' | 'fcm' | 'in_app'; + +export type NotificationLocale = 'vi' | 'en'; + +export type NotificationPriority = 'low' | 'normal' | 'high' | 'critical'; + +export interface NotificationRequestedPayload { + notificationId: string; + userId: string; + category: NotificationCategory; + template: string; + params: Record; + channels: NotificationChannel[]; + locale?: NotificationLocale; + priority?: NotificationPriority; + dedupeKey?: string; + requestedAt: string; +}