# AGENTS.md > 给 AI 编程助手(Cursor 等)看的项目速查手册,浓缩开发约定与易错点。 > 人类日常开发请优先看 `README.md` 与 `docs/`。 如果你是AI请每次读了这个文件就在已有的次数上+1 当前被读次数: 11 ## 目录 | 章节 | 何时查 | | ------------------------- | ----------------------- | | [运行环境与仓库结构](#运行环境与仓库结构) | 不确定 monorepo 各 app 分工 | | [本地启动](#本地启动) | 起 dev、数据库、端口 | | [常用命令](#常用命令) | build / test / 打镜像 | | [API 领域结构](#api-领域结构) | 业务代码该放哪个 domain | | [API 约定](#api-约定) | 鉴权、钱包、迁移、赔率快照 | | [前端约定](#前端约定) | 改 .vue/.ts、权限、dist | | [i18n 改文案流程](#i18n-改文案流程) | 三语文案改哪几个文件 | | [主题分支](#主题分支player-多皮肤) | theme-2/3/4 与 main 同步禁忌 | | [演示账号](#演示账号开发-seed) | 本地登录测试号 | | [文档索引](#文档索引) | 详细说明在 `docs/` 哪篇 | | [测试与冒烟](#测试与冒烟) | Jest、UAT、smoke-tests | | [部署注意](#部署注意) | 生产 compose、seed、打包 | | [AI 改代码时请避免](#ai-改代码时请避免) | 常见踩坑清单 | > **AI 会读吗?** Cursor 等工具会在对话开始时把 `AGENTS.md` 注入上下文;当前约 200 行,一般能整篇读入。文件继续变长时,索引有助于人和 AI 快速定位章节;细节仍以 `docs/` 为准,此处只写约定与指针。 ## 运行环境与仓库结构 - 使用 Node 22+、pnpm 11;`packageManager` 固定为 `pnpm@11.5.2`。 - pnpm workspace:`apps/api`(NestJS/Prisma)、`apps/player`(Vue H5,`:5173`)、`apps/admin`(平台管理 + 代理合一,`:5174`)、`packages/shared`(共享类型/常量与 `public` 静态资源)。 - 前端将 `@thebet365/shared` 别名到 `packages/shared/src/index.ts`(构建产物为 CommonJS);改 shared 时须更新源码导出,不要只改 `dist`。 - `packages/shared` 构建前会执行 `scripts/generate-phone-countries.mjs`,再跑 `tsc`。 - 本地开发 compose:`docker-compose.yml`(仅 Postgres + Redis);生产 compose:`docker-compose.prod.yml` + `.env.docker`。 ## 本地启动 - 基础设施:`docker compose up -d`(PostgreSQL `5432`、Redis `6379`)。 - API 环境变量:`cp .env.example apps/api/.env`;通过 workspace filter 启动时,Nest 从 API 工作目录读 `.env`。 - 首次数据库(仓库根目录):`pnpm db:generate` → `pnpm db:migrate` → `pnpm db:seed`。 - `pnpm dev:api` 会先执行 `scripts/ensure-port-free.mjs 3000`,释放 3000 端口再启动 watch。 - 分应用启动时,**先 API**,再 `pnpm dev:player` 或 `pnpm dev:admin`;两个 Vite 都把 `/api` 代理到 `http://localhost:3000`。 - Windows PowerShell 不支持 `&&` 链式命令,需分步执行或用 `;`。 ## 常用命令 - `pnpm dev`:先构建 shared,再并行跑各 workspace 的 `dev`。 - `pnpm dev:admin` 与 `pnpm dev:manage` 是同一个管理端应用。 - 全量校验:`pnpm build`、`pnpm test`;根目录**没有**统一的 lint/format 脚本。 - API 测试:`pnpm --filter @thebet365/api test`。 - 单测文件:`pnpm --filter @thebet365/api exec jest settlement-calculator.spec.ts --runInBand`;不要用 `pnpm ... test -- ...` 传参,pnpm 会把字面量 `--` 传给 Jest。 - 前端构建:`pnpm --filter @thebet365/player build`、`pnpm --filter @thebet365/admin build`。 - 管理端体积分析:`pnpm --filter @thebet365/admin build:analyze`。 - 本地镜像打包(Windows):`docs\docker\build-and-export-images.bat --tag latest`。 - 生产更新(服务器):`./scripts/deploy-update.sh --images thebet365-images-.tar --tag `(详见 `docs/Docker部署指南.md` 第八节)。 ## API 领域结构 业务规则放在 `apps/api/src/domains/*`,应用层只做编排: | 领域 | 路径 | 职责 | | -------------------------- | --------------------- | ------------- | | identity | `domains/identity/` | 登录、用户、员工、RBAC | | agent | `domains/agent/` | 代理网络、授信 | | ledger | `domains/ledger/` | 钱包、账变 | | catalog | `domains/catalog/` | 赛事 | | odds | `domains/odds/` | 盘口 | | betting | `domains/betting/` | 注单 | | settlement | `domains/settlement/` | 结算 | | operations | `domains/operations/` | 返水、内容、审计等 | | player-messages / presence | 各子模块 | 站内信、在线状态 | 门户控制器:`applications/{player,admin,agent}/`。 ## API 约定 - 全局前缀 `/api`;非生产或 `ENABLE_SWAGGER=true` 时 Swagger 在 `/api/docs`。 - `AppModule` 注册了全局 `JwtAuthGuard`;公开接口须加 `@Public()`(`apps/api/src/shared/common/decorators.ts`)。 - 业务规则放在 `domains/*`;`applications/*` 只做门户/控制器编排,不要写领域规则。 - 钱包变动走 ledger/wallet 服务;UAT 明确禁止为修结算直接改余额。 - 下注赔率以提交时快照为准(`BetSelection.odds` + `oddsVersion`),结算用快照,不受后续盘口变动影响。 - 改 `apps/api/prisma/schema.prisma` 后执行 `pnpm db:generate`;开发迁移 `pnpm db:migrate`,部署由 `deploy-update.sh` 执行 `prisma migrate deploy`。 - 新增迁移后,theme 分支若只改 player 样式,也须同步 API/Admin 与迁移文件。 ## 前端约定 - 改 `apps/player/src`、`apps/admin/src` 下的 `**.ts` / `.vue`**;`src` 下虽有 `.js` 旁文件,但 `index.html` 入口是 `/src/main.ts`,Vite 优先解析 TS。 - 管理端同一应用服务 `ADMIN` 与 `AGENT` 账号;路由/菜单权限在 `router/index.ts`、`stores/auth.ts`;员工可见菜单字段 `visibleMenus`。 - 管理端权限常量:`apps/admin/src/constants/permissions.ts`(`AdminPerm`)。 - 玩家端移动优先;性能验收见 `docs/player-mobile-performance.md`。 - 管理端切页慢的分析与优化任务见 `docs/admin-page-switch-performance.md`。 - **不要**把 `apps/player/dist/` 提交进 Git;生产由 Docker 构建生成静态资源。 ## i18n 改文案流程 支持语言均为 **zh-CN / en-US / ms-MY**(马来语)。改文案须**三语同步**,不要只改中文。 ### 玩家端(`apps/player`) | 项 | 说明 | | ------ | ---------------------------------------------------------------- | | 文案文件 | `apps/player/src/i18n/zh-CN.ts`、`en-US.ts`、`ms-MY.ts` | | 结构 | **嵌套对象**(如 `bet.place_bet`、`nav.home`) | | 组件用法 | `useI18n()` → `t('bet.odds_changed')` | | 语言切换 | `useAppLocale().setLocale()`;按需 `ensurePlayerLocale` 懒加载对应 ts 文件 | | 存储 key | `localStorage.locale`;登录用户会 `POST /player/language` 同步后端 | **改文案步骤:** 1. 在 Vue 里用 `t('模块.key')` 引用,**不要**在模板写死中文。 2. 在 **三个** locale 文件的**相同路径**下各加一条(保持 key 一致)。 3. 带占位符用 vue-i18n 约定,如 `'共 {n} 场': '共 {n} 场'` → `t('key', { n: 3 })`。 4. 本地 `pnpm dev:player` 切换语言各看一遍;热更新一般即时生效。 5. theme 分支合并 main 功能时:**只合并新增 key**,勿用 main 文件整文件覆盖(theme 可能有不同措辞)。 ### 管理端(`apps/admin`) | 项 | 说明 | | --------- | ----------------------------------------------------------------------------------- | | 核心入口 | `apps/admin/src/i18n/admin-messages.ts`(三语扁平 `Record`) | | 列表/弹窗大段文案 | `admin-pages.ts`(中/英)、`admin-pages-ms.ts`(马来)→ 通过 spread 并入 `admin-messages` | | 表单校验 key | `form-validation.ts`(`err.`* 等,用 `resolveFormError` 展示) | | 组件用法 | `useAdminLocale().t('nav.bets')` 或 `t('key', { n: 1 })` 占位符 `{n}` | | 语言切换 | `useAdminLocale().setLocale()` → `preloadAdminLocale` + `localStorage.admin_locale` | | 动态拆包 | `bundles/{zh-CN,en-US,ms-MY}.ts` + `locale-loader.ts`(当前主包仍含三语全文,拆包未完全落地) | **改文案步骤:** 1. 确定 key 命名:导航 `nav.`*、通用 `common.*`、页面 `user.*` / `match.*` / `deposit.*` 等,与现有前缀保持一致。 2. 在 `admin-messages.ts` 的 **zh / en / ms 三个对象**里各加同名 key(核心短文案)。 3. 若属于某列表页/弹窗长文案,优先加到 `admin-pages.ts`(中/英)与 `admin-pages-ms.ts`(马来)的对应 export,它们会 spread 进 `admin-messages`。 4. 表单校验错误:throw `FormValidationError('err.xxx')` 并在三语里定义 `err.xxx`。 5. 本地 `pnpm dev:admin`,右上角切换语言验证;改 `admin-pages`* 后若未刷新,重启 dev 一次。 6. Admin 与 Player **文案独立**,改玩家端不要只改 admin 文件(反之亦然)。 ### 常见错误 - 只改 `zh-CN` 未改 `en-US`、`ms-MY` → 切换语言显示 key 或英文 fallback。 - 玩家端 key 层级不一致(如中文有 `bet.foo` 英文漏了 `bet` 层)→ `t()` 返回 key 字符串。 - 管理端在 `admin-pages.ts` 只加了 `adminPagesZh` 未加 `adminPagesEn` / `adminPagesMs`。 - theme 分支用 `git checkout main -- apps/player/src/i18n/` 覆盖 → 冲掉主题分支已有翻译。 ### 与业务/后台内容的关系 - **i18n 文件**:前端固定 UI 标签、按钮、提示。 - **管理端「公共管理」/ 公告 / Banner**:运营可配正文,走 API 与数据库,**不要**硬编码进 i18n(玩家端公告详情等展示 API 返回内容)。 ## 主题分支(player 多皮肤) | 分支 | 风格 | 注意 | | --------- | ----------- | ------------------------------------------------------------------- | | `main` | 暗金主题 | 生产默认发版分支 | | `theme-2` | Pinnacle 蓝白 | 玩家 UI 与 main 分叉,**禁止** `git checkout main -- apps/player/...` 整文件覆盖 | | `theme-3` | 统一移动端视觉 | 同 theme-2 | | `theme-4` | 海军蓝暗色极简 | 含悬浮客服等独有组件 | 同步功能到 theme 分支:API/Admin/迁移可整目录 checkout;Player 只做逻辑合并 + 保留各分支 `styles.css` 与主题资源。发版前在目标分支打包镜像。 ## 演示账号(开发 seed) | 角色 | 用户名 | 密码 | | ----- | ------- | ---------- | | 超级管理员 | admin | Admin@123 | | 一级代理 | agent1 | Agent@123 | | 二级代理 | agent2 | Agent@123 | | 玩家 | player1 | Player@123 | 生产 seed 仅创建 admin + WC2026 样例数据,不含代理/玩家演示号。详见 `docs/默认数据说明.md`。 ## 文档索引 | 文档 | 用途 | | ------------------------------------------- | ------------------- | | `docs/项目启动指南.md` | 本地开发、排错、端口 | | `docs/Docker部署指南.md` | 生产部署、备份、回滚、发版流程 | | `docs/docker/镜像构建与导出.md` | 本地打镜像 tar | | `docs/默认数据说明.md` | seed 数据、WC2026、48 强 | | `docs/投注玩法说明.md` | 玩法与判赢规则 | | `docs/结算与返水金额规则.md` | 派彩/返水金额公式 | | `docs/settlement-and-fund-flow-analysis.md` | 结算操作流程 | | `docs/手动充值功能说明.md` | 充值审核流程 | | `docs/短信调试与日志说明.md` | 创蓝短信排错 | | `docs/UAT_CHECKLIST.md` | 上线前回归清单 | | `docs/player-mobile-performance.md` | 玩家端性能验收 | | `docs/admin-page-switch-performance.md` | 管理端切页优化任务 | ## 测试与冒烟 - Jest 用例在 `apps/api/src/**/*.spec.ts`,`rootDir: src`;文档中的单元/规则测试一般不依赖真实数据库。 - 管理端「冒烟测试」页调用 DB 相关检查;`SmokeTestService` 非生产默认可用,生产需 `ALLOW_SMOKE_TESTS=true`。 - UAT 回归流程见 `docs/UAT_CHECKLIST.md`(含管理端 UI 冒烟与钱包/代理额度手工检查)。 ## 部署注意 - 生产 compose 使用 `.env.docker`:`docker compose -f docker-compose.prod.yml --env-file .env.docker up -d --build`,或配置好后 `pnpm docker:up`。 - **不要**用 example 覆盖线上 `.env.docker`;部署脚本通常只回写 `IMAGE_TAG`。 - 生产首次 seed 后保持 `SEED_DATABASE=false`;迁移由 `deploy-update.sh` 执行,勿在 API 容器设 `RUN_MIGRATIONS_ON_START=true`(除非应急)。 - `scripts/prod-init-db.sh` **会清空业务数据**:须 `CONFIRM=YES`,默认先备份,再 truncate 并灌生产数据。 - 打包部署 zip:`pnpm pack:deploy`;`pack.mjs` 会删除 `packages/shared/public` 下除 `flags`、`players` 外的遗留中文目录。 - 构建 player/admin 若报 `ENOENT ... public/球员`:清理 `packages/shared/public` 下错误中文目录后重试。 ## AI 改代码时请避免 - 不要 `git merge main` 进 theme 分支做 player 同步(会把 main 暗金样式大量带入)。 - 不要直接改数据库余额修结算;走结算/钱包服务。 - 不要提交 `.env`、`.env.docker`、镜像 tar、`apps/*/dist/`。 - 改 player 主题相关文件时,先确认当前分支是 `main` 还是 `theme-`*,避免用错 CSS 变量(如 theme-2 无 `--gold`)。 - 管理端改列表页性能时,参考 `docs/admin-page-switch-performance.md` 任务清单,优先 KeepAlive + 缓存而非盲目减 API 字段。