Files
thebet365/docs/四套主题Docker部署任务.md
Mars e0ce36cc48 docs: 新增四套主题 Docker 部署与邀请链接选主题任务文档
汇总多 player 容器部署、分支同步、发版流程及后台按主题生成邀请链接的阶段 F 设计,便于下次直接实施。
2026-06-22 14:57:56 +08:00

22 KiB
Raw Blame History

四套主题 Docker 生产部署任务

目标:在同一台服务器、同一套 Docker Compose 栈内,同时运行 4 套玩家端主题4 个 player 容器 + 1 套共用 api/admin/db
适用分支main(暗金)、theme-2Pinnacle 蓝白)、theme-3(统一移动端视觉)、theme-4(海军蓝暗色极简)。
关联文档Docker部署指南.mddocker/镜像构建与导出.mdAGENTS.md「主题分支」章节。


一、架构总览

域名 A主站     → 127.0.0.1:8082 → thebet365-player      镜像 tag: main
域名 Btheme-2  → 127.0.0.1:8083 → thebet365-player2     镜像 tag: theme-2
域名 Ctheme-3  → 127.0.0.1:8084 → thebet365-player3     镜像 tag: theme-3
域名 Dtheme-4  → 127.0.0.1:8085 → thebet365-player4     镜像 tag: theme-4

管理后台           → 127.0.0.1:8081 → thebet365-admin       镜像 tag: latest或统一 IMAGE_TAG
                              ↓
                    thebet365-apiDocker 内网,不映射宿主机端口)
                              ↓
                    thebet365-postgres + thebet365-redis
要点 说明
不是「一个容器四套皮肤」 4 个 player 容器,各跑各自构建好的静态资源
后端共用 api / postgres / redis / uploads 只有一套,账号与余额互通
本地开发 仍只需 pnpm dev:player:5173切分支预览不同主题;不必本地开 4 端口
deploy-update.sh 默认只维护 一套 api/player/admin多主题 player2~4 需 单独 load + compose up
邀请注册链接 当前仅 VITE_PLAYER_URL 单域名;需 阶段 F 实现后台按主题选链接(见第十三节)

二、任务清单(实施顺序)

按顺序勾选,下次上线可直接照着做。

阶段 A — 仓库改动(一次性)

  • A1 新增 docker-compose.themes.ymlplayer2 / player3 / player4 服务定义)
  • A2 更新 .env.docker.examplePLAYER2_* ~ PLAYER4_*CORS_ORIGINS 示例)
  • A3 更新 docker-compose.prod.ymlplayer 使用 PLAYER_IMAGE_TAG(与 IMAGE_TAG 解耦,见下文片段)
  • A4(可选)在 docs/Docker部署指南.md 增加「多主题」小节链接到本文
  • A5(可选)在 AGENTS.md 文档索引增加本文链接

阶段 B — 各主题分支同步 main 功能(发版前每个 theme 分支各做一遍)

  • B1theme-2 / theme-3 / theme-4 同步 API、Admin、shared、迁移禁止整目录覆盖 player
  • B2 Player 侧只做逻辑/i18n 增量合并,保留各分支 styles.css 与主题资源
  • B3 各分支本地 pnpm buildpnpm dev:player 冒烟
  • B4 main 分支照常维护;若 api/admin 有变更,四个 player 镜像可共用同一 api/admin 包

阶段 C — 本地打镜像Windows 构建机)

  • C1 四个分支分别打 player 镜像tag 互不相同)
  • C2api + admin 一包(在 main 或任意已同步分支tag 如 latest
  • C3 核对 .manifest.txtgit_commit 与分支一致
  • C4 上传 tar 到服务器(勿覆盖 .env.docker

阶段 D — 服务器首次启用多主题

  • D1 备份:执行 deploy-update 前会自动备份;首次改 compose 前建议手动 ./scripts/backup-prod.sh
  • D2 docker load 四个 player tar + api/admin tar
  • D3 编辑 .env.docker(端口、镜像 tag、CORS、域名
  • D4 docker compose -f docker-compose.prod.yml -f docker-compose.themes.yml --env-file .env.docker up -d
  • D5 宝塔为 4 个玩家域名 + 1 个管理域名配置反代
  • D6 执行下方「验收清单」

阶段 E — 日常更新(重复)

  • 仅换某一主题 UI → 只 rebuild/load 对应 player tag → up -d playerN
  • API/Admin/迁移变更 → deploy-update.sh 更新 api/admin必要时四个 player 无需重建
  • 发版后强刷浏览器 / 清 CDN

阶段 F — 邀请链接按主题选择(功能开发,可与 D 并行)

  • F1 APISystemConfig 存四套玩家站域名配置(见第十三节)
  • F2 管理端「全局设置」可编辑主题名称 + 公网 URL + 默认项
  • F3 邀请面板 / 邀请历史:下拉选择主题后再复制注册链接
  • F4 代理端邀请弹窗同样可读主题列表并选择(只读,不能改 URL
  • F5 部署四套主题后,在全局设置填齐 4 个 https 域名并验收邀请链接

三、仓库待实现:docker-compose.themes.yml

任务 A1:在仓库根目录新建此文件,与 docker-compose.prod.yml 合并使用。

# 四套主题扩展 — 与 docker-compose.prod.yml 一起使用:
# docker compose -f docker-compose.prod.yml -f docker-compose.themes.yml --env-file .env.docker up -d

services:
  player2:
    image: thebet365-player:${PLAYER2_IMAGE_TAG:-theme-2}
    container_name: thebet365-player2
    depends_on:
      api:
        condition: service_healthy
    ports:
      - '${BIND_ADDR:-127.0.0.1}:${PLAYER2_PORT:-8083}:80'
    healthcheck:
      test: ['CMD-SHELL', 'wget -q -O /dev/null http://127.0.0.1/ || exit 1']
      interval: 10s
      timeout: 5s
      retries: 6
      start_period: 10s
    restart: unless-stopped
    networks:
      - thebet365

  player3:
    image: thebet365-player:${PLAYER3_IMAGE_TAG:-theme-3}
    container_name: thebet365-player3
    depends_on:
      api:
        condition: service_healthy
    ports:
      - '${BIND_ADDR:-127.0.0.1}:${PLAYER3_PORT:-8084}:80'
    healthcheck:
      test: ['CMD-SHELL', 'wget -q -O /dev/null http://127.0.0.1/ || exit 1']
      interval: 10s
      timeout: 5s
      retries: 6
      start_period: 10s
    restart: unless-stopped
    networks:
      - thebet365

  player4:
    image: thebet365-player:${PLAYER4_IMAGE_TAG:-theme-4}
    container_name: thebet365-player4
    depends_on:
      api:
        condition: service_healthy
    ports:
      - '${BIND_ADDR:-127.0.0.1}:${PLAYER4_PORT:-8085}:80'
    healthcheck:
      test: ['CMD-SHELL', 'wget -q -O /dev/null http://127.0.0.1/ || exit 1']
      interval: 10s
      timeout: 5s
      retries: 6
      start_period: 10s
    restart: unless-stopped
    networks:
      - thebet365

任务 A3调整 docker-compose.prod.ymlplayer 服务

player.image${IMAGE_TAG} 改为独立变量(避免与 api/admin 的 IMAGE_TAG 绑死):

  player:
    image: thebet365-player:${PLAYER_IMAGE_TAG:-main}
    # build / ports / healthcheck 等其余保持不变

player2~4 不要build:,生产只 load 预构建镜像。


四、.env.docker 配置模板

任务 A2:追加到 .env.docker.example;服务器 .env.docker 按真实域名填写。

# ── 共用后端 ──
IMAGE_TAG=latest
ADMIN_PORT=8081
BIND_ADDR=127.0.0.1

# 管理端邀请链接默认指向的主玩家站(勿带末尾 /
VITE_PLAYER_URL=https://www.example.com

# 四个玩家站域名都需列入(逗号分隔,无空格或统一 trim
CORS_ORIGINS=https://www.example.com,https://theme2.example.com,https://theme3.example.com,https://theme4.example.com,https://admin.example.com

# ── 四套 player 镜像 tag 与宿主机端口 ──
PLAYER_IMAGE_TAG=main
PLAYER_PORT=8082

PLAYER2_IMAGE_TAG=theme-2
PLAYER2_PORT=8083

PLAYER3_IMAGE_TAG=theme-3
PLAYER3_PORT=8084

PLAYER4_IMAGE_TAG=theme-4
PLAYER4_PORT=8085

修改 CORS_ORIGINS 后必须重启 api

docker compose -f docker-compose.prod.yml -f docker-compose.themes.yml --env-file .env.docker restart api

五、分支合并代码main → theme-*

发版前在每个 theme-* 分支执行。目标:功能与 main 一致,皮肤不变

5.1 禁止事项

禁止 原因
git merge main 后直接发 player 易把 main 暗金样式大量带入
git checkout main -- apps/player/ 整目录覆盖会冲掉主题 CSS/组件
git checkout main -- apps/player/src/i18n/ 会冲掉主题分支已有措辞

5.2 推荐整目录同步API / Admin / shared / 迁移)

在目标主题分支上(示例 theme-2

git checkout theme-2
git fetch origin

# 同步后端与共享包(可按需增减路径)
git checkout origin/main -- apps/api
git checkout origin/main -- apps/admin
git checkout origin/main -- packages/shared
git checkout origin/main -- pnpm-lock.yaml
git checkout origin/main -- pnpm-workspace.yaml

# 若有新迁移,务必带上
git checkout origin/main -- apps/api/prisma/migrations
git checkout origin/main -- apps/api/prisma/schema.prisma

git status   # 确认没有误改 apps/player 大段样式文件
git commit -m "sync: api/admin/shared/migrations from main"

5.3 Player只做逻辑与文案增量

方式 1 — 按文件 cherry-pick有明确 commit 时)

git log origin/main --oneline -- apps/player/src/composables apps/player/src/stores
git cherry-pick <commit-hash>   # 冲突时保留 theme 分支的 styles / 主题组件

方式 2 — 按目录选择性 checkout仅非 UI 目录)

# 示例:只同步 stores、composables、api 封装(执行前确认路径在 main 有变更)
git checkout origin/main -- apps/player/src/stores
git checkout origin/main -- apps/player/src/composables
git checkout origin/main -- apps/player/src/api

方式 3 — i18n 只合并新增 key

  • 对比 apps/player/src/i18n/*.ts,手工把 main 新增的 key 补进三语文件
  • 不要用 main 文件整文件覆盖

5.4 合并后本地验证(每个 theme 分支)

pnpm install
pnpm db:generate          # 若 schema 有变
pnpm --filter @thebet365/shared build
pnpm --filter @thebet365/player build
pnpm dev:api              # 另开终端
pnpm dev:player           # http://localhost:5173 目视确认仍是本主题皮肤

5.5 main 分支

  • 日常功能开发在 main 完成后再同步到各 theme 分支
  • main 自身 player 镜像 tag 建议使用 mainlatest(与 .env.dockerPLAYER_IMAGE_TAG 一致即可)

六、构建与上传镜像

6.1 四个 player 镜像Windows CMD

cd C:\path\to\thebet365

git checkout main
docs\docker\build-and-export-player.bat --tag main

git checkout theme-2
docs\docker\build-and-export-player.bat --tag theme-2

git checkout theme-3
docs\docker\build-and-export-player.bat --tag theme-3

git checkout theme-4
docs\docker\build-and-export-player.bat --tag theme-4

产物(项目根目录,已在 .gitignore

文件 加载后镜像名
thebet365-player-main.tar thebet365-player:main
thebet365-player-theme-2.tar thebet365-player:theme-2
thebet365-player-theme-3.tar thebet365-player:theme-3
thebet365-player-theme-4.tar thebet365-player:theme-4

6.2 api + admin 一包

git checkout main
docs\docker\build-and-export-images.bat --tag latest

或 Linux./docs/docker/build-and-export-images.sh --tag latest

6.3 上传至服务器

目录示例:/www/wwwroot/thebet365

必传 说明
四个 player tar 四套皮肤
thebet365-images-latest.tar(或带版本 tag api + admin
docker-compose.prod.yml 若仓库有更新
docker-compose.themes.yml 首次多主题必传
scripts/ 若部署脚本有更新

勿覆盖.env.docker、Docker 数据卷、backups/


七、服务器部署命令

7.1 首次启用四套主题

cd /www/wwwroot/thebet365
chmod +x scripts/*.sh

# 导入全部镜像
docker load -i thebet365-images-latest.tar
docker load -i thebet365-player-main.tar
docker load -i thebet365-player-theme-2.tar
docker load -i thebet365-player-theme-3.tar
docker load -i thebet365-player-theme-4.tar

# 编辑 .env.docker见第四节模板后启动
docker compose -f docker-compose.prod.yml -f docker-compose.themes.yml --env-file .env.docker up -d

若当前环境已由 deploy-first.sh 跑通,只需 load 新 player 镜像 + 合并 compose + up -d player2 player3 player4,并调整 .env.docker

7.2 更新共用 api/admin

仍用现有脚本(不会自动更新 player2~4

./scripts/deploy-update.sh --images thebet365-images-latest.tar --tag latest

之后确认多主题 compose 仍生效:

docker compose -f docker-compose.prod.yml -f docker-compose.themes.yml --env-file .env.docker up -d

7.3 只更新某一主题(例如 theme-4

docker load -i thebet365-player-theme-4.tar
docker compose -f docker-compose.prod.yml -f docker-compose.themes.yml --env-file .env.docker up -d player4

其他主题容器不受影响。

7.4 回滚某一 player

# 加载旧 tag 的 tar 后
docker compose -f docker-compose.prod.yml -f docker-compose.themes.yml --env-file .env.docker up -d player3

api 回滚仍用 ./scripts/rollback.sh --to <tag>回滚数据库)。


八、宝塔 / Nginx 反代

每个玩家站 只反代到对应端口,容器内已处理 /api/uploads,宝塔无需再写 API 规则。

宝塔网站 proxy_pass
主站main http://127.0.0.1:8082
theme-2 站 http://127.0.0.1:8083
theme-3 站 http://127.0.0.1:8084
theme-4 站 http://127.0.0.1:8085
管理后台 http://127.0.0.1:8081

示例:

location / {
    proxy_pass http://127.0.0.1:8082;
    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;
}

四套站点分别申请 SSLCORS_ORIGINS 使用 https 域名。


九、验收清单

部署完成后逐项检查:

  • docker compose ... ps — api、admin、player、player2、player3、player4 均为 healthy
  • 四个玩家域名首页 UI 皮肤互不相同
  • 各站登录同一账号,余额一致
  • 各站下注、充值、站内信、公告正常
  • 管理后台 :8081 正常;员工菜单与 Inbox 开关已配置(见 Docker部署指南.md 第八节步骤 5
  • npx prisma migrate status(在 api 容器内)无 pending 迁移
  • 浏览器 Network 无 CORS 报错(若有,检查 CORS_ORIGINS 并 restart api
  • theme-4 独有组件(如悬浮客服)仅在 theme-4 站出现
  • 阶段 F 完成后:邀请面板切换四套主题,复制链接分别打开对应域名 /register?code=...

十、常见问题

现象 处理
某站 502 docker compose ps 看对应 player 是否 healthydocker logs thebet365-player3
接口 401/403 仅某一域名 检查 CORS_ORIGINS 是否包含该 https 域名
四套变成同一皮肤 检查是否四个 tag 打错或 .env.dockerPLAYER*_IMAGE_TAG 写错
deploy-update 后 player2 消失 脚本未管理 themes compose重新 up -d 并带 -f docker-compose.themes.yml
邀请链接域名不对 未做阶段 F:改 VITE_PLAYER_URL 重建 admin仅一个默认站已做阶段 F:到「全局设置 → 玩家主题站点」核对 URL邀请面板选对应主题
构建 ENOENT public/球员 清理 packages/shared/public 下除 flagsplayers 外的中文目录后重试

十一、与本地开发的区别

场景 做法
日常改某一主题 UI 切到对应分支 → pnpm dev:player5173
本地同时对比 4 套 可选:多开终端 --port 5173/5174/5175/5176(非必须)
生产 4 套并存 4 个 player 容器 + 4 个端口 + 4 个域名

十二、邀请链接按主题选择(阶段 F 详细设计)

现状apps/admin/src/utils/invite-link.ts 用构建时注入的 VITE_PLAYER_URL 拼链接;四套主题并存时后台无法选择注册落地页。
目标:管理员(及代理)生成/复制邀请链接时,下拉选择要落地的玩家主题站;配置存数据库,改域名不必重建 admin 镜像

12.1 行为说明

角色 能力
平台管理员(settings.manage 在「全局设置」维护主题列表:显示名、公网 URL、是否启用、哪一项为默认
管理员 / 代理 在「邀请」弹窗选主题 → 复制链接 {所选站}/register?code=xxx
玩家 无感知;任意主题站注册,同一邀请码、同一后端

邀请码本身与主题无关(仍走现有 InvitesService仅注册链接里的域名随所选主题变化。

12.2 数据模型(SystemConfig

配置键:player.theme_sites
JSON 字符串,结构示例:

{
  "themes": [
    { "id": "main", "label": "暗金主站", "baseUrl": "https://www.example.com", "enabled": true, "isDefault": true },
    { "id": "theme-2", "label": "Pinnacle 蓝白", "baseUrl": "https://theme2.example.com", "enabled": true, "isDefault": false },
    { "id": "theme-3", "label": "统一移动端", "baseUrl": "https://theme3.example.com", "enabled": true, "isDefault": false },
    { "id": "theme-4", "label": "海军蓝极简", "baseUrl": "https://theme4.example.com", "enabled": true, "isDefault": false }
  ]
}

规则:

  • id 与 Git 分支 / Docker 镜像 tag 对齐(maintheme-2theme-3theme-4
  • baseUrl 勿带末尾 /;保存时 API 侧 trim + 校验 https?://
  • 有且仅有一个 isDefault: true;未配置时 API 回退 VITE_PLAYER_URL(兼容旧环境)
  • enabled: false 的主题不出现在邀请下拉里

12.3 API 任务(apps/api

F1 — SystemConfigService 新增:

// apps/api/src/shared/config/system-config.service.ts
getPlayerThemeSites(): Promise<PlayerThemeSitesSettings>
updatePlayerThemeSites(data): Promise<PlayerThemeSitesSettings>
listEnabledPlayerThemes(): Promise<PlayerThemePublicOption[]>  // 仅 id/label/baseUrl/isDefault

F1 — Admin 控制器:

方法 路径 权限 说明
GET /admin/settings/player-themes settings.manage 完整配置(含 disabled
PUT /admin/settings/player-themes settings.manage 保存;写审计 UPDATE_PLAYER_THEME_SITES
GET /admin/player-themes/options 登录员工/代理即可 enabled 主题,供邀请 UI

代理门户若走 /manage/*,在 auth.controller 或 manage 控制器增加同等 GET options(复用 service

校验:

  • 至少保留 1 个 enabled 主题
  • URL 格式合法;禁止重复 baseUrl
  • 更新后无需重启 api读 DB

12.4 管理端任务(apps/admin

F2 — GlobalSettingsView.vue 增加卡片「玩家主题站点」:

  • 表格编辑label、baseUrl、enabled、设为默认
  • 保存调用 PUT /admin/settings/player-themes
  • 与第四节四个域名保持一致(部署后首次必填)

F3 — 邀请 UI

涉及文件:

  • apps/admin/src/utils/invite-link.ts — 改为 buildPlayerRegisterUrl(code, baseUrl?)
  • apps/admin/src/components/InviteCodePanel.vue — 加载 optionsel-select 选主题,registerUrl 随选择变化
  • apps/admin/src/components/InviteHistoryPanel.vue — 复制链接前同样选主题(或记住上次选择)

交互建议:

  • 默认选中 API 返回的 isDefault 主题
  • localStorageadmin_invite_theme_id 记住上次选择(可选)
  • 无配置时回退 VITE_PLAYER_URL,与现网行为一致

F4 — i18n三语同步

admin-messages.ts / admin-pages*.ts 增加 key例如

  • invite.theme_site — 注册落地主题
  • invite.theme_site_hint — 选择玩家看到的注册页面风格
  • settings.player_themes — 玩家主题站点
  • settings.player_themes_hint — 与四套 Docker 玩家域名对应

12.5 与 Docker 四套主题的对应关系

部署完四套 player 后,在 全局设置 填:

id 对应容器 示例 baseUrl
main thebet365-player :8082 https://www.example.com
theme-2 thebet365-player2 :8083 https://theme2.example.com
theme-3 thebet365-player3 :8084 https://theme3.example.com
theme-4 thebet365-player4 :8085 https://theme4.example.com

VITE_PLAYER_URL 仍可保留为 构建默认值未配置 DB 时的回退;多主题上线后以 DB 配置为准。

12.6 阶段 F 验收

  • 全局设置保存 4 个 URL 后刷新仍生效
  • 邀请面板切换主题,链接域名随之变化,邀请码不变
  • 四套链接均可打开注册页并带 code 参数
  • 代理账号邀请弹窗可选主题(不能进全局设置改 URL
  • 禁用某主题后下拉里消失
  • 未配置 DB 时行为与现网一致(VITE_PLAYER_URL

12.7 实施顺序建议

F1 API 配置读写 → F2 全局设置页 → F3 邀请面板 → F4 代理端 → 部署四套主题后填 URL → 12.6 验收

可与 阶段 A~DDocker 多 player 并行开发;功能不依赖 player2~4 已上线,但验收需要四个域名可访问。


十三、文档维护

变更类型 更新本文
新增 theme-5 复制 player4 模式,追加端口 8086
修改 deploy 脚本支持多 player 更新第七节命令
分支合并策略变化 更新第五节

下次实施入口

  • 基础设施:阶段 A → B → C → D → 第九节验收
  • 邀请多主题:阶段 F第十二节可与 A~D 并行,四套域名就绪后做 12.6 验收