No description
  • TypeScript 87.9%
  • Go 5.5%
  • Shell 4.1%
  • CSS 0.9%
  • HTML 0.8%
  • Other 0.8%
Find a file
2026-05-13 22:58:45 +07:00
.github/workflows ci(docs): auto-sync README changelog from CHANGELOG 2026-04-26 17:42:20 +07:00
baileys_whatsapp_patch fix: postbuild also copies .next/static to standalone dir [2.31.3] 2026-05-10 00:54:19 +07:00
bin feat: Go backend Phase 2+ — PPPoE, Billing, Radius, Hotspot, Agent, Network, WhatsApp, Tickets, Cron, Customer Portal 2026-05-09 23:37:09 +07:00
cmd/server feat: Go backend Phase 2+ — PPPoE, Billing, Radius, Hotspot, Agent, Network, WhatsApp, Tickets, Cron, Customer Portal 2026-05-09 23:37:09 +07:00
docs feat: Go backend Phase 1 - OLT monitoring server 2026-05-09 23:22:19 +07:00
freeradius-config fix: FreeRADIUS REST errors - HTTP 204 pass-through + timeouts + export payment filter 2026-05-01 17:35:03 +07:00
internal feat: add batch 7 handlers - customer_ext, whatsapp_crud, network_ext, admin_jobs, misc_handler (v2.34.7) 2026-05-13 22:40:55 +07:00
prisma feat: centralized cron schedule management - edit schedules from UI [2.32.0] 2026-05-11 02:13:34 +07:00
production fix: agent portal categories 401 + salfanet-wa missing from PM2 on fresh install 2026-04-28 22:20:01 +07:00
public redesign: technician tickets with detail modal, chat, photo upload, GPS, notif sound 2026-04-27 02:52:35 +07:00
scripts fix: wg-peer-watchdog restore peers from DB + store localNetworks in description 2026-05-07 09:03:48 +07:00
src feat: add missing menu items to admin sidebar 2026-05-13 15:30:07 +07:00
tests
vps-install fix: CustomerAuthMiddleware DB session validation, OTP send, deploy VPS [2.31.1] 2026-05-10 00:09:36 +07:00
.air.toml feat: Go backend Phase 1 - OLT monitoring server 2026-05-09 23:22:19 +07:00
.env.example feat: add all GenieACS feature files to git tracking (provisions, presets, VP scripts, device detail, WAN, components, lib) 2026-04-30 02:40:29 +07:00
.env.production.example
.gitattributes
.gitignore Add oltc320_v2.1.1_linux to .gitignore 2026-05-13 22:58:26 +07:00
audit_routing.sh feat: settings, permissions, customer portal extensions (v2.34.0) 2026-05-13 07:50:02 +07:00
CHANGELOG.md docs: remove Go migration entries from CHANGELOG, fix dates (Next.js only) 2026-05-13 22:55:05 +07:00
check_admin.py feat: settings, permissions, customer portal extensions (v2.34.0) 2026-05-13 07:50:02 +07:00
check_config.py feat: settings, permissions, customer portal extensions (v2.34.0) 2026-05-13 07:50:02 +07:00
components.json
cron-service.js
deploy-restart.sh feat: settings, permissions, customer portal extensions (v2.34.0) 2026-05-13 07:50:02 +07:00
docker-compose.genieacs.yml feat: add all GenieACS feature files to git tracking (provisions, presets, VP scripts, device detail, WAN, components, lib) 2026-04-30 02:40:29 +07:00
docker-compose.yml feat: Go backend Phase 1 - OLT monitoring server 2026-05-09 23:22:19 +07:00
Dockerfile feat: Go backend Phase 1 - OLT monitoring server 2026-05-09 23:22:19 +07:00
eslint.config.mjs
go.mod feat: Go backend Phase 2+ — PPPoE, Billing, Radius, Hotspot, Agent, Network, WhatsApp, Tickets, Cron, Customer Portal 2026-05-09 23:37:09 +07:00
go.sum feat: Go backend Phase 2+ — PPPoE, Billing, Radius, Hotspot, Agent, Network, WhatsApp, Tickets, Cron, Customer Portal 2026-05-09 23:37:09 +07:00
Makefile feat: Go backend Phase 1 - OLT monitoring server 2026-05-09 23:22:19 +07:00
next.config.ts fix: health endpoint APP_VERSION dari build-time, bump v2.31.6 2026-05-10 08:00:58 +07:00
nginx-frontend.conf fix: HTTPS domain radius.hotspotapp.net, SSL cert Let's Encrypt, bump v2.31.7 2026-05-10 20:52:41 +07:00
package-lock.json fix: remove overflow-hidden from all admin page root divs - fix mobile scroll [2.31.9] 2026-05-11 00:13:11 +07:00
package.json fix: copy .prisma client to standalone in postbuild to prevent 500 after deploy 2026-05-11 06:40:10 +07:00
postcss.config.mjs
README.md docs: sync README changelog 2026-05-13 15:55:23 +00:00
test_login.sh feat: settings, permissions, customer portal extensions (v2.34.0) 2026-05-13 07:50:02 +07:00
test_otp.py feat: settings, permissions, customer portal extensions (v2.34.0) 2026-05-13 07:50:02 +07:00
tsconfig.json
verify_session.py feat: settings, permissions, customer portal extensions (v2.34.0) 2026-05-13 07:50:02 +07:00
vitest.config.ts
vpn-watchdog.sh fix: persistent VPN routes — WG PostUp, watchdog WG+L2TP route restore, L2TP ip-up.d localNetworks 2026-05-07 18:25:11 +07:00
vps_audit.py feat: settings, permissions, customer portal extensions (v2.34.0) 2026-05-13 07:50:02 +07:00
wa-service.js fix: spinner stays on WAITING, auto-restart wa-service on logged_out state 2026-04-26 19:42:09 +07:00
ZTE_OID_TABLE.md feat: Go backend Phase 1 - OLT monitoring server 2026-05-09 23:22:19 +07:00

SALFANET RADIUS - Billing System for ISP/RTRW.NET

Modern, full-stack billing & RADIUS management system for ISP/RTRW.NET with FreeRADIUS integration supporting PPPoE and Hotspot authentication.

Latest: v2.25.2 — Native Baileys WhatsApp gateway built-in di VPS, QR modal auto-retry, auto-reconnect setelah device disconnect (Apr 26, 2026)


🤖 AI Development Assistant

READ FIRST: docs/AI_PROJECT_MEMORY.md — contains full architecture, VPS details, DB schema, known issues, and proven solutions.


🎯 Features

Category Key Capabilities
RADIUS / Auth FreeRADIUS 3.0.26, PAP/CHAP/MS-CHAP, VPN L2TP/IPSec, PPPoE & Hotspot, CoA real-time speed/disconnect
VPN Management MikroTik CHR via API, VPS built-in WireGuard & L2TP/IPsec peer management, configurable IP pool & gateway per protocol, auto-generated RouterOS scripts
PPPoE Management Customer accounts, profile-based bandwidth, isolation, IP assignment, MikroTik auto-sync, foto KTP+instalasi via kamera HP, GPS otomatis
Hotspot Voucher 8 code types, batch up to 25,000, agent distribution, auto-sync with RADIUS, print templates
Billing Postpaid/prepaid invoices, auto-generation, payment reminders, balance/deposit, auto-renewal
Payment Manual upload (bukti transfer), Midtrans/Xendit/Duitku gateway, approval workflow, 05 bank accounts
Notifications WhatsApp (Fonnte/WAHA/GOWA/MPWA/Wablas/WABlast/Kirimi.id/Baileys native), Email SMTP, broadcast (outage/invoice/payment), webhook pesan masuk
Agent/Reseller Balance-based voucher generation, commission tracking, sales stats
Financial Income/expense tracking with categories, keuangan reconciliation
Network (FTTH) OLT/ODC/ODP management, customer port assignment, network map, distance calculation
GenieACS TR-069 CPE/ONT management, WiFi config (SSID/password), device status & uptime
Isolation Auto-isolate expired customers, customizable WhatsApp/Email/HTML landing page templates
Cron Jobs 16 automated background jobs (tsx runner via PM2 fork), history, distributed locking, manual trigger
Roles & Permissions 53 permissions, 5 portals (Admin/Customer/Agent/Technician + SuperAdmin)
Activity Log Audit trail with auto-cleanup (30 days)
Security Session timeout 30 min, idle warning, RBAC, HTTPS/SSL
Bahasa Bahasa Indonesia (full)
PWA Installable di semua portal (admin, customer, agent, technician), offline fallback, service worker cache
Web Push VAPID-based browser push notifications, subscribe/unsubscribe toggle, admin broadcast
System Update Update via SSH menggunakan updater.sh, tidak ada web-based update
Mobile App Flutter customer portal (WiFi control, invoice, payment)
WhatsApp Baileys Native WhatsApp gateway built-in VPS via @whiskeysockets/baileys, PM2 proses terpisah, scan QR langsung di admin panel, auto-reconnect

📱 WhatsApp Baileys (Native Gateway)

Provider WhatsApp bawaan tanpa layanan pihak ketiga. Berjalan sebagai proses PM2 terpisah (salfanet-wa) di VPS.

Setup

Provider Baileys otomatis di-setup saat menjalankan updater.sh. Tidak ada konfigurasi tambahan.

# Cek status wa-service
pm2 status
pm2 logs salfanet-wa --lines 20

Cara Pakai

  1. Buka Admin → Pengaturan → WhatsApp → Penyedia
  2. Klik + Tambah Provider, pilih tipe Baileys
  3. Klik QR Code → scan dengan HP (WhatsApp → Linked Devices)
  4. Setelah scan berhasil, modal menampilkan centang hijau konfirmasi
  5. Provider siap digunakan untuk kirim notifikasi

PM2 Processes

Process Mode Port Purpose
salfanet-radius cluster 3000 Next.js app
salfanet-wa fork 4000 (internal) Baileys WA service
salfanet-cron fork Background jobs

Auth Session

Session WhatsApp tersimpan di /var/data/salfanet/baileys_auth/ dan persist meski PM2 restart. Untuk logout/scan ulang, klik Restart Session di admin panel.


🚀 Tech Stack

Component Technology
Framework Next.js 16 (App Router, standalone output)
Language TypeScript
Styling Tailwind CSS
Database MySQL 8.0 + Prisma ORM
RADIUS FreeRADIUS 3.0.26
Process Manager PM2 (cluster × 2)
Session Tracking FreeRADIUS radacct (real-time)
Maps Leaflet / OpenStreetMap

📁 Project Structure

salfanet-radius/
├── src/
│   ├── app/
│   │   ├── admin/          # Admin panel
│   │   ├── agent/          # Agent/reseller portal
│   │   ├── api/            # API route handlers
│   │   ├── customer/       # Customer self-service portal
│   │   └── technician/     # Technician portal
│   ├── server/             # DB, services, jobs, cache, auth
│   ├── features/           # Vertical slices (queries, schemas, types)
│   ├── components/         # Shared React components
│   ├── locales/            # i18n translations (id, en)
│   └── types/              # Shared TypeScript types
├── prisma/
│   ├── schema.prisma       # Database schema (~45 models)
│   └── seeds/              # Seed scripts
├── freeradius-config/      # FreeRADIUS config (deployed by installer)
├── vps-install/            # One-command VPS installer scripts
├── production/             # PM2 & Nginx config templates
├── mobile-app/             # Flutter customer app
├── scripts/                # Utility & tuning scripts
└── docs/                   # Documentation & AI memory

⚙️ Installation

ssh root@YOUR_VPS_IP

git clone https://github.com/s4lfanet/salfanet-radius.git /root/salfanet-radius
cd /root/salfanet-radius
bash vps-install/vps-installer.sh

Installer akan berjalan interaktif — mendeteksi environment otomatis, memandu konfigurasi, lalu menjalankan semua step.


Metode 2 — Upload Manual via SCP (Tanpa Akses Internet di Server)

# Jalankan di terminal LOKAL (bukan di server)
scp -r ./salfanet-radius root@YOUR_VPS_IP:/root/salfanet-radius

# SSH ke server, lalu jalankan installer
ssh root@YOUR_VPS_IP
cd /root/salfanet-radius
bash vps-install/vps-installer.sh

Environment yang Didukung

Environment Flag Akses
Public VPS (DigitalOcean, Vultr, Hetzner, AWS) --env vps Internet
Proxmox LXC --env lxc LAN/VLAN
Proxmox VM / VirtualBox --env vm LAN
Bare Metal / Server Fisik --env bare LAN
# Contoh: paksa environment + IP
bash vps-install/vps-installer.sh --env lxc --ip 192.168.1.50

Updating Existing Installation

Cara paling aman. Semua data upload (logo, foto KTP pelanggan, bukti bayar) otomatis dipreservasi.

bash /var/www/salfanet-radius/vps-install/updater.sh

Atau update dari branch terbaru secara manual:

cd /var/www/salfanet-radius
git pull origin master
npm install --legacy-peer-deps
npx prisma db push
npm run build
pm2 reload all

Lihat detail lengkap di vps-install/README.md.


Data yang Aman Saat Update

Data Status
Logo perusahaan (public/uploads/logos/) Dipreservasi
Foto KTP & dokumen pelanggan Dipreservasi
Bukti pembayaran Dipreservasi
File .env (database, secrets) Tidak disentuh
Database MySQL (semua data pelanggan) Tidak disentuh

Default Credentials

Admin URL http://YOUR_VPS_IP/admin/login
Username superadmin
Password admin123

⚠️ Ganti password segera setelah login pertama!


🔌 FreeRADIUS

Key config files at /etc/freeradius/3.0/:

File Purpose
mods-enabled/sql MySQL connection for user auth
mods-enabled/rest REST API for voucher management
sites-enabled/default Main auth logic (PPPoE realm support)
clients.conf NAS/router clients (+ $INCLUDE clients.d/)
sites-enabled/coa CoA/Disconnect-Request virtual server

Config backup in freeradius-config/ is auto-deployed by the installer.

Auth Flow

PPPoE: MikroTik → FreeRADIUS → MySQL (radcheck/radusergroup/radgroupreply) → Access-Accept with Mikrotik-Rate-Limit

Hotspot Voucher: Same RADIUS path + REST /api/radius/post-auth → sets firstLoginAt, expiresAt, syncs keuangan

RADIUS Tables

Table Purpose
radcheck User credentials
radreply User-specific reply attrs
radusergroup User → Group mapping
radgroupreply Group reply (bandwidth, session timeout)
radacct Session accounting
nas NAS/Router clients (dynamic)

Cron Jobs (16 automated)

Job Schedule Function
Voucher Sync Every 5 min Sync voucher status with RADIUS
Disconnect Sessions Every 5 min CoA disconnect expired vouchers
Auto Isolir (PPPoE) Every hour Suspend overdue customers
FreeRADIUS Health Every 5 min Auto-restart if down
PPPoE Session Sync Every 10 min Sync radacct sessions
Agent Sales Daily 1 AM Update sales statistics
Invoice Generate Daily 2 AM Generate monthly invoices
Activity Log Cleanup Daily 2 AM Delete logs >30 days
Invoice Reminder Daily 8 AM Send payment reminders
Invoice Status Daily 9 AM Mark overdue invoices
Notification Check Every 10 min Process notification queue
Auto Renewal Daily 8 AM Prepaid auto-renew from balance
Webhook Log Cleanup Daily 3 AM Delete webhook logs >30 days
Session Monitor Every 5 min Security session monitoring
Cron History Cleanup Daily 4 AM Keep last 50 per job type
Suspend Check Every hour Activate/restore suspend requests

All jobs can be triggered manually from Settings → Cron in the admin panel.


<EFBFBD> Android APK Builder

Buat APK Android (WebView wrapper) untuk 4 portal langsung di server VPS — tanpa GitHub Actions, tanpa Android Studio.

1) Setup Android SDK (satu kali via SSH)

apt-get update && apt-get install -y openjdk-17-jdk wget unzip && \
mkdir -p /opt/android/cmdline-tools && \
wget -q https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip -O /tmp/cmdtools.zip && \
unzip -q /tmp/cmdtools.zip -d /opt/android/cmdline-tools && \
mv /opt/android/cmdline-tools/cmdline-tools /opt/android/cmdline-tools/latest && \
yes | /opt/android/cmdline-tools/latest/bin/sdkmanager --licenses && \
/opt/android/cmdline-tools/latest/bin/sdkmanager "platforms;android-34" "build-tools;34.0.0" && \
echo 'export ANDROID_HOME=/opt/android' >> /etc/environment && \
echo 'Selesai!'

Perkiraan waktu: ~510 menit (download ~500MB). Disk yang dibutuhkan: ~2GB.

2) Build APK via Admin Panel

Buka Admin → Download Aplikasi Android → klik Build APK pada role yang diinginkan.

  • Build berjalan di background (tidak timeout meski butuh beberapa menit)
  • Status diperbarui otomatis setiap 3 detik
  • Setelah selesai, tombol Download APK muncul

3) Build via API (opsional)

# Cek environment
curl http://YOUR_VPS/api/admin/apk/trigger

# Mulai build (role: admin | customer | technician | agent)
curl -X POST http://YOUR_VPS/api/admin/apk/trigger?role=customer \
  -H "Cookie: next-auth.session-token=..."

# Cek status
curl http://YOUR_VPS/api/admin/apk/status?role=customer

# Download APK
curl -OJ http://YOUR_VPS/api/admin/apk/file?role=customer \
  -H "Cookie: next-auth.session-token=..."

Storage APK

Path Keterangan
/var/data/salfanet/apk/{role}/app.apk File APK hasil build
/var/data/salfanet/apk/{role}/status.json Status & metadata build
/var/data/salfanet/apk/{role}/build.log Log Gradle
/var/data/salfanet/gradle-cache Cache Gradle (mempercepat build berikutnya)

Paket Aplikasi

Role Package ID Warna
Admin net.salfanet.admin Biru
Customer net.salfanet.customer Cyan
Technician net.salfanet.technician Hijau
Agent net.salfanet.agent Ungu

<EFBFBD>🛠️ Common Commands

# PM2
pm2 status ; pm2 logs salfanet-radius
pm2 restart ecosystem.config.js --update-env

# FreeRADIUS
systemctl restart freeradius
freeradius -XC    # Test config
radtest 'user@realm' password 127.0.0.1 0 testing123

# Database
mysql -u salfanet_user -psalfanetradius123 salfanet_radius
mysqldump -u salfanet_user -psalfanetradius123 salfanet_radius > backup.sql

🧯 Troubleshooting Cepat

1) Website tidak bisa diakses dari IP VPS

Jika Nginx dan app sudah jalan di server tapi dari internet tetap tidak bisa akses, biasanya masalah ada di layer jaringan (NAT/forwarding/firewall external), bukan di aplikasi.

# Di VM/VPS guest
ss -tulpn | grep -E ':80|:443|:3000'
curl -I http://127.0.0.1:3000
curl -I http://127.0.0.1
systemctl status nginx --no-pager
pm2 status

Jika semua check local di atas OK, cek mapping di host Proxmox/router/cloud firewall:

  1. Public:2020 -> VM:22 (SSH)
  2. Public:80 -> VM:80 (HTTP)
  3. Public:443 -> VM:443 (HTTPS)

Catatan: IP:2020 adalah port SSH, bukan URL web aplikasi.

2) PM2 jalan tapi web tetap blank/error

pm2 status
pm2 logs salfanet-radius --lines 100
cd /var/www/salfanet-radius
npm run build
pm2 restart ecosystem.config.js --update-env

4) Jalankan diagnosa Nginx otomatis dari installer

Installer Nginx terbaru menambahkan self-check internal (127.0.0.1:3000, 127.0.0.1) dan best-effort check publik (HTTP/HTTPS).

cd /var/www/salfanet-radius
bash vps-install/install-nginx.sh

Jika warning menunjukkan HTTP publik tidak reachable, fokus perbaikan di NAT/port-forward/security-group, bukan di Next.js.


🔐 Security

# Firewall
ufw allow 22/tcp && ufw allow 80/tcp && ufw allow 443/tcp
ufw allow 1812/udp && ufw allow 1813/udp && ufw allow 3799/udp
  1. Change default admin password on first login
  2. Change MySQL passwords in .env
  3. Configure SSL (Let's Encrypt or Cloudflare)
  4. Enable UFW

📡 CoA (Change of Authorization)

Sends real-time speed/disconnect commands to MikroTik without dropping PPPoE connections.

MikroTik requirement: /radius incoming set accept=yes port=3799

API: POST /api/radius/coa — actions: disconnect, update, sync-profile, test

Auto-triggered when: PPPoE profile speed is edited (syncs all active sessions).


📲 WhatsApp Providers

Provider Base URL Auth
Fonnte https://api.fonnte.com/send Token
WAHA http://IP:PORT API Key
GOWA http://IP:PORT user:pass
MPWA http://IP:PORT API Key
Wablas https://pati.wablas.com Token

⏱️ Timezone

Layer Timezone Note
Database (Prisma) UTC Prisma default
FreeRADIUS WIB (UTC+7) Server local time
PM2 env WIB TZ: 'Asia/Jakarta' in ecosystem.config.js
API / Frontend WIB Auto-converts UTC ↔ WIB

For WITA (UTC+8) or WIT (UTC+9): change TZ in .env, ecosystem.config.js, and src/lib/timezone.ts.


📋 Admin Modules

Dashboard · PPPoE · Hotspot · Agent · Invoice · Payment · Keuangan · Sessions · WhatsApp · Network (OLT/ODC/ODP) · GenieACS · Settings

Roles: SUPER_ADMIN · FINANCE · CUSTOMER_SERVICE · TECHNICIAN · MARKETING · VIEWER


📝 Changelog

Bagian ini otomatis sinkron dari CHANGELOG.md saat file changelog berubah di GitHub.

v2.34.4 — 2026-05-13

Added

  • Sidebar: Permintaan Top-Up & Suspend — tambah nav.topupRequests (/admin/topup-requests) dan nav.suspendRequests (/admin/suspend-requests) sebagai child PPPoE
  • Sidebar: ODC, ODP, Peta Jaringan — tambah 3 item ke Topology: Network Map, ODC, ODP
  • Sidebar: Fiber ODC & Fiber ODP — tambah ke seksi Manajemen Fiber
  • Sidebar: GenieACS Files — tambah child nav.files ke seksi GenieACS
  • Sidebar: Kelola Teknisi — tambah item standalone di catManagement
  • Sidebar: Log Aktivitas — tambah item standalone di catManagement
  • Sidebar: Pengaturan Keamanan — tambah child /admin/settings/security ke settingsMenu
  • Sidebar: WhatsApp jadi submenu — ubah dari single link ke children (Settings, Riwayat, Template, Kirim, Notifikasi, Providers)
  • i18n: tambah nav keystopupRequests, suspendRequests, activityLogs, security, fiberOdcs, fiberOdps

Files

  • src/app/admin/AdminClientLayout.tsx — tambah menu items, WhatsApp jadi submenu, import UserCog
  • src/locales/id.json — tambah 6 nav translation keys

v2.32.2 — 2026-05-13

Fixed

  • System Info API: silent git errors — Semua execSync git di /api/admin/system/info kini pakai stdio: 'pipe' sehingga stderr tidak bocor ke PM2 log; getAppDir() kini mencari /var/www/salfanet-frontend lebih dulu (direktori dengan .git) sebelum fallback ke path lain

Files

  • src/app/api/admin/system/info/route.ts — tambah stdio: 'pipe' pada execSync/execFileSync, perbarui urutan kandidat getAppDir()

v2.32.1 — 2026-05-11

Fixed

  • PPPoE Session Sync error 1264acctsessiontime di-clamp ke range INT MariaDB (GREATEST(0, LEAST(..., 2147483647))) pada semua 4 UPDATE query; sesi dengan acctstarttime tidak valid (0000-00-00 atau sangat lama) tidak lagi menyebabkan cron gagal

Files

  • src/server/jobs/pppoe-session-sync.ts — clamp TIMESTAMPDIFF ke INT range, tambah filter acctstarttime > '2000-01-01' pada update aktif

v2.32.0 — 2026-05-11

Added

  • Centralized Cron Schedule Management — jadwal semua cron job kini bisa diatur dari satu halaman Admin → Settings → Cron tab "Jadwal Cron"; perubahan disimpan ke DB cron_schedule_config, aktif setelah pm2 restart salfanet-cron
  • Schedule Editor modal — 17 preset waktu (Every minute, Every 5 min, dll.) + custom cron expression; menampilkan default schedule sebagai referensi
  • 3-tab layout cron page — Tab: Status & Trigger, Jadwal Cron, Riwayat Eksekusi
  • API /api/cron/schedules — GET/PUT/DELETE untuk manajemen schedule override per job (SUPERADMIN only)
  • DB table cron_schedule_config — menyimpan override schedule per jobType

Changed

  • runner.ts — load schedule overrides dari DB saat startup; fallback ke default jika tidak ada override atau tabel belum ada; support preload.cjs mock untuk server-only
  • jobs.config.ts — hapus import 'server-only' guard (redundant; diganti comment penjelasan)

Fixed

  • Duplicate CronSettingsPage declaration — page.tsx memiliki dua export default function CronSettingsPage() yang menyebabkan build error Turbopack; baris duplikat dihapus
  • server-only module block tsx cron runnersrc/cron/preload.cjs mocking module server-only sebelum tsx load file apapun agar standalone cron runner bisa berjalan

Files

  • src/app/admin/settings/cron/page.tsx — rewrite lengkap dengan 3-tab layout + ScheduleEditor modal
  • src/app/api/cron/schedules/route.ts — NEW: CRUD API untuk schedule override
  • src/cron/runner.ts — load schedule overrides dari DB via initSchedules()
  • src/cron/preload.cjs — NEW: mock server-only agar tsx bisa load server files
  • src/cron/runner-wrapper.cjs — NEW: CJS wrapper entry point (opsional)
  • src/server/jobs/jobs.config.ts — hapus import 'server-only'
  • prisma/schema.prisma — tambah model cronScheduleConfig

v2.31.12 — 2026-05-11

Fixed

  • MikroTik timeout empty error messagenode-routeros melempar empty string "" saat timeout (bukan Error object); sekarang ada fallback message yang jelas jika error kosong atau {}
  • Library timeout conflictnode-routeros internal timeout diset ke 9999s agar tidak interferensi dengan Promise.race timeout kita yang memberikan pesan error yang lebih informatif

Files

  • src/server/services/mikrotik/client.ts — set library timeout ke 9999s, tambah fallback untuk empty error message

See full changelog: docs/getting-started/CHANGELOG.md

📚 Documentation

File Description
docs/INSTALLATION-GUIDE.md Complete VPS installation
docs/GENIEACS-GUIDE.md GenieACS TR-069 setup & WiFi management
docs/AGENT_DEPOSIT_SYSTEM.md Agent balance & deposit
docs/RADIUS-CONNECTIVITY.md RADIUS architecture
docs/FREERADIUS-SETUP.md FreeRADIUS configuration guide

📝 License

MIT License - Free for commercial and personal use

👨‍💻 Development

Built with ❤️ for Indonesian ISPs

Important: Always use formatWIB() and toWIB() functions when displaying dates to users.