Skip to content

Manager (Backend API)

The vgate-manager/ component is the control plane: a Go service (Gin + GORM) that owns users, nodes, plans, orders, traffic, and system config — including per-user and per-node speed caps — and exposes both the human-facing REST API and the node data plane.

Source: github.com/vgate-project/vgate-manager

Build & run

bash
cd vgate-manager
go build -o vgate-manager .
./vgate-manager --config config.yml     # defaults to ./config.yml; HTTP on server.port (8081)

Other commands (cobra subcommands):

bash
vgate-manager admin create --username X --password Y --role admin|super_admin

GORM AutoMigrate runs automatically on startup (idempotent; the cmd/migrate.go data-migration hook is currently empty). On first start the DB is auto-migrated and an initial admin is bootstrapped from admin.bootstrap in config.yml (default username admin; the bundled docker-compose.yml sets the password to change-me).

Test & lint

bash
go test ./...
go vet ./... && gofmt -l .

Layered structure (internal/)

  • api/ — HTTP layer: router.go (Gin engine + middleware wiring), handler/ (one file per resource: admin_node.go, admin_user.go, server.go, user.go, order.go, plan.go, …), dto/ (request/response structs). Tests: admin_test.go, server_test.go, sub_test.go, auth-level tests.
  • middleware/cors.go, jwt.go (user/admin auth), node_auth.go (node token auth), logger.go, ratelimit.go.
  • service/ — business logic: auth, user, node, plan, order/billing, traffic, stats, subscription, system_config, email/invite, announcement, telegram, ticket. Many have _test.go.
  • model/ — GORM models. util/ — helpers. wire/ — dependency wiring. pkg/crypto/ — shared crypto (VLESS credential helpers).

Startup sequence (run())

  1. Load config (viper).
  2. Open DB (SQLite default via glebarez/sqlite, or Postgres via db.dialect / db.dsn).
  3. AutoMigrate all GORM models.
  4. Run the data-migration hook (cmd/migrate.go, currently empty).
  5. Merge DB-backed system-config overrides on top of config.yml.
  6. Bootstrap the admin.
  7. Build router via api.NewRouter.
  8. Start background tickers: expired-order closer (5 min), hourly-stats pruning (startup + every 24 h), quota reset (startup + every 24 h), and an hourly traffic-reminder scanner (reminderSvc.CheckAndSend). Hourly traffic stats are recorded as nodes report it, not by a scheduler.

API surface (all under /api/v1)

GroupEndpoints
Public / user/user/login, /user/register, /user/verify-email, /user/resend-verification, /user/dashboard, /sub/:sub_token, profile / subscribe / plans / nodes / traffic, orders (+ /:id/pay, /:id/close, /:id/apple-verify), /user/payment-methods, /user/balance, /user/change-plan (+ /change-plan/preview), invites, redemption codes, reminder-channel, support tickets, self-service Telegram link, /billing/:platform/notify (alipay, wechat, stripe, paypal, apple)
Node data planeGET /server/config, GET /server/users, POST /server/traffic
Adminnodes (incl. /:id/users, /:id/regenerate-token), users (incl. /:id/balance read/adjust, /:id/nodes), traffic, stats, system-config, orders, plans, traffic-packages, reference, payment-methods, full admins[/:id] CRUD, invites, redemption codes, announcements, email, tickets, Telegram broadcast/admin-link, zombie-user preview/cleanup
HealthGET /health

Auth

  • JWT. Admin login returns an access token plus a refresh token, and a 401 on a protected endpoint triggers one automatic silent refresh; user login returns only an access token (users get no refresh token — a 401 means re-login).
  • Roles: admin vs super_admin gate plan/admins endpoints.
  • Node endpoints use a separate node token (node_auth middleware).

Telegram & notifications

The manager can run a Telegram bot that delivers alerts and announcements and lets users and admins bind their personal accounts for ticket notifications. It is enabled and configured via DB-backed system config (TelegramConfig):

KeyDefaultMeaning
telegram.enabledfalseMaster switch for the bot.
telegram.bot_token""BotFather token (secret).
telegram.bot_username""Bot @username, used to build /start deep links.
telegram.user_bot_enabledfalseAllow users to self-bind via deep link.
telegram.alert_ticketfalseNotify linked admins on new tickets / user replies.
telegram.alert_announcementfalseForward announcements to linked users.
telegram.alert_order_paidfalseNotify on paid orders (and other alert toggles).
telegram.alert_new_registrationfalseNotify linked admins on new user registrations.
telegram.alert_node_upfalseNotify linked admins when a node comes online.
telegram.alert_node_downfalseNotify linked admins when a node goes offline.
telegram.alert_traffic_exceededfalseNotify linked admins when a user exceeds their traffic quota.

Binding uses a /start <code> deep link. The code carries a u_ (user) or a_ (admin) prefix so the bot routes the bind to the right account: admins link from Settings → Telegram in the admin console, users from Settings in the portal.

When an admin replies to a ticket, the owner is notified on the channel they chose when opening it (none / email / telegram). Every admin with a linked Telegram account also receives an alert on each new ticket and user reply.

Support tickets

Tickets are a lightweight support channel between users and admins.

  • Users open tickets (POST /user/tickets), reply, and can close their own ticket (POST /user/tickets/:id/close). When opening one they pick a notification method (notify_method: none | email | telegram); if omitted it defaults to telegram when their account is Telegram-linked, else none.
  • Admins list/view all tickets, reply (POST /admin/tickets/:id/messages), and move them through a status machine open → in_progress → resolved → closed (PUT /admin/tickets/:id/status). A later user reply reopens a closed ticket.

Admins can also broadcast a message to every linked Telegram user via POST /admin/telegram/broadcast (optionally also published as an announcement).

Config split

File / env onlyDB-backed (hot-reloadable)
server.portjwt TTLs, log.level / log.format
db.*cors.allowed_origins, server.read/write_timeout_secs
jwt.secretquota.reset_day, password.*, registration (user.register_enabled, user.register_require_invite, user.register_require_email_verify, user.register_email_suffix_whitelist) & invite settings, site.* / sub.base_urls, email.*, captcha.*, telegram.*, payment gateway creds (alipay.*, wechat.*, stripe.*, paypal.*, apple.*), reminder.*
admin.bootstrap.*(used only on first run)

The DB-backed set is broad — see Configuration Reference for the full list of hot-reloadable keys. viper maps SERVER_PORT-style env vars.

Database

  • SQLite by default (glebarez/sqlite) — zero external dependencies, great for small deployments.
  • Postgres via db.dialect: postgres and db.dsn.

Production notes

  • Set jwt.secret and a strong admin.bootstrap.password (Docker Compose defaults to change-me).
  • Put the manager behind a reverse proxy (nginx/Caddy) for TLS and to serve the frontends.
  • Enable ratelimit middleware for public endpoints.

Licensed under AGPL-3.0.