📜 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.
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
Companion to 21c2611 (feat: DEFAULT_RTP_BY_GAME constant) — closes the documentation side of FLEET-N-024 M-6 marker: - 00-scenarios.md:344 ⚠️ TO VERIFY → 📌 RESOLVED with full house_edge defaults table + override path + cross-link to code - FLEET-N-024-tracker.md M-6 row status → ✅ closed; summary 4/6 → 5/6 closed; open count 2 → 1 (only M-4 slot.report API remains, external dependency defe
Closes M-6 (house_edge defaults) — the last code-side marker in FLEET-N-024. M-4 (slot.report API shape) remains open, deferred to Phase F collector sprint (requires external API probe, not codifiable in this cycle). ## Changes - `packages/ev-calculator/src/index.ts`: NEW exported const `DEFAULT_RTP_BY_GAME` with industry-standard RTPs per FLEET-N-024 § M-6 product decision (slot 0.96, table
Self-audit revealed two drifts between claimed-shipped and actual-running: ## /user/me composite missing `stats` Actor A iter-7 P3 claim: 8-key composite (profile + preferences + stats + streak + quests + cashback + badges + rg_status). E2E probe confirmed only 7 keys — stats was named in the return shape but never wired. Fixed: 3 sub-query aggregate via c.env.DB.prepare() (1 D1 sub-request): -
Drafts written for product-ops Phase 1 (ASO + locale): - 01-aso/tg-miniapp.md: BotFather description + about + commands + welcome message × zh-Hant / en / ja - 01-aso/web.md: meta title + description + OG cards for /, /bonuses, /operators × zh-Hant / en / ja - 01-aso/seo.md: 10 target keywords × 3 locales (manual since no GSC MCP); content pillars (EV literacy / freshness / trust); on-pag
First real run of product-ops skill on this project. Phase 0 actions: - Triaged gitleaks 15 hits → all false-positive (i18n key field patterns: badge-streak-30-criteria etc.). Added .gitleaks.toml allowlist for the specific paths + regex patterns. Re-scan: 0 leaks. - Leveraged iter-8 polish-loop work (CHANGELOG + 4 design docs, 1,617 lines) for release-readiness / editor/vc/vet-eye / i18n-n
iter-8 Actor A + B all deployed end-to-end. Smoke tests green; DLQs bound; R2 lifecycle applied to 4 buckets. Fixed scripts/apply-r2-lifecycle.sh — wrangler 4.x renamed `r2 bucket lifecycle put` → `set`. Verified-by-session: 421_gambli_path-a-iter-5-me-search-3-band
Actor B closes the perf + storage gaps surfaced by iter-8 audit (D1 perf 6 / storage-GC 6 / quota-guards 6 — alongside Actor A P0 critical fixes in 4ae74c6). ## Storage GC (4 sub-tasks) ### SG-A — gdpr-finalize.ts cron (NEW) Runbook docs/design/26-runbooks/gdpr-delete-request.md:41 referenced this file but it didn't exist. Created daily 03:00 UTC cron in apps/collector-cron: - Query users WHERE
iter-8 4 deep critics (D1 perf / storage-GC / quota-guards / product-completion) all returned 6-7 (NOT just polish — found real production bugs + security gaps). Actor A pass closes the 14 P0 items. ## CB-1 — dailyMaintenance bug (PRODUCTION-CORRUPTING) collector-cron line 329 `UPDATE bonuses SET status='expired' WHERE status='active'` — missing `AND expiry < unixepoch()`. EVERY cron tick wiped a
Phase F-5 staging deploy complete. Path A end-to-end live on staging. ## Deployments - mini-app-api staging: kaching-mini-app-api-staging (v a1b5a7be...) - mini-app-api prod: kaching-mini-app-api-prod (v e4ae1eb3...) - mini-app-web staging: https://8eef930e.kaching-app-staging.pages.dev ## Smoke verification - /healthz: 200 OK (both envs) - /api/v1/public/stats: 200 OK + valid JSON - /api/v1/
Iter-7 api-wired-deep critic returned 7 (estimated 9). Closed remaining doc gaps in one pass. ## F-3 — Spec sync (14-api-contract.md +599/-117) ### Path renames spec → prod-aligned (4 patterns) - /user/quests → /user/quest (singular) - /user/quests/:id/claim → /user/quest/claim with body {user_quest_id} - /user/ad/serve → /user/ad/request - /user/stars/invoice → /user/subscribe/invoice - Removed
Phase F-2 actor pass found the bulk UI re-skin already in (commits f83c8df + 8fbba5b from concurrent session). 4 pre-pivot literals slipped past: - apps/mini-app-web/public/styles/tokens.css:29 — `--tg-theme-destructive-text-color: #d14e4e` → `#ef4444` (Path A canonical red) - apps/mini-app-web/src/pages/bonus/[id].astro — unused `verdictColorClass` removed (typecheck hint cleanup) - apps/mini-ap
- index.astro: rebuilt with cosmic SVG radar hero (Path A), copy split via isZh heuristic (5-locale Fluent bundle migration to follow) - bonus/[id].astro: editorial detail layout, sticky claim CTA with emerald glow restraint (one per viewport) - BonusCard.astro, Layout.astro: cosmic accent integration - bonuses.astro (NEW): /bonuses listing landing page wired to API - path-a-patterns.css (NEW)
After the 2026-05-19 Path A pivot (Kaching Green #28a85c → Kaching Emerald #10b981, deep navy #0a1730 → #0a0f1f), the spec tokens lived only in prototypes/tokens/{tokens.ts,tokens.css} with no automated guard against accidental rollback. With 100+ files touching design docs in this round, a stale paste could easily reintroduce the retired palette unnoticed. Add @kaching/brand-tokens — tiny packag
v1 0006_user_rg_and_nullable_age.sql attempted SQLite table-rebuild to make `users.age_confirmed_at` NULL-able. D1 rejected at commit: FOREIGN KEY constraint failed: SQLITE_CONSTRAINT (extended: 7500) D1 enforces FK at tx commit even with `PRAGMA foreign_keys=OFF`. Other tables (user_preferences / streaks / quests / cashback_credits / referrals / etc.) reference users.telegram_id → rebuild chur
polish-loop v4 design-driver-protocol executed end-to-end via Chrome MCP: navigate claude.ai/design → existing Kaching prototype → paste pushback message per `docs/design/design-requests/web-templates-pathA-followup.md` → poll → click Share → Handoff to Claude Code → capture URL → curl bundle → extract → README banner. ## Bundle - URL: https://api.anthropic.com/v1/design/h/vhBo6CUjY1TyErmKK6iZtw
Iter-7 api-wired-deep critic (score 7, was estimated 9) found 4 spec↔prod handler gaps causing real user-facing failures. ## P1 — /auth/verify return shape (PRODUCTION-BLOCKING) Pre: returned {jwt, user} Post: returns {jwt, expires_at, user_id, age_confirm_required, rg_status: {self_excluded_until, cooloff_until}} The Mini App deep-link age gate (02-miniapp-spec § 1.5) requires age_confirm_requi
Iter-7 three deep critics (i18n-localization 8 / api-wired-deep 7 / copy-clarity-per-locale 7) flagged ~15 mechanical locale text issues across 5 .ftl files. This commit addresses ALL locale polish; production code + spec sync fixes are next. ## Brand voice violations fixed ### Banned emoji 🎉 (brand spec 31-bot-uiux.md:70 hard ban on 🎉🎊🥳🤑) - subscribe-success / vip-upgraded / svip-upgraded