Appearance
Type Deep Dive — Campaign Lifecycle And Publishing
1. Bức tranh tổng
Campaign lifecycle của lucky-shaking đang đi qua ba đường khác nhau:
- create mới bằng nested insert trực tiếp trên Hasura
- update campaign qua action
updateGamification - change status qua action
changeGamificationStatus
Ngoài ra còn có đường thứ tư là scheduler auto-end campaign hết hạn.
2. Create / Edit Flow ở FE
CampaignCreateUpdate.tsx là shell stepper cho:
- general info,
- gifts,
- UI assets,
- notifications.
Điểm quan trọng:
- create và edit dùng chung component,
- create có thể chọn save draft hoặc publish ngay,
- edit mode giữ snapshot ban đầu để detect dirty state.
3. Insert Path
Khi tạo mới, FE build mutationObject rồi gọi insert_gamification_one.
Rule đáng chú ý:
- nếu mode là
draftthì setstatus = gf_status_draft, - nếu không, insert thẳng
status = gf_status_published(CampaignCreateUpdate.tsx:1058-1061).
Nested create gồm:
missionsgift_configsfilesnotification_configs
Nghĩa là campaign mới không cần publish action riêng để xuất hiện ở trạng thái phát hành.
4. Update Path
Edit mode gọi action updateGamification(data: ...), không update thẳng Hasura.
Backend rule:
- chỉ cho update campaign ở
draft,published,paused(update_gamification.go:116-123) - nếu đã
published/paused, backend coi làisPublished = true - khi
isPublished = true, trườngfromkhông được đổi (update_gamification.go:189-205)
Update action còn chia rule nested:
- missions: soft delete / reopen theo
condition - gift configs: draft và published có handling khác
- notification configs: delete old -> insert new
- files: delete old -> insert new
5. State Machine Action
changeGamificationStatus map action sang target status như sau:
| Action | Từ trạng thái | Sang trạng thái |
|---|---|---|
action_publish | draft | published |
action_stop | published | paused |
action_continue | paused | published |
action_end | non-draft | ended |
action_cancel | logic check còn lỏng | cancelled |
FE popup action đang phát action_publish, action_stop, action_continue, action_end, action_cancel trực tiếp (CampaignActionPopup.tsx:31-45).
6. Copy Flow
duplicateGamification:
- fetch source campaign cùng missions/gift configs/noti/files,
- tạo ID mới,
- đặt tên
"Bản sao của ...", - ép status mới về
draft, - reset time window sang
now -> now + 30 ngày, - clone toàn bộ nested data (
duplicate_gamification.go:124-236).
Copy vì vậy là đường tạo campaign mới từ template sống, không phải snapshot read-only.
7. Scheduler Auto End
end_expired_gamification:
- query campaign
publishedmàto < now, - update status sang
ended, - đồng thời set
to = now(end_expired_gamification.go:28-76).
Điều này có nghĩa:
- timestamp
toban đầu có thể bị ghi đè khi scheduler end, - nếu dùng
tovừa như “planned end” vừa như “actual end”, semantics sẽ bị trộn.
8. QA Focus
- Tạo campaign draft rồi publish bằng action menu.
- Tạo campaign và publish ngay từ create flow, bỏ qua action menu.
- Sửa campaign đã published để xác minh
fromkhông đổi. - Copy campaign có missions, gifts, notifications và files để xác minh clone đủ nested data.
- Pause -> resume -> end -> cancel để xác minh state transitions và guard.
- Chạy giả lập scheduler với campaign quá hạn để xác minh auto-end và việc rewrite
to.
9. Rủi ro / Findings kỹ thuật
| ID | Mức | Finding |
|---|---|---|
| LC-F01 | P1 | Publish không tập trung vào một engine; create flow có thể insert thẳng published, nên audit hoặc analytics chỉ nhìn action publish sẽ thiếu case. |
| LC-F02 | P1 | Nhánh cancel trong changeGamificationStatus có comment TODO và check chưa chặt, cho thấy business rule chưa được khóa dứt điểm. |
| LC-F03 | P2 | Scheduler auto-end đang rewrite cả to, nên field này mang nghĩa “actual end” hơn là “configured end” sau khi cron chạy. |