Telegram Bot PRD
x3 TàiChính — Challenge Bot Platform — Go + PostgreSQL + Redis + Cloudflare R2 + Webhook
01Tổng Quan & KPI
Bot Telegram tự động hóa 90% quy trình vận hành lớp 21 Ngày Thử Thách Tài Chính — onboarding học viên sau khi cọc, nhắc nhở nhiệm vụ hàng ngày/tuần, thu thập bằng chứng ảnh, tính điểm/streak, và hoàn tiền cọc cuối khóa.
Go (Gin/Fiber)
PostgreSQL
Redis
Cloudflare R2
Telegram Webhook
SePay
90%
Automation
Không cần admin can thiệp
<500ms
Response Time
User message → bot reply
0
Reminder bỏ sót
Mỗi lớp / khóa học
95%
Onboarding Rate
Cọc → join group <24h
80%
Daily Completion
Submit đúng ngày
02Kiến Trúc Hệ Thống
Ctrl/Cmd + scroll = zoom • Kéo = pan • Nút ↺ = fit
...
Key Decisions: 1 bot — multi-class routing qua
telegram_group_id • Webhook, không polling • Session key = (user_id, bot_token) TTL 30ph • Snapshot reward_amount vào TaskLog ngay lúc tạo (immutable ledger)
03Bot Identity & Commands
Bot Identity
- Username:
@x3taichi_bot - Backup:
@thuthachx3_bot - Display: "x3 TàiChính — Bot Thử Thách"
- Avatar: logo 256×256px
- Description: "Đồng hành 21 ngày tự do tài chính"
Callback Schema
daily_done:{tasklog_id}daily_notyet:{tasklog_id}confirm_link:{enrollment_id}zoom_attend:{tasklog_id}admin_approve:{tasklog_id}- HMAC signed — chống tamper
| Command | Mô Tả | Ai Dùng |
|---|---|---|
/start <code?> | Khởi tạo / liên kết enrollment qua deep-link | Học viên |
/today | Xem nhiệm vụ hôm nay + status + reward | Học viên |
/diem | Tổng hợp: streak, earned, level tích lũy | Học viên |
/lop | Thông tin lớp: lịch zoom, group link | Học viên |
/help | Hướng dẫn dùng bot | Tất cả |
/huy | Thoát flow hiện tại — reset session | Học viên |
/admin | Menu quản trị (chỉ admin lớp) | Admin |
/broadcast <msg> | Gửi tin nhắn toàn lớp | Admin |
04Onboarding Flow
State machine — liên kết tài khoản Telegram với enrollment
...
Câu hỏi mở #5: Invite link expire 24h. Học viên cọc sớm nhưng /start sau 3 ngày → link đã chết. Cần flow re-generate link on-demand khi user /start lại.
Deep-link format:
t.me/x3taichi_bot?start=ENR_ABC123 — landing page tự động inject code vào URL sau khi payment callback.
05Daily Task Flow
Sequence — Luồng chính hàng ngày
...
Retry & Escalation Timeline
T+0
Initial
send_reminder
→
T+30m
Retry 1
PENDING → resend
→
T+60m
Retry 2
resend lần 2
→
T+20h
Phone Call
Vbee fallback
(Phase 2)
(Phase 2)
→
T+22h
Cutoff
MISSED nếu PENDING
Photo Proof — R2 Upload
1
getFile()
Download từ
Telegram CDN
Telegram CDN
→
2
Compress
→ WebP <50KB
max 600px
max 600px
→
3
Upload R2
private bucket
key: class/enr/date
key: class/enr/date
→
4
Save URL
proof_url → DBTaskLog = DONE
Edge Cases
| Case | Xử Lý |
|---|---|
| User gửi text thay vì click nút | "Vui lòng bấm nút ở trên 👆" |
| User gửi nhiều ảnh | Lấy ảnh đầu, ignore còn lại + reply confirm |
| User submit 2 lần cùng task | "Bạn đã hoàn thành rồi! +50k đã ghi nhận" |
| Submit task ngày trước | Reject: "Hôm nay là ngày X, bạn đang xem ngày Y" |
| Telegram ảnh fail download | Retry 3 lần → admin queue |
| R2 upload fail | Retry 2 lần → lưu file_id tạm, re-upload async |
| Ảnh >20MB (Telegram limit) | Telegram tự reject → bot catch MediaTooLarge |
| User gửi ảnh qua group | Bot ignore — chỉ nhận proof trong private chat |
06Weekly Task & Zoom Check-in
Weekly Task — Dispatch Thứ 5 12:00
Luồng chính
- Bot gửi video bài học YouTube + link Google Form
- Học viên nộp link bài viết Facebook (public)
- Admin review queue (SLA 24h)
- Auto-accept form khi Google webhook về (Phase 2)
- Sau duyệt:
+50kreward → thông báo học viên
| Thời Điểm | Action |
|---|---|
deadline − 12h | Nhắc "Còn 12h, gửi gấp!" |
deadline − 1h | Nhắc lần cuối |
deadline + 0 | Status = LATE (cho nộp 24h) |
deadline + 24h | Status = MISSED |
Zoom Check-in Flow
Trước Zoom 11h (22:00 đêm trước)
- Bot gửi nhắc nhở + nút "Tôi sẽ tham dự"
- Click → xác nhận phone đã đăng ký
- Confirm → nhận link Zoom lúc 04:00 sáng
- Vắng mặt =
−50kvia PaymentLog
Sau Zoom: Đối chiếu
Match → TaskLog DONE (reward = 0, không phạt)
Không match → TaskLog MISSED → trừ 50k
participant_phone ↔ enrollment.phoneMatch → TaskLog DONE (reward = 0, không phạt)
Không match → TaskLog MISSED → trừ 50k
07Scheduler Jobs
| Job | Cron | Hành Động |
|---|---|---|
daily_reminder_dispatch | 08:00 mỗi ngày | Tạo TaskLog(DAILY) + gửi reminder toàn lớp active |
daily_reminder_retry | Mỗi 30ph (08:00–22:00) | Resend cho TaskLog PENDING |
daily_call_trigger | 20:00 mỗi ngày | Trigger Vbee phone call (Phase 2) |
weekly_task_dispatch | 12:00 T5/T7/T3 | Gửi video bài học + link form |
weekly_deadline_check | Mỗi 1h | Mark LATE / MISSED khi quá deadline |
zoom_reminder | 22:00 đêm trước + 04:00 sáng | Nhắc + gửi link Zoom |
group_celebration | Mỗi 60ph (08:00–22:00) | Group message tổng hợp hoàn thành — skip nếu 0 người mới |
payment_reconcile | 23:59 mỗi ngày | Sync PaymentLog từ TaskLog DONE / MISSED |
class_complete_check | 23:59 ngày cuối lớp | Auto-trigger REFUND nếu đủ điều kiện |
Implementation: Go
ticker + time.AfterFunc, lưu state vào Redis. Distributed lock nếu scale nhiều instance.
08Session & State Redis
Redis Key Schema
session:{user_id}:{bot_token}
state: WAITING_PHOTO
| WAITING_FB_LINK
| IDLE
context: {task_log_id, retry_count,
last_message_id}
TTL: 30 phut
ratelimit:{user_id} → max 30 msg/min
ratelimit:group:{group_id} → max 20 msg/min
queue:fb_review → Redis list
celebration:lock:{class_id}→ TTL 60 phut
State Transitions
IDLE
├─ /start → WAITING_LINK_CONFIRM
│ └─ IDLE (success)
├─ /today → IDLE (info only)
└─ click DA_LAM → WAITING_PHOTO
├─ photo received → IDLE
├─ /huy → IDLE
└─ timeout 30m → IDLE
WAITING_FB_LINK
├─ URL pasted → IDLE (queue review)
├─ /huy → IDLE
└─ timeout 30m → IDLE
Anti-spam group: Max 1 message/giờ/group • Skip nếu cùng nội dung trong 2h • Tag username (không tag full name) — privacy
09Bảo Mật & Reliability
Security
| Mối Nguy | Mitigation |
|---|---|
| Webhook spoofing | Verify Telegram X-Telegram-Bot-Api-Secret-Token |
| Admin escalation | Bảng class_admins(class_id, telegram_id) |
| User impersonation | Match telegram_id ↔ enrollment.telegram_id |
| SQL injection | pgx parameterized queries 100% |
| Bot token leak | Lưu env var, rotate khi nghi ngờ |
| Callback tamper | HMAC-SHA256 signature trên callback data |
| Group join unauth | Invite link per-enrollment, expire 24h, single-use |
Rate Limiting & Reliability
| Limit / Failure | Strategy |
|---|---|
| 30 msg/sec/bot (Telegram) | Token bucket golang.org/x/time/rate |
| 20 msg/min/group | Per-group bucket |
| >30 msg/min/user flood | Auto-ignore + warning một lần |
| Webhook 5xx | Telegram retry exp, alert >100 fail/h |
| DB pool exhaust | pgx max=20, queue timeout 5s |
| Redis down | Degrade stateless — chấp nhận user gõ lại |
Logging: Mọi message bot ↔ user →
bot_message_log (Postgres) • Lỗi server → Sentry • Audit admin actions: ai review FB link nào
10Admin Panel
Dashboard Realtime
Tỷ lệ hoàn thành lớp, streak top, daily active enrollments
Queue Duyệt FB Link
Review từng bài với nút Duyệt / Reject / Xem. Counter hiển thị số chờ. SLA 24h.
Danh Sách Học Viên
Trạng thái, streak, số tiền tích lũy, link Telegram của từng học viên
Broadcast Cả Lớp
/broadcast <msg> — gửi tới toàn bộ active enrollment trong lớpCan Thiệp Khẩn
Học viên không phản hồi >3 ngày liên tiếp, cần phone call thủ công
Config Lớp
reminder_interval_min, cutoff_hour, reward_amount, lịch zoom
Metrics Prometheus:
bot_message_received_total, task_completion_rate{class,task_type}, reminder_response_time_seconds (histogram), admin_review_queue_depth — expose /metrics
11Phase Plan
P0 — MVP
Tuần 1–2
- Webhook + /start onboarding
- DAILY reminder + photo proof
- Reward calc + streak
- Group celebration
- Admin /broadcast
P1 — Core
Tuần 3–4
- WEEKLY flow + FB queue duyệt
- ZOOM check-in
- Admin dashboard web (read-only)
- Prometheus + Grafana
P2 — Sau MVP
Khi có ROI
- Phone call fallback (Vbee)
- Google Form auto-accept
- AI proof moderation (Gemini)
- Multi-bot per class
12Testing Strategy
| Layer | Scope | Công Cụ |
|---|---|---|
| Unit | FSM transitions, reward calc, snapshot logic, HMAC verify | Go testing |
| Integration | Telegram webhook → DB write end-to-end | testcontainers Postgres + Redis |
| Bot Interaction | Gửi message thật qua staging bot | gotgproto test client |
| Load | 1000 webhook/s — đo p99 latency <500ms | k6 |
| Chaos | Kill Redis 30s, Postgres reconnect, Telegram 5xx | Manual / Chaos Monkey |
| Manual | Daily/weekly/zoom full flow, edge cases, timeout, retry | Staging environment |
Câu hỏi mở: Bot down lúc 08:00 (giờ vàng) → cần backfill reminder? Queue persistent (Redis Streams) hay chấp nhận mất? Anti-cheat ảnh proof: perceptual hash so sánh 21 ngày?