发布于 2026-01-06 1 阅读
0

使用 Novu 打造一款热门的全新外卖应用(TL;DR)

与 Novu 一起打造一款热门的全新外卖应用

太长不看

太长不看

在本教程中,我们将创建一个工具来管理外卖应用程序的通知系统。为此,我们将利用 Novu 的开源通知基础架构 、我们自定义的平台以及 PostMark。

帕特里克

加入 ConnectNovu 黑客马拉松

展示你的技能,突破创新界限,结识志同道合的社区成员。

ConnectNovu Hackathon 是一项专注于通知功能的全球性活动。如果您喜欢研究应用内通知、短信、推送通知、电子邮件和聊天功能,那么这里就是您的理想之选!

你准备好打造下一个伟大产品了吗?🚀

点击这里加入

开球

我们都喜欢外卖应用程序的新时代。无需打电话,几分钟就能在手机上完成下单,支付高额配送费,然后就可以满怀期待地等待美食送到家门口。

但在这个过程中,这些外卖应用会让你随时了解整个流程——从下单到包裹送达。但要做到这一点,你需要一个强大的通知系统来处理。

在本教程中,我们将学习如何使用功能强大的开源通知基础架构 Novu 为食品配送应用程序创建通知管理系统。

如果你想直接查看本教程的源代码,请点击这里

投身商界

在本教程中,我们将从一个名为Foody 的简单应用开始。我们将使用 Nuxt 和 Supabase 创建项目,但您也可以使用任何您喜欢的 JavaScript 框架。您还需要 Node.js 的 LTS 版本。

通常,我们会期望在任何电子商务服务中收到一系列通知,外卖系统也不例外。对于 Foody,我们至少需要以下几种类型的通知:

  • 客户接待通知:欢迎和感谢用户。
  • 服务特定通知:- 订单提交、发货状态、反馈请求、促销活动。
  • 法律和安全更新通知:条款和隐私等。

让我们看看 Novu 如何在食品配送服务环境中处理这些通知。

项目启动

我们需要注册一个 Novu 账号,然后开始设置我们的项目。

之后,我们需要至少设置一个配送服务提供商。该配送服务提供商将用于管理我们应用内的所有通知。请前往集成商店查看我们的选项。

截至撰稿时,Novu 支持三种通知渠道:电子邮件、短信和应用内通知中心。如果您想创建除已提供渠道之外的其他通知提供程序,请参阅其文档

我们将使用 Postmark 为Foody设置一个新的服务提供商。让我们开始吧。

设置 PostMark

首先,我们需要一个PostMark 账户。注册完成后,我们需要验证发件人身份,如果服务器 API 令牌尚不存在,则需要创建一个新的令牌。

返回 Novu 集成商店 页面,点击 Postmark 连接,填写  表单中的“发件人”信息,并将发件人设置Server API token 为  Postmark 上已验证的发件人。最后,提供发件人信息 ,将发件人切换为“激活”状态,然后点击 连接 按钮。API Keyfrom emailsender name

在 Novu 上创建通知

要在 Novu 上创建新通知,请点击 “通知” 页面,然后点击右上角的 “新建”Notification Name按钮。填写新模板的通知设置,包括提供通知 类型Notification Description、通知宽度和 Notification Group通知类型(默认设置 为“常规”)  。

图片描述

发送欢迎通知

对于Foody,我们将设置一封客户欢迎电子邮件,以演示如何在 Novu 中设置通知。填写上图中的字段,设置 Notification Name to welcome-new-user和 Notification Description to  Notification for welcoming newly registered users

前往新通知的“工作流编辑器”选项卡添加步骤。在本例中,我们希望发送一封欢迎客户的电子邮件通知,然后接收该客户的应用内管理员控制面板通知。因此,在此页面上,将 电子邮件 步骤拖到画布上,然后再 拖放应用内 步骤。

图片描述

选择  画布中当前的电子邮件步骤并编辑模板。您可以使用可视化模板编辑器,也可以为电子邮件渠道编写自定义标记。我们将使用模板编辑器:

图片描述

 编辑器右侧的 “步骤变量”部分 列出了我们在 Handlebars 邮件模板中使用的变量{{}}。这些变量将由通过 Novu 触发器发送的已提交邮件有效负载填充。您可以在完成后预览和测试创建的电子邮件通知,以便进行故障排除。

返回工作流程编辑器,选择 应用内 步骤并编辑其模板:

图片描述

在用户帐户验证之后调用此触发器,以在 Foody 中触发此通知。

将 Novu 集成到 Foody 中

如果您按照本教程提供的 Nuxt 应用进行操作,则服务器 API 端点文件中已设置了以下逻辑 /server/api/register-notifications-subscriber.js。此通知有两个用途,第一个用途是将应用用户注册为 Novu 通知订阅者,第二个用途是发送欢迎电子邮件。

// dependency imports

export default defineEventHandler(async (event) => {
    // variable declarations

    // Send welcome notification to new user
    const [firstName, lastName] = user.user_metadata.full_name.split(" ");
      await novu.trigger('welcome-new-user', {
          to: {
            subscriberId: user.id,
            email: user.user_metadata.email,
            firstName,
            lastName,
            phone: user.user_metadata.phone,
          },
          payload: {
            firstName
          },
        });

    // other code
})
Enter fullscreen mode Exit fullscreen mode

尽管我们没有在邮件模板中使用这些数据,但我们仍然在上述代码中尽可能多地向触发器提供了订阅者数据。为什么呢?因为当触发器被调用时,Novu 会将数据更新插入到新的订阅者列表中;如果列表中不存在订阅者,则会创建一个新的订阅者。

要显式创建新订阅者,请使用以下命令:

    await novu.subscribers.identify(user.id, {
      email,
      firstName,
      lastName,
      phone: user.user_metadata.phone,
    });
Enter fullscreen mode Exit fullscreen mode

注册了一些用户之后,访问  Novu 控制面板的“活动动态”部分时,我们应该会看到以下内容:

图片描述

活动动态会监控与 Novu 项目相关的所有外发消息。它可以监控活动并发现提供商或渠道可能存在的问题。

使用 Novu 发送订单特定通知

现在我们已经了解了如何向 Foody 用户发送欢迎邮件,接下来让我们再来处理实际订单!

发送订单确认信息

和其他外卖应用一样,我们希望让顾客随时了解订单状态。因此,接下来我们需要设置一个通知功能,在顾客下单后发送确认信息。

按照前面的步骤创建一个新的通知,设置 Notification Name 到 "order-confirmation" 和 Notification Description到 "Notifying users on order placement"

本次通知中,我们希望发送一份用户购买菜品的列表。因此,编写邮件模板的合适方法是使用以下自定义标记:

<div>
 Hello {{subscriber.firstName}},
</div>

<div style="padding: 4px">
 You successfully placed order number #{{orderNumber}}.
</div>

<ul style="padding: 4px">
 {{#each dishes }}
  <li>{{count}} x {{name}} </li>
 {{/each}}
</ul>

<div style="padding: 4px">
 Delivery Fees: {{deliveryFee}}$
</div>

<div style="padding: 4px; font-weight: 800">
 Total: {{totalFee}}$
</div>

<div style="padding: 4px">
 Please notify us if any dish is out of order.
</div>
Enter fullscreen mode Exit fullscreen mode

我们可以看到上面的模板有两个新特点,它与我们之前创建的电子邮件模板有所不同。

首先,我们有 subscriber.firstName 变量。Novu 使用特定的订阅者数据模型来管理应用程序的用户,这使得 API 能够管理通知流程的不同方面,同时提供一个便捷的通知触发接口。该 subscriber.firstName 变量来自 订阅者对象的用户数据 点,因此可以将其放置在通知模板中。我们还可以从 用户数据点中获取其他数据, 例如 lastName …… avatar

与之前的模板不同的是,第二个不同之处在于数组的遍历 dishes 。这得益于 Handlebars#each辅助函数。我们还可以 使用#if Handlebars 条件辅助函数,我们将在后续的通知章节中演示它的用法。

要使用创建的模板向我们的 Foody 客户发送订单确认通知,请添加以下触发器:

// imports and global functions

export default defineEventHandler(async (event) => {
    // variable declarations

    // order creation logic providing us with orderDetails variable

      await novu.trigger('order-confirmation', {
          to: {
            subscriberId: user.id,
            email: user.user_metadata.email
          },
          payload: {
            dishes: order.dishes,
            orderNumber: orderDetails.order_number,
            deliveryFee: order.deliveryFee,
            totalFee: order.totalFee
          },
        });

    // other code
})
Enter fullscreen mode Exit fullscreen mode

发送配送状态通知

为了让客户随时了解订单状态,我们需要通知他们订单的配送状态变更。请创建一个新的 delivery-status 通知,并使用以下代码作为模板:

<div>
 Hello {{subscriber.firstName}},
</div>

<div style="padding: 4px">
 You order #{{orderNumber}} has been {{status}}.
</div>

<div style="padding: 4px">
 Click the following link to give us a feedback of your order.

 {{#if delivered}}
  <p>
   <a href="{{feedbackUrl}}" target="_blank" style="padding: 2px">
    Give us feedback
   </a>
  </p>
 {{/if }}
</div>
Enter fullscreen mode Exit fullscreen mode

配送状态通知可以包括“订单已取走”、“订单已送达”等。订单送达后, #if 我们还可以借助车把助手向用户发送链接,以便用户提供配送反馈。

我们为Foody创建的最后一条基于订阅者的通知  是反馈感谢通知。由于这条通知比前两条通知简单,我们可以使用模板编辑器来创建它。

图片描述

以下代码可用作应用内通知的触发器:

// imports
export default defineEventHandler(async (event) => {
// Declarations and user feedback database-submission logic

      await novu.trigger('feedback-appreciation', {
          to: {
            subscriberId: user.id,
            email: user.email
          },
          payload: {
            firstName
          },
        });

    return {
        message: 'Appreciated user!',
    }
})
Enter fullscreen mode Exit fullscreen mode

使用 Novu Topics 发送批量订阅通知

如果我们需要向一组客户或所有客户批量发送通知该怎么办?例如,我们希望批量发送促销、折扣、服务更新以及条款和服务变更等通知。如何在不进行成本高昂的数据循环处理的情况下实现这一点?

Novu 通过主题功能解决了这一难题 。Novu 主题功能允许我们根据自定义的任何条件向一组用户发送批量通知。借助主题功能,我们可以根据用户的兴趣、订阅或其他任何可确定的属性向他们发送多封电子邮件。

在我们的场景中,我们可能希望根据顾客经常购买的菜品向他们发送促销和折扣通知。例如,如果我们把顾客购买某道菜的次数视为他们喜欢这道菜,我们会将他们添加到一个包含喜欢这道菜的顾客的话题中。我们可以将这样的话题命名为“喜欢这道菜的顾客”  customers:favorite:dish_id

在我们的应用程序中添加此类功能,将使我们能够针对部分用户群体投放定向广告,而不是依赖广撒网式的客户互动方式。

创建 Novu 主题

现在我们已经了解了 Novu 中有哪些主题,接下来让我们学习如何创建一个主题。

我们将为Foody创建一个主题 ,用于根据客户的购买行为向他们发送促销通知,就像我们之前讨论的那样。但在为主题分配订阅者之前,我们需要先创建该主题。

在我们的外卖服务场景中,每当向应用程序数据库添加一道菜品时,都必须创建一个主题。以下创建主题的代码最好放在向数据库提交新菜品的逻辑之后:

// Dish data submission logic

const result = await novu.topics.create({
   key: "customers:favorite:" + newDishData.id,
   name: "Customers that like " + newDishData.name
});
Enter fullscreen mode Exit fullscreen mode

请记住,Novu 主题键应该是唯一的,并且一旦创建就不能更改。

添加新订阅者并发送通知

要向某个主题添加新的订阅者,我们需要使用以下 addSubscriber() 方法:

// Order placement logic

// When customer fulfils criteria to be added to topic involving dish[0]
const result = await novu.topics.addSubscribers(
    'customer:favorites:' + order.dishes[0].id,
    {
        subscribers: [user.id]
    })
Enter fullscreen mode Exit fullscreen mode

在应用内部,这段代码应该紧接在订单提交代码之后调用。符合条件的用户将被添加到相应的主题中。

创建主题并添加订阅者后,下一步是向订阅者发送通知。首先,为该主题创建一个通知,例如“主题已创建 dish-based-promotional-notification”。别忘了也为此添加一个模板!

图片描述

最后,创建一个发送通知的触发器。Novu 的主题通知触发器与用于向单个订阅者发送通知的触发器相同。区别在于,在字段中 to ,我们传递的不是单个订阅者的身份信息,而是一个主题数组,我们希望将通知发送给这些主题的订阅者。

以下是创建通知的触发示例:

import { Novu } from '@novu/node';
import { TriggerRecipientsTypeEnum } from '@novu/shared'

export default defineEventHandler(async (event) => {
    // initiate Novu

    const result = await novu.trigger('dish-based-promotional-notification',{
        to: [{ type: TriggerRecipientsTypeEnum.TOPIC, topicKey }],
        payload: {
            promotionTitle,
            promotionDetails
        }
    });
})
Enter fullscreen mode Exit fullscreen mode

自定义通知选项

并非所有顾客都希望收到外卖服务发送的所有类型的通知。因此,我们应该允许他们选择不接收某些主题的通知。我们所做的仅仅是对特定主题的订阅者进行管理。

为了演示这一点,我们将打开 dish-based-promotional-notification 之前创建的通知模板,并在底部添加一个取消订阅链接。由于无法在模板编辑器中添加链接,我们需要将整个模板转换为自定义代码,并使用以下标记:

<div>
 Hello {{subscriber.firstName}},
</div>

<div style="padding: 4px">
 We have an offer you wouldn't want to miss.
</div>

<div style="padding: 4px">
 {{promotionDetails}}
</div>

<div style="padding: 4px">
 <a href="{{optOutLink}}?userId={{subscriber.subscriberId}}&topicKey={{topicKey}}" target="_blank">Click here</a> to unsubcribe from these emails.
</div>
Enter fullscreen mode Exit fullscreen mode

我们需要订阅者的 ID 和主题键才能从主题中移除订阅者,如上面的标记所示。由于我们从未在涉及此通知的触发器中传递主题键,因此我们需要对其进行以下更改:

const result = await novu.trigger('dish-based-promotional-notification',{
    to: [{ type: TriggerRecipientsTypeEnum.TOPIC, topicKey }],
    payload: {
        promotionTitle,
        promotionDetails,
        topicKey
    }
});
Enter fullscreen mode Exit fullscreen mode

现在,我们可以继续为用户创建订阅topic-opting-out trigger者。如前所述,我们只需从主题中移除订阅者即可。为此,我们需要按 removeSubscribers() 如下方式调用该方法。

const result = await novu.topics.removeSubscribers(topicKey, {
    subscribers: [userId]
});
Enter fullscreen mode Exit fullscreen mode

总结

原来这些外卖应用背后有很多运作!虽然我们还没有功能齐全的 Foody 应用,但多亏了 Novu,我们已经搭建了一个非常棒的通知系统!我们使用 Supabase 来处理用户身份验证,但最重要的部分是添加通知功能。

如果您喜欢这里的内容,请在下方评论区留言!非常荣幸能与您分享,希望您能将 Foody 推向新的高峰!

PS ConnectNovu 黑客马拉松正在进行中,欢迎大家注册,还有一些很棒的奖品,点击这里查看

ConnectNovu

文章来源:https://dev.to/novu/creating-a-hot-new-food-delivery-app-with-novu-2e75