Panel-side POST /api/reality/scan performs real TLS handshakes
against operator input (domains / IPs / CIDRs, port suffixes) or the
built-in pool (form presets plus microsoft/google/nvidia/samsung/
cloudflare and friends) and reports per target: usable or not, TLS
version, ALPN, key exchange, first cert SAN, latency, and a short
failure reason. Key-exchange support is proven by restricted-group
handshakes (X25519MLKEM768 first, then X25519, then a combined offer)
since the negotiated group is not exposed to Go clients. Bounds: 32
targets, 8 concurrent, 4s per probe. Node form gains a 查找目标
button beside the Reality preset; the scanner is a stacked overlay
so form state survives, and 使用 backfills SNI/dest/port.
Item 10: remove the disabled decorative topbar search input (each page
has its own working search); CSS rule and media-query reference removed.
Item 11: menu/title renames — 服务器 -> 节点管理, 客户与订阅 -> 用户订阅,
转发与节点 -> 入站&出站, 设置与运维 -> 设置 (nav, TITLES/breadcrumb and
cross-references synced); the chains page add button is now 添加入站 and
its count reads N 个入站; the 安装与命令 page is merged into 设置
(commandsHTML block between the settings grid and the jobs table) and
the page itself is removed from nav, PAGES, TITLES, load() and the view
map — an old #commands hash now lands on the SPA's standard overview
fallback.
Item 12: remove the system page's 最近活动 panel (rendering and its
audit label map plus orphaned CSS); backend audit records untouched.
Item 13: the settings jobs table gets the w-jobs treatment — ID, status
and time cells never wrap, compact row padding, and the error column is
capped at 22% width so an empty error column no longer balloons.
Also fixes a class collision from the item-8 batch: the exit-mode
segmented control is renamed .seg -> .segctl so it no longer draws a
border box around the system page info-bar segments.
Golden re-captured: the only diff is the served index HTML inside
errors.badSubscription, audited character by character as exactly these
renames and removals.
A forward node's exit target is now a choice: a managed panel server
(existing behavior) or a manual landing endpoint — address + port +
protocol (VLESS / SS2022 / SOCKS5) + operator-supplied credentials,
including third-party nodes the panel does not run. The panel only
builds the entry-side sing-box outbound and route rule; there is no
exit resource, no exit job, and the node is exit-ready by definition.
- model: Node.ExitMode/ExitAddress; manual exits force fixed port mode
and skip the exit-server port table entirely
- validation: address/port required; per-protocol credential presence;
SS2022 passwords must be base64 key material of the method's key
length (one PSK segment or serverKey:userKey) — the exact form
sing-box accepts, rejected up front instead of failing at deploy
- orchestration: resource building, deploy validation and rebuilds all
branch on manualExit; switching managed->manual queues removal of the
old exit resource, manual->managed mints a fresh exit resource id
(deploy validation previously dereferenced the nil exit server —
regression test locks the fix)
- UI: exit target segmented control, link paste box that parses
vless:// / ss:// / socks5:// links into the form, per-protocol
credential fields (blank keeps the stored value on edit)
- golden: new manualCreate/manualAssign/manualDeploy/manualJobs/
manualNodes sections — exactly one entry-side job whose outbound
targets the manual address; all prior sections unchanged
- the generated combined sing-box config passes the real sing-box
1.13.21 check
GET /api/customers gains a summary object (total/online/depleted/
depletingSoon/disabled/enabled) computed server-side; the customers page
renders it as a six-cell stats strip above the toolbar.
Predicates aligned verbatim with 3x-ui client_paging.go:
- depleted = (limit>0 && used>=limit) || (expiry set && expiry<=now),
counted regardless of status;
- depletingSoon = active && !depleted && (expiry within expireDiff days
|| remaining traffic < trafficDiff GB), thresholds from new settings
expireDiff/trafficDiff with 3x-ui's factory default 0 (nobody counts
until configured);
- enabled = status active; disabled = manual suspensions only.
Online reuses the existing 3-minute presence projection.
Golden diff confined to the additive summary keys; summary_test.go
covers every bucket with thresholds off (soon=0) and on (soon=2).