accounts/docs/architecture/overview.md
2026-04-14 16:32:15 +08:00

8.6 KiB
Raw Blame History

Architecture Overview / 架构总览

中文

系统边界

accounts.svc.plus 是一个以 Gin 为 HTTP 入口的 Go 单体服务。它同时承担四类职责:

  1. 账号与认证注册、登录、会话、MFA、OAuth、密码重置。
  2. 账号控制面管理员权限矩阵、用户管理、Sandbox 假扮、黑名单。
  3. Agent / Xray 控制:向 agent 提供客户端列表、接收 agent 心跳、按数据库状态生成 Xray 配置。
  4. 使用量与计费读面:账户流量桶、账本、配额、策略、节点健康和调度决策读取。

主启动链路

cmd/accountsvc/main.go 的 server 路径可以概括为:

  1. 读取配置并选择运行模式:serveragentserver-agent
  2. 初始化主 store 与管理面 GORM DB后者负责 admin_settings、homepage video、sandbox binding、tenant / XWorkmate 相关模型。
  3. 应用 RBAC schema并确保 root / review / sandbox 用户以及相关体验性账户状态满足当前契约。
  4. 根据 SMTP 配置决定是否启用真实邮件发送;未配置或是示例域名时自动退回“禁用邮件验证”。
  5. auth.enable 为真时构造 auth.TokenService,否则系统仍以 session token 主路径工作。
  6. 构造 agentserver.Registry,将静态 credential、持久化 agent 状态、sandbox binding 预加载到内存读面。
  7. xray.sync.enabled 为真时启动 xrayconfig.PeriodicSyncer,以数据库为源周期性重建 Xray 配置并执行 validate / restart 命令。
  8. 构造 api.Option 列表,把 store、mailer、token service、Stripe、Vault、OAuth provider、metrics provider、agent registry、GORM DB 注入 api.RegisterRoutes
  9. 启动 Gin HTTP 服务,对外提供 /healthz/api/auth/*/api/internal/*/api/admin/*/api/agent-server/v1/*/api/account/*

运行时主数据流

1. 账号登录与会话

  • POST /api/auth/login 读取 store.Store 中的用户和密码哈希。
  • 成功后由 handler.createSession 在 session store 中落 token再由 sanitizeUser 组装用户返回体。
  • 若用户启用 MFA则先返回 challenge再由 POST /api/auth/mfa/verify 完成会话签发。

2. 配置化管理面

  • internal/service/admin_settings.go 使用 GORM 读写 model.AdminSetting
  • API 层通过 requireAdminPermission + service.GetAdminSettings / SaveAdminSettings 组合出“会话鉴权 + 权限矩阵”的控制面能力。
  • internal/service/homepage_video_settings.go 复用同一套 GORM DB负责首页视频默认项和域名覆盖项。

3. Xray 配置生成

  • Controller 模式下,internal/xrayconfig.GormClientSource 从数据库读取用户并转换为 xrayconfig.Client
  • xrayconfig.GeneratorDefinition 模板渲染成 JSON再替换 inbounds[0].settings.clients
  • xrayconfig.PeriodicSyncer 周期性执行 Generate,可选执行 validate / restart 命令。
  • Agent 模式下,internal/agentmode.Client 通过 /api/agent-server/v1/users 获取客户端列表,复用同一套 PeriodicSyncer 本地生成配置并上报 /status

4. 使用量与计费读取

  • internal/store.Store 暴露分钟桶、账本、配额、账单 profile、策略快照、节点健康、调度决策等读取方法。
  • api/accounting.go 将这些事实表组合为 /api/account/*/api/admin/traffic/* 读接口。
  • 这些接口的 source of truth 是 PostgreSQL 事实表,不依赖 Prometheus 聚合。

后台循环与状态持有者

  • agentserver.Registry 在内存中持有 credential digest、agent 身份、最新状态快照和 sandbox agent 集。
  • handler 在 API 层持有 session、MFA challenge、邮箱验证码、密码重置 token、OAuth exchange code 等进程内状态。
  • PeriodicSynceragentmode.runStatusReporter 是主要后台循环;前者负责配置文件收敛,后者负责 agent 健康上报。

当前明确边界

  • Session、MFA challenge、邮箱验证码、OAuth exchange code 都是进程内状态,不是横向可共享存储。
  • JWT token service 是可选增强,不是当前主控制面的唯一鉴权来源;大部分业务仍围绕 session token 设计。
  • GORM 只承载管理面模型,不替代主业务 store。
  • /api/agent/nodes 是 legacy alias规范路径是 /api/agent-server/v1/nodes

English

System Scope

accounts.svc.plus is a Gin-based Go monolith. It owns four main responsibility areas:

  1. Identity and authentication: registration, login, sessions, MFA, OAuth, password reset.
  2. Account control plane: admin permission matrix, user operations, sandbox assume flows, blacklist management.
  3. Agent / Xray control: serving client lists to agents, receiving agent heartbeats, generating Xray configs from database state.
  4. Usage and billing read models: traffic buckets, ledger entries, quota state, policy snapshots, node health, and scheduler decisions.

Main Startup Chain

The server path in cmd/accountsvc/main.go is:

  1. Load config and choose runtime mode: server, agent, or server-agent.
  2. Initialize the primary store plus a GORM-backed admin DB used for admin settings, homepage video, sandbox binding, and tenant / XWorkmate models.
  3. Apply RBAC schema and normalize root / review / sandbox accounts so runtime invariants are satisfied.
  4. Build the mailer if SMTP is configured; otherwise email verification is disabled automatically.
  5. Build auth.TokenService only when auth.enable is true; the service still keeps session-token flows as the primary path.
  6. Build agentserver.Registry, hydrate it from configured credentials and persisted agent rows, and preload sandbox bindings.
  7. Start xrayconfig.PeriodicSyncer when xray.sync.enabled is true so Xray configs are regenerated from database state and optionally validated / restarted.
  8. Build the api.Option list and inject store, mailer, token service, Stripe, Vault, OAuth providers, metrics provider, agent registry, and GORM DB into api.RegisterRoutes.
  9. Start Gin and expose /healthz, /api/auth/*, /api/internal/*, /api/admin/*, /api/agent-server/v1/*, and /api/account/*.

Primary Runtime Flows

1. Identity and Session Flow

  • POST /api/auth/login reads users and password hashes from store.Store.
  • On success, handler.createSession writes a session token and sanitizeUser shapes the user payload.
  • If MFA is enabled, login first returns a challenge and POST /api/auth/mfa/verify completes session issuance.

2. Configurable Admin Surface

  • internal/service/admin_settings.go reads and writes model.AdminSetting through GORM.
  • The API layer combines requireAdminPermission with service.GetAdminSettings / SaveAdminSettings to enforce session-based access plus permission-matrix rules.
  • internal/service/homepage_video_settings.go uses the same GORM DB for default and per-domain homepage video entries.

3. Xray Config Generation

  • In controller mode, internal/xrayconfig.GormClientSource loads users from the database and converts them into xrayconfig.Client records.
  • xrayconfig.Generator renders a Definition template into JSON and replaces inbounds[0].settings.clients.
  • xrayconfig.PeriodicSyncer repeatedly calls Generate and may run validate / restart commands.
  • In agent mode, internal/agentmode.Client fetches /api/agent-server/v1/users, feeds the same PeriodicSyncer, and reports /status.

4. Usage and Billing Reads

  • internal/store.Store exposes traffic buckets, ledger, quota, billing profile, policy snapshot, node health, and scheduler decision reads.
  • api/accounting.go composes those facts into /api/account/* and /api/admin/traffic/* responses.
  • The source of truth for those reads is PostgreSQL-backed fact tables, not Prometheus.

Background Loops and State Owners

  • agentserver.Registry owns credential digests, agent identities, latest status snapshots, and sandbox-agent flags in memory.
  • API handler owns process-local session, MFA challenge, email verification, password reset, and OAuth exchange state.
  • PeriodicSyncer and agentmode.runStatusReporter are the main background loops for config convergence and agent health reporting.

Current Hard Boundaries

  • Sessions, MFA challenges, email verification state, and OAuth exchange codes are process-local, not horizontally shared.
  • JWT is optional and not the sole authentication source for the current control plane; most business flows are still session-centric.
  • GORM is used for admin-side models only and does not replace the primary business store abstraction.
  • /api/agent/nodes is a legacy alias; /api/agent-server/v1/nodes is the canonical route family.