Skip to content

Subscriber Detail Page

The Subscriber Detail page is the single source of truth for one customer. From this one screen you edit every field on the subscriber row, view the decrypted PPPoE password, see live and historical usage, manage CPE routers, override speeds with bandwidth rules, and read the audit trail of every change.

It loads with raw SQL queries in places (to avoid certain GORM edge cases) and Preloads where safe. The whole page is permission-gated section by section — a reseller with only subscribers.view sees a read-only render with most action buttons hidden.

  • From Subscribers — click any row’s Edit button or the username itself.
  • Direct URL: /subscribers/:id.

Visible to anyone who can see the subscriber in the list (admin, owning reseller, parent reseller, anyone with subscribers.view_all).

Tab strip across the top; each tab is described below.

TabContents
ProfileAccount fields, contact, address, service, reseller, expiry, balance, password, static IP, MAC binding, notes
UsageDaily and monthly download/upload, per-day breakdown chart, last-N-days table, FUP tier indicator
SessionsLast 100 PPPoE sessions from radacct (start, stop, duration, bytes, NAS, IP, MAC)
Bandwidth RulesPer-subscriber speed override rules (custom speeds, time windows)
CDN UpgradesPer-subscriber CDN tier overrides, CDN add-on data top-ups
CPE DevicesTR-069 routers linked by IP — WiFi SSID/password, reboot, connected clients
TicketsOpen and historical support tickets attached to this subscriber
Audit LogEvery change made to this subscriber, who made it, when, and what changed

The page sends one PATCH with an allowedFields map; anything outside the map is ignored server-side. This list is the complete, current allowedFields.

FieldNotes
usernameRenaming uses the dedicated Rename flow because RADIUS attributes are keyed on username.
passwordPlain text in the form. Stored as ENC:-prefixed AES-256-GCM in password_plain plus separately in rad_check as the active credential. See Password viewing below.
mac_addressOptional MAC binding. If set, RADIUS rejects logins from any other MAC.
statusactive / inactive. Setting inactive immediately writes Auth-Type := Reject and disconnects the live session.
expiry_dateDate picker. Past dates put the subscriber in the “Expired” stat counter.
service_idChanging this triggers the Change Service flow with prorating.
nas_idOverride the auto-detected NAS for accounting/CoA. Usually left blank — RADIUS sets it from accounting Start packets.
reseller_idMove ownership. Admins only; resellers can only assign within their own subtree.
FieldNotes
pricePer-subscriber price override. Used when override_price = true.
override_priceCheckbox “Override service price for this subscriber”. When unchecked, the service’s default price applies on renewal.
balanceSubscriber prepaid balance (separate from reseller balance). Drawn down by Refill and TopUp transactions.

full_name, phone, email, address, building, region, country, nationality. All free-text except country and nationality which are dropdowns with 70+ entries each.

FieldNotes
static_ipIf set, RADIUS issues this as Framed-IP-Address in the Access-Accept. Must be unique system-wide — the server checks both subscribers.static_ip and radreply Framed-IP-Address entries before allowing assignment.
is_staticBoolean — treats this user as a static-IP customer for IP pool accounting.
monthly_quota_override / daily_quota_overridePer-subscriber quota overrides (bytes). 0 = use service’s quota.
bonus_dataAdmin/reseller gift of extra GB on top of the monthly quota. Tracked separately from monthly_quota_used so it survives a Reset FUP.
skip_wan_checkBypass the global WAN reachability check for this user (useful when the customer’s CPE is behind double-NAT).

Free-text note field for internal operator notes — visible to everyone with access to the subscriber.

password_plain is encrypted at rest (AES-256-GCM with the license-derived key). On the GET endpoint, the handler runs a separate raw SQL query that decrypts it server-side and returns it in the password field of the response. The frontend shows it as a masked input with an eye-icon toggle to reveal.

Toggling the eye does not re-fetch — the decrypted password is already in the page state. It is never persisted to localStorage. Each refresh re-decrypts server-side.

Resellers without subscribers.view_password (if your install gates this) see the password as a row of dots with no toggle.

Three sub-sections.

Two large progress rings:

  • Dailydaily_download_used + daily_upload_used over the service’s daily_quota. Below the ring, the current FUP tier (1–6) badge.
  • Monthly — same for monthly counters and monthly_quota (plus bonus_data if any). Monthly FUP tier badge.

If the service has unlimited quota (daily_quota = 0 and monthly_quota = 0), the ring becomes “Unlimited”.

Bar chart, one bar per day of the current calendar month. Data comes from a raw SQL query on radacct that groups Accounting-Stop records by day:

SELECT date_trunc('day', acctstoptime),
SUM(acctinputoctets), SUM(acctoutputoctets)
FROM radacct
WHERE username = $1 AND acctstoptime IS NOT NULL
GROUP BY 1

The x-axis runs from day 1 to today (not hardcoded to 31 days — fixed in v1.0.227).

Last 30 days of sessions with start, stop, duration, downloaded, uploaded, NAS, framed IP, calling-station-id (MAC).

Pagination of radacct filtered to this username. Read-only. To force-disconnect, use the Disconnect button at the top of the Profile tab (or the Sessions page).

List of subscriber_bandwidth_rules rows attached to this user. Each rule has: name, time window (from_hour:from_minute → to_hour:to_minute), days of week, download speed (kb), upload speed (kb), enabled flag.

When active, QuotaSync overrides the service’s RADIUS Mikrotik-Rate-Limit with this rule’s speeds. Subscriber-rule speed can also be multiplied by an active global Bandwidth Rule — the formula:

FINAL_SPEED = subscriber_rule_speed × (global_bandwidth_rule_multiplier ÷ 100)

So a subscriber rule of 50000k combined with a global NIGHT rule at 200% gives 100000k. See Bandwidth Rules for the full chain.

Permission: subscribers.bandwidth_rules.

For installs with CDN Management configured. Lets you grant this subscriber extra CDN tier or extend their CDN monthly quota beyond the service default.

If TR-069 is enabled and the subscriber’s PPPoE IP matches a registered CPE device’s WANIPConnection.ExternalIPAddress, the device appears here. Buttons:

  • Set WiFi — Change SSID and/or password for 2.4 GHz, 5 GHz, or both. Pushes via TR-069 SetParameterValues.
  • Reboot — Sends Reboot RPC.
  • Show clients — Click the connected-clients badge to see HostName / IP / MAC / Active flag.

Routers without a TR-069 client (or with the wrong ACS URL) won’t appear. The ACS URL is http://your-server-ip/acs (nginx proxies port 80 → internal 7547).

Embedded list of tickets where subscriber_id = this. Click any to open the conversation in a side panel.

Every change to this subscriber. The middleware builds a per-field diff and stores it in the audit_logs.changes JSONB column. Example entry:

Updated subscriber "info1633":
Status: Active → Inactive
Price: $0.00 → $25.00

Password changes appear only when the password actually changed (the handler compares submitted plaintext against security.DecryptPassword(subscriber.PasswordPlain) — fixed in v1.0.256).

ButtonEffectPermission
SaveSubmit PATCH. Triggers RADIUS attribute rewrite, audit log entry.subscribers.edit
RenewEquivalent to bulk Renew, scoped to this user.subscribers.renew
Reset FUPResets daily counters and FUP level; restores full-speed Mikrotik-Rate-Limit. Monthly counters unchanged.subscribers.reset_fup
Reset MACClears MAC binding so the user can reconnect with a different device.subscribers.reset_mac
DisconnectCoA disconnect → MikroTik API fallback.subscribers.disconnect
Add DaysAdds N days to expiry_date without charging.subscribers.add_days
Change ServiceOpens the prorate calculator — see below.subscribers.change_service
RefillAdds a custom amount to subscriber balance.subscribers.refill_quota
Top-up DataBuys extra monthly GB (extends FUP).subscribers.refill_quota
RenameRenames username — see below.subscribers.rename
PingMikroTik-side ping.subscribers.ping
Live TorchReal-time per-connection traffic graph.subscribers.view_graph
DeleteSoft-delete with confirmation.subscribers.delete

Opens a modal that calls CalculateChangeServicePrice first to show:

  • Days remaining on current plan
  • Pro-rata credit from current plan
  • Pro-rata charge for new plan
  • Net amount (positive = customer owes; negative = credit applied to balance)

On confirm, the system:

  1. Deletes the old radreply Framed-IP-Address (so the user gets a new IP from the new service’s pool).
  2. Releases the IP in ip_pool_assignments.
  3. Writes new Mikrotik-Rate-Limit, Filter-Id (generic RADIUS), Framed-Pool.
  4. Disconnects the user via CoA (with MikroTik API fallback) so they reconnect to the new pool.
  5. Sets last_session_download = 0 and last_session_upload = 0 so QuotaSync re-baselines (v1.0.388 — prevents inflated-delta bugs from inheriting bytes from the old IP’s queue).

Opens a modal asking for the new username. The handler rewrites:

  • subscribers.username
  • All rad_check rows with the old username
  • All radreply rows
  • All radacct rows (active ones get rewritten so accounting continues; closed ones get rewritten for history)

If the new username already exists (excluding soft-deleted rows), the handler returns 409 Conflict.

  1. Open Subscriber Detail.
  2. Profile tab → check status (Inactive blocks login) and expiry_date.
  3. Sessions tab → look at the most recent session’s stop time and acctterminatecause.
  4. Audit Log tab → see if anyone changed something recently (e.g. Reset MAC kicked them off).
  1. Top of page → Reset FUP.
  2. Confirm. Daily counters zero out, FUP level → 0, Mikrotik-Rate-Limit restored to full service speed via CoA.
  3. Within 30 seconds the user is back at full speed without disconnecting.
  1. Profile tab → scroll to Bonus Data.
  2. Enter 5 (GB).
  3. Save. The Usage tab now shows an additional 5 GB capacity above their monthly quota; bonus survives Reset FUP and renews until explicitly cleared.

Section-by-section, summarised here:

PermissionUnlocks
subscribers.viewPage loads
subscribers.editSave button + most fields become editable
subscribers.view_passwordPassword reveal toggle (if your install separates this)
subscribers.bandwidth_rulesBandwidth Rules tab
subscribers.view_graphLive Torch button + Usage tab charts
subscribers.change_serviceChange Service button
subscribers.renameRename button
subscribers.reset_fup / subscribers.reset_mac / subscribers.disconnectCorresponding action buttons
  • Subscribers — the list view this page is reached from.
  • Sessions — full session search across all users.
  • Bandwidth Rules — global time-based speed rules that stack on top of per-subscriber rules.
  • CDN Management — where the CDN Upgrades tab pulls from.
  • Services & Plans — defines the service the subscriber is on.
  • Audit — system-wide audit log.