# ROLAC — 通知系統設計

**文件版本:** v0.1 (2026-05-24)

---

## 通知渠道總覽

| 渠道 | 技術 | 適用場景 | 狀態 |
|------|------|----------|------|
| **Email** | SendGrid / SMTP | 年度收據、週報、重要公告 | Phase 0 |
| **Push Notification** | Capacitor Push | 服事提醒、排班更新、活動通知 | Phase 1 |
| **SMS** | Twilio | 緊急通知、服事前一天提醒 | Phase 2 |
| **App 內通知** | Angular 元件 | 所有通知的 in-app 備份 | Phase 1 |

---

## 各渠道設計

> **實作狀態 (2026-06-23)：** Email (SMTP/MailKit) + Line 已於 API 端實作，見
> [docs/superpowers/specs/2026-06-23-notification-service-email-line-design.md](superpowers/specs/2026-06-23-notification-service-email-line-design.md)。
> 本檔早期願景中的 SendGrid/Push/SMS 仍為未來規劃。

### Email (SendGrid)

**觸發時機**

| 事件 | 收件人 | 說明 |
|------|--------|------|
| 年度奉獻收據產生 | 個別教友 | 含 PDF 附件 |
| 歡迎新教友 | 新教友 | 帳號啟用信 |
| 密碼重設 | 帳號持有人 | OTP / Reset Link |
| 服事排班確認 | 當週服事同工 | 每週四自動發送 |
| 系統 Build 失敗 | admin@rolac.org | Jenkins CI 通知 |

**Email 範本要求**
- 雙語（EN / zh-TW），依教友語言偏好發送
- 教會 Logo header
- 手機版 Responsive HTML
- Unsubscribe 連結（行銷類）

---

### Push Notification (Capacitor)

**使用 `@capacitor/push-notifications`**  
後端使用 **Firebase Cloud Messaging (FCM)** 作為推播服務（Android + iOS 共用）。

**推播事件**

| 事件 | 時機 | 內容範例 |
|------|------|----------|
| 服事提醒 | 服事前 2 天 09:00 | "您下週日的敬拜服事提醒" |
| 排班更新 | 立即 | "您的服事排班已更新，請查閱" |
| 新消息公告 | 發佈後立即 | "[公告] 復活節特別聚會" |
| 生日祝福 | 當天 08:00 | 可選，需教友同意 |

**裝置 Token 管理**

```
UserDevice
├── Id
├── UserId
├── DeviceToken       (FCM token)
├── Platform          (ios | android)
├── AppVersion
├── LastSeenAt
└── IsActive
```

- Token 登入時更新，登出時標記 `IsActive = false`
- FCM token 失效時（delivery failure）自動清理

---

### SMS (Twilio)

**使用時機：輔助通知，非主要渠道**

| 事件 | 觸發條件 | 說明 |
|------|----------|------|
| 服事前一天提醒 | 前一天 16:00 | 確保沒裝 App 的同工也收到 |
| 緊急取消通知 | 手動觸發 | 主日緊急狀況（天氣、設備） |
| 新教友歡迎 | 首次建立帳號 | 可選 |

**教友設定**
- 預設 **關閉** SMS，教友自行在個人設定開啟
- 須明確同意才接收（Opt-in 機制）
- 每則 SMS 結尾附 "Reply STOP to unsubscribe"

**Twilio 設定**
```csharp
// appsettings.json（實際值存環境變數）
"Twilio": {
  "AccountSid": "${TWILIO_ACCOUNT_SID}",
  "AuthToken": "${TWILIO_AUTH_TOKEN}",
  "FromNumber": "${TWILIO_FROM_NUMBER}"   // e.g. +1-xxx-xxx-xxxx
}
```

**費用估算（50–100 人教會）**
- 假設 30 人開啟 SMS、每月約 8 次通知
- 30 人 × 8 次 = 240 SMS/月
- Twilio 美國 SMS ~$0.0079/則 → **約 $2/月**

---

## 通知偏好設定（教友端）

教友在 App 個人設定頁面可控制：

```
通知設定
├── Email 通知
│   ├── ✅ 服事排班（必開，不可關）
│   ├── ✅ 重要公告
│   └── ☐ 活動資訊
├── Push 通知
│   ├── ✅ 服事提醒
│   ├── ✅ 排班更新
│   └── ☐ 生日祝福
└── SMS 通知（預設關閉）
    ├── ☐ 服事前一天提醒
    └── ☐ 緊急通知
```

---

## 後端通知服務架構

```csharp
// INotificationService 統一介面
public interface INotificationService
{
    Task SendEmailAsync(NotificationRequest request);
    Task SendPushAsync(NotificationRequest request);
    Task SendSmsAsync(NotificationRequest request);
    Task SendAllAsync(NotificationRequest request);  // 依偏好自動選渠道
}

// NotificationRequest
public record NotificationRequest(
    string UserId,
    string TemplateKey,          // e.g. "roster.reminder"
    Dictionary<string, string> Data,
    NotificationChannel[] Channels
);
```

**排程通知（Hangfire 或 Quartz.NET）**
- 服事提醒：每週六 09:00 掃描下週服事表，批次發送
- SMS 提醒：每週六 16:00 補發 SMS（對已開啟 SMS 的教友）
- 生日提醒：每天 08:00 掃描當天生日教友

---

## 通知語言規則

1. 以教友個人語言偏好為準（`Member.LanguagePreference: en | zh-TW`）
2. 若未設定，預設英文
3. 批次發送（如年度收據）依每人偏好分別產生對應語言的郵件
