AI

Wedding Saving

A savings dashboard where every deposit is a real QRIS payment — verified server-side, announced by a Telegram bot, and counted exactly once — running on one Cloudflare Worker with D1.

Cloudflare WorkersHonoQRISTelegram Bot
Impact247 tests

In production since September 2026; public demo runs on a separate sandbox database

247Automated tests
2Webhooks verified
4Notification types

Case Study

The Challenge

Saving for a wedding as a couple raises the same questions every week: how much is in, who put in what, and are we on pace for the date? A spreadsheet answers none of them reliably. I wanted an app where deposits aren't typed in by hand at all — every one is a real payment — and where nobody ever has to chase the other person for an update.

My Approach

Everything runs on one Cloudflare Worker (Hono) with D1, serving the Vue SPA, the JSON API, two webhooks and the cron jobs. Money paths are defensive by default. The payment provider doesn't sign its webhooks, so the webhook path carries a random secret and every notification is verified back against the provider's transaction-status API before a single rupiah is added. A sandbox/live mode guard rejects mismatches in both directions, and one-way status transitions mean a webhook delivered twice never counts twice.

Login is a 4-digit code sent over Telegram: it burns after five wrong tries, expires in five minutes, is rate-limited per username, and the response is identical whether a username exists or not. Sessions store only SHA-256 hashes. Notifications — deposits, 25/50/75/100% milestones, a monthly summary and an evening reminder — are claimed with INSERT OR IGNORE, so each is sent exactly once. The bot's command handlers are pure functions, portable off Cloudflare without a rewrite.

The Results

In production with live QRIS since September 2026, with 247 tests (207 worker, 40 client) written test-first. A separate demo environment with its own database and read-only guard lets anyone try the full flow without touching real savings.

Tech Stack

Vue 3.5ViteTailwind CSS 4PiniaHonoCloudflare WorkersD1Cron TriggersPakasir QRISTelegram Bot APIVitest