📜 Recent updates
What we shipped lately. We update Kaching multiple times per week — every change is git-tracked and public.
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
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
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
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
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
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
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
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
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
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-
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
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
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
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
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.__
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 -
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:
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
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
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
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
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
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
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
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
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
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
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
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
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