Files
open-isp/docs/DATABASE_SCHEMA.md
T
oxpoe eaf05f2811 OPEN-ISP v0.5 (pickle-lime) — rilis open-source perdana
Aplikasi billing & manajemen ISP (fiber optic) — PWA pelanggan, portal teknisi & kolektor,
admin panel lengkap, multi-vendor OLT, RADIUS, WhatsApp/Telegram, pembayaran QRIS.

Kredit & lisensi (ISC):
- Base kode & repo: alijayanet/billing-rtrw oleh Alijaya Net — terima kasih banyak
  atas base kode dan repo yang bermanfaat.
- Add-on: GoWA, LibreSpeed/OpenSpeedTest, Uptime Kuma, notification-forwarder.
- Dikembangkan menjadi OPEN-ISP oleh oxpoe — https://github.com/oxpoe/open-isp
2026-10-09 05:51:21 +07:00

15 KiB

DATABASE SCHEMA - Aplikasi Billing B481

Database Type: SQLite 3 (better-sqlite3)
Location: database/billing.db
Journal Mode: WAL (Write-Ahead Logging)
Foreign Keys: Enabled


Schema Overview

1. Configuration & Settings

  • settings - Key-value store untuk runtime configuration
  • expense_categories - Master kategori pengeluaran

2. Master Data

  • packages - Paket layanan ISP
  • customers - Data pelanggan
  • routers - MikroTik router configuration
  • olts - OLT devices
  • odps - ODP distribution points

3. Billing & Payment

  • invoices - Tagihan pelanggan
  • payments - Pembayaran/transaksi
  • payment_approvals - Approval workflow kolektor

4. Network Management (PPPoE)

  • pppoe_users - User PPPoE list
  • pppoe_profiles - Speed profile PPPoE
  • pppoe_traffic_samples - Traffic monitoring samples
  • pppoe_sessions - Active PPPoE sessions

5. Hotspot Management

  • hotspot_users - Hotspot user list
  • hotspot_profiles - Hotspot speed profiles
  • hotspot_sessions - Active hotspot sessions

6. Voucher Management

  • voucher_batches - Batch voucher grouping
  • vouchers - Individual voucher codes

7. Device Management (ACS/TR-069)

  • acsdevices - Daftar perangkat ACS (ONU/CPE)
  • acs_sessions - TR-069 session tracking
  • acs_device_params - Device parameters per ONU

8. OLT & ONU Management

  • onu_mapping - Pemetaan ONU ke customer
  • onu_provision - Status provisioning ONU
  • olu_ports - OLT port information

9. Operational Data

  • audit_trail - Log aktivitas sensitif
  • expenses - Catatan pengeluaran operasional
  • cash_in - Catatan pemasukan uang
  • technicians - Data teknisi + login
  • cashiers - Data kasir
  • agents - Data agen penjualan
  • collectors - Data kolektor
  • inventory_items - Item gudang
  • attendance - Kehadiran karyawan
  • tickets - Tiket support pelanggan

10. Payment & Digital

  • digiflazz_transactions - Transaksi pulsa/data Digiflazz
  • vomit_log - Log webhook pembayaran (generic)

Detailed Table Structures

settings

CREATE TABLE settings (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  key TEXT NOT NULL UNIQUE,
  value TEXT,
  type TEXT DEFAULT 'string',
  created_at DATETIME DEFAULT (NOW_LOCAL()),
  updated_at DATETIME DEFAULT (NOW_LOCAL())
);

Purpose: Store dynamic settings without restart
Examples:

  • company_name, company_phone, company_email
  • billing_day, isolir_day
  • Feature flags: whatsapp_enabled, login_otp_enabled

packages

CREATE TABLE packages (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  name TEXT NOT NULL,
  price INTEGER NOT NULL DEFAULT 0,        -- Harga reguler (Rp)
  promo_price INTEGER DEFAULT NULL,        -- Harga promo (Rp)
  promo_cycles INTEGER DEFAULT 0,          -- Jumlah siklus promo
  speed_down INTEGER DEFAULT 0,            -- Kecepatan download (Mbps)
  speed_up INTEGER DEFAULT 0,              -- Kecepatan upload (Mbps)
  description TEXT DEFAULT '',
  is_active INTEGER DEFAULT 1,
  jam_kalong_enabled INTEGER DEFAULT 0,    -- Night profile feature
  jam_kalong_profile_malam TEXT,           -- Night profile name
  fup_enabled INTEGER DEFAULT 0,           -- Fair Usage Policy
  fup_limit INTEGER DEFAULT 0,             -- GB limit
  fup_profile_turun TEXT,                  -- Degraded profile
  is_hotspot INTEGER DEFAULT 0,
  created_at DATETIME DEFAULT (NOW_LOCAL())
);

Purpose: Define service packages offered
Example:

id=1, name='Premium 10Mbps', price=100000, speed_down=10, speed_up=5

customers

CREATE TABLE customers (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  no_pelanggan TEXT UNIQUE NOT NULL,       -- Customer ID
  nama_pelanggan TEXT NOT NULL,
  email TEXT,
  phone TEXT NOT NULL,
  alamat TEXT,
  paket_id INTEGER REFERENCES packages(id),
  pppoe_user TEXT UNIQUE,                  -- PPPoE username
  pppoe_secret TEXT,                       -- PPPoE password
  password_wifi TEXT,                      -- Wi-Fi password
  install_date DATE,                       -- Installation date
  latitude REAL,                           -- GPS coordinate
  longitude REAL,
  odp_id INTEGER REFERENCES odps(id),      -- ODP location
  router_id INTEGER REFERENCES routers(id), -- MikroTik router
  genieacs_tag TEXT,                       -- GenieACS device tag
  status TEXT DEFAULT 'active',            -- active, suspended, inactive
  isolir_date DATE,                        -- Isolate date
  hari_isolir INTEGER DEFAULT 20,          -- Day to isolate
  isolir_otomatis INTEGER DEFAULT 1,       -- Auto-isolate flag
  tipe_koneksi TEXT DEFAULT 'pppoe',       -- pppoe, hotspot, onu
  promo_cycles_used INTEGER DEFAULT 0,     -- Promo cycle counter
  last_payment_date DATE,
  notes TEXT,
  created_at DATETIME DEFAULT (NOW_LOCAL())
);

Indexes:

  • no_pelanggan (UNIQUE)
  • pppoe_user (UNIQUE)
  • email
  • phone

Foreign Keys:

  • paket_id → packages(id)
  • odp_id → odps(id)
  • router_id → routers(id)

invoices

CREATE TABLE invoices (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  customer_id INTEGER NOT NULL REFERENCES customers(id),
  period_year INTEGER NOT NULL,            -- 2026
  period_month INTEGER NOT NULL,           -- 1-12
  amount INTEGER NOT NULL,                 -- Total Rp
  amount_paid INTEGER DEFAULT 0,           -- Sudah dibayar Rp
  status TEXT DEFAULT 'pending',           -- pending, paid, overdue, cancelled
  due_date DATE,                           -- Jatuh tempo
  payment_date DATE,                       -- Tanggal pembayaran
  payment_method TEXT,                     -- cash, transfer, qris
  payment_gateway TEXT,                    -- midtrans, tripay, manual
  qris_code TEXT,                          -- QRIS payload
  qris_unique_id TEXT UNIQUE,              -- Kode unik untuk matching
  notes TEXT,                              -- AUTO: promo siklus X, AUTO: prorata
  created_at DATETIME DEFAULT (NOW_LOCAL()),
  updated_at DATETIME DEFAULT (NOW_LOCAL())
);

Indexes:

  • customer_id, period_year, period_month (UNIQUE composite)
  • status
  • due_date

payments

CREATE TABLE payments (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  invoice_id INTEGER NOT NULL REFERENCES invoices(id),
  amount INTEGER NOT NULL,                 -- Jumlah bayar Rp
  method TEXT DEFAULT 'cash',              -- cash, transfer, ewallet
  gateway TEXT,                            -- midtrans, tripay, xendit, manual
  gateway_ref_id TEXT UNIQUE,              -- Reference ID dari gateway
  proof_image_url TEXT,                    -- Bukti transfer (foto)
  status TEXT DEFAULT 'pending',           -- pending, verified, failed
  notes TEXT,
  recorded_by_user TEXT,                   -- User yang input
  recorded_by_role TEXT,                   -- admin, kasir, agen
  created_at DATETIME DEFAULT (NOW_LOCAL())
);

routers (MikroTik)

CREATE TABLE routers (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  name TEXT NOT NULL UNIQUE,
  host TEXT NOT NULL,
  port INTEGER DEFAULT 8728,
  username TEXT NOT NULL,
  password TEXT NOT NULL,
  is_active INTEGER DEFAULT 1,
  is_default INTEGER DEFAULT 0,            -- Default router
  notes TEXT,
  last_connection_test DATETIME,
  connection_status TEXT DEFAULT 'unknown',
  created_at DATETIME DEFAULT (NOW_LOCAL())
);

olts (OLT Devices)

CREATE TABLE olts (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  name TEXT NOT NULL UNIQUE,
  host TEXT NOT NULL,
  snmp_community TEXT DEFAULT 'public',
  snmp_port INTEGER DEFAULT 161,
  snmp_version TEXT DEFAULT '2c',
  brand TEXT,                              -- ZTE, Huawei, FiberHome
  model TEXT,
  web_user TEXT,                           -- Web interface login
  web_password TEXT,
  telnet_port INTEGER,                    -- Telnet untuk command
  telnet_password TEXT,
  telnet_enable_password TEXT,             -- ZTE enable password
  api_base_url TEXT,                       -- go-api-c320 endpoint
  is_active INTEGER DEFAULT 1,
  created_at DATETIME DEFAULT (NOW_LOCAL())
);

odps (ODP - Distribution Points)

CREATE TABLE odps (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  name TEXT NOT NULL UNIQUE,
  latitude REAL NOT NULL,
  longitude REAL NOT NULL,
  port_count INTEGER DEFAULT 8,            -- Banyak port fiber
  port_used INTEGER DEFAULT 0,
  address TEXT,
  olt_id INTEGER REFERENCES olts(id),
  is_active INTEGER DEFAULT 1,
  notes TEXT,
  created_at DATETIME DEFAULT (NOW_LOCAL())
);

pppoe_users

CREATE TABLE pppoe_users (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  customer_id INTEGER NOT NULL REFERENCES customers(id),
  router_id INTEGER NOT NULL REFERENCES routers(id),
  username TEXT NOT NULL UNIQUE,
  secret TEXT NOT NULL,
  profile_name TEXT NOT NULL,              -- Speed profile
  status TEXT DEFAULT 'active',            -- active, inactive, disabled
  date_added DATE,
  last_seen DATETIME,
  created_at DATETIME DEFAULT (NOW_LOCAL())
);

invoices (dengan fields lengkap)

CREATE TABLE invoices (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  customer_id INTEGER NOT NULL REFERENCES customers(id),
  
  -- Period
  period_year INTEGER NOT NULL,
  period_month INTEGER NOT NULL,
  due_date DATE,
  
  -- Amount
  amount INTEGER NOT NULL,
  amount_paid INTEGER DEFAULT 0,
  
  -- Status
  status TEXT DEFAULT 'pending',
  payment_date DATE,
  
  -- Payment Method
  payment_method TEXT,                     -- cash, transfer, qris
  payment_gateway TEXT,                    -- midtrans, tripay, xendit
  qris_code TEXT,
  qris_unique_id TEXT UNIQUE,
  gateway_ref_id TEXT,
  
  -- Metadata
  notes TEXT,
  created_at DATETIME DEFAULT (NOW_LOCAL()),
  updated_at DATETIME DEFAULT (NOW_LOCAL())
);

pppoe_traffic_samples

CREATE TABLE pppoe_traffic_samples (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  pppoe_user_id INTEGER NOT NULL REFERENCES pppoe_users(id),
  bytes_in INTEGER DEFAULT 0,
  bytes_out INTEGER DEFAULT 0,
  timestamp DATETIME DEFAULT (NOW_LOCAL())
);

Purpose: Track data usage per session
Auto-cleanup: Runs every 10 minutes via cron


audit_trail

CREATE TABLE audit_trail (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  user_id TEXT,                            -- User ID / username
  user_role TEXT,                          -- admin, kasir, etc
  action TEXT NOT NULL,                    -- login, update_customer, payment
  table_name TEXT,
  record_id INTEGER,
  old_value TEXT,                          -- JSON of old data
  new_value TEXT,                          -- JSON of new data
  ip_address TEXT,
  status TEXT DEFAULT 'success',           -- success, failed
  notes TEXT,
  created_at DATETIME DEFAULT (NOW_LOCAL())
);

Auto-cleanup: Delete records older than 90 days (configurable)


tickets

CREATE TABLE tickets (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  customer_id INTEGER NOT NULL REFERENCES customers(id),
  title TEXT NOT NULL,
  description TEXT NOT NULL,
  status TEXT DEFAULT 'open',              -- open, assigned, resolved, closed
  priority TEXT DEFAULT 'normal',          -- low, normal, high
  assigned_to_technician TEXT,             -- Technician ID
  attachment_url TEXT,                     -- Foto bukti
  resolution TEXT,
  created_at DATETIME DEFAULT (NOW_LOCAL()),
  updated_at DATETIME DEFAULT (NOW_LOCAL())
);

agents

CREATE TABLE agents (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  nama_agen TEXT NOT NULL,
  phone TEXT NOT NULL,
  email TEXT,
  alamat TEXT,
  username TEXT NOT NULL UNIQUE,
  password TEXT NOT NULL,                  -- MUST use bcrypt!
  saldo_agen INTEGER DEFAULT 0,            -- Saldo Rp
  status TEXT DEFAULT 'active',
  created_at DATETIME DEFAULT (NOW_LOCAL())
);

voucher_batches

CREATE TABLE voucher_batches (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  name TEXT NOT NULL,
  quantity INTEGER NOT NULL,
  nominal INTEGER NOT NULL,                -- Harga voucher
  price_per_unit INTEGER NOT NULL,         -- Harga beli
  router_id INTEGER REFERENCES routers(id),
  status TEXT DEFAULT 'active',
  generated_count INTEGER DEFAULT 0,
  printed_count INTEGER DEFAULT 0,
  used_count INTEGER DEFAULT 0,
  created_at DATETIME DEFAULT (NOW_LOCAL())
);

vouchers

CREATE TABLE vouchers (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  batch_id INTEGER NOT NULL REFERENCES voucher_batches(id),
  code TEXT NOT NULL UNIQUE,
  status TEXT DEFAULT 'available',         -- available, used, expired
  sold_to_agent TEXT,                      -- Agent ID
  used_by_customer TEXT,
  expiry_date DATE,
  created_at DATETIME DEFAULT (NOW_LOCAL())
);

digiflazz_transactions

CREATE TABLE digiflazz_transactions (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  agent_id INTEGER NOT NULL REFERENCES agents(id),
  ref_id TEXT NOT NULL UNIQUE,             -- Digiflazz reference ID
  phone_or_code TEXT NOT NULL,             -- Tujuan nomor / kode
  product_sku TEXT NOT NULL,
  amount INTEGER NOT NULL,
  status TEXT DEFAULT 'pending',           -- pending, success, failed
  response_data TEXT,                      -- JSON response
  created_at DATETIME DEFAULT (NOW_LOCAL())
);

Query Examples

Generate Invoice (Monthly)

SELECT c.id, c.paket_id, p.price, c.promo_cycles_used, p.promo_cycles
FROM customers c
JOIN packages p ON c.paket_id = p.id
WHERE c.status = 'active'
AND NOT EXISTS (
  SELECT 1 FROM invoices 
  WHERE customer_id = c.id 
  AND period_year = 2026 
  AND period_month = 6
);

Get Overdue Invoices

SELECT c.id, c.nama_pelanggan, i.amount
FROM invoices i
JOIN customers c ON i.customer_id = c.id
WHERE i.status = 'pending'
AND i.due_date < DATE('now')
ORDER BY i.due_date ASC;

Check Customer Usage (Daily)

SELECT 
  pu.id,
  pu.username,
  SUM(pts.bytes_in) / 1000000 as total_gb_in,
  SUM(pts.bytes_out) / 1000000 as total_gb_out
FROM pppoe_users pu
LEFT JOIN pppoe_traffic_samples pts ON pu.id = pts.pppoe_user_id
WHERE DATE(pts.timestamp) = DATE('now')
GROUP BY pu.id;

Find Payments Pending Verification

SELECT p.*, i.amount, c.nama_pelanggan
FROM payments p
JOIN invoices i ON p.invoice_id = i.id
JOIN customers c ON i.customer_id = c.id
WHERE p.status = 'pending'
ORDER BY p.created_at DESC;

Optimization Tips

  1. Add Indexes for Performance:
CREATE INDEX idx_invoices_customer ON invoices(customer_id);
CREATE INDEX idx_payments_invoice ON payments(invoice_id);
CREATE INDEX idx_pppoe_users_customer ON pppoe_users(customer_id);
CREATE INDEX idx_audit_trail_action ON audit_trail(action, created_at);
  1. Regular Maintenance:
-- Cleanup old traffic samples (older than 30 days)
DELETE FROM pppoe_traffic_samples 
WHERE timestamp < datetime('now', '-30 days');

-- Cleanup old audit trail (older than 90 days)
DELETE FROM audit_trail 
WHERE created_at < datetime('now', '-90 days');

-- Vacuum database to reclaim space
VACUUM;
  1. Monitor Database Size:
ls -lh database/billing.db

Backup & Recovery

Backup

sqlite3 database/billing.db ".backup 'backup-2026-06-19.db'"

Restore

sqlite3 database/billing.db ".restore 'backup-2026-06-19.db'"

Manual SQL Backup

sqlite3 database/billing.db ".dump" > backup.sql

Restore from SQL

sqlite3 database/billing.db < backup.sql

Document Version: 1.0
Last Updated: Juni 2026