Files
goodgo-platform/apps/web/components
Ho Ngoc Hai 603ef7db86 feat(notifications): Zalo OA v3 OAuth account linking + sendTemplate — TEC-3065
- Add `ZaloAccountLink` Prisma model (`zalo_account_links` table) with AES-256-GCM
  encrypted access/refresh tokens and `lastInteractAt` for the ZNS 24-hour window.
- Migration: 20260421010000_add_zalo_account_links
- Expand `ZaloOaService`:
  - `getOAuthAuthorizeUrl(state)` — OA consent redirect
  - `handleOAuthCallback(userId, code)` — token exchange, UID resolution, encrypted upsert
  - `sendTemplate(userId, templateId, params)` — resolves linked UID, checks 24h window,
    auto-refreshes near-expiry tokens, delegates to ZNS
  - `recordInteraction(zaloUserId)` — updates `lastInteractAt` on follow/message webhooks
  - `unlinkAccount(userId)` — removes link row
  - Legacy `sendMessage(dto)` retained for backwards compat
- New `ZaloOaLinkController` (notifications module, `/auth/zalo-oa`):
  - GET  /auth/zalo-oa/link      — initiate linking (JWT-guarded)
  - GET  /auth/zalo-oa/callback  — OAuth callback (rate-limited)
  - DELETE /auth/zalo-oa/link    — unlink (JWT-guarded)
- Webhook controller: record interaction on follow/user_send_text, check OA link
  table before legacy OAuthAccount fallback
- Env vars: ZALO_OA_APP_ID, ZALO_OA_SECRET, ZALO_OA_REDIRECT_URI, ZALO_OA_TOKEN_KEY
- Tests: updated webhook spec + new ZaloOaService spec covering OAuth flow, encryption,
  token refresh, interaction window, and unlink

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-21 04:49:35 +07:00
..