diff --git a/AGENTS.md b/AGENTS.md index 8bd0e39..264db03 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -3,3 +3,56 @@ This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` before writing any code. Heed deprecation notices. + +# Repository Notes For Coding Agents + +This file is for agents working in this repository. Product, deployment, API, and operations documentation belongs in `README.md`, `docs/API.md`, and `agent/jboard-agent/README.md`. + +## Project Shape + +J-Board is a Next.js App Router application backed by Prisma/PostgreSQL and Redis. It integrates with 3x-ui rather than replacing it: + +- J-Board owns users, orders, plans, subscriptions, payments, support, notifications, audit logs, settings, and risk review. +- 3x-ui owns actual inbound runtime configuration and Xray clients. +- `agent/jboard-agent` is a read-only sidecar for latency, route trace, and optional Xray access log telemetry. + +Do not add a new node control plane or Xray process manager unless the user explicitly changes the product direction. + +## Next.js Work + +Before editing App Router files, route handlers, server actions, metadata, or caching behavior, read the relevant docs from `node_modules/next/dist/docs/` for the installed Next.js version. + +Common areas to check: + +- App Router file conventions. +- Route Handler request/response behavior. +- Server Actions and `use server` requirements. +- Caching, `revalidatePath`, and dynamic rendering rules. + +## Version And Release Policy + +Panel and Agent versions are not forced to move together. + +- Website/admin/UI/docs/server-only changes can be committed and pushed to `main` without creating a GitHub Release. +- Only create a new Agent tag and GitHub Release when Agent code, Agent install/upgrade behavior, or Agent release artifacts change. +- Agent releases must include `jboard-agent-linux-amd64`, `jboard-agent-linux-arm64`, and `SHA256SUMS`. +- Agent runtime version is in `agent/jboard-agent/cmd/agent/main.go`. +- Agent build version is in `agent/jboard-agent/Makefile`. +- Panel package version is in `package.json` and does not need to match the Agent version. + +## Documentation Policy + +When changing behavior, update docs in the same change: + +- User/deployment/admin docs: `README.md`. +- HTTP API and Server Actions: `docs/API.md` and, for public HTTP changes, `docs/openapi.yaml`. +- Agent install, runtime, logs, and release behavior: `agent/jboard-agent/README.md`. +- Agent-facing repository rules: this file. + +Keep docs factual and operational. Avoid promising features that are not implemented. + +## Risk And Privacy Notes + +Subscription risk and node access telemetry contain sensitive evidence: user IPs, locations, Xray client email, target hosts, timestamps, and admin review decisions. Treat these as sensitive data in logs, docs, screenshots, and tests. + +Agent Xray log telemetry must remain read-only. It may read access logs and post aggregates to J-Board; it must not mutate 3x-ui or Xray runtime configuration. diff --git a/README.md b/README.md index 7bf5416..2db6cef 100644 --- a/README.md +++ b/README.md @@ -1,176 +1,156 @@ # J-Board -J-Board(也称 JB面板)是一个面向代理订阅售卖与流媒体共享的全栈应用。节点运行、入站和客户端配置由 3x-ui 面板维护;J-Board 负责售卖、订单、订阅、用户、支付、工单和探测展示;自带 Go 程序只做延迟与线路探测上报。 +J-Board(也称 JB 面板)是一个面向代理订阅售卖与流媒体共享的全栈管理面板。它负责用户、套餐、订单、支付、订阅、工单、邮件、公告、审计、探测展示与订阅风控;节点实际运行、入站协议、Xray 客户端配置仍由 3x-ui 维护。 -## 架构 +J-Board 的定位很明确:它不是新的节点控制面,也不替代 3x-ui。它把售卖、开通、订阅交付、售后和风险审查做成一个完整面板,并通过只读 Agent 从节点侧采集延迟、路由和 Xray access log 证据。 + +## 快速认识 ```text -用户浏览器 +用户浏览器 / 客户端订阅 ↓ Next.js App Router 面板 - ├─ PostgreSQL / Redis - ├─ 3x-ui API:同步入站、开通/暂停/删除客户端 - └─ Probe API:接收 jboard-agent 的延迟与路由上报 + ├─ PostgreSQL:用户、订单、套餐、订阅、审计、风控事件 + ├─ Redis:限流、后台任务与缓存辅助 + ├─ 3x-ui API:同步入站、开通/暂停/删除代理客户端 + └─ Agent API:接收 jboard-agent 上报的延迟、路由、节点真实连接日志 + +节点 VPS + ├─ 3x-ui / Xray:真实入站、客户端、流量限制与代理运行 + └─ jboard-agent:旁路只读探测与日志聚合,不修改 3x-ui 配置 ``` -J-Board 只保存售卖和展示所需的节点、入站、客户端镜像数据,不下发 Xray/Hy2 配置,也不维护自建节点控制面。 +J-Board 只保存售卖和展示需要的节点镜像数据。入站协议、端口、Reality/TLS、Xray 运行状态和客户端真实配置仍以 3x-ui 为准。 -## 功能 +## 功能概览 用户端: -- 注册、登录、Cloudflare Turnstile 人机验证 -- 代理套餐与流媒体套餐购买、续费、增流量 -- 线路体验:三网延迟、延迟历史、三网路由追踪详情 -- 代理订阅查看、订阅链接下载、订阅访问重置 -- 流媒体订阅查看与凭据展示 -- 通知中心、工单售后、账号资料、邀请码 -- 响应式移动端适配 +- 注册、登录、邮箱验证、忘记密码、邮箱变更验证。 +- 支持 Cloudflare Turnstile 人机验证。 +- 代理套餐和流媒体套餐购买、续费、增流量。 +- 购物车、订单、支付状态查询和支付方式切换。 +- 代理订阅查看、订阅链接下载、订阅访问重置。 +- 线路体验展示:三网延迟、延迟历史、三网路由追踪。 +- 流媒体订阅凭据展示。 +- 通知中心、工单售后、账号资料、邀请码。 +- 暗色/夜间模式和移动端适配。 管理端: -- 3x-ui 节点管理:保存面板地址、账号、密码,测试连接并同步入站 -- 本地入站展示名称维护,套餐绑定同步后的入站线路 -- 探测 Token 管理:仅用于 `/api/agent/latency` 与 `/api/agent/trace` -- 用户、订单、套餐、订阅、流媒体服务、支付配置 -- 公告、工单、系统设置、审计日志、任务中心、备份恢复 -- 流量视图:基于本地订阅与 3x-ui 同步结果展示客户端用量 +- 3x-ui 节点管理:保存面板地址、账号、密码,测试连接并同步入站。 +- 本地入站展示名维护,套餐绑定同步后的入站线路。 +- 探测 Token 管理:用于 Agent 上报延迟、路由和节点日志。 +- 用户、订单、套餐、订阅、流媒体服务、支付配置。 +- SMTP 邮件服务设置、注册邮箱验证开关、邮件模板发送。 +- 公告、工单、系统设置、审计日志、任务中心、备份恢复。 +- 支持工单上限配置,默认每个用户最多开启 2 个未关闭工单。 +- 流量视图:基于本地订阅与 3x-ui 同步结果展示客户端用量。 +- 订阅访问风控:IP、城市、省/地区、国家变化审查。 +- 节点日志风控:基于 Xray access log 分析真实来源 IP、连接数、不同目标数。 +- 风控人工处理:查看用户、订阅、地图、IP、分析日志,生成风险报告,选择解除限制或保持封禁/暂停。 节点侧: -- 3x-ui 负责入站、客户端、协议配置和节点运行 -- J-Board 通过 3x-ui API 同步入站并执行客户端增删改 -- `agent/jboard-agent` 只负责三网 TCP 延迟和三网路由追踪 +- 3x-ui 负责入站、客户端、协议配置和节点运行。 +- J-Board 通过 3x-ui API 同步入站并执行客户端增删改。 +- `agent/jboard-agent` 负责三网 TCP 延迟、三网路由追踪和可选 Xray access log 风控上报。 +- Agent 只读日志文件,不重启 Xray,不修改 3x-ui 配置。 -## 核心流程 +## 版本与发布规则 -节点接入: +J-Board 面板和 Agent 使用相对独立的版本节奏。 -1. 管理员在 3x-ui 中创建真实入站。 -2. 管理员在 J-Board 添加节点并填写 3x-ui 面板地址、用户名、密码。 -3. J-Board 登录 3x-ui,读取入站列表并写入 `NodeInbound`。 -4. 管理员将套餐绑定到已同步入站。 -5. 用户购买代理套餐后,J-Board 调用 3x-ui API 创建客户端,并保存 `NodeClient`。 -6. 订阅暂停、恢复、删除、重置访问时,同步调用 3x-ui API 更新客户端。 +- 面板代码变更可以只提交到 `main`,不一定创建 GitHub Release。 +- Agent 二进制发生变化时,才需要升级 Agent 版本、打 tag、创建 Release,并上传 `jboard-agent-linux-amd64`、`jboard-agent-linux-arm64`、`SHA256SUMS`。 +- Agent 安装/升级脚本默认下载 GitHub 最新 Release 中的 Agent 产物。 +- 不要为了普通网站页面或后台文案改动强行更新 Agent tag。 -支付开通: - -1. 用户选择套餐、入站和流量规格并创建订单。 -2. 支付平台回调后,`src/services/payment/process.ts` 标记订单已支付。 -3. `src/services/provision.ts` 创建或更新 `UserSubscription`。 -4. 代理订阅通过 `src/services/node-panel` 调用 3x-ui 创建或更新客户端。 -5. 流媒体订阅分配 `StreamingSlot`。 - -探测上报: - -1. 管理员为节点生成探测 Token。 -2. 节点运行 `agent/jboard-agent`,配置 `SERVER_URL` 和 `AUTH_TOKEN`。 -3. 探测程序定时调用 `POST /api/agent/latency` 和 `POST /api/agent/trace`。 -4. J-Board 按 Token 匹配节点并更新延迟、历史和路由数据。 +当前项目版本写在 `package.json`,Agent 运行时版本写在 `agent/jboard-agent/cmd/agent/main.go`,Agent 构建版本写在 `agent/jboard-agent/Makefile`。 ## 技术栈 - Next.js 16 App Router + React 19 - Prisma 7 + PostgreSQL 16 -- NextAuth 4 Credentials + Cloudflare Turnstile +- NextAuth 4 Credentials - Redis 7 - Tailwind CSS 4 + Base UI + Sonner + Recharts -- Go probe agent +- Nodemailer SMTP 邮件 +- MaxMind MMDB GeoIP +- Go jboard-agent - Docker / Docker Compose -## 目录 +注意:本项目使用的 Next.js 版本包含和旧版本不同的约定。开发前请阅读 `AGENTS.md`,并按 `node_modules/next/dist/docs/` 中的当前文档实现。 -- `src/app`:页面、布局、Route Handlers -- `src/actions`:Server Actions,负责写操作、权限校验、审计和缓存刷新 -- `src/services`:领域服务与第三方适配 -- `src/services/node-panel`:3x-ui 面板适配层 -- `src/services/provision.ts`:支付成功后的订阅开通与 3x-ui 客户端同步 -- `src/services/subscription.ts`:订阅内容生成 -- `src/lib`:Prisma、鉴权、加密、Turnstile、通用工具 -- `prisma/schema.prisma`:数据模型事实源 -- `agent/jboard-agent`:延迟与线路探测程序 -- `docs/API.md`:HTTP 接口与 Server Actions 参考 -- `docs/openapi.yaml`:对外 HTTP 接口的 OpenAPI 描述 +## 目录结构 + +| 路径 | 说明 | +| --- | --- | +| `src/app` | 页面、布局、Route Handlers。 | +| `src/actions` | Server Actions,负责写操作、权限校验、审计和缓存刷新。 | +| `src/services` | 领域服务与第三方适配。 | +| `src/services/node-panel` | 3x-ui 面板适配层。 | +| `src/services/provision.ts` | 支付成功后的订阅开通与 3x-ui 客户端同步。 | +| `src/services/subscription-risk.ts` | 订阅访问与节点日志风控判定。 | +| `src/services/subscription-risk-review.ts` | 风控事件证据整理、报告生成辅助。 | +| `src/lib` | Prisma、鉴权、加密、Turnstile、GeoIP、工具函数。 | +| `prisma/schema.prisma` | 数据模型事实源。 | +| `data/GeoLite2-City.mmdb` | 默认 GeoIP 城市库。 | +| `agent/jboard-agent` | Go Agent 源码、构建脚本和 Agent 文档。 | +| `scripts/install-jboard-panel.sh` | 面板一键安装向导。 | +| `scripts/upgrade-jboard-panel.sh` | 面板升级脚本。 | +| `scripts/install-jboard-agent.sh` | Agent 安装脚本。 | +| `scripts/upgrade-jboard-agent.sh` | Agent 升级脚本。 | +| `docs/API.md` | HTTP 接口与 Server Actions 参考。 | +| `docs/openapi.yaml` | 对外 HTTP 接口 OpenAPI 描述。 | ## 环境变量 -以 `.env.example` 为准。生产部署推荐直接使用一键脚本生成 `.env`,手动配置时请重点确认这些值: +以 `.env.example` 为准。生产部署推荐使用一键脚本生成 `.env`,手动配置时重点确认下列变量。 | 变量 | 用途 | 说明 | | --- | --- | --- | | `APP_PORT` | 面板监听端口 | 默认 `3000`。反向代理应转发到 `http://127.0.0.1:APP_PORT`。 | | `SITE_NAME` | 站点名称 | 初始化系统设置和邮件模板会使用。 | -| `NEXTAUTH_URL` | 网站访问地址 | 必须填写你准备反代到面板的正式域名,例如 `https://panel.example.com`。不要填容器内地址。 | -| `SUBSCRIPTION_URL` | 订阅访问地址 | 可选。用于生成客户端订阅链接,例如 `https://sub.example.com`;留空时复用 `NEXTAUTH_URL`。如果使用独立订阅域名,也要反代到同一个面板服务。 | +| `NEXTAUTH_URL` | 网站访问地址 | 必须填写准备反代到面板的正式域名,例如 `https://panel.example.com`。不要填 `localhost`、容器名或内网地址。 | +| `SUBSCRIPTION_URL` | 订阅访问地址 | 可选。用于生成客户端订阅链接,例如 `https://sub.example.com`;留空时复用 `NEXTAUTH_URL`。 | | `NEXTAUTH_SECRET` | 登录会话密钥 | 生产环境必须使用随机长字符串。 | -| `ENCRYPTION_KEY` | 敏感信息加密密钥 | 至少 32 字节。生产使用后不要更换,否则 3x-ui 密码、探测 Token、流媒体凭据等已加密数据会无法解密。 | +| `ENCRYPTION_KEY` | 敏感信息加密密钥 | 至少 32 字节。生产使用后不要更换,否则 3x-ui 密码、探测 Token、SMTP 密码、流媒体凭据等已加密数据会无法解密。 | | `DATABASE_URL` | PostgreSQL 连接 | 本地工具使用;Docker 部署时 Compose 会覆盖为容器内数据库地址。 | | `POSTGRES_PASSWORD` | Docker PostgreSQL 密码 | 一键脚本会自动生成。 | | `REDIS_URL` | Redis 连接 | 本地工具使用;Docker 部署时 Compose 会覆盖为容器内 Redis 地址。 | +| `GEOIP_MMDB_PATH` | GeoIP 城市库 | 默认 `data/GeoLite2-City.mmdb`。可换成自己的 MaxMind City MMDB。 | | `ADMIN_EMAIL` / `ADMIN_PASSWORD` / `ADMIN_NAME` | 初始管理员 | 首次 `db:seed` 创建管理员账号。已有数据库不会强制重置旧管理员密码。 | -SMTP 邮件服务、注册邮箱验证开关、支付方式、3x-ui 节点等业务配置都在管理后台填写,不建议写进 `.env`。 +SMTP 邮件服务、注册邮箱验证开关、支付方式、3x-ui 节点等业务配置在管理后台填写,不建议写进 `.env`。 -## 本地开发 +## 一键部署 + +适合全新 Linux 服务器。脚本会安装基础依赖、安装 Docker 与 Compose 插件、拉取代码、生成 `.env`、初始化数据库并启动面板。 ```bash -npm install -cp .env.example .env -npm run db:push -npm run db:seed -npm run dev +bash <(curl -fsSL https://raw.githubusercontent.com/JetSprow/J-Board/main/scripts/install-jboard-panel.sh) ``` -默认管理员账号: +脚本会交互询问: -- 邮箱:`admin@jboard.local` -- 密码:`admin123` - -常用检查: - -```bash -npx prisma generate -npx tsc --noEmit -npm run lint -npm run build -``` - -数据库变更: - -- 修改 `prisma/schema.prisma` 后运行 `npx prisma generate` -- 使用 `npm run db:push` 同步 schema 到数据库 -- 不维护 Prisma migrations,不提交迁移脚本 -- 删除字段或模型时同步清理引用、文档和导出逻辑 - -## 部署 - -### 一键部署(推荐) - -适合全新的 Linux 服务器。脚本会自动安装 Docker 与 Compose 插件,拉取代码,询问并生成 `.env`,初始化数据库,启动面板,最后输出访问地址、反代目标和管理员账号。 - -```bash -curl -fsSL https://raw.githubusercontent.com/JetSprow/J-Board/main/scripts/install-jboard-panel.sh | bash -``` - -脚本会询问这些信息;直接回车即可使用默认值或自动生成值: - -| 提示项 | 含义 | +| 问题 | 如何填写 | | --- | --- | | 安装目录 | 默认 `/opt/jboard`;如果在仓库内运行脚本则默认当前仓库。 | | 站点名称 | 面板标题、邮件模板和初始化系统设置会使用。 | | 网站访问地址 | 你准备反向代理到本机 `3000` 端口的面板域名,例如 `https://panel.example.com`。没有域名时可先用 `http://服务器IP:3000` 测试。 | -| 订阅访问地址 | 用于生成 Clash/V2rayN/Shadowrocket 等客户端订阅链接。可与网站访问地址相同,也可填独立订阅域名,例如 `https://sub.example.com`。 | -| 本机监听端口 | 默认 `3000`,Nginx/Caddy/宝塔反代目标就是 `http://127.0.0.1:3000`。 | +| 订阅访问地址 | 用于生成 Clash/V2rayN/Shadowrocket 等客户端订阅链接。可以和网站地址相同,也可以填独立订阅域名,例如 `https://sub.example.com`。 | +| 本机监听端口 | 默认 `3000`。Nginx、Caddy、宝塔或 1Panel 的反代目标就是 `http://127.0.0.1:3000`。 | | 管理员邮箱和密码 | 首次初始化会创建该管理员,脚本完成后会再次打印。 | | PostgreSQL 密码、`NEXTAUTH_SECRET`、`ENCRYPTION_KEY` | 可手动输入;回车会自动生成安全值。 | -也可以用环境变量覆盖默认行为: +也可以通过环境变量覆盖默认行为: ```bash APP_DIR=/opt/jboard GH_REPO=JetSprow/J-Board BRANCH=main bash <(curl -fsSL https://raw.githubusercontent.com/JetSprow/J-Board/main/scripts/install-jboard-panel.sh) ``` -脚本完成后,你会看到类似信息: +脚本完成后会输出: ```text 访问地址:https://panel.example.com @@ -180,39 +160,9 @@ APP_DIR=/opt/jboard GH_REPO=JetSprow/J-Board BRANCH=main bash <(curl -fsSL https 管理员密码:自动生成或你输入的密码 ``` -### 反向代理 +请把管理员密码保存到密码管理器。已有数据库重复部署时,脚本会尽量沿用现有配置,不会随意重置管理员。 -`NEXTAUTH_URL` 和后台“系统设置 -> 网站 URL”都应该填写面板公网域名,也就是你准备给用户访问、并反向代理到 J-Board 的域名。不要填写 `localhost`、容器名或内网地址。 - -`SUBSCRIPTION_URL` 和后台“系统设置 -> 订阅 URL”只用于生成客户端订阅链接。它可以和网站 URL 相同;如果你想单独做 Cloudflare/WAF/访问风控,建议使用 `https://sub.example.com` 这类独立域名,并把它也反向代理到同一个 J-Board 服务。独立订阅域名只需要承载 `/api/subscription/*`,后续可以在反代或 WAF 层对其他路径返回 404。 - -Nginx 示例: - -```nginx -server { - listen 80; - server_name panel.example.com sub.example.com; - - location / { - proxy_pass http://127.0.0.1:3000; - proxy_http_version 1.1; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; - } -} -``` - -正式上线建议再用 Certbot、宝塔、1Panel、Caddy 或 CDN 申请 HTTPS 证书,然后把 `NEXTAUTH_URL` 改为 `https://panel.example.com`。如果单独使用订阅域名,把 `SUBSCRIPTION_URL` 或后台订阅 URL 改为 `https://sub.example.com`。 - -订阅域名套 Cloudflare 时,源站应只允许 Cloudflare 回源或通过 Cloudflare Tunnel 暴露服务,并正确传递 `CF-Connecting-IP` / `X-Forwarded-For`。否则后续订阅访问风控中的真实 IP 可能被直连源站请求伪造。 - -J-Board 会记录订阅 API 的真实 IP、User-Agent 和可用的地理位置头,并按后台“系统设置 -> 订阅访问风控”配置执行限流、跨城市/省份告警与自动暂停。默认规则保持为:24 小时内 4 个城市警告、5 个城市暂停;2 个省/地区警告、3 个省/地区暂停;2 个国家/地区警告、3 个国家/地区暂停;IP 180 次/小时、订阅 60 次/小时。管理员可以关闭风控总控,或关闭自动暂停改为只记录警告;也可以在后台“订阅风控”查看关联用户、订阅、IP、地区统计,并将事件标记为待处理、已确认或已解决,必要时可人工恢复被暂停的订阅。项目内置 `data/GeoLite2-City.mmdb` 作为本地 GeoIP 城市库,默认通过 `GEOIP_MMDB_PATH=data/GeoLite2-City.mmdb` 读取;如果反代或 CDN 已传地理位置头,系统优先使用请求头,并用 MMDB 补齐缺失字段。Cloudflare 场景建议在 Rules -> Settings -> Managed Transforms 开启 Add visitor location headers,让回源请求带上 `cf-ipcity`、`cf-region`、`cf-region-code` 等字段;未提供城市/省份字段且 MMDB 不可用时,系统只记录 IP,不会触发地区变化规则。 - -### 手动 Docker 部署 +## 手动 Docker 部署 首次启动: @@ -241,21 +191,53 @@ docker compose up -d app 常用排障: -- 查看状态:`docker compose ps` -- 查看日志:`docker compose logs -f app` -- 页面仍是旧版本:确认已执行 `docker compose build init app` 和 `docker compose up -d app` -- Schema 没有生效:单独运行 `docker compose --profile setup run --rm init sh -lc 'npm run db:push'` -- 登录回调、邮件链接或支付回跳出现 `localhost`:检查 `.env` 里的 `NEXTAUTH_URL` 和后台系统设置里的网站 URL。 -- 订阅链接仍然使用主站域名:检查 `.env` 里的 `SUBSCRIPTION_URL` 或后台系统设置里的订阅 URL;后台配置优先于环境变量。 +```bash +docker compose ps +docker compose logs -f app +docker compose --profile setup run --rm init sh -lc 'npm run db:push' +``` -### 部署后检查清单 +如果页面仍是旧版本,确认已执行 `docker compose build init app` 和 `docker compose up -d app`。如果 schema 没生效,单独运行 `npm run db:push` 对应的 setup 命令。 -1. 登录 `/admin`,进入“系统设置”,确认网站 URL 是面板反代域名,订阅 URL 是你准备给客户端拉取订阅的域名。 -2. 配置 SMTP 邮件服务并点击“测试”,再按需要开启注册邮箱验证。 -3. 进入“支付配置”,填写并启用至少一种支付方式。 -4. 添加 3x-ui 节点,测试连接并同步入站。 -5. 创建套餐,绑定入站或流媒体服务。 -6. 用普通用户注册、下单、支付、查看订阅,走一遍完整流程。 +## 反向代理与域名 + +`NEXTAUTH_URL` 和后台“系统设置 -> 网站 URL”都应该填写面板公网域名,也就是给用户访问、并反向代理到 J-Board 的域名。不要填写 `localhost`、容器名或内网地址,否则登录回调、邮件链接、支付回跳和退出登录提示可能出现错误地址。 + +`SUBSCRIPTION_URL` 和后台“系统设置 -> 订阅 URL”只用于生成客户端订阅链接。它可以和网站 URL 相同;如果希望单独做 Cloudflare/WAF/访问风控,建议使用独立订阅域名,例如 `https://sub.example.com`,并把它也反向代理到同一个 J-Board 服务。 + +Nginx 示例: + +```nginx +server { + listen 80; + server_name panel.example.com sub.example.com; + + location / { + proxy_pass http://127.0.0.1:3000; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + } +} +``` + +正式上线建议使用 Certbot、宝塔、1Panel、Caddy 或 CDN 配置 HTTPS。订阅域名套 Cloudflare 时,源站建议只允许 Cloudflare 回源或通过 Cloudflare Tunnel 暴露,并正确传递 `CF-Connecting-IP` / `X-Forwarded-For`。如果源站允许绕过 Cloudflare 直连,订阅访问风控中的真实 IP 可能被伪造。 + +## 后台初始化清单 + +1. 登录 `/admin`,进入“系统设置”,确认网站 URL 和订阅 URL。 +2. 配置 SMTP 邮件服务并点击“测试发信”。 +3. 按需要开启注册邮箱验证。忘记密码和邮箱变更也会使用 SMTP。 +4. 进入“支付配置”,填写并启用至少一种支付方式。 +5. 添加 3x-ui 节点,测试连接并同步入站。 +6. 创建代理套餐,绑定入站;或创建流媒体服务和套餐。 +7. 在节点页生成探测 Token,安装 Agent。 +8. 用普通用户注册、下单、支付、查看订阅,走一遍完整流程。 +9. 进入“订阅风控”,确认地图、IP、分析日志、人工操作按钮都能正常展示。 可以展示给用户的常用入口: @@ -264,10 +246,23 @@ docker compose up -d app - 套餐商店:`https://你的域名/store` - 用户中心:`https://你的域名/dashboard` - 订阅列表:`https://你的域名/subscriptions` +- 工单中心:`https://你的域名/support` + +## 邮件与邮箱验证 + +SMTP 配置在后台“系统设置”中完成,密码会加密保存在数据库中。支持的邮件场景包括: + +- 注册邮箱验证,可由管理员开启或关闭。 +- 忘记密码重置链接。 +- 修改邮箱验证。 +- 管理员测试发信。 +- 风控报告发送和通知辅助。 + +建议使用专用发信邮箱或应用专用密码。Gmail、企业邮箱和大多数 SMTP 服务都可以使用 `host + port + user + password + from` 的方式接入。生产环境请优先使用 587 STARTTLS 或服务商推荐端口。 ## 支付配置 -支付配置在后台 `/admin/payments` 完成,密钥会保存在数据库中,不写入 `.env`,也不要提交到仓库或截图外传。创建订单时,系统会根据用户选择的支付方式生成支付链接、二维码或链上收款信息;支付成功后进入 `src/services/payment/process.ts` 完成订单确认和订阅开通。 +支付配置在后台 `/admin/payments` 完成,密钥会加密保存在数据库中,不写入 `.env`,也不要提交到仓库或截图外传。创建订单时,系统会根据用户选择的支付方式生成支付链接、二维码或链上收款信息;支付成功后进入 `src/services/payment/process.ts` 完成订单确认和订阅开通。 | 支付方式 | 适用场景 | 必填信息 | 回调 / 查询说明 | | --- | --- | --- | --- | @@ -277,21 +272,54 @@ docker compose up -d app 支付上线前建议: -- 在支付平台后台把通知域名、回跳域名、应用网关白名单都设置为你的公网域名。 +- 在支付平台后台把通知域名、回跳域名、应用网关白名单设置为公网域名。 - 先创建低金额测试套餐,确认“创建订单 -> 支付 -> 回调/查询 -> 自动开通订阅”完整可用。 -- 易支付的 API 地址不要带尾部路径,例如填 `https://pay.example.com`,系统会自动请求 `/mapi.php`、`/submit.php` 和 `/api.php`。 +- 易支付 API 地址不要带尾部路径,例如填 `https://pay.example.com`,系统会自动请求 `/mapi.php`、`/submit.php` 和 `/api.php`。 - 支付宝密钥可以填写纯 key 内容或 PEM 格式;系统会自动补 PEM 包装。 - USDT TRC20 按金额匹配入账,测试时避免短时间出现多笔完全相同金额。 -## 节点与探测 +## 节点、3x-ui 与 Agent + +节点接入流程: 1. 在 VPS 安装并配置 3x-ui,确认面板 API 可访问。 -2. 管理后台添加 3x-ui 节点。 -3. 保存后 J-Board 会登录 3x-ui 并同步入站。 -4. 在代理套餐中绑定已同步入站。 -5. 如需前台展示延迟/线路,点击“生成探测 Token”,复制弹窗里的一键安装命令到节点执行。 +2. 在 3x-ui 中创建真实入站。 +3. 管理后台添加 3x-ui 节点,填写面板地址、用户名和密码。 +4. 保存后 J-Board 会登录 3x-ui 并同步入站到 `NodeInbound`。 +5. 在代理套餐中绑定已同步入站。 +6. 用户购买代理套餐后,J-Board 调用 3x-ui API 创建客户端,并保存 `NodeClient`。 +7. 订阅暂停、恢复、删除、重置访问时,同步调用 3x-ui API 更新客户端。 +8. 如需前台展示延迟、线路和节点日志风控,点击“生成探测 Token”,复制一键安装命令到节点执行。 -探测程序也可手动运行: +Agent 安装脚本会: + +- 下载 GitHub Release 中对应架构的 Agent 二进制。 +- 安装或复用 `nexttrace`。 +- 自动查找 `/usr/local/x-ui/access.log` 等常见 Xray access log 路径。 +- 创建 `/var/lib/jboard-agent` 和 `/var/log/jboard`。 +- 尝试让 Agent 具有 access log 读取权限。 +- 写入 `/etc/jboard-agent.env`。 +- 停用并移除旧的 Agent systemd 服务,避免冲突。 +- 写入并启动 `jboard-agent.service`。 + +节点机常用命令: + +```bash +systemctl status jboard-agent --no-pager -l +journalctl -u jboard-agent -n 100 --no-pager +journalctl -u jboard-agent -f --no-pager +journalctl -u jboard-agent -f --no-pager | grep --line-buffered xray-log +cat /etc/jboard-agent.env +cat /var/lib/jboard-agent/xray-log-state.json +``` + +升级 Agent: + +```bash +curl -fsSL https://raw.githubusercontent.com/JetSprow/J-Board/main/scripts/upgrade-jboard-agent.sh | bash +``` + +如果只想手动运行 Agent: ```bash SERVER_URL=https://your-domain.com \ @@ -299,14 +327,63 @@ AUTH_TOKEN=后台生成的探测Token \ ./jboard-agent ``` -可选变量: +更多 Agent 说明见 `agent/jboard-agent/README.md`。 -- `LATENCY_INTERVAL`:默认 `5m` -- `TRACE_INTERVAL`:默认 `30m` +## 订阅访问风控 -路由探测依赖 `nexttrace`。没有该命令时,延迟探测仍可运行,路由探测会记录错误日志。 +J-Board 的订阅风控分两层。 -## 备份与安全 +第一层是订阅 API 访问风控。用户或客户端拉取 `/api/subscription/*` 时,系统记录真实 IP、User-Agent、国家、省/地区、城市、经纬度,并按后台配置判断: + +- 单 IP 每小时访问次数。 +- 单订阅 token 每小时访问次数。 +- 24 小时窗口内不同城市数量。 +- 24 小时窗口内不同省/地区数量。 +- 24 小时窗口内不同国家/地区数量。 + +第二层是节点真实连接风控。Agent 读取 Xray access log,将日志里的 `email: user@example.com-xxxx` 匹配到本地 `NodeClient.email`,再归属到用户和订阅。系统记录: + +- 真实来源 IP。 +- 真实来源 IP 的 GeoIP。 +- 入站 tag。 +- tcp/udp。 +- 样本目标域名或 IP。 +- 目标端口。 +- 聚合窗口内连接数。 +- 聚合窗口内不同目标数。 +- 首次和最近连接时间。 + +管理员可在“系统设置 -> 订阅访问风控”中配置总开关、自动暂停开关、窗口时长、城市/省/国家阈值、IP/订阅访问频率阈值,以及节点日志风控中的连接数和不同目标数阈值。 + +默认规则保持为: + +- 24 小时内 4 个城市警告,5 个城市暂停。 +- 2 个省/地区警告,3 个省/地区暂停。 +- 2 个国家/地区警告,3 个国家/地区暂停。 +- IP 180 次/小时,订阅 60 次/小时。 +- 节点日志风控默认开启,连接数和不同目标数按 Agent 单次聚合窗口计算。 + +风控事件会进入后台“订阅风控”。管理员可以: + +- 查看关联用户和订阅详情。 +- 查看 IP、国家、省/地区、城市统计。 +- 在世界地图上查看可识别坐标点。 +- 展开分析日志,看到每条证据的 IP、时间、来源、Xray 解析详情、连接数和不同目标数。 +- 生成风险报告。 +- 选择是否发送到用户端。 +- 解除限制或保持封禁/暂停。 + +用户收到管理员发送的风险报告后,会看到全屏不可关闭的限制通知,只能新建工单联系客服,不能继续进行其他用户端操作。 + +## GeoIP 与 Cloudflare + +项目内置 `data/GeoLite2-City.mmdb` 作为本地 GeoIP 城市库,默认通过 `GEOIP_MMDB_PATH=data/GeoLite2-City.mmdb` 读取。系统会优先使用反向代理或 CDN 提供的地理位置头,并用 MMDB 补齐缺失字段。 + +Cloudflare 场景建议在 Rules -> Settings -> Managed Transforms 开启 Add visitor location headers,让回源请求带上 `cf-ipcity`、`cf-region`、`cf-region-code` 等字段。未提供城市/省份字段且 MMDB 不可用时,系统只记录 IP,不会触发地区变化规则。 + +如果网站域名和订阅域名相同,系统只统计订阅 API 访问,不会把普通网站浏览计入订阅风控。 + +## 备份与恢复 下载 SQL 备份: @@ -316,29 +393,113 @@ docker compose exec -T db pg_dump -U jboard jboard > backup_$(date +%Y%m%d_%H%M% 后台也可通过 `/admin/backups` 导出或恢复数据库。恢复前务必先保存当前数据库备份。 -安全建议: +建议: -- 不要提交 `.env`、探测 Token、3x-ui 密码、支付密钥 -- 数据库备份里包含用户、订单和支付配置,建议加密保存并限制下载权限 -- 生产环境不要公开 PostgreSQL 和 Redis 端口 -- 3x-ui 面板建议限制来源 IP 或使用反向代理鉴权 -- `ENCRYPTION_KEY` 一旦生产使用不要随意更换,否则已加密数据会无法解密 +- 定期备份 PostgreSQL volume。 +- 将备份加密保存。 +- 备份恢复后立即检查管理员登录、支付配置、节点密码、SMTP、订阅 URL 和 Agent 上报。 -## 开发原则 +## 本地开发 -- 节点入站与客户端运行配置以 3x-ui 为准,J-Board 只保存售卖镜像 -- 后端只保留探测上报接口,不再新增节点控制面接口 -- Server Actions 负责权限、校验、审计和缓存刷新 -- Route Handlers 仅用于外部 HTTP 接口或文件下载 -- 重要副作用必须记录审计日志或任务记录 +```bash +npm install +cp .env.example .env +npm run db:push +npm run db:seed +npm run dev +``` + +默认管理员账号: + +- 邮箱:`admin@jboard.local` +- 密码:`admin123` + +常用检查: + +```bash +npx prisma generate +npx tsc --noEmit +npm run lint +npm run build +``` + +数据库变更: + +- 修改 `prisma/schema.prisma` 后运行 `npm run db:push`。 +- 生产 Docker 部署更新后,运行 `docker compose --profile setup run --rm init sh -lc 'npm run db:push'`。 +- 当前项目使用 `prisma db push --accept-data-loss`,上线前请确认 schema 变更不会误删重要数据。 + +Agent 开发: + +```bash +cd agent/jboard-agent +go test ./... +make build-linux +shasum -a 256 jboard-agent-linux-amd64 jboard-agent-linux-arm64 > SHA256SUMS +``` + +## 安全建议 + +- 不要提交 `.env`、探测 Token、3x-ui 密码、SMTP 密码、支付密钥。 +- 数据库备份包含用户、订单、支付配置、节点凭据和邮件配置,建议加密保存并限制下载权限。 +- 生产环境不要公开 PostgreSQL 和 Redis 端口。 +- 3x-ui 面板建议限制来源 IP 或使用反向代理鉴权。 +- `ENCRYPTION_KEY` 一旦生产使用不要随意更换。 +- 管理后台账号建议使用强密码和专用邮箱。 +- 订阅域名套 CDN 时应避免源站裸露,否则真实 IP 风控可信度会下降。 +- Agent 只读 Xray access log,但日志中包含用户 IP、访问目标和 client email,应按敏感数据处理。 + +## 常见问题 + +### 登录、退出或邮件链接出现 localhost + +检查 `.env` 中的 `NEXTAUTH_URL` 和后台系统设置中的网站 URL。后台配置优先于环境变量。生产环境必须填写公网域名。 + +### 订阅链接使用了错误域名 + +检查 `.env` 中的 `SUBSCRIPTION_URL` 和后台系统设置中的订阅 URL。后台配置优先于环境变量。 + +### 点击测试发信报错 + +先确认 SMTP 是否启用、Host/Port/User/Password/From 是否正确。Gmail 等服务通常需要应用专用密码。生产环境隐藏原始异常时,可查看 `docker compose logs -f app`。 + +### 用户不验证邮箱也能注册 + +确认后台“注册邮箱验证”已经开启,并检查 SMTP 是否启用。邮箱验证开启后,新用户会进入待验证状态,必须通过邮件链接激活。 + +### Agent 没有 xray-log 输出 + +先看 Agent 是否运行: + +```bash +systemctl status jboard-agent --no-pager -l +journalctl -u jboard-agent -n 100 --no-pager +``` + +再确认 access log 状态: + +```bash +cat /etc/jboard-agent.env | grep XRAY +cat /var/lib/jboard-agent/xray-log-state.json +tail -n 50 /usr/local/x-ui/access.log +grep "email:" /usr/local/x-ui/access.log | tail -n 20 +``` + +Agent 默认 `XRAY_LOG_START_AT_END=1`,首次启动会从文件末尾开始,只分析启动后的新连接。需要真实客户端连接节点并产生带 `email:` 的 access log,后台才会出现节点真实连接分析。 + +### Xray client email 带后缀是否有影响 + +没有影响。J-Board 用户邮箱可能是 `user@example.com`,Xray client email 可能是 `user@example.com-cmojtnp3`。节点日志风控用 Xray access log 里的 client email 匹配本地 `NodeClient.email`,再找到真实用户和订阅。不要手动在 3x-ui 改 client email,否则会导致日志无法归属。 ## 文档 -- `docs/API.md`:HTTP 接口与 Server Actions 参考 -- `docs/openapi.yaml`:对外 HTTP 接口的 OpenAPI 3.1 描述 -- `agent/jboard-agent/README.md`:探测程序说明 +- `docs/API.md`:HTTP 接口与 Server Actions 参考。 +- `docs/openapi.yaml`:对外 HTTP 接口 OpenAPI 3.1 描述。 +- `agent/jboard-agent/README.md`:Agent 安装、升级、日志与排障说明。 +- `AGENTS.md`:给代码协作 Agent 的仓库规则。 ## 请我喝杯咖啡 + ![JsPYre9xe7W1Ad6mwPgrfuXBYJ8iy6oC.webp](https://cdn.nodeimage.com/i/XuxZ7NoLsc51fS99S6AtMB9K9ekTTQcD.webp) USDT-TRC20: TQfaGEBdnB89V4y6R6bypZXx7Za5QfXBCi diff --git a/agent/jboard-agent/README.md b/agent/jboard-agent/README.md index 6f83b7d..dc5cc3a 100644 --- a/agent/jboard-agent/README.md +++ b/agent/jboard-agent/README.md @@ -1,12 +1,289 @@ # jboard-agent -`jboard-agent` 以旁路方式负责节点探测和可选的 Xray access log 风控上报: +`jboard-agent` 是 J-Board 的节点侧旁路程序。它运行在节点 VPS 上,负责把节点体验和节点真实连接证据上报到 J-Board。 -- 三网 TCP 延迟:`POST /api/agent/latency` -- 三网路由跟踪:`POST /api/agent/trace` -- Xray access log 聚合:`POST /api/agent/node-access`,安装/升级脚本会自动探测并写入 `XRAY_ACCESS_LOG_PATH` +它做三件事: -节点入站、客户端开通、暂停、删除、流量限制等配置均由 3x-ui 面板维护。Agent 只读日志文件,不修改 3x-ui 配置、不重启 Xray。 +- 三网 TCP 延迟探测:`POST /api/agent/latency` +- 三网路由追踪:`POST /api/agent/trace` +- Xray access log 聚合:`POST /api/agent/node-access` + +它不做这些事: + +- 不创建、删除或修改 3x-ui 入站。 +- 不创建、删除或修改 Xray 客户端。 +- 不重启 3x-ui 或 Xray。 +- 不接管节点流量。 +- 不作为公共代理或透明代理。 + +节点入站、客户端开通、暂停、删除、流量限制等配置均由 3x-ui 面板维护。Agent 只读日志文件,并通过 J-Board 的 Agent Token 上报结果。 + +## 工作方式 + +```text +jboard-agent + ├─ LatencyLoop:定时 TCP connect 三网目标 + ├─ TraceLoop:定时调用 nexttrace 获取三网路由 + └─ XrayAccessLogLoop:读取 Xray access log,聚合真实来源 IP、连接数和不同目标数 + ↓ +J-Board /api/agent/* + ↓ +后台节点体验、订阅风控、分析日志、风险报告 +``` + +Agent 使用 `AUTH_TOKEN` 认证。这个 token 在 J-Board 后台节点页生成,服务端会通过它匹配到具体 `NodeServer`。 + +## 安装 + +推荐在 J-Board 后台“节点管理”中点击生成 Agent Token,然后复制弹窗中的一键安装命令到节点机执行。安装脚本会自动完成: + +- 下载 GitHub Release 中对应架构的二进制。 +- 校验 `SHA256SUMS`。 +- 安装或复用 `nexttrace`。 +- 自动查找 Xray access log。 +- 创建 `/var/lib/jboard-agent` 和 `/var/log/jboard`。 +- 写入 `/etc/jboard-agent.env`。 +- 停用并移除旧的 Agent systemd 服务,避免冲突。 +- 写入并启动 `jboard-agent.service`。 + +手动安装命令形如: + +```bash +curl -fsSL https://raw.githubusercontent.com/JetSprow/J-Board/main/scripts/install-jboard-agent.sh | SERVER_URL=https://panel.example.com AUTH_TOKEN=你的Token bash +``` + +如果需要指定 Agent Release: + +```bash +curl -fsSL https://raw.githubusercontent.com/JetSprow/J-Board/main/scripts/install-jboard-agent.sh | AGENT_TAG=v3.0.2 SERVER_URL=https://panel.example.com AUTH_TOKEN=你的Token bash +``` + +## 升级 + +```bash +curl -fsSL https://raw.githubusercontent.com/JetSprow/J-Board/main/scripts/upgrade-jboard-agent.sh | bash +``` + +升级脚本会读取现有 `/etc/jboard-agent.env`,保留服务器地址、Token、探测间隔和 Xray 日志配置,并重新写入当前 systemd service。 + +升级后确认版本: + +```bash +journalctl -u jboard-agent -n 30 --no-pager +``` + +你应该看到类似: + +```text +[agent] jboard-agent v3.0.2 starting in probe-only mode +``` + +## 环境变量 + +| 变量 | 默认值 | 说明 | +| --- | --- | --- | +| `SERVER_URL` | 必填 | J-Board 面板公网地址,例如 `https://panel.example.com`。 | +| `AUTH_TOKEN` | 必填 | 后台节点页生成的 Agent Token。 | +| `LATENCY_INTERVAL` | `5m` | 延迟探测间隔,支持 `30s`、`5m` 或纯秒数。 | +| `TRACE_INTERVAL` | `30m` | 路由探测间隔,支持 `30m` 或纯秒数。 | +| `XRAY_ACCESS_LOG_PATH` | 自动探测 | Xray access log 路径。为空时节点真实连接风控禁用。 | +| `XRAY_LOG_INTERVAL` | `1m` | access log 读取、聚合、上报间隔。 | +| `XRAY_LOG_STATE_FILE` | `/var/lib/jboard-agent/xray-log-state.json` | access log offset 状态文件。 | +| `XRAY_LOG_START_AT_END` | `1` | 首次启动从文件末尾开始,避免上传历史巨量日志;设为 `0` 可从头读取。 | +| `INSTALL_NEXTTRACE` | `1` | 安装脚本是否自动安装 nexttrace。 | + +systemd 环境文件默认位于: + +```bash +/etc/jboard-agent.env +``` + +修改环境文件后需要重启: + +```bash +systemctl restart jboard-agent +``` + +## Xray access log + +安装/升级脚本会优先查找这些路径: + +- `/usr/local/x-ui/access.log` +- `/usr/local/x-ui/bin/access.log` +- `/usr/local/x-ui/xray/access.log` +- `/etc/x-ui/access.log` +- `/etc/x-ui/xray/access.log` +- `/var/log/xray/access.log` +- `/var/log/x-ui/access.log` +- `/opt/3x-ui/access.log` +- `/opt/x-ui/access.log` +- `/usr/local`、`/etc`、`/var/log`、`/opt`、Docker volume 下名称包含 `access.log` 或 `xray` 的日志 + +如果没有找到,脚本会提示你在 3x-ui 的 Xray Config 中开启: + +```json +"log": { + "access": "/usr/local/x-ui/access.log", + "error": "/usr/local/x-ui/error.log", + "loglevel": "warning" +} +``` + +然后重启 x-ui,再重跑 Agent 安装或升级脚本。 + +### 支持的日志格式 + +Agent 支持常见 Xray access log 格式,包括: + +```text +2026/04/29 10:11:12 203.0.113.9:51820 accepted tcp:example.com:443 [proxy-in >> freedom] email: user@example.com-cabc1234 +``` + +也支持 3x-ui/Xray 新格式: + +```text +2026/04/29 09:20:05.982584 from 220.240.111.193:59425 accepted tcp:example.com:443 [inbound-17583 >> direct] email: user@example.com-cmojtnp3 +2026/04/29 09:20:06.006542 from tcp:220.240.111.193:59433 accepted udp:71.18.167.208:443 [inbound-17583 >> direct] email: user@example.com-cmojtnp3 +``` + +Agent 会解析: + +- `sourceIp`:真实来源 IP。 +- `clientEmail`:Xray client email。 +- `inboundTag`:入站 tag,例如 `inbound-17583`。 +- `network`:`tcp` 或 `udp`。 +- `targetHost` / `targetPort`:样本目标。 +- `action`:`accepted` 或 `rejected`。 +- `connectionCount`:聚合窗口内连接数。 +- `uniqueTargetCount`:聚合窗口内不同目标数。 +- `firstSeenAt` / `lastSeenAt`:窗口内首次和最近连接时间。 + +没有 `email:` 的日志会跳过,因为服务端无法把它归属到 J-Board 的 `NodeClient`。`[api -> api]` 这类 3x-ui 本地 API 通信通常也会跳过。 + +## Xray client email 与用户邮箱 + +J-Board 用户邮箱和 Xray client email 不一定完全相同。例如: + +```text +J-Board 用户邮箱:user@example.com +Xray client email:user@example.com-cmojtnp3 +``` + +这是正常设计。节点日志风控使用 Xray access log 里的 `email:` 匹配本地 `NodeClient.email`,再找到对应用户和订阅。不要手动在 3x-ui 修改 client email,否则日志会无法归属。 + +## systemd 运维 + +查看服务状态: + +```bash +systemctl status jboard-agent --no-pager -l +``` + +实时日志: + +```bash +journalctl -u jboard-agent -f --no-pager +``` + +看最近 100 行: + +```bash +journalctl -u jboard-agent -n 100 --no-pager +``` + +只看 Xray 日志采集: + +```bash +journalctl -u jboard-agent -f --no-pager | grep --line-buffered xray-log +``` + +查看配置: + +```bash +cat /etc/jboard-agent.env +``` + +查看 access log offset 状态: + +```bash +cat /var/lib/jboard-agent/xray-log-state.json +``` + +## 排障 + +### Agent 没有启动 + +```bash +systemctl status jboard-agent --no-pager -l +journalctl -u jboard-agent -n 100 --no-pager +``` + +常见原因: + +- `/etc/jboard-agent.env` 缺少 `SERVER_URL` 或 `AUTH_TOKEN`。 +- 二进制没有执行权限。 +- 旧服务没有清理干净。新安装/升级脚本会自动停用并移除旧服务。 + +### 没有 `[xray-log]` 输出 + +这不一定是错误。Agent 只在禁用、报错或成功推送时打印 `xray-log`。如果没有新 access log,实时 grep 会一直等待。 + +按顺序检查: + +```bash +cat /etc/jboard-agent.env | grep XRAY +cat /var/lib/jboard-agent/xray-log-state.json +tail -n 50 /usr/local/x-ui/access.log +grep "email:" /usr/local/x-ui/access.log | tail -n 20 +``` + +如果状态文件类似: + +```json +{"path":"/usr/local/x-ui/access.log","inode":393262,"offset":180} +``` + +说明 Agent 已经找到并跟踪日志。它会从 offset 之后继续读。 + +### access log 只有 `[api -> api]` + +例如: + +```text +2026/04/29 09:16:07.001315 from 127.0.0.1:43702 accepted tcp:127.0.0.1:62789 [api -> api] +``` + +这是 3x-ui / Xray 本地 API 通信,不是用户节点连接。你需要让真实客户端连接节点,再查看是否出现带 `email:` 的记录。 + +### 强制从头重读 access log + +仅用于测试。生产环境不建议长期保持从头读取。 + +```bash +systemctl stop jboard-agent +rm -f /var/lib/jboard-agent/xray-log-state.json +sed -i 's/^XRAY_LOG_START_AT_END=.*/XRAY_LOG_START_AT_END=0/' /etc/jboard-agent.env +systemctl start jboard-agent +journalctl -u jboard-agent -n 100 --no-pager | grep xray-log +``` + +测试完成后改回: + +```bash +sed -i 's/^XRAY_LOG_START_AT_END=.*/XRAY_LOG_START_AT_END=1/' /etc/jboard-agent.env +systemctl restart jboard-agent +``` + +### 服务端没有收到节点日志风控 + +检查: + +- 后台系统设置是否开启订阅风控总控。 +- 后台是否开启节点日志风控。 +- access log 是否包含 `email:`。 +- `email:` 是否与 J-Board 数据库里的 `NodeClient.email` 一致。 +- Agent Token 是否属于当前节点。 +- 面板日志是否有 `/api/agent/node-access` 的错误。 ## 构建 @@ -16,31 +293,27 @@ make build make build-linux ``` -## 运行 +生成校验和: ```bash -SERVER_URL=https://your-domain.com \ -AUTH_TOKEN=后台生成的探测Token \ -./jboard-agent +shasum -a 256 jboard-agent-linux-amd64 jboard-agent-linux-arm64 > SHA256SUMS ``` -可选环境变量: +## Release 规则 -| 变量 | 默认值 | 说明 | -| --- | --- | --- | -| `LATENCY_INTERVAL` | `5m` | 延迟探测间隔,支持 `30s`、`5m` 或秒数 | -| `TRACE_INTERVAL` | `30m` | 路由探测间隔,支持 `30m` 或秒数 | -| `XRAY_ACCESS_LOG_PATH` | 自动探测 | Xray access log 路径;安装/升级脚本会优先查找 `/usr/local/x-ui/access.log` 等常见路径,仍为空时禁用节点真实连接风控 | -| `XRAY_LOG_INTERVAL` | `1m` | 日志读取和聚合上报间隔 | -| `XRAY_LOG_STATE_FILE` | `/var/lib/jboard-agent/xray-log-state.json` | 日志 offset 状态文件 | -| `XRAY_LOG_START_AT_END` | `1` | 首次启动从文件末尾开始,避免上传历史巨量日志;设为 `0` 可从头读取 | +只有 Agent 代码或 Agent 安装/升级体验需要随二进制发布时,才创建新的 Agent tag 和 GitHub Release。普通面板页面、后台 UI、文档或 Server Action 改动不需要强行更新 Agent release。 -路由探测依赖 `nexttrace` 命令;延迟探测无需额外依赖。 +Release 需要包含: -## systemd +- `jboard-agent-linux-amd64` +- `jboard-agent-linux-arm64` +- `SHA256SUMS` -推荐从 J-Board 后台节点页复制一键安装命令。该命令会下载 release 二进制、安装 `nexttrace`、自动探测 3x-ui/Xray access log、写入 systemd 服务并启动。 +安装/升级脚本默认使用 GitHub 最新 Release。需要固定版本时传入 `AGENT_TAG=vX.Y.Z`。 -## 延迟算法 +## 安全边界 -延迟探测使用三组 zstaticcdn 运营商目标,先解析域名再开始计时,只统计 TCP connect 耗时,避免 DNS 抖动混入延迟;当单次结果超过 1000ms 时会额外重试最多 3 次并采用更低的有效结果。 +- Agent 只读 Xray access log,但日志中包含真实来源 IP、访问目标和 client email,应按敏感数据处理。 +- Agent Token 等同节点上报凭据,不要外传。 +- 节点服务器上不要公开 `/etc/jboard-agent.env`。 +- 3x-ui 面板建议限制来源 IP 或使用反向代理鉴权。 diff --git a/docs/API.md b/docs/API.md index c39952f..914c171 100644 --- a/docs/API.md +++ b/docs/API.md @@ -1,20 +1,22 @@ -# J-Board API +# J-Board API 与 Server Actions -本文整理当前有效的 HTTP Route Handlers 和内部 Server Actions。对外 HTTP 结构化描述见 `docs/openapi.yaml`。 +本文整理 J-Board 当前有效的 HTTP Route Handlers 和内部 Server Actions。HTTP 对外结构化描述见 `docs/openapi.yaml`;本文更偏向工程阅读和排障。 -## 1. 通用约定 +## 通用约定 -- 用户会话:NextAuth Cookie -- 管理接口:必须是管理员会话 -- 探测接口:`Authorization: Bearer ` -- 返回格式:JSON,文件下载接口除外 -- 时间字段:ISO 8601 字符串 +- 普通用户身份:NextAuth Cookie 会话。 +- 管理员身份:NextAuth Cookie 会话,且用户角色为 `ADMIN`。 +- Agent 身份:`Authorization: Bearer `。 +- 返回格式:默认 JSON,订阅内容和文件下载接口除外。 +- 时间字段:ISO 8601 字符串。 +- 写操作:必须做权限校验、输入校验、审计记录和必要的 `revalidatePath`。 +- 3x-ui 密码、Agent Token、SMTP 密码、支付密钥等敏感字段在数据库中加密保存。 -## 2. 认证 +## 认证与公开信息 ### `POST /api/auth/register` -注册普通用户。 +注册普通用户。是否允许注册、是否必须邀请码、是否需要邮箱验证由后台系统设置控制。 请求体: @@ -28,15 +30,21 @@ } ``` +行为: + +- 校验邮箱、密码、邀请码和 Turnstile。 +- 当注册邮箱验证开启时,用户会进入 `PENDING_EMAIL` 状态并收到验证邮件。 +- 当注册邮箱验证关闭时,用户直接成为可登录用户。 + ### `GET|POST /api/auth/[...nextauth]` NextAuth 内置登录、登出、会话接口。 -## 3. 公共数据 - ### `GET /api/public/app-info` -返回站点名称、注册策略、维护公告、Turnstile 配置等公开信息。 +返回站点名称、注册策略、维护公告、Turnstile 配置、网站公开配置等信息。前端登录页、注册页和公共布局会使用它。 + +## 延迟与路由展示 ### `GET /api/latency?nodeId=` @@ -44,17 +52,21 @@ NextAuth 内置登录、登出、会话接口。 ### `GET /api/latency/history?nodeId=&carrier=telecom&range=7d` -返回节点延迟历史,`range` 支持 `1d`、`7d`、`30d`。 +返回节点延迟历史。`carrier` 通常为 `telecom`、`unicom`、`mobile`;`range` 支持 `1d`、`7d`、`30d`。 + +### `GET /api/latency/recommendations` + +返回前台线路推荐所需的延迟聚合结果。 ### `GET /api/traces?nodeId=` -返回节点三网路由追踪结果。 +返回节点三网路由追踪结果。服务端会重新归一化历史数据,修正 CN2 GIA、CN2 GT、CMIN2、CMI 等线路分类。 -## 4. 支付 +## 支付接口 ### `GET /api/payment/providers` -返回当前启用的支付方式。 +返回当前启用的支付方式。普通用户创建订单或切换支付方式时使用。 ### `POST /api/payment/create` @@ -69,19 +81,63 @@ NextAuth 内置登录、登出、会话接口。 } ``` +行为: + +- 校验订单属于当前用户且仍待支付。 +- 根据支付方式生成支付链接、二维码或链上支付信息。 +- 记录支付流水,便于后续回调或查询。 + ### `GET /api/payment/order/{orderId}` 查询当前用户自己的订单支付状态。 ### `GET /api/payment/query/{tradeNo}` -按支付流水号查询支付状态。 +按支付流水号主动查询支付状态。用于前端轮询或支付平台回调异常时兜底。 ### `GET|POST /api/payment/notify/{provider}` -支付平台异步通知入口。 +支付平台异步通知入口。当前 provider 包括: -## 5. 管理导出与节点读取 +- `epay` +- `alipay_f2f` +- `usdt_trc20` 的链上入账由查询任务处理,不依赖传统 HTTP 回调。 + +行为: + +- 校验签名或链上入账。 +- 标记订单已支付。 +- 调用 `src/services/provision.ts` 创建或续费订阅。 +- 代理订阅会同步 3x-ui client。 + +## 订阅与用户资源 + +### `GET /api/subscription/{id}?token=` + +无需登录,但必须提供合法下载 token。成功返回 `text/plain` 订阅内容。 + +行为: + +- 校验订阅状态、到期时间和 token。 +- 记录订阅访问日志和真实 IP。 +- 执行订阅访问限流和地区变化风控。 +- 当订阅被暂停或风控限制时,返回错误内容或拒绝访问。 + +### `GET /api/subscription/all` + +返回用户聚合订阅内容。用于部分客户端的一键导入或总订阅入口。 + +### `GET /api/notifications` + +返回当前用户通知列表。 + +### `GET /api/support/attachments/{id}` + +工单附件访问接口。要求登录用户是附件所属工单用户本人或管理员。加 `?download=1` 可触发下载。 + +## 管理读取与导出 + +以下接口要求管理员会话。 ### `GET /api/admin/nodes` @@ -89,11 +145,11 @@ NextAuth 内置登录、登出、会话接口。 ### `GET /api/admin/nodes/{id}/inbounds` -返回指定节点的已同步入站。 +返回指定节点的已同步入站。套餐绑定和节点详情页会使用。 ### `GET /api/admin/export/config` -导出配置快照,包含站点设置、公告、服务、套餐、节点、入站、支付配置等。 +导出配置快照,包含站点设置、公告、服务、套餐、节点、入站、支付配置等。敏感值会按实现规则脱敏或加密保存,不应公开传播。 ### `GET /api/admin/export/audit-logs?q=` @@ -101,11 +157,17 @@ NextAuth 内置登录、登出、会话接口。 ### `GET /api/admin/backup/database` -导出 SQL 数据库备份。 +导出 SQL 数据库备份。备份包含用户、订单、节点、支付、SMTP 等敏感信息,应加密保存。 -## 6. 探测上报 +## Agent 上报接口 -以下接口由 `agent/jboard-agent` 调用,探测 Token 存储在 `NodeServer.agentToken` 中并加密保存。 +以下接口由 `agent/jboard-agent` 调用。Agent Token 存储在 `NodeServer.agentToken` 中,并加密保存。请求头必须为: + +```http +Authorization: Bearer +``` + +服务端会通过 Token 匹配到具体节点 `nodeId`。 ### `POST /api/agent/latency` @@ -121,7 +183,11 @@ NextAuth 内置登录、登出、会话接口。 } ``` -行为:更新 `NodeLatency` 并写入 `NodeLatencyLog`。 +行为: + +- 更新 `NodeLatency`。 +- 写入 `NodeLatencyLog`。 +- 前台节点延迟、历史图表和推荐会使用这些数据。 ### `POST /api/agent/trace` @@ -132,7 +198,17 @@ NextAuth 内置登录、登出、会话接口。 "traces": [ { "carrier": "telecom", - "hops": [{ "hop": 1, "ip": "*", "geo": "", "latency": 0 }], + "hops": [ + { + "hop": 1, + "ip": "203.0.113.1", + "geo": "CN", + "latency": 3.5, + "asn": "AS4809", + "owner": "China Telecom CN2", + "isp": "China Telecom" + } + ], "summary": "CN2 GIA", "hopCount": 12 } @@ -140,53 +216,111 @@ NextAuth 内置登录、登出、会话接口。 } ``` -行为:按 `nodeId + carrier` 更新 `RouteTrace`。 +行为: -## 7. 订阅与附件 +- 服务端重新分类线路,避免旧 Agent 或 nexttrace 文案导致误判。 +- 按 `nodeId + carrier` 更新 `RouteTrace`。 +- 线路分类会优先识别 CN2 GIA、CN2 GT、CMIN2、CMI 等常见中国方向线路。 -### `GET /api/subscription/{id}?token=` +### `POST /api/agent/node-access` -无需会话,但必须提供合法下载 token。成功返回 `text/plain` 订阅内容。 +接收 Agent 从 Xray access log 聚合出的真实节点连接事件。 -### `GET /api/support/attachments/{id}` +请求体: -工单附件访问接口,要求登录用户是附件所属工单用户本人或管理员。加 `?download=1` 可触发下载。 +```json +{ + "events": [ + { + "clientEmail": "user@example.com-cmojtnp3", + "sourceIp": "220.240.111.193", + "inboundTag": "inbound-17583", + "network": "tcp", + "targetHost": "example.com", + "targetPort": 443, + "action": "accepted", + "connectionCount": 18, + "uniqueTargetCount": 14, + "firstSeenAt": "2026-04-29T09:20:05+10:00", + "lastSeenAt": "2026-04-29T09:20:07+10:00" + } + ] +} +``` -## 8. Server Actions +行为: -Server Actions 是后台和用户端写操作的主要入口。所有管理动作必须经过 `requireAdmin()`,用户动作必须校验资源归属。 +- 通过 `clientEmail` 匹配 `NodeClient.email`。 +- 同时要求该 client 属于当前 Agent Token 对应节点。 +- 写入 `SubscriptionAccessLog`,来源标记为“节点真实连接”。 +- 使用 `sourceIp` 执行国家、省/地区、城市变化风控。 +- 使用 `connectionCount` 和 `uniqueTargetCount` 执行节点日志行为风控。 +- 创建 `SubscriptionRiskEvent`、通知、审计日志,并在需要时自动暂停订阅。 -### 管理端 +返回示例: -节点:`src/actions/admin/nodes.ts` +```json +{ + "ok": true, + "processed": 1, + "skipped": 0, + "warnings": 0, + "suspended": 0 +} +``` -- `createNode(formData)`:创建 3x-ui 节点并同步入站 -- `updateNode(id, formData)`:更新 3x-ui 节点连接信息并重新同步入站 -- `deleteNode(id)`:删除节点及本地关联数据 -- `testNodeConnection(id)`:测试 3x-ui 登录并同步入站 -- `batchTestNodeConnections(formData)`:批量测试并同步节点 -- `updateInboundDisplayName(id, formData)`:修改同步入站的前台展示名称 -- `deleteInbound(id)`:仅删除本地入站镜像,不删除 3x-ui 入站 -- `generateAgentToken(nodeId)`:生成探测 Token -- `revokeAgentToken(nodeId)`:撤销探测 Token +常见跳过原因: -订阅:`src/actions/admin/subscriptions.ts` +- Xray access log 没有 `email:` 字段。 +- `email:` 与本地 `NodeClient.email` 不一致。 +- 日志来自 `[api -> api]` 这类 3x-ui 本地 API 通信。 +- 后台关闭了订阅风控总控或节点日志风控。 -- `suspendSubscription(id)`:暂停订阅,并通过 3x-ui 禁用代理客户端 -- `activateSubscription(id)`:恢复订阅,并通过 3x-ui 启用代理客户端 -- `cancelSubscription(id)`:取消订阅 -- `deleteSubscriptionPermanently(id)`:删除订阅,并通过 3x-ui 删除代理客户端 -- `reassignStreamingSlot(...)`:调整流媒体槽位 -- `batchSubscriptionOperation(formData)`:批量处理订阅 +## Server Actions -订单:`src/actions/admin/orders.ts` +Server Actions 是后台和用户端写操作的主要入口。它们不是公开 HTTP API,不建议第三方直接调用。 -- `confirmOrder(orderId)`:手动确认订单并触发开通 -- `cancelOrder(orderId)`:取消订单 -- `updateOrderReview(...)`:更新风控/复核状态 -- `batchOrderOperation(formData)`:批量操作订单 +### 管理端 Actions -其他管理动作: +#### 节点:`src/actions/admin/nodes.ts` + +- `createNode(formData)`:创建 3x-ui 节点并同步入站。 +- `updateNode(id, formData)`:更新 3x-ui 节点连接信息并重新同步入站。 +- `deleteNode(id)`:删除节点及本地关联数据。 +- `testNodeConnection(id)`:测试 3x-ui 登录并同步入站。 +- `batchTestNodeConnections(formData)`:批量测试并同步节点。 +- `updateInboundDisplayName(id, formData)`:修改同步入站的前台展示名称。 +- `deleteInbound(id)`:仅删除本地入站镜像,不删除 3x-ui 入站。 +- `generateAgentToken(nodeId)`:生成 Agent Token。 +- `revokeAgentToken(nodeId)`:撤销 Agent Token。 + +#### 订阅:`src/actions/admin/subscriptions.ts` + +- `suspendSubscription(id)`:暂停订阅,并通过 3x-ui 禁用代理客户端。 +- `activateSubscription(id)`:恢复订阅,并通过 3x-ui 启用代理客户端。 +- `cancelSubscription(id)`:取消订阅。 +- `deleteSubscriptionPermanently(id)`:强制删除订阅及名下关联数据,并尽量删除 3x-ui 客户端。 +- `reassignStreamingSlot(...)`:调整流媒体槽位。 +- `batchSubscriptionOperation(formData)`:批量处理订阅。 + +#### 订阅风控:`src/actions/admin/subscription-risk.ts` + +- 更新复核状态和复核备注。 +- 生成风险报告。 +- 向用户发送风险报告并开启用户端全屏限制。 +- 解除封控限制并恢复可恢复的代理订阅。 +- 保持封禁/暂停并记录最终处理结果。 + +后台“订阅风控”页面依赖 `src/services/subscription-risk-review.ts` 整理地图、IP、分析日志和报告文本。 + +#### 订单:`src/actions/admin/orders.ts` + +- `confirmOrder(orderId)`:手动确认订单并触发开通。 +- `cancelOrder(orderId)`:取消订单。 +- `updateOrderReview(...)`:更新风控/复核状态。 +- `batchOrderOperation(formData)`:批量操作订单。 + +#### 其他管理动作 - 用户:`src/actions/admin/users.ts` - 套餐:`src/actions/admin/plans.ts` @@ -200,20 +334,37 @@ Server Actions 是后台和用户端写操作的主要入口。所有管理动 - 流量视图刷新:`src/actions/admin/traffic.ts` - 优惠券与促销:`src/actions/admin/commerce.ts` -### 用户端 +### 用户端 Actions -- `src/actions/user/purchase.ts`:立即购买、续费、增流量、查询库存 -- `src/actions/user/cart.ts`:加入购物车、移除、清空、结算 -- `rotateSubscriptionAccess(subscriptionId)`:重置代理订阅访问凭据,并同步更新 3x-ui 客户端 -- `src/actions/user/account.ts`:资料、密码、邀请码 -- `src/actions/user/notifications.ts`:已读、删除、清空 -- `src/actions/user/support.ts`:创建、回复、关闭、删除工单 -- `src/actions/user/orders.ts`:取消待支付订单、重新选择支付方式 +- `src/actions/user/purchase.ts`:立即购买、续费、增流量、查询库存。 +- `src/actions/user/cart.ts`:加入购物车、移除、清空、结算。 +- `rotateSubscriptionAccess(subscriptionId)`:重置代理订阅访问凭据,并同步更新 3x-ui 客户端。 +- `src/actions/user/account.ts`:资料、密码、邀请码、邮箱变更。 +- `src/actions/user/notifications.ts`:已读、删除、清空。 +- `src/actions/user/support.ts`:创建、回复、关闭、删除工单。创建工单会受后台工单上限控制。 +- `src/actions/user/orders.ts`:取消待支付订单、重新选择支付方式。 -### 约定 +## 风控数据模型要点 -- 写操作必须做权限校验和输入校验 -- 重要副作用必须记录审计日志 -- 影响页面展示后必须 `revalidatePath` -- 代理客户端变更必须通过 `src/services/node-panel` 同步 3x-ui -- 不再新增节点控制面、运行配置下发、进程管理类 Action +- `SubscriptionAccessLog`:保存订阅 API 访问和节点真实连接证据。 +- `SubscriptionRiskEvent`:保存风控事件、复核状态、报告、用户端限制和最终处理动作。 +- `SubscriptionRiskReason`:包含城市、省/地区、国家变化,以及节点高频、目标分散等原因。 +- `AppConfig`:保存订阅风控总控、自动暂停开关、阈值、节点日志风控阈值。 +- `NodeClient.email`:用于匹配 Xray access log 中的 `email:`。它可能形如 `user@example.com-cmojtnp3`,不要手动在 3x-ui 修改。 + +## 错误处理约定 + +- 输入校验失败:返回 400 或在 Server Action 中返回可展示错误。 +- 未登录:返回 401 或跳转登录。 +- 权限不足:返回 403 或抛出权限错误。 +- 资源不存在:返回 404 或抛出 not found。 +- 外部服务失败:保留审计日志或任务记录,前端展示简洁错误。 +- 生产环境 Server Components 会隐藏原始堆栈;排障时看 `docker compose logs -f app`。 + +## 维护约定 + +- 新增公开 HTTP 接口时,同时更新 `docs/API.md` 和 `docs/openapi.yaml`。 +- 新增 Agent 上报字段时,同时更新 `agent/jboard-agent/README.md`。 +- 新增系统设置时,同时更新 `.env.example` 或 README 中对应后台配置说明。 +- 涉及 3x-ui 客户端状态的写操作必须通过 `src/services/node-panel` 同步。 +- 不再新增节点控制面、运行配置下发、Xray 进程管理类 Action。