Saya baru siapkan satu side project untuk urus kewangan peribadi, dan keseluruhan app ini saya build guna Cloudflare stack. Dalam post ini saya kongsi seni bina teknikal, kenapa saya pilih stack ini, dan beberapa keputusan reka bentuk yang saya rasa paling penting.
Tech Stack
| Komponen | Teknologi |
|---|---|
| Frontend | HTML, CSS, JavaScript (Vanilla) |
| Backend API | Cloudflare Workers + Hono.js |
| Database | Cloudflare D1 (SQLite) |
| Authentication | JWT + bcrypt |
| Hosting | Cloudflare Pages |
| PWA | Service Worker untuk offline support |
Mengapa Cloudflare?
Saya pilih Cloudflare stack sebab beberapa benda ini memang kena dengan apa yang saya nak:
- Serverless sepenuhnya - Tiada pelayan untuk diurus
- Global edge network - Respons pantas dari mana-mana lokasi
- Kos rendah - Free tier sangat generous untuk projek peribadi
- D1 Database - SQLite yang di-host, mudah untuk schema migrations
- Integrasi Pages + Workers - Deploy frontend dan API dari satu repository
Seni Bina Sistem
┌─────────────────┐ ┌─────────────────────────────┐
│ Cloudflare │ │ Cloudflare Workers │
│ Pages │────▶│ (Hono.js REST API) │
│ (Frontend) │ │ │
└─────────────────┘ └─────────────┬───────────────┘
│
▼
┌─────────────────────────────┐
│ Cloudflare D1 │
│ (SQLite Database) │
└─────────────────────────────┘
Ciri-ciri Utama
1. Multi-User Authentication
- Pendaftaran dan log masuk dengan email/password
- Password hashing menggunakan bcrypt
- JWT tokens dengan 7 hari expiry
- Session management via localStorage
2. Pengurusan Perbelanjaan & Pendapatan

- Rekod transaksi dengan kategori
- Periode kewangan bulanan (24hb - 23hb)
- Sokongan untuk description/catatan
- Import/export data JSON
3. Senarai Transaksi

4. Laporan & Analitik

- Dashboard dengan ringkasan
- Carta pecahan mengikut kategori (Doughnut chart)
- Trend bulanan (Bar chart)
- Laporan tahunan dengan kadar simpanan
5. Progressive Web App (PWA)
- Boleh di-install pada telefon
- Responsive design untuk mobile dan desktop
- Dark theme dengan glassmorphism UI
6. Admin Panel
- Pengurusan pengguna
- Statistik penggunaan
- Padam akaun pengguna
Deployment ke Cloudflare Pages + D1
Kalau nak deploy app macam ini ke Cloudflare Pages dengan D1, ini flow yang saya guna.
1. Struktur Projek
Struktur projek lebih kurang macam ini:
expense-tracker/
├── frontend/ # Static files (HTML, CSS, JS)
├── functions/ # Cloudflare Pages Functions (API)
│ └── api/
│ └── [[route]].js
├── src/
│ └── db/
│ └── schema.sql # Database schema
├── wrangler.toml # Konfigurasi Wrangler
└── package.json
2. Konfigurasi wrangler.toml
Fail wrangler.toml ini yang jadi penghubung utama antara Pages dengan D1:
name = "expense-tracker"
compatibility_date = "2024-01-01"
# D1 Database binding
[[d1_databases]]
binding = "DB"
database_name = "expense-tracker-db"
database_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
Nota:
database_idakan dapat lepas create database pada langkah seterusnya.
3. Mencipta D1 Database
Jalankan arahan berikut dalam terminal:
# Login ke Cloudflare (jika belum)
npx wrangler login
# Create database baru
npx wrangler d1 create expense-tracker-db
Lepas run command itu, output dia lebih kurang macam ini:
✅ Successfully created DB 'expense-tracker-db'
[[d1_databases]]
binding = "DB"
database_name = "expense-tracker-db"
database_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
database_id itu nanti perlu letak semula dalam wrangler.toml.
4. Setup Database Schema
Jalankan migration untuk create tables:
# Local development
npx wrangler d1 execute expense-tracker-db --local --file=./src/db/schema.sql
# Production
npx wrangler d1 execute expense-tracker-db --remote --file=./src/db/schema.sql
5. Deploy ke Cloudflare Pages
Biasanya ada dua cara untuk deploy:
Cara A: Melalui Cloudflare Dashboard (Disyorkan)
- Pergi ke Cloudflare Dashboard → Workers & Pages
- Klik Create → Pages → Connect to Git
- Pilih repository GitHub/GitLab anda
- Konfigurasi build settings:
- Build command: (kosongkan untuk static files)
- Build output directory:
frontend
- Klik Save and Deploy
Cara B: Menggunakan Wrangler CLI
npx wrangler pages deploy frontend --project-name=expense-tracker
6. Binding D1 ke Pages Project
Ini bahagian yang paling selalu orang terlepas pandang:
- Pergi ke Cloudflare Dashboard → Workers & Pages
- Pilih Pages project anda
- Pergi ke Settings → Functions → D1 database bindings
- Klik Add binding:
- Variable name:
DB - D1 database: Pilih
expense-tracker-db
- Variable name:
- Klik Save
⚠️ Penting: Tanpa langkah ini, Pages Functions tidak akan dapat akses database!
7. Environment Variables (Jika Perlu)
Untuk secrets seperti JWT_SECRET:
- Pergi ke Settings → Environment variables
- Tambah variables yang diperlukan:
JWT_SECRET= (rahsia anda)ADMIN_EMAIL= admin@example.com
8. Custom Domain (Optional)
- Pergi ke Custom domains dalam Pages project
- Klik Set up a custom domain
- Masukkan domain anda (contoh:
duit.hafism.xyz) - Cloudflare akan auto-configure DNS dan SSL
9. Local Development
Kalau nak buat development di local machine:
# Start local server dengan D1
npx wrangler pages dev frontend --d1=DB=expense-tracker-db
Ini akan start local server di http://localhost:8788 dengan akses kepada local D1 database.
Kemaskini: Ciri Pengurusan Hutang
Dikemaskini: 28 Disember 2025
Saya juga dah tambah ciri pengurusan hutang yang lebih lengkap dalam Expense Tracker, supaya pengguna boleh jejak hutang peribadi, ansuran kad kredit, dan balance transfer dalam tempat yang sama.
Ciri-ciri Baru
1. Penjejakan Hutang Peribadi
- Hutang Diterima (Wang yang anda berhutang kepada orang lain)
- Hutang Diberi (Wang yang orang lain berhutang kepada anda)
- Rekod pembayaran separa dengan sejarah penuh
- Notifikasi tarikh akhir (amaran 7 hari sebelum)
- Pilihan auto-tambah pembayaran ke perbelanjaan
2. Pengurusan Kad Kredit
- Simpan berbilang kad kredit
- Jejaki hari penyata dan tarikh akhir pembayaran
- Tetapkan had kredit
3. Penjejakan Ansuran (EPP & Balance Transfer)
- Hubungkan ansuran ke kad kredit tertentu
- Jejaki pembayaran bulanan dan kemajuan
- Penciptaan perbelanjaan automatik semasa pembayaran
Implementasi Teknikal
Database Schema
Empat jadual baru ditambah ke D1:
-- Kad Kredit
CREATE TABLE credit_cards (
id INTEGER PRIMARY KEY,
user_id TEXT NOT NULL,
name TEXT NOT NULL,
card_type TEXT DEFAULT 'credit',
last_four TEXT,
statement_day INTEGER,
payment_due_day INTEGER,
credit_limit REAL
);
-- Hutang Peribadi
CREATE TABLE debts (
id INTEGER PRIMARY KEY,
user_id TEXT NOT NULL,
type TEXT NOT NULL, -- 'receivable' or 'payable'
person_name TEXT NOT NULL,
original_amount REAL NOT NULL,
current_balance REAL NOT NULL,
interest_rate REAL,
due_date TEXT,
status TEXT DEFAULT 'active',
auto_add_expense INTEGER DEFAULT 0
);
-- Pembayaran Hutang
CREATE TABLE debt_payments (
id INTEGER PRIMARY KEY,
debt_id INTEGER REFERENCES debts(id),
user_id TEXT NOT NULL,
amount REAL NOT NULL,
payment_date TEXT NOT NULL,
notes TEXT,
expense_id INTEGER REFERENCES expenses(id)
);
-- Ansuran
CREATE TABLE installments (
id INTEGER PRIMARY KEY,
user_id TEXT NOT NULL,
card_id INTEGER REFERENCES credit_cards(id),
type TEXT NOT NULL, -- 'epp' or 'balance_transfer'
name TEXT NOT NULL,
total_amount REAL NOT NULL,
monthly_payment REAL NOT NULL,
interest_rate REAL,
total_months INTEGER NOT NULL,
months_paid INTEGER DEFAULT 0,
payment_day INTEGER NOT NULL,
start_date TEXT NOT NULL,
status TEXT DEFAULT 'active',
auto_add_expense INTEGER DEFAULT 0
);
API Endpoints
16 endpoints baru ditambah:
| Method | Endpoint | Keterangan |
|---|---|---|
| GET | /api/credit-cards | Senarai semua kad kredit |
| POST | /api/credit-cards | Cipta kad kredit |
| PUT | /api/credit-cards/:id | Kemaskini kad kredit |
| DELETE | /api/credit-cards/:id | Padam kad kredit |
| GET | /api/debts | Senarai semua hutang |
| POST | /api/debts | Cipta hutang |
| PUT | /api/debts/:id | Kemaskini hutang |
| DELETE | /api/debts/:id | Padam hutang |
| GET | /api/debts/:id/payments | Dapatkan sejarah pembayaran |
| POST | /api/debts/:id/payments | Rekod pembayaran |
| GET | /api/installments | Senarai ansuran |
| POST | /api/installments | Cipta ansuran |
| PUT | /api/installments/:id | Kemaskini ansuran |
| DELETE | /api/installments/:id | Padam ansuran |
| POST | /api/installments/:id/pay | Rekod pembayaran ansuran |
| GET | /api/summary/debts | Dapatkan ringkasan hutang |
Frontend Components
- Seksyen navigasi “Hutang” baru
- Antara muka tiga-tab (Hutang Diterima, Hutang Diberi, Ansuran)
- Modal pengurusan kad kredit
- Borang hutang dan ansuran dengan validasi
- Progress bars untuk penjejakan hutang/ansuran
- Rakaman pembayaran dengan paparan sejarah
Langkah Deployment
1. Kemaskini Wrangler
cd workers
npm install --save-dev wrangler@4
2. Apply Database Migration
npx wrangler d1 execute expense-tracker-db --file=./src/db/schema.sql --remote
3. Deploy Worker
npx wrangler deploy
Output Deployment
⛅️ wrangler 4.54.0
Total Upload: 175.85 KiB / gzip: 41.37 KiB
Worker Startup Time: 1 ms
Uploaded expense-tracker-api (10.80 sec)
Deployed expense-tracker-api triggers (4.61 sec)
https://your-worker-name.your-subdomain.workers.dev
Fail yang Diubah
| Fail | Perubahan |
|---|---|
workers/src/db/schema.sql | +40 baris (4 jadual baru) |
workers/src/index.ts | +490 baris (16 endpoints) |
frontend/js/debts.js | Fail baru (~700 baris) |
frontend/js/api.js | +190 baris (fungsi API) |
frontend/js/app.js | +20 baris (integrasi) |
frontend/index.html | +310 baris (komponen UI) |
frontend/css/styles.css | +660 baris (styling) |
Paparan Hutang yang baru ini memaparkan:
- Kad ringkasan menunjukkan jumlah hutang
- Antara muka bertab untuk jenis hutang berbeza
- Progress bars untuk penjejakan pembayaran
- Butang tindakan untuk pembayaran dan suntingan
Demo
Kalau nak cuba sendiri:
- URL: https://duit.hafism.xyz
- Demo Account: demo@example.com / demo123
Kesimpulan
Bagi saya, Cloudflare stack memang sangat sedap untuk aplikasi web moden macam ini:
- Zero cold starts berbanding Lambda/Cloud Functions
- SQLite compatibility dengan D1 memudahkan development
- Generous free tier sesuai untuk side projects
Source code ada di GitHub. Kalau ada soalan atau nak sembang pasal implementation, boleh hubungi saya di X (@xhafism) atau Threads (@haf.ism).
Artikel ini sebahagian daripada siri “Building with Cloudflare”, tempat saya kongsi pengalaman build app atas edge stack yang ringan dan practical.