YD-WEB/COMPETITION-DEPLOY.md
ltx 84b7b0f893 feat(website): add competition results and service deployment
- Add the event results page with schedule, rankings, Battle bracket, athletes, records, bilingual labels, and navigation entry.
- Add the read/write competition data service, a complete Excel example, empty public state, and validation smoke tests.
- Handle Furion statusCode/data responses from the production API and retain static fallback for the public page.
- Document Docker sidecar deployment beside test_eventapi, persistent storage, private admin access, Nginx routing, and OSS asset rewriting.

Verification:
- node server/competition-api.smoke.mjs
- node scripts/competition-response-test.mjs
- node scripts/battle-layout-test.mjs
- npm run build -- --base=https://assets.example.test/static/test/
- npm run rewrite:oss -- https://assets.example.test/static/test/
- Production /api/competition/state returned HTTP 200 after the sidecar started.

Deployment note: publish the updated YD-WEB static build before public results can consume the unwrapped API response. The event remains unpublished until an administrator saves and publishes data.
2026-10-20 13:38:23 +08:00

6.6 KiB
Raw Blame History

官网赛事成绩接入

官网入口为 /#/sports/competition 的第 4 项「赛事成绩」,独立页面为 /#/sports/results。YD_Event.Web 的「官网赛事信息」页面负责维护与发布。原需求文档的系统 B(现场评分控制台)不在此接入链路中。

运行接口

接口使用 Node.js 18+,没有额外依赖。生产环境必须设置以下环境变量后运行 npm run serve:competition-api:

变量 用途
COMPETITION_DATA_PATH 持久化 JSON 文件路径;默认 server/data/competition-state.json。生产环境应放在持久化磁盘并备份
COMPETITION_PORT 监听端口,默认 8787
COMPETITION_HOST 监听地址,默认 127.0.0.1;分机部署时设为赛事服务的私网 IP,并用防火墙限制 8787 端口只允许后台服务器访问
COMPETITION_ADMIN_ALLOWED_IPS 允许直接访问内部管理接口的客户端 IP,逗号分隔;分机部署时填写 YD_Event.Admin 服务器的私网 IP。服务默认还允许本机环回地址
COMPETITION_ALLOWED_ORIGINS 仅在浏览器直接访问赛事服务时需要;当前正式链路由 YD_Event.Admin 转发,官网浏览器不直接连接赛事服务

官网通过 https://jitsi-web.yuedongsports.com/api/competition/state 读取已发布数据。这个匿名只读接口由 YD_Event.Admin 提供,并通过私网读取赛事服务的 /api/competition/state;未发布时赛事服务只返回空态。管理页仍通过需要登录的 /api/website-competition 读取草稿及保存,不需要管理密钥。官网每 10 秒重新读取一次公开数据。

启动赛事服务时设置 COMPETITION_HOST=<赛事服务私网 IP> 和 COMPETITION_ADMIN_ALLOWED_IPS=<后台服务器私网 IP>;在 YD_Event.Admin 设置 CompetitionApi__AdminUrl=http://<赛事服务私网 IP>:8787/api/competition/admin。防火墙只允许后台服务器访问赛事服务的 8787 端口。先从后台服务器执行 curl -i http://<赛事服务私网 IP>:8787/api/competition/ping,确认服务返回 200。jitsi-web.yuedongsports.com 沿用现有 /api/ 到 YD_Event.Admin 的代理,无需将公开请求直接代理到赛事服务。

若运维已应用旧版赛事 Nginx 片段,应改用 deploy/nginx/jitsi-competition-api.conf:只屏蔽公网 /api/competition/admin,让公开 /api/competition/state 走现有后台代理。修改后执行 nginx -t 再重载 Nginx。

部署后从官网域名验证公开接口及 CORS 响应头:

curl -i -H 'Origin: https://www.yuedongsports.com' https://jitsi-web.yuedongsports.com/api/competition/state
curl -i https://jitsi-web.yuedongsports.com/api/competition/admin

第一条请求应返回 200 和允许 https://www.yuedongsports.com 的 Access-Control-Allow-Origin;第二条公网管理路径应返回 404。若公开接口仍返回 404,先确认 YD_Event.Admin 已部署匿名只读控制器,且旧版 Nginx 赛事代理已移除。若返回 502,检查内网赛事服务、CompetitionApi__AdminUrl 和防火墙。内部管理接口只接受 COMPETITION_ADMIN_ALLOWED_IPS 中的来源地址;公网不可直连赛事服务的 8787 端口。

2026-10-20 排查发现:此前线上 /api/competition/state 返回后台生成的 502,原因是 test_eventapi 容器未配置 CompetitionApi__AdminUrl,同机没有监听 8787 的赛事数据服务。部署共享网络的赛事容器后,公开接口已恢复 200。当前后台响应由 Furion 包装为 statusCode/data,官网读取代码会解包其中的赛事 JSON;官网更新构建后才会使用这项解析修复。

若赛事服务与 test_eventapi 部署在同一台 Docker 主机,可按 deploy/competition-api/README.md 启动独立的 Node 容器并共享后台容器的网络命名空间。两个容器因此共用回环地址,后台现有默认 127.0.0.1:8787 可用,且 8787 不需要对公网开放。后台容器被 Jenkins 重建时必须同步重建该赛事服务容器。

方法 路径 用途
GET jitsi-web.yuedongsports.com/api/competition/state YD_Event.Admin 的匿名只读接口;只返回已发布数据
GET/PUT jitsi-web.yuedongsports.com/api/website-competition 后台登录后读取草稿、保存或发布
GET/PUT <赛事服务私网 IP>:8787/api/competition/admin 仅供 YD_Event.Admin 内部调用;按来源 IP 放行

官网生产构建默认从 https://jitsi-web.yuedongsports.com/api/competition/state 读取,每 10 秒刷新一次,不再请求 https://www.yuedongsports.com/api/competition/state。如需覆盖,在构建官网时设置 VITE_COMPETITION_API_URL 为完整接口基地址。开发时官网 Vite 会把 /api/competition 代理到 http://localhost:8787,可用 COMPETITION_API_TARGET 覆盖。

YD_Event.Web 的「官网赛事信息」路由隐藏于菜单,未登录访问会跳转登录页;管理接口要求已有后台登录态。正式环境访问基地址为 https://jitsi-web.yuedongsports.com/。分机部署时将 CompetitionApi__AdminUrl 设为 http://<赛事服务私网 IP>:8787/api/competition/admin。后台管理和公开只读接口均由 YD_Event.Admin 通过私网转发到赛事服务。

升级两端服务后,旧的 COMPETITION_ADMIN_TOKEN、CompetitionApi__AdminToken 和 CompetitionApi__AdminTokenFile 可从部署配置中移除;它们不再被本功能读取。上线前由运维确认后台私网 IP 白名单、防火墙入站规则及公网管理路径屏蔽均已生效,再验证无密钥的后台保存流程。

上传格式

管理页提供包含填写说明和示例行的 Excel 模板。一次上传 .xlsx 文件会将赛程、全能成绩、挑战成绩、Battle、选手和纪录载入草稿,点击「保存官网赛事信息」才写入接口。页面也可下载当前数据的 Excel 文件。

Excel 工作表依次为「填写说明」「赛程」「全能成绩」「挑战成绩」「Battle场次」「选手」「纪录」。六张数据表的表头必须保留;删除示例行后可填写正式数据。全能成绩的名次使用官方成绩册数据,前台不重算名次。挑战成绩的「榜单」区分决赛和资格赛。

缺失的图片回退到默认头像。照片字段应使用浏览器可访问的 HTTPS 地址或官网同源路径;上传图片文件本身由现有图片存储服务负责。仓库内的 public/competition-state.json 是静态只读空态,不会存放管理后台的未发布数据。

运行接口验证:node server/competition-api.smoke.mjs。