Integration
Overview
This guide provides comprehensive instructions for integrating the CoreBanq notification service into your modules. The notification system supports multilingual content, multiple delivery channels, and user preference management.
Quick Start
1. Service Initialization
Add the notification service to your module handler:
package yourmodule
"corebanq/modules/notifications"
// other imports...
)
type Handler struct {
storage storage.CoreBanqStorage
notificationService *notifications.NotificationService
// other fields...
}
func NewHandler(ctx context.Context, storage storage.CoreBanqStorage, qs queue.Store, db *gorm.DB) *Handler {
return &Handler{
storage: storage,
notificationService: notifications.NewNotificationService(ctx, qs, db),
}
}2. Basic Notification
notification := ¬ifications.Notification{
Type: notifications.NotificationTypeTask,
Event: "account_created",
Title: "Account Created",
Content: "Your new account has been successfully created",
CustomerID: customerID,
UserIDs: []uuid.UUID{userID},
Metadata: map[string]any{
"account_id": accountID.String(),
},
}
err := notificationService.SendNotification(ctx, notification)Integration Patterns
Module Initialization Pattern
type Module struct {
Handler *Handler
NotificationService *notifications.NotificationService
}
func InitModule(ctx context.Context, db *gorm.DB, qs queue.Store, storage storage.CoreBanqStorage) *Module {
notificationService := notifications.NewNotificationService(ctx, qs, db)
handler := &Handler{
storage: storage,
notificationService: notificationService,
}
return &Module{
Handler: handler,
NotificationService: notificationService,
}
}Practical Examples
Account Creation Notification
func (h *Handler) sendAccountCreatedNotification(ctx context.Context, userID, customerID, accountID uuid.UUID) error {
// Get user's preferred language
language := h.notificationService.GetUserPreferredLanguage(ctx, userID, customerID)
// Get localized messages
title := h.notificationService.GetLocalizedMessage(ctx, userID, customerID, "accounts_m.created_title")
content := h.notificationService.GetLocalizedMessage(ctx, userID, customerID, "accounts_m.created_content")
// Generate contextual link
linkParams := map[string]string{
"account_id": accountID.String(),
}
linkURL, linkText := h.notificationService.GetLinkInfo("account_created", language, linkParams)
notification := ¬ifications.Notification{
Type: notifications.NotificationTypeTask,
Event: "account_created",
Title: title,
Content: content,
LinkURL: linkURL,
LinkText: linkText,
CustomerID: customerID,
UserIDs: []uuid.UUID{userID},
Metadata: map[string]any{
"account_id": accountID.String(),
"event_type": "account_created",
},
}
// Send notification (non-blocking)
if err := h.notificationService.SendNotification(ctx, notification); err != nil {
logger.Errorf("Failed to send account created notification: %v", err)
// Don't fail the main operation
}
return nil
}Chat Message Notification
func (h *Handler) sendChatNotification(ctx context.Context, params ChatNotificationParams) error {
// Get room participants (excluding sender)
participants, err := h.storage.GetRoomParticipants(params.RoomID)
if err != nil {
return fmt.Errorf("failed to get room participants: %w", err)
}
room, err := h.storage.GetChatRoomByID(params.RoomID)
if err != nil {
return fmt.Errorf("failed to get chat room: %w", err)
}
var recipientIDs []uuid.UUID
for _, participant := range participants {
if participant.UserID != params.SenderID {
recipientIDs = append(recipientIDs, participant.UserID)
}
}
if len(recipientIDs) == 0 {
return nil
}
// Get localized content
language := h.notificationService.GetUserPreferredLanguage(ctx, params.SenderID, room.CustomerID)
title := h.notificationService.GetLocalizedMessage(ctx, params.SenderID, room.CustomerID, "chat_m.new_message_title")
content := h.notificationService.GetLocalizedMessage(ctx, params.SenderID, room.CustomerID, "chat_m.new_message_content")
// Generate link
linkParams := map[string]string{
"room_id": params.RoomID.String(),
"message_id": params.MessageID.String(),
}
linkURL, linkText := h.notificationService.GetLinkInfo("new_message", language, linkParams)
notification := ¬ifications.Notification{
Type: notifications.NotificationTypeChat,
Event: "message_received",
Title: title,
Content: content,
LinkURL: linkURL,
LinkText: linkText,
CustomerID: room.CustomerID,
UserIDs: recipientIDs,
Metadata: map[string]any{
"room_id": params.RoomID.String(),
"message_id": params.MessageID.String(),
"sender_id": params.SenderID.String(),
},
}
return h.notificationService.SendNotification(ctx, notification)
}
type ChatNotificationParams struct {
RoomID uuid.UUID
SenderID uuid.UUID
MessageID uuid.UUID
Content string
}Transaction Notification
func (h *Handler) notifyTransactionCompleted(ctx context.Context, transaction *models.Transaction) error {
userIDs := []uuid.UUID{transaction.SenderID}
if transaction.ReceiverID != uuid.Nil {
userIDs = append(userIDs, transaction.ReceiverID)
}
for _, userID := range userIDs {
language := h.notificationService.GetUserPreferredLanguage(ctx, userID, transaction.CustomerID)
title := h.notificationService.GetLocalizedMessage(ctx, userID, transaction.CustomerID, "transactions_m.completed_title")
content := h.notificationService.GetLocalizedMessage(ctx, userID, transaction.CustomerID, "transactions_m.completed_content")
linkParams := map[string]string{
"transaction_id": transaction.ID.String(),
}
linkURL, linkText := h.notificationService.GetLinkInfo("transaction_completed", language, linkParams)
notification := ¬ifications.Notification{
Type: notifications.NotificationTypeTask,
Event: "transaction_completed",
Title: title,
Content: content,
LinkURL: linkURL,
LinkText: linkText,
CustomerID: transaction.CustomerID,
UserIDs: []uuid.UUID{userID},
Metadata: map[string]any{
"transaction_id": transaction.ID.String(),
"amount": transaction.Amount,
"currency": transaction.Currency,
"type": transaction.Type,
},
}
if err := h.notificationService.SendNotification(ctx, notification); err != nil {
logger.Errorf("Failed to send transaction notification to user %s: %v", userID, err)
}
}
return nil
}Bulk System Notification
func (h *Handler) notifySystemMaintenance(ctx context.Context, customerID uuid.UUID, maintenanceTime time.Time) error {
// Get all active users for the customer
users, err := h.storage.GetActiveUsersByCustomer(customerID)
if err != nil {
return fmt.Errorf("failed to get active users: %w", err)
}
var userIDs []uuid.UUID
for _, user := range users {
userIDs = append(userIDs, user.ID)
}
if len(userIDs) == 0 {
return nil
}
language := h.notificationService.GetUserPreferredLanguage(ctx, userIDs[0], customerID)
title := h.notificationService.GetLocalizedMessage(ctx, userIDs[0], customerID, "system_m.maintenance_title")
content := h.notificationService.GetLocalizedMessage(ctx, userIDs[0], customerID, "system_m.maintenance_content")
notification := ¬ifications.Notification{
Type: notifications.NotificationTypeTask,
Event: "system_maintenance",
Title: title,
Content: content,
CustomerID: customerID,
UserIDs: userIDs,
Metadata: map[string]any{
"maintenance_time": maintenanceTime.Format(time.RFC3339),
"event_type": "system_maintenance",
},
}
return h.notificationService.SendNotification(ctx, notification)
}Conditional Notification with User Preferences
func (h *Handler) notifyBalanceThreshold(ctx context.Context, account *models.Account, threshold float64) error {
// Check if user has enabled balance notifications
preferences, err := h.notificationService.GetNotificationPreferences(account.UserID, account.CustomerID)
if err != nil {
logger.Errorf("Failed to get notification preferences: %v", err)
return nil
}
// Check if balance notifications are enabled
balanceNotificationsEnabled := false
for _, group := range preferences.Groups {
if group.Type == "balance_alerts" && group.Enabled {
for _, event := range group.Events {
if event.Type == "low_balance" && event.Enabled {
balanceNotificationsEnabled = true
break
}
}
}
}
if !balanceNotificationsEnabled {
return nil // User has disabled these notifications
}
language := h.notificationService.GetUserPreferredLanguage(ctx, account.UserID, account.CustomerID)
title := h.notificationService.GetLocalizedMessage(ctx, account.UserID, account.CustomerID, "balance_m.low_balance_title")
content := h.notificationService.GetLocalizedMessage(ctx, account.UserID, account.CustomerID, "balance_m.low_balance_content")
linkParams := map[string]string{
"account_id": account.ID.String(),
}
linkURL, linkText := h.notificationService.GetLinkInfo("low_balance", language, linkParams)
notification := ¬ifications.Notification{
Type: notifications.NotificationTypeTask,
Event: "low_balance",
Title: title,
Content: content,
LinkURL: linkURL,
LinkText: linkText,
CustomerID: account.CustomerID,
UserIDs: []uuid.UUID{account.UserID},
Metadata: map[string]any{
"account_id": account.ID.String(),
"current_balance": account.Balance,
"threshold": threshold,
"currency": account.Currency,
},
}
return h.notificationService.SendNotification(ctx, notification)
}Configuration
Message Configuration
Create config/samples/yourmodule_m.yaml:
messages:
account_created_title:
en: "Account Created"
de: "Konto erstellt"
fr: "Compte créé"
it: "Account creato"
account_created_content:
en: "Your new account has been successfully created"
de: "Ihr neues Konto wurde erfolgreich erstellt"
fr: "Votre nouveau compte a été créé avec succès"
it: "Il tuo nuovo account è stato creato con successo"
transaction_completed_title:
en: "Transaction Completed"
de: "Transaktion abgeschlossen"
fr: "Transaction terminée"
it: "Transazione completata"
transaction_completed_content:
en: "Your transaction has been processed successfully"
de: "Ihre Transaktion wurde erfolgreich verarbeitet"
fr: "Votre transaction a été traitée avec succès"
it: "La tua transazione è stata elaborata con successo"Notification Links
Add to config/samples/notifications.yaml:
links:
account_created:
link: "/accounts/{account_id}"
title:
en: "View Account"
de: "Konto anzeigen"
fr: "Voir le compte"
it: "Visualizza account"
transaction_completed:
link: "/transactions/{transaction_id}"
title:
en: "View Transaction"
de: "Transaktion anzeigen"
fr: "Voir la transaction"
it: "Visualizza transazione"
events:
account_created:
link: "/accounts/{account_id}"
title:
en: "View Account"
de: "Konto anzeigen"
fr: "Voir le compte"
it: "Visualizza account"Notification Groups
Add to config/samples/notifications.yaml:
groups:
- title:
en: "Account Management"
de: "Kontoverwaltung"
fr: "Gestion de compte"
it: "Gestione account"
type: "accounts"
enabled: true
channels:
- title:
en: "Email"
de: "E-Mail"
fr: "E-mail"
it: "Email"
type: "email"
- title:
en: "System"
de: "System"
fr: "Système"
it: "Sistema"
type: "system"
events:
- title:
en: "Account Created"
de: "Konto erstellt"
fr: "Compte créé"
it: "Account creato"
type: "account_created"
description:
en: "Notify when a new account is created"
de: "Benachrichtigung, wenn ein neues Konto erstellt wird"
fr: "Notifier lorsqu'un nouveau compte est créé"
it: "Notifica quando viene creato un nuovo account"
enabled: trueBest Practices
Error Handling
Always handle notification errors gracefully:
if err := h.notificationService.SendNotification(ctx, notification); err != nil {
logger.Errorf("Failed to send notification: %v", err)
// Log the error but don't fail the main operation
}Non-blocking Integration
Send notifications asynchronously to avoid blocking main operations:
// Process main operation first
if err := h.processMainOperation(); err != nil {
return err
}
// Send notification in background
go func() {
if err := h.sendNotification(context.Background(), notification); err != nil {
logger.Errorf("Failed to send notification: %v", err)
}
}()Retry with Backoff
For critical notifications, implement retry logic:
func (h *Handler) sendNotificationWithRetry(ctx context.Context, notification *notifications.Notification) error {
maxRetries := 3
backoff := time.Second
for i := 0; i < maxRetries; i++ {
if err := h.notificationService.SendNotification(ctx, notification); err != nil {
if i == maxRetries-1 {
return fmt.Errorf("failed after %d retries: %w", maxRetries, err)
}
logger.Warnf("Notification failed (attempt %d/%d): %v", i+1, maxRetries, err)
time.Sleep(backoff)
backoff *= 2
continue
}
return nil
}
return nil
}Rich Metadata
Include relevant metadata for debugging and filtering:
notification := ¬ifications.Notification{
// ... other fields
Metadata: map[string]any{
"entity_id": entityID.String(),
"entity_type": "order",
"action": "created",
"timestamp": time.Now().Unix(),
"module": "orders",
"version": "1.0",
},
}Language Handling
Always get user's preferred language with fallback:
language := h.notificationService.GetUserPreferredLanguage(ctx, userID, customerID)
title := h.notificationService.GetLocalizedMessageWithFallback(
ctx, userID, customerID,
"yourmodule_m.notification_title",
"Default Title", // fallback
)API Reference
Core Methods
SendNotification(ctx, notification)- Send a notificationGetUserPreferredLanguage(ctx, userID, customerID)- Get user's language preferenceGetLocalizedMessage(ctx, userID, customerID, messageKey)- Get localized messageGetLocalizedMessageWithFallback(ctx, userID, customerID, messageKey, fallback)- Get localized message with fallbackGetLinkInfo(event, language, params)- Generate contextual linksGetNotificationPreferences(userID, customerID)- Get user notification preferencesUpdateNotificationPreferences(userID, customerID, groups)- Update user preferences
Notification Types
const (
NotificationTypeChat NotificationType = "chat"
NotificationTypeTask NotificationType = "task"
)Delivery Channels
const (
ChannelEmail DeliveryChannel = "email"
ChannelSMS DeliveryChannel = "sms"
ChannelSystem DeliveryChannel = "system"
ChannelPushNotification DeliveryChannel = "push_notification"
)Testing
Unit Test Example
func TestSendAccountNotification(t *testing.T) {
ctx := context.Background()
mockStorage := &MockStorage{}
mockNotificationService := &MockNotificationService{}
handler := &Handler{
storage: mockStorage,
notificationService: mockNotificationService,
}
userID := uuid.New()
customerID := uuid.New()
accountID := uuid.New()
err := handler.sendAccountCreatedNotification(ctx, userID, customerID, accountID)
assert.NoError(t, err)
assert.Equal(t, 1, mockNotificationService.SendNotificationCallCount)
sentNotification := mockNotificationService.LastSentNotification
assert.Equal(t, notifications.NotificationTypeTask, sentNotification.Type)
assert.Equal(t, "account_created", sentNotification.Event)
assert.Equal(t, customerID, sentNotification.CustomerID)
assert.Contains(t, sentNotification.UserIDs, userID)
assert.Equal(t, accountID.String(), sentNotification.Metadata["account_id"])
}Architecture
The notification system follows a queue-based architecture:
- Notification Creation - Notifications are created and queued
- Queue Processing - Background workers process notifications
- Delivery - Notifications are delivered via configured channels
- State Tracking - Delivery and read states are tracked
- Real-time Updates - SSE provides instant notifications to connected clients
This ensures reliable delivery, scalability, and real-time user experience.