Files
trade-message-center/README.md
T

13 KiB
Raw Blame History

Trade Message Center

本地开发要求

  • Node.js >=22.22.2 <23
  • pnpm 11.7.0
  • 可连接的 PostgreSQL 数据库
  • Chrome 或 Chromium(用于加载和调试扩展)

安装依赖:

pnpm install

环境变量与授权配置

环境变量文件统一放在仓库根目录,供 server、Chrome 扩展和数据库迁移共享:

  • .env.example:提交到仓库的变量模板,不放真实密钥。
  • .env.env.development:可选的基础或开发环境配置,不提交。
  • .env.local:本机通用配置,不提交。

文件名统一使用 .env.example.env.development;不要使用 .env.Example.env.dev

开发环境可以从模板开始:

cp .env.example .env.local

server 开发入口和迁移命令按以下顺序读取文件,后面的文件覆盖前面的同名变量:

.env.env.local.env.development

必填基础配置

变量 说明
HOST server 监听地址,例如 127.0.0.1
PORT server 监听端口,必须是 1-65535 的整数,例如 7878
DATABASE_URL Bright PostgreSQL 连接串;启动 server 和执行 migration 都需要。

本地默认配置如下:

HOST=127.0.0.1
PORT=7878
DATABASE_URL=postgres://postgres:postgres@127.0.0.1:5432/trade_message_center

OneTalk 本地开发

pnpm dev 会以 NODE_ENV=development 启动 Bright server,并同时启动本地 Mind HTTP mock(默认 127.0.0.1:8787)。Bright 通过 MIND_AUTH_BASE_URL 访问 mock 的两个授权接口,不再需要 ONETALK_DEV_* 身份 fixturemock 只模拟 Mind HTTP 授权结果,不是生产授权实现,也不会连接 Mind 数据库。

本地 .env.local 至少应将 MIND_AUTH_BASE_URL 指向 mock,并将 MIND_PAGE_ORIGIN 指向 Bright 页面地址:

MIND_AUTH_BASE_URL=http://127.0.0.1:8787
MIND_PAGE_ORIGIN=http://127.0.0.1:7878
ONETALK_PLUGIN_ORIGINS=chrome-extension://ogdbffjakeeidblabkeakakdecfbcmlf

apps/chrome-extension/.keys/extension-private-key.pem 是本地生成的扩展私钥,权限应保持为 600,不会提交到 Git;生成的 dist/manifest.json 内置从该私钥导出的固定公钥,因此从不同目录加载 apps/chrome-extension/dist/ 不会再导致扩展 ID 变化。当前固定 ID 是 ogdbffjakeeidblabkeakakdecfbcmlfONETALK_PLUGIN_ORIGINS 仍必须是这个扩展的精确 Origin,不能改成任意 OriginMIND_PAGE_ORIGIN 是浏览器访问 Bright 的页面 Origin,不是 mock 的监听地址。

开发 server 会输出 [mind-auth][diagnostic],只包含 binding/session endpoint、授权 operation、request_started/allowed/rejected/request_failed、HTTP status 和稳定 code,可据此判断请求是否发出、Mind 是否返回以及最终拒绝原因;不包含 Cookie、binding、请求体或原始异常。扩展握手的 Origin 拒绝会出现在 [onetalk][diagnostic] 中。

Mind/Bright 生产认证边界

生产部署使用同一二级域名下的不同三级域名,例如 mind.example.combright.example.com。Mind 登录 Cookie 由 Mind 配置为覆盖两个三级域名的 Domain=.example.comPath=/SecureHttpOnly CookieMind 页面调用 Bright HTTP 时使用 credentials: "include"Bright 只允许精确 Mind Origin,并对页面 WS 和扩展 WS 分别执行 Origin allowlist。

Bright 不连接 Mind 数据库、不读取认证视图、不共享 Mind 登录密钥,也不签发 mind_page credential。Bright 只把页面请求中的 Cookie 转发给 Mind 的 Session 授权接口,并把插件的 channelAccountId + binding 转发给 Mind 的 binding 授权接口;Cookie 不进入 URL、WS payload、日志或持久化数据。

Mind HTTP 本地模拟

仓库提供一个无状态的本地 Mind HTTP mock,只实现上述两个授权接口。它默认监听 127.0.0.1:8787,默认 fixture 是账号 286995452、binding binding-1 和 Cookie mind_session=mock-valid;通过 MIND_MOCK_* 环境变量覆盖 fixture 后重启即可模拟 binding/version/cookie 切换。两个 endpoint 还可独立设置结果:MIND_MOCK_BINDING_RESULT=allow|scope_mismatch|binding_revoked|authorization_unavailableMIND_MOCK_SESSION_RESULT=allow|auth_required|scope_mismatch|authorization_rejected|authorization_unavailable

根目录执行 pnpm dev 时会先清理各 workspace 包的开发 dist,重新构建共享 contract,再自动启动 mock;也可以单独运行 pnpm dev:mock

直接验证两个接口:

curl -sS http://127.0.0.1:8787/internal/bright/onetalk/authorize-binding \
  -H 'content-type: application/json' \
  --data '{"channelAccountId":"286995452","binding":"binding-1"}'
curl -sS http://127.0.0.1:8787/internal/bright/onetalk/authorize-session \
  -H 'content-type: application/json' \
  -H 'cookie: mind_session=mock-valid' \
  --data '{"channelAccountId":"286995452"}'

根目录执行 pnpm dev 会自动启动 mock 和 Bright;也可以单独运行:

pnpm dev:mock

pnpm --filter @trade-message-center/server dev:mind-http 是仅供显式测试配置使用的 server 启动脚本;普通 pnpm dev 已直接使用 development-only 的 loopback Mind HTTP 配置。这个 mock 不模拟真实 Mind 的 Cookie Domain/SameSite/Secure、三级域 CORS/TLS、浏览器页面或 takeover 事务。

mind-http-mock 只参与本地 dev、类型检查和测试,不参与根 pnpm build,也不会被 Dockerfile.server 复制到生产镜像。

VITE_BRIGHT_WEBSOCKET_URL 用于 Chrome 扩展构建:

VITE_BRIGHT_WEBSOCKET_URL=ws://127.0.0.1:7878/ws/plugin

它会在扩展构建时注入,必须使用 ws://wss://。开发或生产构建未设置该变量时会直接失败,不再回退到代码内置地址。

该变量是四个扩展入口共用的构建配置,应放在根目录 .env.local,或通过命令行/CI 环境变量注入。

只有以 VITE_ 开头的变量会暴露给扩展代码,数据库连接串和 binding 等服务端敏感配置不得使用该前缀。

Workspace 版本

根目录 package.jsonversion 是 workspace 发布版本的唯一编辑点。根目录的 devdev:extensionbuildtypechecktestformat:check 会自动先执行版本镜像同步,再检查一致性;修改根版本后可以直接运行这些命令,不会因为子包镜像尚未更新而中断。

如需手动执行或单独审计,可使用:

pnpm version:sync
pnpm version:check

也可以用一次命令完成“同步后检查”:

pnpm version:ensure

版本必须是 Chrome 扩展和 package metadata 都支持的三段数字版本,例如 0.1.0;不使用 prerelease、build metadata 或额外段。协议、配置、IndexedDB 和授权版本仍是独立概念,不随 workspace 版本修改。

启动 server 与数据库

首次启动或数据库结构有变化时,先执行迁移:

pnpm --filter @trade-message-center/server db:migrate

如需重置本地开发数据库,执行以下命令:

pnpm --filter @trade-message-center/server db:reset

该命令会删除开发库的 publicdrizzle schema,重建 public schema,并重新执行全部 migration。它只接受 NODE_ENV=development 和 loopback 主机(localhost127.0.0.1::1)的 DATABASE_URL;请确保目标是专用的本地开发库,命令不会保留其中的数据。

再从仓库根目录启动 server 和扩展开发构建:

pnpm dev

根命令会统一生成并注入 BUILD_HASH,同时启动 server 和 Popup、MAIN world、ISOLATED world、Service Worker 四个扩展 watch 构建。因此扩展开发不要直接运行底层 Vite 命令。

如果只需要重启 Bright server,使用:

pnpm dev:server

该命令直接启动 server watch,不调用 workspace 级 with-build-hash,也跳过 server predev 的 contract 构建;因此不会重新构建 Chrome 扩展,也不会改变当前扩展产物中的 BUILD_HASH。首次 checkout 或修改 onetalk-contract 后,请先执行 pnpm --filter @trade-message-center/onetalk-contract build。如果 server 需要本地 Mind HTTP mock,请另开终端运行 pnpm dev:mock

检查 server 是否启动:

curl http://127.0.0.1:7878/health

预期返回:

{ "status": "ok" }

本地 Bright 联调页位于:

http://127.0.0.1:7878/harness

本地 harness 中的 OneTalk account 应与 MIND_MOCK_CHANNEL_ACCOUNT_ID(默认 286995452)一致;生产 Mind 页面不提交可信的 user/workspace header,而由 Cookie Session 授权结果派生。页面 WebSocket 使用 /ws/mind,插件使用 /ws/plugin

加载和配置 Chrome 扩展

  1. 执行 pnpm dev,确认生成 apps/chrome-extension/dist/
  2. 打开 chrome://extensions,启用“开发者模式”,选择“加载已解压的扩展程序”,加载 apps/chrome-extension/dist/
  3. 打开 OneTalk 页面 https://onetalk.alibaba.com/,点击扩展图标打开 Popup;Popup 会从页面运行时读取登录人账号 ID(currentUserAccountId),不要填写 URL 的 activeAccountId
  4. 在 Binding 输入框填入 MIND_MOCK_BINDING(默认 binding-1)对应的值后保存配置;Popup 首次运行会自动生成 Device ID。URL 中的 activeAccountId 仅是当前对话账号。
  5. Bright WebSocket URL 仅展示当前构建使用的地址,不在 Popup 中手工填写。配置保存或清除后,Service Worker 会动态建立、重建或关闭 Bright 连接和同步引擎。

扩展配置保存在 chrome.storage.local。Popup 不配置 mindUserIdworkspaceId;保存 binding 时留空表示保持已有 binding,输入新值才会替换它。清除配置不会重置自动生成的 Device ID。

生产构建:

pnpm build

构建完成后仍可将 apps/chrome-extension/dist/ 作为未解压扩展加载。

生成并发布 Chrome 扩展

推送指向 main 历史的 Git tag 后,生成流程会在发布前检查中的同一次构建基础上打包扩展,并将版本包上传到 OSS:

oss://<OSS_BUCKET>/chrome-extension/<package-version>/trade-message-center-chrome-extension-<package-version>.zip

OSS Bucket、Endpoint 和 Region 已直接写在 .github/workflows/release_ci.yml 中。production Environment 只需要配置以下密钥:

  • SecretsOSS_ACCESS_KEY_IDOSS_ACCESS_KEY_SECRET

上传账号只需要目标 Bucket 对应版本目录的写权限。Git tag 仍用于触发发布和定位源码,但不会作为扩展发布版本;版本目录和文件名使用根 package.jsonversion。现有同版本覆盖语义保持不变。

Server 数据库迁移

server 使用 Drizzle 的 TypeScript schema 生成版本化 SQL migration。业务表定义放在 apps/server/src/database/schema/,迁移文件和元数据放在 apps/server/drizzle/,相关命令从仓库根目录执行:

pnpm --filter @trade-message-center/server db:generate
pnpm --filter @trade-message-center/server db:check
pnpm --filter @trade-message-center/server db:migrate

生产部署时,先以独立的一次性 job 执行 db:migrate,成功后再启动或滚动更新 server;应用启动不会自动修改数据库结构。已执行的 migration 不可修改,破坏性变更使用新的补偿 migration 和 expand-contract 流程。

测试与质量检查

常用检查:

pnpm format:check
pnpm typecheck
pnpm test
pnpm build
git diff --check

需要执行真实 PostgreSQL 集成测试时,将 TEST_DATABASE_URL 放在根目录 .env.local 中(或显式导出),运行专用测试命令:

pnpm --filter @trade-message-center/server test:integration

该命令会按 server 迁移命令相同的顺序加载根目录 .env.env.local.env.development。普通 pnpm test 会排除 *.integration.test.*,不会自动连接 PostgreSQL;未设置 TEST_DATABASE_URL 时,单独运行集成测试会明确标记为 skip,不代表真实数据库迁移和事务边界已经验证。

VSCode 开发环境

本项目统一使用 Oxfmt 格式化代码,缩进为 4 个空格。请在 VSCode 中安装 Oxc 插件 oxc.oxc-vscode,否则保存文件时可能使用其它 formatter,导致代码在提交钩子中再次变化。

安装方式:

  1. 打开 VSCode 扩展面板(macOS 快捷键:⇧⌘X)。
  2. 搜索 Oxc,安装扩展 oxc.oxc-vscode
  3. 重新打开项目窗口,确认右下角或状态栏使用 Oxc formatter。

仓库已经在 .vscode/settings.json 中配置 Oxc 保存格式化,并通过 .oxfmtrc.json 固定 4 空格规则。项目本地依赖已经包含 Oxfmt,不需要单独全局安装。

如果暂时不安装插件,请关闭 VSCode 的 formatOnSave,需要格式化时在项目根目录执行:

pnpm format
pnpm format:check

不要同时启用 Prettier、Biome 或 VSCode 内置 TypeScript formatter。