Email: PRD
Domain Notifications · function
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.sendtrự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.modelà bất kỳ giá trị nào When gửilogin_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á
claimScheduledRuntheo 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òngdaily_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 cron0 1 * * *chạy Thendaily.tskhô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). Ởpreviewhayoffvò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óbgcolorsong song; không hex 8 ký tự;primarychỉ ở 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êmops_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 NguyenhoặcĐặng HồngWhen dựng tiêu đề Then gọiHienvà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.