Changelog

Product milestones for the XCTL control plane, Client agent, and admin console. For upgrade steps, see the upgrade guide.

Line provisioning moves to logical nodes

Dedicated inbound provisioning (legacy Mode A) is removed from the roadmap. New lines and per-order routing now go through logical nodes and the Admin API instead.

  • Adapter integrations should create or bind logical nodes rather than per-order inbounds
  • WHMCS and panel plugins align with the logical-node lifecycle
  • Docs updated for upgrade paths and integration overview

This keeps multi-tenant routing consistent and avoids one-off inbound sprawl on XUI nodes.

Panel integrations and TLS inline certificate fixes

V2RaySocks panel_full

  • Hysteria2 root-level act=config parsing and inbound build on the V2RaySocks adapter path
  • WHMCS plugin: VLESS tcp/tls and HY2 SNI/obfs subscription shapes
  • Runbook added for end-to-end panel_full validation

TLS inline certificates

  • Fixed empty-line PEM edge cases when fullchain or imported certs reached panel wire format
  • PEMToLines + prepareDesiredCerts hard validation before sync
  • Remark-based cert claim and Master fingerprint dedup to stop duplicate TLS refs on the same host

OpenAPI (InboundSyncPayload, DesiredInbound, TLSCertRef) and WebSocket protocol docs were updated to match.

Dashboard traffic analytics, Hysteria2, and WireGuard

Business traffic statistics

  • New node_traffic_daily aggregation table (logical node ↔ host, 90-day retention)
  • Inbound-stats reporter computes deltas from cumulative XUI counters
  • GET /admin/overview/traffic-summary with 1d / 7d / 30d / 90d ranges: totals, daily trend, and rankings by server, logical node, protocol, and region
  • Admin dashboard ops charts now use this API; live NIC vitals remain for real-time speed graphs only

Hysteria2

  • Client hysteria_auth and XUI clients[].auth alignment
  • hysteria2:// share links (Salamander, allowInsecure)
  • newV2board and V2RaySocks panel fallbacks for HY2 auth fields

WireGuard

  • wireguard_peers table and WireGuardPeerService
  • Config sync injects peers[] into desired inbounds
  • .conf download via admin and user APIs; peers disabled on user suspend/delete
  • User detail dialog: WireGuard config download in the admin console

Device limits and relay true-IP handling

Online device enforcement and relay topologies are now documented and partially shipped across Master, templates, and the admin UI.

Device limits

  • Users page: over-limit visualization and risk-state storage split from core user records
  • device_limit semantics aligned with alive reporting
  • Template-level acceptProxyProtocol with per-host override for landing nodes behind relays

Relay / true client IP

  • Realm-panel → landing IP propagation in alive paths
  • Xray acceptProxyProtocol option documented as an alternative to Nginx set_real_ip_from on some layouts
  • Ops checklist for shared-IP abuse vs strict device caps

Implementation tracked in PR-1/2/3; see the device-limit docs for rollout order (visibility first, full enforcement second).

Host groups and node mapping (PR-7)

The control plane now models host groups and node mapping so logical nodes can fan out across physical hosts without manual per-host edits.

Console

  • Host group CRUD, membership, and reconcile flows in the admin UI
  • Logical node detail: host binding tab with manual override and reconcile
  • Node mapping v2 form, mapping table, sync, and export (E2E validation ongoing)

Master

  • Migration 008 + Admin API for node groups
  • Migration 013 + host-group reconcile; soft-delete and purge regression tests
  • Pull safety invariants for multi-tenant user sync

Config sync safety hardening

A full audit closed several classes of accidental user or inbound deletion during panel pull and host lifecycle events.

Master

  • User pull no longer uses ETag/304; stale cached bodies cannot skip reconciliation
  • reconcileUnionAfterMappingPulls only prunes when a fresh 200 body is available
  • Host soft-delete runs ReconcileHostBindings including manual direct binds
  • Host group delete: rows removed first, then reconcile — no orphan bindings left behind

Client

  • Runner requires a second confirmation before pruning on empty desired state or narrowed scope
  • Orphan client cleanup: user.invalidate + PruneOrphanClients + panel pull reconcile when union is zero

Regression coverage: panel_group_pull_test.go, runner_test.go, host_group_service_test.go.

Platform admin, licensing, and observability

Generic control-plane operations that sit above panel-specific sync logic.

Settings & security

  • master_settings registry with DB-backed cache and /admin/settings API
  • Admin login + JWT + optional TOTP 2FA (migrations/009)
  • Secret fields encrypted at rest (enc:v1:) with API redaction

License client (P4)

  • Remote validate + AES decrypt into xuictl_license
  • Grace / degraded modes instead of hard exit on transient center outages
  • max_hosts / max_users / max_logical_nodes enforced on create
  • Admin license panel + banner; host/user/logical-node create blocked when degraded

Alerts (P3)

  • AlertDispatcher with Telegram delivery and dedup windows
  • Host offline, stale vitals, webhook event_dead, and license expiry hooks
  • POST /admin/notification/test from system settings

Dashboard & audit (P5)

  • GET /admin/overview with per-module failure degradation
  • GET /admin/audit-logs with tenant scoping and secret redaction on read
  • Admin UI: /xuictl/dashboard stats layout and /xuictl/audit-logs with shared pagination component

Protocol catalog, templates, and config sync pipeline

The data-driven inbound pipeline replaced hand-edited per-host JSON as the source of truth.

Protocol catalog

  • protocol_catalog table with seeded capability matrix (internal/xui/catalog)
  • Admin API: list, get, patch, import/export with audit on mutating calls
  • Transactional import and MarkDeprecatedExcept guardrails

Protocol templates

  • JSON settings / stream templates with quoted {{placeholder}} rendering
  • Multi-version templates, dry-run API, and delete protection when still referenced by logical nodes

Logical nodes

  • CRUD + host bind/unbind; auto-generated Reality keys and shortIds when missing
  • render.Compose builds the full inbound set per node
  • POST .../render and POST .../sync push inbound.sync over the agent WebSocket

Client inbound syncer

  • Diff by tag prefix, ordered Add → Update → Delete, hash cache to skip no-op updates
  • POST /server/UniProxy/inbound-sync reports binding status back to Master

Subscription output

  • internal/xui/share generators for VLESS, VMess, Trojan, Shadowsocks (+ xhttp/kcp matrix)
  • Users GET .../subscribe now emits real share links from enabled logical nodes
  • Admin issue-subscribe-url for support tooling (raw, Clash, Sing-box, etc.)

Phase 4 code review fixes (revision stale guard, NodeVars merge PATCH, duplicate tag handling) landed the same week.

Orphan cleanup and AgentHub control messages

Closed the loop when panel users disappear or panel API tokens rotate mid-flight.

Orphan clients

  • Cleanup synced state transitions emit user.invalidate to edge agents
  • Client PruneOrphanClients removes stale XUI clients after invalidate
  • Inbound delete triggers OnApplied reconcile
  • Scheduled panel pull reconcile including union=0 edge case

AgentHub

  • Reconcile ops broadcast user.invalidate
  • PATCH panel_api_token pushes config.update so agents drop etag and force PullUsers
  • Master /ws/agent registry with connection-scoped IDs (race-safe register/unregister)

Panel token tooling

  • GET .../probe for pre-flight panel reachability
  • scripts/e2e-vps.sh gate script for VPS bring-up
  • Migration 004_add_panel_api_token_id for token lineage

These changes sit between the protocol-catalog pipeline and host-group work; they reduced “ghost users” on nodes after mapping changes.

Certificate Center shipped

TLS for inbounds and edges can be managed from the Certificate Center instead of hand-editing every node.

  • Issue, renew, and attach certificates from the admin console
  • ACME workflows with platform settings under certificates.*
  • DNS-01 support: Aliyun, DNSPod, and Tencent Cloud providers
  • Delete protection, CA-friendly names, and last_error surfaced in the UI

OpenAPI and WebSocket protocol docs were synced with the new certificate events.

Config sync queue and SSH provisioning

Operations that touch real hosts are now queued, streamed, and observable from the console.

Config sync queue

  • config_sync_tasks table and ConfigSyncQueueService
  • Bind, unbind, patch, delete, and manual sync enqueue instead of failing inline when a host is offline
  • waiting_host state with flush on agent reconnect
  • Admin /admin/config-sync-queue + UI batch modal
  • Logical node delete no longer returns 409 “unbind first” — work is queued

SSH provisioning

  • POST /admin/hosts/provision NDJSON stream for one-click install
  • SSH credential vault, test-ssh, install sessions, ops actions, and Web SSH entry
  • Recycle bin: soft delete, restore, purge with streamed progress
  • GET .../probe and panel token rotation helpers for field rollout

Inbound observability

  • node_hosts inbound client count and traffic snapshot columns
  • Client reporter → POST /server/UniProxy/inbound-stats for per-binding cards in the UI

Users API and OpenAPI contract gate

M1 backend surface: tenant-scoped user lifecycle with a frozen REST contract.

Users REST API

  • POST /api/v1/users with idempotency keys and subscribe URL in the response
  • Cursor-paginated list, get, patch, soft delete by biz_ref
  • reset-uuid, reset-traffic, traffic read, and subscribe endpoints
  • HMAC-signed subscription URLs (?token= or Bearer)

Master skeleton

  • GET /healthz, /readyz, /version
  • Bearer auth with tenant scope via adapter tokens
  • MariaDB + GORM migrations with xuictl_ table prefix

Quality gate

  • Schemathesis contract tests on the M1 OpenAPI subset — 56/56 passing
  • make regression-users for user lifecycle regressions
  • Prism mock + local Docker dev stack (make dev-up) for panel integrators

Client agent at this stage was still Mode B mocks; real XUI sync followed in the April milestone.

Client agent: real XUI sync and Master WebSocket

The Client agent graduated from mock placeholders to production-shaped sync against real 3x-ui panels.

  • REST session + centralized Batch API against XUI
  • WebSocket link to Master with host.status.tick vitals
  • UniProxy HTTP push/status/alive/pull on the Client transport path
  • Traffic collector, alive reporter, and panel alive push back to Xboard-style panels
  • Reload batching and user syncer aligned with the architecture spec

Master M2 backend phases A–E are closed; multi-node field validation is next.

Admin console foundation

The self-hosted admin UI (frontweb) reached a demo-ready slice on top of the Master Admin API.

  • Tenants, users, permission groups, and Adapter token management
  • Logical nodes, protocol catalog, and protocol templates (multi-version + dry-run)
  • Physical hosts: CRUD, SSH credentials, streamed SSH provision, ops actions, and recycle bin
  • Config sync queue, events console, and audit-oriented admin tokens
  • Static export build wired into make web-build for co-deployment with Master

Users REST API (CRUD, traffic, subscribe URL) and OpenAPI contract tests (56/56 on the M1 surface) shipped in the same milestone.