AGENTS.md 9.41 KB

Repository Guidelines

VOKO Agent 世界(voko-world)。pnpm 11 + Turbo monorepo,Node >=24,ESM JavaScript + JSDoc。应用在 apps/*,可复用包在 packages/*。

本仓库于 2026-10-10 从 shadiao-2d 搬入 19 个包后独立演进;搬入来源与后续同步记录见 docs/voko/upstream.md。产品与设计文档见 docs/voko/README.md。

应用与端口

app 说明 dev 端口
@voko/server VOKO API(/v1 公开接口、/api/voko 网页与后台接口),连 voko 库 9201
@voko/worker 定时任务与 Webhook 投递(与 server 同目录,独立进程) —
@voko/web 员工端与 /admin 后台,/api → 9201 5201

命令

  • pnpm install;pnpm mysql:up 启动本地 MySQL 并确保 voko 库存在(与 shadiao-2d 共用同一个本地 MySQL 服务也可以,库名不同)。
  • pnpm lint / pnpm test:架构红线与全量测试。CI 即 install → lint → test → schema:check。

文档入口

  • 产品、设计、计划:docs/voko/README.md。
  • 执行启动、数据库、验收或部署任务时,先从运行目标索引进入对应手册。
  • 新增或修改可执行流程时,必须新增或更新运行手册(docs/runbooks/)并登记到索引。只增加脚本或 package.json 命令不算完成。

边界(ESLint 强制)

  • app 之间禁止源码级互相导入;跨应用只走 HTTP/API、contracts 或 packages 公开能力。
  • 包一律从 @drama/<name> 公开入口导入(各包 API 从 src/index.js 汇出),禁止深挖别包 src/*。
  • 数据库和外部服务连接只在 composition root 创建;包内禁止顶层创建连接。运行参数在实际使用点读取 process.env,禁止为转发配置增加通用配置对象和无业务逻辑的参数链路。
  • 包职责:contracts 接口 schema 与快照;auth/account/billing/payment 业务域;core/render-pixi/player-vue 播放链路;ui 基础组件与主题 token;config 共享预设。

数据库

  • 本产品使用独立库 voko,不连接 shadiao-2d 的 idearun / idearun_visual_game。
  • 结构事实源:packages/*/src/db/tables/*.cjs(当前完整结构)+ apps/voko-server/src/db/migrations/*.js(版本间变更)。迁移历史表 voko_schema_migrations。服务启动不执行 DDL。
  • 迁移只在合入主干后,才允许在 stage / 生产等共享库执行;开发只连本地库。
  • 时间列一律 DATETIME(3),值为 UTC;写入传 Date 对象,API 返回 ISO 8601 字符串。
  • 全链路 snake_case:库列、函数参数、返回对象、contracts、请求/响应体、前端状态同名透传,不做任何大小写转换或多名兜底。

环境变量

  • 连接与基础设施配置由各 app 的 src/env.js 统一解析;业务运行参数由所属模块直接读取。
  • 真实密钥放各 app gitignored 的 .env,不提交;也不提交本地数据库文件和 node_modules。

代码

  • 两空格缩进、单引号、无分号;类型说明用 JSDoc,不写 TypeScript 语法。
  • 工艺规范唯一权威源 ~/.codex/code-standards.md;写代码、改代码、写脚本、做评审前必须读取并遵守该文件。评审对照它逐条举反例,lint 干净不作质量证据。
  • 服务方法把 ctx 作为显式第一参数一路传到 service/repo(packages/observability/CONVENTION.md),不用 AsyncLocalStorage 或全局单例。

代码生成硬规则

心智模型(最高优先级,先读这个)

系统分为入口和内部。入口有且只有四类:

  1. HTTP controller 的请求入参
  2. 消息/任务消费的 payload
  3. 第三方 API / 外部服务的响应
  4. DB row 读取后转成业务数据的那一次转换

数据在入口处被一次性校验并构造成正确形状,校验失败立即 throw。 过了入口的数据无条件信任:内部代码不判空、不兜底、不猜字段、不怀疑。 内部代码觉得数据可疑 = 入口漏了或构造函数没把不变量执行到位, 去修入口和构造函数,禁止在现场打补丁。

事实源

  • 写任何代码前,先定位:数据生产者、schema/migration、现有调用方、相关测试。 以生产者和 schema 为唯一事实源。
  • 字段结构不确定时,读代码、读 migration、查真实数据。查完仍不确定就停下来问。
  • 禁止一切猜测式读取:a || b || c、x?.foo ?? x?.bar、 typeof x.foo === 'string' 探测、Array.isArray 兜底分支,全部不许。

数据形状

  • 每类核心业务数据(订单、会员段、积分流水等)有唯一构造点, 普通函数即可(如 orderFromRow):非法输入当场 throw, 带数据 id 和具体哪个字段的问题。
  • 状态相关的必有字段由构造点按 status 保证(paid 必有 paidAt,缺失即 throw), 下游读取零判空——内部代码出现判空,视为构造点没做到位,回去修构造点。
  • 核心格式使用 JSDoc / d.ts 说明清楚。

状态消费

  • 消费 status 的 switch 必须穷举所有已知状态,且必须写 default 分支, default 只许 throw new Error("Unhandled status: <值>, id: <数据id>")。 禁止 default 里给默认行为或静默跳过。
  • 同一个 status 的 switch 散落超过两三处时,把行为收进该数据的变换函数 或 reducer,不许继续复制分支。

数据库约束

  • 唯一性、非空、状态与字段的组合合法性,一律下沉为 DB 约束: NOT NULL / UNIQUE / CHECK(如 CHECK (status != 'refunded' OR refunded_at IS NOT NULL))。
  • 禁止用"先 SELECT 判断再 INSERT/UPDATE"在应用层模拟约束——有并发窗口,不可靠。

错误处理

  • 区分两类失败:
    • 预期失败(用户输错、余额不足、并发冲突):用显式返回值或明确的业务错误建模, 调用方必须处理;
    • 程序 bug(不变量被违反、不可能的状态):带完整上下文 throw, 交给全局 error handler 记日志、报警、返回 500。
  • 中间层禁止 try-catch。禁止 catch 后吞掉、catch 后返回默认值、 catch 后包一层泛化错误重抛。
  • try-catch 只允许出现在三处:全局 error handler、入口校验处、 对外部 IO(第三方 API、文件、网络)的最小包裹。
  • 原则:宁可当场 500,不许静默写脏数据。涉及金额、会员权益的路径尤其如此。

兼容与迁移

  • 新代码禁止同时支持新旧两套数据形状。禁止:多字段兜底、大小写兜底、 旧字段别名、猜测式解析、默认值吞错、空数组/空对象兜底、遗留分支保留。
  • 发现存量数据、线上接口、已发版客户端依赖旧形状时:停止,报告冲突, 给出迁移方案(migration 脚本 + 切换步骤 + 回滚点),等确认后执行。 禁止自行改线上 schema、删在用字段,也禁止用兼容层绕过。

测试与诊断

  • 生产、开发、测试、诊断、验收代码一律禁止 fake / mock / stub / spy、内存替身、 伪造第三方响应、伪造数据库结果、手工插入业务终态,也禁止 broken implementation 或测试专用开关。外部系统只用真实服务或官方 sandbox/test mode;真实依赖不可用就明确 BLOCKED / 未验证,不准用替身补绿。任务触达范围内的既有替身必须删除并改走真实链路。
  • 禁止无用纯单元测试。纯单元测试只有在直接调用现有生产纯算法、零替身、验证明确业务 不变量/数学公式/完整状态全集,且同任务已有真实端到端链路时才允许;字段搬运、配置映射、 默认值、getter/setter、调用次数、mock 交互和代码存在性测试一律禁止。
  • 测试数据必须符合生产 schema 的真实形状,禁止 mock 出宽容的假结构 为兼容代码制造存在理由。
  • 涉及状态机的测试,必须覆盖全部已知 status 值—— 没有编译器做穷尽检查,测试就是穷尽检查。
  • 诊断脚本必须验证具体问题,复用生产 schema 和生产函数; 失败就直接失败,失败信息要能定位到数据,不写通用兼容层。负路径必须把真实非法输入 或真实失败状态送入同一套生产入口,禁止另造错误实现证明脚本会红。

前端

  • 文案走 vue-i18n,新增 key 补齐 en/zh/ja/es/id/pt。
  • 颜色/间距/圆角/阴影用 var(--drama-*) token(packages/ui/src/theme/),不硬编码 hex/rgba。
  • 优先复用 @drama/ui 的 Button/Card/Modal/ToastHost;页面只做装配,不写鉴权协议、SQL、厂商 SDK。
  • 设计参考 docs/design/IMPLEMENTATION-STANDARD.md、docs/design/screen-to-module-map.md。

测试

  • Vitest 是自动化测试套件的唯一 runner,用例放各 workspace 的 test/*.test.js;真实链路验收脚本放对应 app/package 的 tools/scenarios/,通过明确的 node 或 pnpm 命令运行,不伪装成纯单元测试。
  • 自动化测试禁止 CREATE DATABASE / DROP DATABASE,也禁止随机生成数据库名。真实链路场景只连接本地 voko 库,通过真实业务入口写入生产形状数据并按场景精确清理。
  • 改哪个包先 pnpm --filter <workspace> test;改共享契约、路由守卫、支付、鉴权、播放链路再跑全量 pnpm test + pnpm lint。这些命令只作回归门禁,不能替代真实链路验收。

提交与 PR

  • 提交信息用短 scope 风格(fix(server): ...),写清变更对象和动作。
  • PR 带变更摘要与验证命令结果;UI 改动附截图;contract/schema 改动说明迁移影响。