103 lines
5.6 KiB
Markdown
103 lines
5.6 KiB
Markdown
# 14. Backend Router — Email, Push, and SMS Notifications
|
|
|
|
meta:
|
|
id: shieldai-unified-restructure-14
|
|
feature: shieldai-unified-restructure
|
|
priority: P1
|
|
depends_on: [shieldai-unified-restructure-11]
|
|
tags: [backend, notifications, email, push, sms, api]
|
|
|
|
objective:
|
|
- Build the tRPC router and service layer for sending notifications across all channels: email (Resend), push (FCM/APNs), and SMS (Twilio). Port logic from `packages/shared-notifications/` into a unified `notifications` router.
|
|
|
|
deliverables:
|
|
- `web/src/server/api/routers/notification.ts` — Notification router:
|
|
- `notification.sendEmail` — `adminProcedure` (or internal service use) sending transactional email
|
|
- `notification.sendPush` — `protectedProcedure` sending push to user's devices
|
|
- `notification.sendSMS` — `protectedProcedure` sending SMS
|
|
- `notification.registerDevice` — `protectedProcedure` registering FCM/APNs token
|
|
- `notification.unregisterDevice` — `protectedProcedure` removing device token
|
|
- `notification.listDevices` — `protectedProcedure` listing registered devices
|
|
- `notification.getPreferences` — `protectedProcedure` getting notification preferences
|
|
- `notification.updatePreferences` — `protectedProcedure` updating preferences
|
|
- `web/src/server/services/notification.service.ts` — Business logic:
|
|
- `sendEmail(to, subject, html, text?)` — via Resend API
|
|
- `sendPush(deviceTokens, title, body, data?)` — via FCM for Android, APNs for iOS
|
|
- `sendSMS(phoneNumber, message)` — via Twilio
|
|
- `registerDevice(userId, token, platform, deviceType)` — save to DB
|
|
- `unregisterDevice(userId, token)` — soft-delete or mark inactive
|
|
- `getPreferences(userId)` — read from DB
|
|
- `updatePreferences(userId, prefs)` — write to DB
|
|
- `web/src/server/services/email.templates.ts` — Email template renderer:
|
|
- Welcome email
|
|
- Alert notification email
|
|
- Password reset email
|
|
- Family invite email
|
|
- Billing receipt email
|
|
- Provider clients:
|
|
- `web/src/server/lib/resend.ts` — Resend client
|
|
- `web/src/server/lib/fcm.ts` — Firebase Admin SDK initialization
|
|
- `web/src/server/lib/twilio.ts` — Twilio client
|
|
|
|
steps:
|
|
1. Install dependencies in `web/`:
|
|
- `resend` (email)
|
|
- `firebase-admin` (push notifications)
|
|
- `twilio` (SMS)
|
|
2. Create provider client files:
|
|
- `resend.ts`: initialize with `RESEND_API_KEY`
|
|
- `fcm.ts`: initialize Firebase Admin with service account JSON
|
|
- `twilio.ts`: initialize with `TWILIO_ACCOUNT_SID` and `TWILIO_AUTH_TOKEN`
|
|
3. Create `web/src/server/services/email.templates.ts`:
|
|
- Each template is a function returning `{ subject, html, text }`
|
|
- Use simple HTML with inline CSS (or a minimal template engine)
|
|
- Include ShieldAI branding (logo, colors)
|
|
4. Create `web/src/server/services/notification.service.ts`:
|
|
- `sendEmail`: call Resend, log result, handle errors
|
|
- `sendPush`: iterate device tokens, call FCM for Android tokens, APNs for iOS tokens (or use Firebase Admin which handles both)
|
|
- `sendSMS`: call Twilio Messages API, validate E.164 phone format
|
|
- `registerDevice`: upsert into `DeviceToken` table
|
|
- `unregisterDevice`: set `isActive = false`
|
|
- `getPreferences` / `updatePreferences`: read/write a `NotificationPreferences` table (add to schema if missing)
|
|
5. Create `web/src/server/api/routers/notification.ts`:
|
|
- Define Zod schemas for all inputs
|
|
- `sendEmail`: restricted to admin or internal service calls
|
|
- `sendPush`: accepts `title`, `body`, `data` payload; sends to all active user devices
|
|
- `sendSMS`: accepts `phoneNumber`, `message`
|
|
- Device registration/unregistration procedures
|
|
- Preference get/update procedures
|
|
6. Wire router into `web/src/server/api/root.ts`.
|
|
7. Write unit tests with mocked providers.
|
|
|
|
steps:
|
|
- Unit: `sendEmail` calls Resend with correct parameters
|
|
- Unit: `sendPush` iterates tokens and calls FCM
|
|
- Unit: `sendSMS` validates E.164 format before calling Twilio
|
|
- Unit: `registerDevice` creates DeviceToken record
|
|
- Unit: `unregisterDevice` marks token inactive
|
|
- Integration: `notification.registerDevice` persists token to DB
|
|
|
|
acceptance_criteria:
|
|
- [ ] Email can be sent via Resend with branded templates
|
|
- [ ] Push notifications can be sent to registered Android and iOS devices via FCM
|
|
- [ ] SMS can be sent via Twilio to valid E.164 numbers
|
|
- [ ] Device tokens can be registered and unregistered per user
|
|
- [ ] Notification preferences are persisted and respected (e.g., user can disable SMS alerts)
|
|
- [ ] All provider errors are caught and logged without crashing the app
|
|
- [ ] Email templates include ShieldAI branding
|
|
|
|
validation:
|
|
- Send a test email via Resend to your own address and verify receipt
|
|
- Register a test device token and send a push (use Firebase Console or API)
|
|
- Send a test SMS via Twilio (use test credentials for free)
|
|
- Run `cd web && pnpm test` for notification service tests
|
|
|
|
notes:
|
|
- Reference legacy: `packages/shared-notifications/src/`, `packages/api/src/routes/notifications.routes.ts`
|
|
- For FCM, Firebase Admin SDK requires a service account JSON. Store path in `FIREBASE_SERVICE_ACCOUNT_PATH` env var.
|
|
- For APNs, Firebase Admin can proxy to APNs if configured correctly. Alternatively, use `apn` npm package for direct APNs integration.
|
|
- Twilio test credentials (`TWILIO_TEST_*`) can be used for integration tests without sending real SMS.
|
|
- Resend has a generous free tier (100 emails/day) perfect for development.
|
|
- Consider adding a `notification.queue` table for reliable delivery (retry failed sends). This can be a follow-up task.
|
|
- The `NotificationPreferences` model may need to be added to the Drizzle schema if not already present. Add it as part of this task.
|