iT邦幫忙

2025 iThome 鐵人賽

DAY 25
0
Modern Web

用 LINE OA 打造中小企業訂單系統:從零開始的 30 天實作紀錄系列 第 25

群組與顧客雙向通知設計:一次滿足兩邊需求的智慧推播

  • 分享至 

  • xImage
  •  

在前幾天,我們已經完成了訂單建立、狀態更新與通知 Worker。
但你可能會發現一個問題:
目前的通知只有單向——要嘛通知顧客、要嘛通知管理者。

今天,我們要升級成「雙向通知系統」,讓同一筆訂單能同時通知 顧客與群組,但推播的內容又能依角色不同而有所區分。


為什麼要設計雙向通知?

在實務中,通知的對象不只一種:

  • 顧客端:需要知道訂單進度,例如「您的飲品已完成,請準備取餐」。

  • 店家端(群組):需要接收摘要通知,例如「新訂單 #125,紅茶拿鐵 x2,外送」。

如果用相同訊息推播給兩邊,不僅顯得冗長,還容易造成資訊混亂。
因此,我們要打造一套可彈性推播的邏輯:根據接收者角色,動態產出不同訊息內容。


通知架構設計概念

可以用一張簡單的流程圖來理解整體邏輯:

https://ithelp.ithome.com.tw/upload/images/20251009/20178868fQtjNwDFRo.png


實作步驟

Step 1. 定義群組與顧客推播差異

const GROUP_ID = process.env.LINE_GROUP_ID; // 管理群組
  • 群組 ID 可以從 LINE Developers > Messaging API > Webhook events log 中取得。

    Day 12 有提到過,大家可以去回顧一下!

  • 顧客 userId 則是訂單中儲存的 userId 欄位。


Step 2. 建立推播函式

我們可以建立一個通用的通知方法:

// src/utils/notificationService.js 
const client = require('../lib/lineClient');
const buildUserMsg = require('./notifyUser');
const buildGroupMsg = require('./notifyGroup');
const logger = require('../lib/logger');

const GROUP_ID = process.env.LINE_GROUP_ID;

async function sendOrderNotification(order) {
  const messages = [];
  if (order.userId) {
    messages.push(client.pushMessage(order.userId, buildUserMsg(order)));
  }
  if (GROUP_ID) {
    messages.push(client.pushMessage(GROUP_ID, buildGroupMsg(order)));
  }

  try {
    await Promise.all(messages);
    logger.info(`[Notify] 成功通知 orderId=${order._id}`);
  } catch (err) {
    logger.error(`[NotifyError] orderId=${order._id}`, err);
  }
}

module.exports = { sendOrderNotification };

這樣的設計能確保兩方都能即時獲得訊息,同時保持各自關心的重點內容。


Step 3. Worker 或 API 呼叫邏輯

無論你是在訂單建立的 API、或是 Redis Worker 中執行推播任務,
只要將訂單資料傳入 sendOrderNotification() 即可。

// Worker 例子
queue.process('notifyOrder', async (job) => {
  const order = job.data;
  try {
    await sendOrderNotification(order);
    console.log(`✅ 已通知顧客與群組:${order._id}`);
  } catch (err) {
    console.error(`❌ 通知失敗:${err.message}`);
  }
});

Step 4. 優化訊息格式(Flex Message 可選)

若希望管理群組看到更清晰的訂單摘要,可以升級為 Flex Message:

const groupMessage = {
  type: 'flex',
  altText: '新訂單通知',
  contents: {
    type: 'bubble',
    body: {
      type: 'box',
      layout: 'vertical',
      contents: [
        { type: 'text', text: '🛍 新訂單', weight: 'bold', size: 'lg' },
        { type: 'text', text: `編號:${order._id}`, size: 'sm', color: '#888' },
        { type: 'text', text: `品項:${order.item} x${order.quantity}` },
        { type: 'text', text: `取貨方式:${order.pickupMethod}` },
        { type: 'text', text: `狀態:${order.status}`, color: '#0A84FF', weight: 'bold' },
      ],
    },
  },
};

Step 5. 錯誤處理與 Logger

推播容易出錯的情境包含:

  • 使用者封鎖 BOT。

  • 群組 ID 錯誤。

  • LINE Access Token 過期。

因此建議加上錯誤監控與日誌紀錄:

try {
  await client.pushMessage(order.userId, userMessage);
} catch (err) {
  console.error(`[UserNotifyError] userId=${order.userId}`, err);
}

try {
  await client.pushMessage(GROUP_ID, groupMessage);
} catch (err) {
  console.error(`[GroupNotifyError] groupId=${GROUP_ID}`, err);
}

實測結果

完成後,我們可以看到:

  • 顧客端會收到取貨提醒。

  • 管理者群組則會收到完整訂單摘要。

這讓整個系統真正達到「雙向即時同步」的效果。


重點回顧

  • 理解群組通知與個人通知的差異。

  • 學會如何同時推播不同對象。

  • 讓 Worker 根據角色產生不同的訊息內容。

  • 為後續的金流、Webhook、自動通知打下基礎。


明天(Day 26),我們要進入管理介面的世界,
打造能查看完整訂單明細的 Dashboard
讓整套系統正式邁向「可視化後台」階段!


上一篇
讓通知真正動起來!修復 userId 問題 + 多取貨方式邏輯升級
系列文
用 LINE OA 打造中小企業訂單系統:從零開始的 30 天實作紀錄25
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言