Satu logika, tiga permukaan
Bot Telegram, REST API, dan aplikasi Flutter memakai lapisan logika yang sama. Aturan kategori, konversi dolar, dan penggabungan transfer tidak pernah ditulis dua kali.
Studi Kasus
Bot Telegram pencatat keuangan yang mengerti kalimat sehari-hari, lengkap dengan REST API dan aplikasi Flutter. Saya pakai sendiri setiap hari, dan ia berjalan tanpa ditunggui di VPS sendiri.
Aplikasi pencatat keuangan yang ada menuntut disiplin yang saya tidak punya: buka aplikasi, pilih kategori, pilih dompet, ketik nominal. Tiga langkah terlalu banyak untuk hal yang harus dilakukan lima kali sehari, dan begitu satu hari terlewat, catatannya tidak pernah dikejar lagi.
Jadi saya balik arahnya: pencatatan harus menyesuaikan kebiasaan, bukan sebaliknya. Cukup ketik “makan siang 35rb pakai bni” ke Telegram — aplikasi yang memang sudah terbuka sepanjang hari. Dan untuk transaksi yang meninggalkan jejak email, bahkan mengetik pun tidak perlu.
Empat jalur masuk, satu otak, satu basis data.
Telegram ──webhook──►┐
│
Gmail ──Apps Script──►│ ┌─────────────┐
(POST /ingest) ├──► FastAPI ──ORM──►│ PostgreSQL │
│ (uvicorn) │ (Neon, │
Aplikasi Flutter ────►│ │ │ Singapura) │
(REST /api) │ │ └─────────────┘
│ ▼
systemd timer ──────►┘ Gemini 2.5 Flash-Lite
(/cron/*) + fallback regex
── VPS Ubuntu 24.04, Singapura ──────────────────────
Caddy (HTTPS otomatis) → uvicorn 127.0.0.1:8000
dijaga systemd · timer menggantikan cron eksternal
Bot Telegram, REST API, dan aplikasi Flutter memakai lapisan logika yang sama. Aturan kategori, konversi dolar, dan penggabungan transfer tidak pernah ditulis dua kali.
Gemini menangani kalimat bebas. Kalau kuotanya habis atau responsnya gagal, parser regex mengambil alih — set saldo dan cek saldo tetap jalan tanpa AI sama sekali.
Google Apps Script membaca email notifikasi transaksi dari beberapa dompet dan rekening, lalu mengirimnya ke /ingest. Bot menebak kategori dari nama merchant dan mengirim notifikasi dengan tombol koreksi.
Yang paling banyak mengubah bentuk sistemnya.
Webhook Telegram di Render, satu dompet, satu jenis transaksi. Hambatan pertama justru sepele: WEBHOOK_SECRET bawaan Render memuat karakter yang ditolak Telegram, dan WEBHOOK_URL harus base URL tanpa akhiran /webhook.
Beberapa dompet dan rekening sekaligus, plus transfer antar dompet. Laporan grafik, anggaran per kategori dengan peringatan otomatis, transaksi berulang, tag #event, dan ekspor Excel.
Review kode menemukan tiga cacat senyap: semua tanggal memakai UTC sehingga transaksi pukul 00.00–07.00 WIB tersimpan mundur sehari; pasangan transfer dicari lewat “dua baris terakhir” sehingga bisa menghapus transaksi yang salah; dan update_id Telegram bisa terproses dua kali saat cold start.
Dari Render ke IDCloudHost Singapura. Server dikeraskan sendiri, Caddy memegang HTTPS, dan systemd timer menggantikan cron eksternal. Cold start 30–60 detik hilang sepenuhnya, dan jadwal yang terlewat kini diulang otomatis — sesuatu yang tidak pernah dilakukan layanan cron sebelumnya.
Membangun sesuatu yang saya pakai sendiri setiap hari mengubah cara saya menilai kode. Bug tidak berhenti di laporan — ia mengganggu saya langsung, malam itu juga. Itu yang membuat saya berhenti mengandalkan asumsi dan mulai memeriksa apa yang benar-benar berjalan.