📜 Cập nhật gần đây

Những gì chúng tôi vừa phát hành. Kaching được cập nhật nhiều lần mỗi tuần, mọi thay đổi đều được theo dõi công khai trên git.

ops switch bot webhook + menu button to prod URLs
2026-05-21

Pre-launch ops blocker fix — caught during session 497 audit before any user-facing launch. Three production gaps that would have broken first-user experience: 1. **Bot webhook pointed at STAGING worker** — @kaching_777_bot was delivering all updates to `kaching-bot-webhook-staging.workers.dev` which talks to staging D1 (35 bonuses, test data). New users opening the bot would have hit a

254d814
fix bot-webhook deploy:prod uses bare wrangler deploy
2026-05-21

bot-webhook wrangler.toml top-level IS the prod config (matches mini-app-api + collector-cron pattern). The `--env prod` flag broke prod deploy because there's no `[env.prod]` block — only `[env.staging]` exists at the bottom. This caused all of Wave-6 through Wave-11 to deploy successfully to staging but silently fail on prod (bot-webhook only; the other 3 services were fine). Users on prod were

5ef5c8d
feat streak-break warning surfaces Streak Freeze CTA
2026-05-21

streak-break-warning push fires when a user's streak ends in ~1h. The previous copy just said "open /today to keep it alive" — leaving the Stars-sink product (Streak Freeze, 25⭐ = 1 missed-day save) invisible at the exact churn moment. New copy adds the Streak Freeze option as a clear alternative: "Open /today (free) — or buy 🛡️ Streak Freeze for 25⭐ to skip a day." 5 locales (en / ja / vi / zh

625a9f9
feat ad-CTA polish — front-load reward in quest ad button
2026-05-21

The "📺 Skip via ad" button copy made the rewarded-video path look like a chore. New copy puts the reward FIRST: "📺 Get 50⭐ now (watch ad)" — explicit value exchange instead of vague "skip". UI: 4 ad-flow strings now localized (was hardcoded English) - miniapp-quest-ad-btn = "📺 Get {$reward}⭐ now (watch ad)" - miniapp-quest-ad-loading = "📺 Loading ad…" - miniapp-quest-ad-done = "✓ {$reward}⭐ e

1f165b3
feat ship real SVIP /today personalization signal
2026-05-21

Wave-8 retracted the "AI personalized rec" claim because no code actually delivered a personalized ranking. Wave-9 ships the real signal so we can honestly re-add the claim. NEW: bot-webhook personalizeForSvip(bonuses, userId, env) - Inputs: ev_score-sorted candidate list + user id - Reads last 30d of affiliate_clicks for this user (1 D1 select, fail-soft) - Derives: - claimed_operator_ids: Set

89d4660
docs LOCK closure — polish-loop monetization 9.0/10 (4 iter)
2026-05-21

Iter ledger: 5.6 → 8.2 → 8.2 verify → code apply → 9.0/10 LOCK ✅ Per-critic final: Core 9.0 / Revenue 9.0 / Spec-Code 9.5 / UX 8.5 / OpSafety 9.0 All 5 BLK closed; full ledger in closure doc. Upstream skill fixes (in dotfiles-private LIVING F-W21-008 + product-genesis Phase 0 Q3/Q4/Q5 HARD follow-ups): future projects catch this class of "做到最後發現付費點不好" at design time before code ship. Post-LOCK o

e8e3e91
feat honest copy + cashback-visible push + plain-text mode
2026-05-21

Two-track polish: (a) push notifications now i18n-bundled + show per-user cashback (b) all hollow-promise copy retracted — only list code-enforced perks PUSH ENGINE — i18n + per-user cashback in every push body - packages/push-engine: imports translate from @kaching/i18n + rateForTier from @kaching/cashback-engine. renderDailyText / renderFomoText / renderRealtimeGreenText all switch from

2352659
feat real-time GREEN alert + visible cashback + shop polish
2026-05-21

Polish pass to make the value proposition concrete at every decision moment: bot card, /me page, /subscribe shop, quest reward. PUSH ENGINE — VIP-only real-time GREEN alert - packages/push-engine: new runRealtimeGreenAlert(env) — queries fresh bonuses (verdict=GREEN, scraped_at >= now-6h), anti-joins push_events for idempotency under collector double-runs, fans out to VIP/SVIP cohort by cou

c88d2c0
docs reconcile Channel 3 ad revenue formula (iter-3 follow-up)
2026-05-21

Iter-3 commit f740e40 missed this file (Read-first error). Now applied: 19-cost-model.md § 4 Channel 3 (Ad serving): - Old: 50% MAU × 2 ad/day × $0.01 = ~$13k/mo (abstract placeholder) - New: GigaPub $1.83 CPM × 50% MAU × 5 cap × 30day / 1000 = ~$2.75k/mo rewarded at 200k MAU Mature - Subtotal revised: ~$20k/mo → ~$10k/mo (honest conservative) - Total Mature Revenue: $99k → $89k (down 10%) - Ne

a34d8c9
docs polish-loop iter-3 — fix 3 doc drift items + revenue formula reconcile
2026-05-21

Per polish-loop iter-2 report (8.2/10, below 8.5 LOCK). 3 doc drift items: 1. 32-miniapp-uiux Invite tab (line 348-349, 370): - VIP perks listed were stale (獨家 partner bonus / Bonus 早 2hr) — these were never the code-shipped perks. Replaced with KCH-F-102 real perks (10% cashback / 3× push / ad-free). - Subscribe CTA stale: "300 Stars/wk" → "180 Stars/月" (reconciled to KCH-F-

f740e40
docs BLK-5 propose-only — handleSubscriptionPaused production code patch awaiting auth
2026-05-21

Per polish-loop iter-1 BLK-5 + memory feedback_no_silent_destruction.md: production code changes require explicit user authorization. This doc contains: - Full proposed diff for packages/stars-payment/src/index.ts (new export handleSubscriptionPaused — ~40 lines) - D1 schema check (paused_at column verify, migration if needed) - Webhook router update for apps/bot-webhook/src/index.ts - Test sce

3ecfb1d
docs polish-loop iter-1 — fix 4 BLK monetization gaps
2026-05-21

Per polish-loop product-grade agent report (5.6/10 warning band, 5 BLK). 4 doc patches applied this iter; BLK-5 code fix proposed separately. BLK-1 (core-experience-loop 4/10): No dedicated subscription screen/paywall → NEW docs/design/35-monetization-storyboard.md (per-trigger [前/當/後] + 6 entry surface + 3 conversion benchmarks + alternative-choice impact + stream priority resolved: KC

41adcee
docs retro Phase 0 monetization interview — Kaching post-launch audit
2026-05-21

Per LIVING F-W21-008 (Kaching 2026-05 retrospective): Phase 0 was skipped when project started. Per spec-retrofit Phase 0' pattern, inferring answers from existing design docs + code, then aligning against new Phase 0 Q3/Q4/Q5 HARD follow-ups to find design depth gaps. 3 root causes for "做到最後發現付費點+廣告點不好": 1. 🔴 Backend flow complete but UX storyboard missing (no [前/當/後] for triggers) 2. 🔴 3 mone

4eafa43
feat Wave-6 — three real subscription perks ship together
2026-05-21

Operator pushed the value-prop question hard: '為什麼用戶要看廣告,為什 麼要付費,你能說服你自己嗎?' Audit found: subscription was an empty flag — vip_tier='vip' stored in D1 but NO code read it. Free + VIP got identical experience: same cashback rate (flat 5%), same daily push (1×), same 'Skip via ad' CTAs. I could not honestly recommend the sub. This commit ships three real, code-enforced perks together. Each gated by

8a2dac0
fix F-11 client API base injection + F-12 swap _adsgram → _gigapub
2026-05-21

Operator: '看廣告目前是什麼模式?' Honest audit found TWO critical bugs that meant Mini App client side was largely broken since day 1. F-11 (CRITICAL): window.__API_BASE__ never injected - _api.js fell back to https://api.kaching.gg which is NXDOMAIN - Every Mini App in-Telegram API call (quest/claim/streak/me/badges/ cashback/ad-request/ad-completion) silently died - Fix: Layout.astro injects 'window.__

926d57a
feat /internal/trigger-push + /internal/test-push + e2e push verified
2026-05-21

Operator: '信息推送要正常' (push notifications must work) — verified end-to-end on staging Telegram. New ops endpoints in bot-webhook (Bearer INTERNAL_API_TOKEN gated): - POST /internal/trigger-push?task=daily — fires runDailyPush manually (still honors isLocalHour cohort filter — only fires for users in their 8am local window) - POST /internal/trigger-push?task=fomo — fires runFomoPush manually -

379ca22
polish Stars sub auto-renew + bonuses page real data + no fake stats
2026-05-21

Operator: '追求完美,確保所有都完成' — pursue perfection, all features verified. Deep dive surfaced 3 more real bugs + 1 mock smell. F-Stars (CRITICAL): Stars 'subscriptions' were one-time charges packages/stars-payment/src/createInvoice missed subscription_period parameter per Bot API 7.7+. Telegram saw the invoice as one-time digital good not recurring sub. User paid 180⭐ → 30 days → nothing. Fix:

8c1b526
polish Wave-2 — F-6 today verdict+order, all getUserLang sites, smoke green
2026-05-21

Operator: '繼續修,追求完美' (continue, pursue perfection). All Wave-1 queued items shipped + live-verified in zh-Hant via Telegram Web. F-6 — /today now correct - bot.command('today'): ORDER BY desc(ev_score) — was returning insertion-order top-3 which on staging happened to be 3 RED zero-EV traps. Now surfaces GREEN/YELLOW/RED in EV-desc order. - card-line FTL × 5 locales: add {$verdict} param so e

e7b3dc0
fix user.lang honored across bot handlers + bundle rebuild + deploy:staging branch fix
2026-05-21

Staging smoke test 2026-05-21 found 8 bugs. This commit lands 4 in-session fixes; 4 remain queued. Fixed (this commit): F-1 i18n bundle staleness packages/i18n/src/bundle.generated.ts was 2026-05-20 00:43; iter-7/8 FTL edits never re-bundled. translate() returned empty for any new key → ctx.reply(empty) silently rejected by Telegram. Bundle now regenerated (262 keys × 5 locales). F-3 dep

10de914
docs v2.1 — N-bot future architecture appendix
2026-05-21

Per operator question: can a second formal bot point to same content backend? Can staging bot be promoted to another prod? Answer: yes. Appendix documents the path; deferred to Phase 6+ (not blocking Phase 3 single-bot cutover). Sections: - Why N-bot is well-supported (Telegram user_id global, etc.) - 3 code changes (env vars + webhook routing + schema migration 0010) - Push routing pseudocode (r

2e7fbdd
docs v2 — full-replacement strategy with mars2049.online as canonical domain
2026-05-21

Operator pivot 2026-05-21: - User accepts full brand swap (was: worried about losing 10-20k users by changing name). Original team unreachable → no chat_id list will arrive. - Goal: leverage every existing asset, replace everything else. Discovery delta (over v1): - `mars2049.online` is operator-owned (GoDaddy, exp 2027-03), DNS already on Cloudflare (brady.ns + iris.ns). 1.7 years runway, ze

b386c7d
docs inventory all Kaching Keychain entries
2026-05-21

Per operator request: sync all records / passwords / knowledge (including ad marketing config) to Keychain; produce single index doc. Added 17 operational references to Keychain alongside the 11 true-secret entries already there: True secrets (11): - Cloudflare API Token (pre-existing) - kaching-bot-token (legacy staging) - kaching-mars2049-bot-token (Mars2049 prod) - kaching-bot-webhook-secret

c4f10e3
docs Mars2049 → Kaching bot migration transition plan
2026-05-21

Discovery phase complete (read-only; no Telegram-side or worker-side changes made). Captured via Bot API + @BotFather UI inspection through Chrome MCP. Token + old webhook URL stashed in Keychain only. Key findings (legacy state): - Bot id 7949511493, username @Mars2049_Bot, display "Mars2049_Bot" - has_main_web_app: true; menu button URL = https://mars-launch.miniapp.mobi/ with label "Play"; s

934f540
feat client-side reward completion + dashboard config wired
2026-05-21

Pulled from operator's GigaPub partner dashboard (app 760): - BLOCK_ID = "main" (the single Active placement in app 760) - PROJECT_ID = 760 (the app id, used by client SDK script tag) - Integration model per docs.giga.pub/integration-guide.html: pure client- side reward. `<script src="https://ad.gigapub.tech/script?id=760">` loads SDK; `window.showGiga('main').then()` fires after user watche

47ca995
feat swap Adsgram+Monetag → GigaPub (single provider)
2026-05-21

User direction: actual ad provider is GigaPub, not Adsgram/Monetag (which were design-doc placeholders we never signed up for). Code changes: - packages/ad-mediation/src: AdEnv now exposes GIGAPUB_BLOCK_ID + GIGAPUB_HMAC_SECRET (was ADSGRAM_* + MONETAG_*). AdNetwork type union is just 'gigapub' now. requestAdSlot routes to gigapub when block id is set, no_fill otherwise. handleCompletion no

2ef9708
deploy create kaching-app Pages + 3 HMAC secrets + script drift fix
2026-05-21

User: "整個 Kaching 產品可以送審上架了的要求 ... 你自己去鑰匙圈找" — full authority to use CF API token from Keychain and execute operator-tier setup that I CAN do (skipping items that require buying domains, signing up to third-party services, or having two Telegram accounts). Closed prod blockers: - Cloudflare Pages `kaching-app` project created (production-branch=main); mini-app-web built + deployed; all 9 critic

5258915
polish close final 2 caveats — C-4 multi-lang + E-1 slot.report
2026-05-21

User: "全自動,到完成" — autonomous run to finish all closure-plan items. C-4 (api-wired 9→10) — multi-lang data-model Path A: - migrations/0009_bonuses_multilang.sql: 10 NULL-able TEXT columns added to bonuses (title_{en,ja,vi,zh_hans,zh_hant} + summary_{...}) so the spec at 13-data-model.md matches code; rollback = drop or ignore (NULL fallback) - packages/db/src/schema.ts mirrors - apps/collector

8f7d7b3
polish close 5/7 design-docs-alignment caveats under full authority
2026-05-21

User invoked polish-loop --scope=design-docs-alignment --authority=full --apply-closure-plan=2026-05-21. Took recommended Path A on each decision item. Closed: - D-2 (dark-pattern-free 9→10): responsible-gambling.astro:40 + terms.astro:28 rewritten — removed over-promised "we honour their network's GAMSTOP/OASIS" line; replaced with truthful aggregator-stance ("not a licensed operator; /set

ace46b3
docs inventory design-docs-alignment caveats + per-item resolution path
2026-05-21

Audit of docs/polish-locks/design-docs-alignment.lock.yaml § caveats: - 2 SUPERSEDED (C-3 markers 5/6 closed via FLEET-N-024 tracker; C-5 M10 API done in 12b) - 1 partial-superseded (D-1 Cashback M14 — iter-6 RG gate + $20 cap landed; structural residual still user A/B) - 4 real-open (C-1 plural expansion 0.3d / C-2 CI guard 0.5d / C-4 multi-lang data-model 1.0d / D-2 GAMSTOP retract 0.1d) - 1 ext

28831b5
ops provision 5-locale commands + description + short_description via Bot API
2026-05-21

Closes "Telegram bot register" operator action in docs/external-actions.md. All commercial-grade bot directory metadata now set without computer-use intervention (Bot API calls only). ## Completed via Bot API today (session 454) - `setMyCommands` × 5 locales (default + zh + en + ja + vi), 11 cmds each: start / today / search / invite / streak / quest / subscribe / lang / settings / help / sto

e5aebf4