AGENTS.md
9.37 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 |
(以上 app 在 W1 初始化步骤 3、4 建立。)
命令
pnpm install;pnpm mysql:up启动本地 MySQL 并确保voko库存在(与 shadiao-2d 共用同一个本地 MySQL 服务也可以,库名不同)。pnpm lint/pnpm test:架构红线与全量测试。CI 即 install → lint → test(schema:check 在建立 voko-server 后加入)。
文档入口
- 产品、设计、计划:
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 或全局单例。
代码生成硬规则
心智模型(最高优先级,先读这个)
系统分为入口和内部。入口有且只有四类:
- HTTP controller 的请求入参
- 消息/任务消费的 payload
- 第三方 API / 外部服务的响应
- 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 改动说明迁移影响。