Skip to content

Email: PRD ​

Domain Notifications · function email · mã story NOTIF-EMAIL · SDD · Tests · trang cũ platform/emails

Mục tiêu ​

Mọi email của hệ đi qua một cổng, một nhà cung cấp (Cloudflare Email Service), một khung giao diện; không lượt gửi nào im lặng.

User story ​

NOTIF-EMAIL-01: một cổng gửi ​

Là kỹ sư, tôi muốn mọi domain gửi email qua sendEmail()/fireEmail(), để mọi lượt gửi được ghi sổ, có ảnh theo dõi và bản sao kiểm tra giống nhau.

  • Given mã domain mới cần gửi email When viết env.EMAIL.send trực tiếp Then vi phạm LUẬT EMAIL; đường đúng là sendEmail().

NOTIF-EMAIL-02: mã đăng nhập luôn tới ​

Là người dùng, tôi muốn nhận mã đăng nhập ngay khi yêu cầu, để vào được tài khoản.

  • Given tôi nhập email ở màn đăng nhập When POST /api/user/auth/request-codeThen nhận thư login_code (mã 6 số, 10 phút, tối đa 5 mã/giờ); gửi hỏng thì API trả 503, không giả vờ thành công.
  • Given tôi đã huỷ nhận thư gắn kết When yêu cầu mã Then mã vẫn tới (thư giao dịch không bao giờ bị chặn).

NOTIF-EMAIL-03: mã đăng nhập không có bản sao ​

Là người vận hành, tôi muốn login_code không bao giờ sinh bản sao kiểm tra, để hộp thư của tôi không chứa mã còn hiệu lực của người khác.

  • Given EMAIL_AUDIT_COPY.mode là bất kỳ giá trị nào When gửi login_codeThen không có bản sao.

NOTIF-EMAIL-04: biên nhận ở mọi đường kích hoạt ​

Là người vừa trả tiền, tôi muốn nhận biên nhận dù đơn được duyệt bằng đường nào.

  • Given tài khoản được nâng Master qua webhook ngân hàng, workflow khớp giao dịch, mã 4 số hay admin duyệt tay When kích hoạt xong Then nhận membership_activated (gửi từ activateToMaster(), hàm mọi đường đều gọi).

NOTIF-EMAIL-05: nhắc sự kiện đúng một lần ​

Là người đã đăng ký sự kiện, tôi muốn được nhắc trong 24 giờ trước giờ bắt đầu, đúng một lần.

  • Given cron chạy mỗi giờ trong 24 giờ trước sự kiện, và hai lượt có thể chồng nhau When vòng nhắc chạy Then mỗi người nhận một thư (khoá claimScheduledRun theo giờ + lọc theo sổ gửi, bỏ qua bản sao kiểm tra).

NOTIF-EMAIL-06: tối thiểu một thư gắn kết mỗi ngày, không trùng ​

Là thành viên, tôi muốn nhận nhiều nhất một thư gắn kết mỗi ngày và chỉ khi có lý do.

  • Given cron 0 1 * * * (08:00 giờ VN) chạy hai lượt chồng nhau When vòng gửi hằng ngày chạy Then chỉ một lượt giành được dòng daily_email_runs(run_date); người đã nhận bất kỳ thư nào hôm nay bị bỏ qua; không hợp cảnh nào thì không gửi.
  • Given người vận hành đặt platform_settings.daily_email_enabled = 'false'When cron chạy Then không gửi gì, không cần deploy.
  • Given Nhịp thư ở chế độ liveWhen cron 0 1 * * * chạy Then daily.ts không gửi gì (orchestratorOwnsDaily()): khe "một thư gắn kết mỗi ngày" thuộc về Nhịp thư, và bốn loại của vòng này là ứng viên trong đó (COMM-ORCH-12). Ở preview hay off vòng này chạy như cũ.

Từ 14.10.2026 phần lớn story này do Nhịp thư đảm nhận khi bật live: một dòng kế hoạch mỗi địa chỉ mỗi ngày (khoá chính (plan_date, email_key), gộp cả người chỉ có ở legacy_users), chọn thư theo giá trị kỳ vọng thay vì thứ tự cố định, 18 loại thay vì 4, và xem trước 24 giờ tới hai hộp thư duyệt. Tuỳ chọn nhịp và nhóm ở trang có chữ ký (/api/system/email/prefs) được cổng gửi thi hành cho cả thư của daily.ts. Nút "Dừng mọi thư gắn kết" ở admin tắt cả hai vòng cùng lúc. Xem COMM-ORCH.

NOTIF-EMAIL-07: khung giao diện đồng nhất, đọc được trên điện thoại và Outlook ​

  • Given một thư bất kỳ When mở ở bề ngang 375px Then không tràn ngang; có meta viewport; khối màu có bgcolor song song; không hex 8 ký tự; primary chỉ ở nút.

NOTIF-EMAIL-08: báo cáo cho người vận hành ​

Là người vận hành, tôi muốn thư tổng kết ngày và tuần về email đã gửi và được mở.

  • Given 08:00 giờ VN When cron chạy Then nhận ops_daily_report; thứ Hai thêm ops_weekly_report; mỗi loại đúng một lần nhờ claimScheduledRun.

NOTIF-EMAIL-09: tên người nhận trên tiêu đề ​

  • Given tên đầy đủ Hien Nguyen hoặc Đặng HồngWhen dựng tiêu đề Then gọi Hien và Hồng, không gọi bằng họ; tên rỗng hoặc dài quá 20 ký tự thì dùng tiêu đề dự phòng.

Tài liệu nội bộ nền tảng Conan School.