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.
How to get here
Section titled “How to get here”- 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).
Layout
Section titled “Layout”Tab strip across the top; each tab is described below.
| Tab | Contents |
|---|---|
| Profile | Account fields, contact, address, service, reseller, expiry, balance, password, static IP, MAC binding, notes |
| Usage | Daily and monthly download/upload, per-day breakdown chart, last-N-days table, FUP tier indicator |
| Sessions | Last 100 PPPoE sessions from radacct (start, stop, duration, bytes, NAS, IP, MAC) |
| Bandwidth Rules | Per-subscriber speed override rules (custom speeds, time windows) |
| CDN Upgrades | Per-subscriber CDN tier overrides, CDN add-on data top-ups |
| CPE Devices | TR-069 routers linked by IP — WiFi SSID/password, reboot, connected clients |
| Tickets | Open and historical support tickets attached to this subscriber |
| Audit Log | Every change made to this subscriber, who made it, when, and what changed |
Profile tab — editable fields
Section titled “Profile tab — editable fields”The page sends one PATCH with an allowedFields map; anything outside the map is ignored server-side. This list is the complete, current allowedFields.
Account
Section titled “Account”| Field | Notes |
|---|---|
username | Renaming uses the dedicated Rename flow because RADIUS attributes are keyed on username. |
password | Plain 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_address | Optional MAC binding. If set, RADIUS rejects logins from any other MAC. |
status | active / inactive. Setting inactive immediately writes Auth-Type := Reject and disconnects the live session. |
expiry_date | Date picker. Past dates put the subscriber in the “Expired” stat counter. |
service_id | Changing this triggers the Change Service flow with prorating. |
nas_id | Override the auto-detected NAS for accounting/CoA. Usually left blank — RADIUS sets it from accounting Start packets. |
reseller_id | Move ownership. Admins only; resellers can only assign within their own subtree. |
Pricing
Section titled “Pricing”| Field | Notes |
|---|---|
price | Per-subscriber price override. Used when override_price = true. |
override_price | Checkbox “Override service price for this subscriber”. When unchecked, the service’s default price applies on renewal. |
balance | Subscriber prepaid balance (separate from reseller balance). Drawn down by Refill and TopUp transactions. |
Contact + Address
Section titled “Contact + Address”full_name, phone, email, address, building, region, country, nationality. All free-text except country and nationality which are dropdowns with 70+ entries each.
Network
Section titled “Network”| Field | Notes |
|---|---|
static_ip | If 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_static | Boolean — treats this user as a static-IP customer for IP pool accounting. |
monthly_quota_override / daily_quota_override | Per-subscriber quota overrides (bytes). 0 = use service’s quota. |
bonus_data | Admin/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_check | Bypass 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 viewing
Section titled “Password viewing”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.
Usage tab
Section titled “Usage tab”Three sub-sections.
Daily and monthly counters
Section titled “Daily and monthly counters”Two large progress rings:
- Daily —
daily_download_used + daily_upload_usedover the service’sdaily_quota. Below the ring, the current FUP tier (1–6) badge. - Monthly — same for monthly counters and
monthly_quota(plusbonus_dataif any). Monthly FUP tier badge.
If the service has unlimited quota (daily_quota = 0 and monthly_quota = 0), the ring becomes “Unlimited”.
Daily breakdown chart
Section titled “Daily breakdown chart”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 radacctWHERE username = $1 AND acctstoptime IS NOT NULLGROUP BY 1The x-axis runs from day 1 to today (not hardcoded to 31 days — fixed in v1.0.227).
Recent sessions table
Section titled “Recent sessions table”Last 30 days of sessions with start, stop, duration, downloaded, uploaded, NAS, framed IP, calling-station-id (MAC).
Sessions tab
Section titled “Sessions tab”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).
Bandwidth Rules tab
Section titled “Bandwidth Rules tab”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.
CDN Upgrades tab
Section titled “CDN Upgrades tab”For installs with CDN Management configured. Lets you grant this subscriber extra CDN tier or extend their CDN monthly quota beyond the service default.
CPE Devices tab
Section titled “CPE Devices tab”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
RebootRPC. - 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).
Tickets tab
Section titled “Tickets tab”Embedded list of tickets where subscriber_id = this. Click any to open the conversation in a side panel.
Audit Log tab
Section titled “Audit Log tab”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.00Password changes appear only when the password actually changed (the handler compares submitted plaintext against security.DecryptPassword(subscriber.PasswordPlain) — fixed in v1.0.256).
Action buttons (top of page)
Section titled “Action buttons (top of page)”| Button | Effect | Permission |
|---|---|---|
| Save | Submit PATCH. Triggers RADIUS attribute rewrite, audit log entry. | subscribers.edit |
| Renew | Equivalent to bulk Renew, scoped to this user. | subscribers.renew |
| Reset FUP | Resets daily counters and FUP level; restores full-speed Mikrotik-Rate-Limit. Monthly counters unchanged. | subscribers.reset_fup |
| Reset MAC | Clears MAC binding so the user can reconnect with a different device. | subscribers.reset_mac |
| Disconnect | CoA disconnect → MikroTik API fallback. | subscribers.disconnect |
| Add Days | Adds N days to expiry_date without charging. | subscribers.add_days |
| Change Service | Opens the prorate calculator — see below. | subscribers.change_service |
| Refill | Adds a custom amount to subscriber balance. | subscribers.refill_quota |
| Top-up Data | Buys extra monthly GB (extends FUP). | subscribers.refill_quota |
| Rename | Renames username — see below. | subscribers.rename |
| Ping | MikroTik-side ping. | subscribers.ping |
| Live Torch | Real-time per-connection traffic graph. | subscribers.view_graph |
| Delete | Soft-delete with confirmation. | subscribers.delete |
Change Service
Section titled “Change Service”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:
- Deletes the old
radreplyFramed-IP-Address (so the user gets a new IP from the new service’s pool). - Releases the IP in
ip_pool_assignments. - Writes new Mikrotik-Rate-Limit, Filter-Id (generic RADIUS), Framed-Pool.
- Disconnects the user via CoA (with MikroTik API fallback) so they reconnect to the new pool.
- Sets
last_session_download = 0andlast_session_upload = 0so QuotaSync re-baselines (v1.0.388 — prevents inflated-delta bugs from inheriting bytes from the old IP’s queue).
Renaming
Section titled “Renaming”Opens a modal asking for the new username. The handler rewrites:
subscribers.username- All
rad_checkrows with the old username - All
radreplyrows - All
radacctrows (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.
Common workflows
Section titled “Common workflows”See why a customer is offline
Section titled “See why a customer is offline”- Open Subscriber Detail.
- Profile tab → check
status(Inactive blocks login) andexpiry_date. - Sessions tab → look at the most recent session’s stop time and
acctterminatecause. - Audit Log tab → see if anyone changed something recently (e.g. Reset MAC kicked them off).
Reset a subscriber stuck in FUP tier 3
Section titled “Reset a subscriber stuck in FUP tier 3”- Top of page → Reset FUP.
- Confirm. Daily counters zero out, FUP level → 0, Mikrotik-Rate-Limit restored to full service speed via CoA.
- Within 30 seconds the user is back at full speed without disconnecting.
Give a customer a 5 GB bonus
Section titled “Give a customer a 5 GB bonus”- Profile tab → scroll to Bonus Data.
- Enter
5(GB). - Save. The Usage tab now shows an additional 5 GB capacity above their monthly quota; bonus survives Reset FUP and renews until explicitly cleared.
Permissions
Section titled “Permissions”Section-by-section, summarised here:
| Permission | Unlocks |
|---|---|
subscribers.view | Page loads |
subscribers.edit | Save button + most fields become editable |
subscribers.view_password | Password reveal toggle (if your install separates this) |
subscribers.bandwidth_rules | Bandwidth Rules tab |
subscribers.view_graph | Live Torch button + Usage tab charts |
subscribers.change_service | Change Service button |
subscribers.rename | Rename button |
subscribers.reset_fup / subscribers.reset_mac / subscribers.disconnect | Corresponding action buttons |
Related pages
Section titled “Related pages”- 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.