Dari Keresahan Jadi Kode: Bikin Bot Keuangan Pribadi dengan Python & Telegram
Kenapa Artikel Ini Ada
Maret 2026. Gue duduk sambil ngecek saldo rekening dan ngerasa ada yang aneh. Uang kayak habis gitu aja. Nggak ada yang bisa gue tunjuk — nggak ada pengeluaran besar yang obvious, tapi saldo tetap menyusut tiap minggu.
Masalahnya bukan di pengeluaran yang besar. Masalahnya di pengeluaran kecil yang numpuk tanpa gue sadari. Makan siang 25 ribu, kopi 15 ribu, grab 20 ribu — kecil-kecil tapi kalau dijumlah dalam sebulan, lumayan bikin kaget.
Gue nyoba beberapa aplikasi keuangan. Ada yang bagus tapi ribet input-nya. Ada yang simple tapi datanya nggak bisa gue kontrol. Gue nggak mau data keuangan gue ada di server orang lain yang nggak gue kenal.
Terus gue mikir — gue kan lagi belajar Python. Kenapa nggak bikin sendiri?
Apa yang Mau Dibangun
Kriterianya simpel:
- Input cepat — nggak mau buka app khusus, cukup dari Telegram yang udah always open
- Data gue sendiri — disimpan di server sendiri di rumah
- Bisa lihat summary — kemana aja uang gue bulan ini
Dari situ lahirlah Grandyella Money Tracker — bot Telegram yang jalan 24 jam di homelab gue sendiri.
Stack yang Dipilih
Sebelum nulis satu baris kode pun, gue mutusin stack-nya dulu:
Telegram Bot — interface input yang familiar
Python — bahasa yang lagi gue pelajari
PostgreSQL — database yang proper, bukan SQLite
Docker — semua service jalan di container
systemd — bot jalan 24 jam otomatis
Semua jalan di Dell OptiPlex 7050 yang gue jadiin homelab di rumah — Ubuntu 24.04, RAM 16GB, storage 256GB SSD.
Struktur Project
grandyella_tracker/
├── src/
│ ├── bot.py # main bot
│ ├── db.py # database layer
│ ├── belajar_dictionary.py # parse perintah teks
│ ├── format_rupiah.py # format angka
│ └── .env # credentials
├── logs/
│ └── bot.log
└── requirements.txt
Gue sengaja pisah db.py dari bot.py — semua query SQL ada di satu tempat, bot tidak perlu tahu detail database. Ini yang disebut separation of concerns — konsep yang gue pelajari sambil ngerjain project ini.
Database Schema
CREATE TABLE users (
id BIGINT PRIMARY KEY,
nama VARCHAR(100),
username VARCHAR(100),
created_at TIMESTAMP DEFAULT NOW(),
deleted_at TIMESTAMP
);
CREATE TABLE transaksi (
id SERIAL PRIMARY KEY,
user_id BIGINT REFERENCES users(id),
jumlah BIGINT NOT NULL,
tipe VARCHAR(20) CHECK (tipe IN ('masuk', 'keluar', 'transfer')),
kategori VARCHAR(50),
keterangan TEXT,
tanggal DATE DEFAULT CURRENT_DATE,
created_at TIMESTAMP DEFAULT NOW(),
bank_id INTEGER REFERENCES bank(id),
bank_tujuan_id INTEGER REFERENCES bank(id)
);
CREATE TABLE bank (
id SERIAL PRIMARY KEY,
user_id BIGINT REFERENCES users(id),
nama VARCHAR(100),
tipe VARCHAR(20) CHECK (tipe IN ('bank', 'ewallet', 'cash', 'kartu_kredit')),
no_rekening VARCHAR(50),
saldo_awal BIGINT DEFAULT 0,
limit_kredit BIGINT,
created_at TIMESTAMP DEFAULT NOW()
);
Kenapa deleted_at di tabel users dan bukan DELETE? Ini namanya soft delete — data tidak benar-benar dihapus dari database, hanya ditandai kapan dihapus. Kalau user mau balik, datanya masih ada.
Koneksi ke Database
Ini function pertama yang gue tulis di db.py:
def get_connection():
conn = psycopg2.connect(
host=os.getenv("DB_HOST", "192.168.28.28"),
port=os.getenv("DB_PORT", 5432),
database=os.getenv("DB_NAME", "grandyella_db"),
user=os.getenv("DB_USER", "grandyella"),
password=os.getenv("DB_PASSWORD"),
options="-c timezone=Asia/Jakarta",
)
return conn
Dua hal yang penting di sini:
Pertama — credential disimpan di file .env, bukan hardcode di kode. Ini standard keamanan dasar — kalau kode di-push ke GitHub, password tidak ikut ketahuan.
Kedua — options="-c timezone=Asia/Jakarta" — ini yang bikin semua query otomatis pakai timezone WIB. Tanpa ini, timestamp tersimpan dalam UTC dan semua jam tampil +7 jam lebih awal dari yang seharusnya. Gue ngalamin bug ini dan butuh beberapa sesi debugging buat nemuin root cause-nya.
Flow Catat Transaksi
Bot punya dua cara input yang gue desain untuk kecepatan:
Flow A — Ketik langsung:
User: 50000 makan siang
Bot: 💰 Rp 50.000 — makan siang
Pilih kategori: [🍔 Makan & Minum] [🚗 Transport] ...
User: 🍔 Makan & Minum
Bot: Dari bank mana? [🏦 BCA] [💵 Cash] ...
User: 🏦 BCA
Bot: ✅ Tercatat!
Flow B — Lewat tombol:
User: klik 💸 Keluar
Bot: Berapa jumlahnya?
User: 50000
Bot: Pilih kategori...
Flow A untuk input cepat saat lagi di jalan. Flow B untuk yang lebih teliti. Keduanya berakhir di function yang sama — simpan_transaksi().
Fitur Lengkap
Setelah beberapa minggu development, bot punya fitur:
- Catat keluar, masuk, transfer antar akun sendiri
- Kelola bank — BCA, BRI, GoPay, Cash, Kartu Kredit dengan tracking saldo
- Riwayat harian dengan navigasi per hari
- Dashboard harian dan bulanan dengan progress bar per kategori
- Budget limit per kategori dengan warning 80% dan over budget
- Recurring transaction — transaksi bulanan otomatis di tanggal tertentu
- Export PDF laporan bulanan
- Notifikasi — summary pagi, reminder siang dan malam
Deploy 24 Jam
Bot jalan sebagai systemd service — artinya otomatis start saat server nyala, restart sendiri kalau crash:
[Unit]
Description=Grandyella Tracker Bot
After=network.target docker.service
[Service]
Type=simple
User=grandyella
WorkingDirectory=/home/grandyella/grandyella_tracker/dev
ExecStart=/usr/bin/python3 src/bot.py
Restart=always
RestartSec=10
StandardOutput=null
StandardError=null
[Install]
WantedBy=multi-user.target
Dengan setup ini, bot tetap jalan meski terminal ditutup, server restart, atau bot crash karena error apapun.
Yang Gue Pelajari
Project ini bukan cuma soal bikin bot. Ini soal belajar problem solving yang nyata:
- Timezone bug — data tersimpan UTC, tampil salah WIB. Fix:
AT TIME ZONE 'Asia/Jakarta'di semua query - ConversationHandler stuck — bot hang karena state tidak reset. Fix:
conversation_timeout=300 - Circular import —
db.pytidak sengaja import dari dirinya sendiri. Fix: pahami dependency antar file - Double logging — log muncul dua kali karena systemd dan Python handler sama-sama nulis. Fix:
StandardOutput=nulldi systemd
Setiap error punya pelajaran. Dan pelajaran itu jauh lebih nempel dari tutorial yang cuma jalan mulus.
Apa Selanjutnya
Bot ini belum selesai. Yang masih dalam pipeline:
- Voice note — input transaksi via suara pakai Whisper API
- Foto struk — OCR otomatis baca nominal dari foto nota
- Deteksi lokasi — catat di mana transaksi dilakukan
- Data pipeline — Airflow + dbt + ClickHouse untuk analitik lebih dalam
- Machine learning — prediksi pengeluaran bulan depan
Tapi untuk sekarang, tujuan awal sudah tercapai — gue tahu kemana aja uang gue pergi.
Reach out via LinkedIn atau website kalau mau ngobrol lebih lanjut.
🌐 grandyella-dev.vercel.app 💼 linkedin.com/in/ahmadzulfikartanjung