# foodie_server Codex 项目规范

本文件是 Codex 在仓库根目录直接加载的项目指令。遵循用户最新要求，并按以下规则进行分析、修改和验证。`CLAUDE.md` 保留更完整的背景说明；本文件已包含日常开发必须遵守的关键约束。

## 工作原则

- 动手前确认目标、影响范围和验收方式；存在会实质改变结果的歧义时，先明确说明。
- 只实现用户要求的内容，不增加推测性功能，不为一次性逻辑引入抽象或配置。
- 只修改完成任务必需的代码；不顺手重构、格式化或清理无关代码。
- 匹配现有代码风格。只移除本次修改造成的无用 import、变量或方法。
- 修复缺陷时优先用可复现检查或测试证明问题，再验证修复结果；多步骤任务给出简短、可验证的执行计划。
- 当用户说“只改 X”时，只改 X。简单的格式、显示或单文件修改不要创建任务计划，也不要启动 Agent。

## OMG 支付执行纪律与本次复盘

### 已暴露的问题

- 已确认的需求仍被重复分析、确认和审查，导致实现节奏失控。
- 单个接口被拆成过多小步骤，频繁读取规格、检查状态和执行零散命令，没有一次性收口。
- 用户已要求全部 OMG 功能完成后统一测试，但实现过程中仍沿用逐测试推进方式；在不运行测试的情况下既没有获得反馈，又浪费了时间。
- 工具命令失败后曾重新展开分析，而不是直接修正命令并继续。
- 曾把中间文件修改描述为进展，但源码仍处于接口与实现不一致、不可交付的状态。
- PowerShell 命令换行使用错误，造成暂存失败；执行前没有按当前 Shell 语法一次写对。

### 后续强制执行规则

- 用户已经确认的 OMG 需求不得重复询问、重新设计或反复论证；只有发现会实质改变结果且无法从仓库确认的新歧义时才能暂停说明。
- 每个 OMG 接口按一个批次完成生产代码、测试源码、spec-kit 文档和 SQL；不要把同一接口拆成多个等待用户确认或重复审计的小批次。
- 开始实现前只读取完成当前接口必需的文件；实现过程中不反复运行 `git status`、`rg`、`git diff` 或同类审计命令。
- 每个接口完成后只进行一次统一静态检查、一次暂存范围检查和一次提交；检查发现问题时直接修复，再做一次最终复核，不重新展开方案设计。
- 在用户明确要求的本轮 OMG 重做期间，不运行 Maven、编译或测试；等创建、回调、查询、补单、退款等全部计划功能调整完成后，再统一运行 JDK 21 定向测试、模块构建和完整回归。
- 测试源码可以随接口实现一并编写，但不得借“测试先行”之名增加逐文件、逐方法的工具往返；延后运行测试时必须明确说明测试仅已编写、尚未验证。
- 工具命令失败时优先直接纠正命令；不得因命令语法、路径或暂存错误重新分析已经确认的业务方案。
- PowerShell 多路径命令使用数组传参或其他合法 PowerShell 语法，不使用 Bash 风格反斜杠续行。
- 进度只使用四种状态：`未开始`、`实现中`、`已提交`、`已验证`。未完成提交前统一报告为“实现中”，不得把局部修改、测试源码已写或静态检查部分完成描述成接口已完成。
- `已提交` 只表示代码已形成独立提交；只有实际运行约定的测试和构建并检查结果后，才能报告为 `已验证`。
- 如果违反上述任一规则，立即停止当前低效操作，说明违反的具体条款，纠正执行方式后继续；不得只口头承认后仍沿用原方式。

### 可审计交付要求

- 最终交付必须给出提交 SHA、实际执行的检查以及明确未执行的验证项。
- 提交前核对暂存文件清单，只包含当前 OMG 接口及其规格、测试和 SQL；不得混入工作区原有脏文件。
- 不依赖“我会遵守”的口头承诺；以后以 `AGENTS.md` 本节、命令记录、暂存清单和提交结果作为执行是否合规的依据。

## 技术栈和相关项目

- 后端：Java、Spring Boot、MyBatis XML Mapper、MySQL。
- 前端：Vue.js、Element UI。
- 支持语言：越南语 `vi`、简体中文 `zh`、繁体中文 `tw`、英文 `en`。
- 平台管理前端：`E:\QtwCode\foodie\foodie-admin-vue`。
- 商家管理前端：`E:\QtwCode\foodie\foodie-store`。
- 开发环境以 Windows 为准；编辑时保留文件原有编码和 CRLF/LF 换行风格，不因小改动重写整个文件。

## 订单和支付代码边界

以下代码仍在仓库中但已经废弃，不要参考其业务逻辑，也不要在其上做增量修改：

- `ZaloPayController.java`：整体废弃，ZaloPay 已下线。
- `NewebpayPayController.java` 与 `PosStoreNewebpayController.java`：蓝新支付已废弃（2026-09-02 确认，从未在生产启用），代码仅保留备查，不要参考其业务逻辑，也不要在其上做增量修改或启用。
- `PayController.java`：VNPay 回调和多数方法废弃。仅 `sendAcceptRiderPush(...)` 仍被 `PosOrderController` 的货到付款路径引用；等接入新支付时再迁移。
- `TestTask.java`：其中定时任务全部废弃，包括退款处理、抽成返还、自动开店和超时退款。
- `OrderAppealController.java`：取消/申诉逻辑已失效，仅剩 `parseLocale` 可用。

当前有效的订单操作入口：

- `PosOrderShOprateController`：商家出餐和取消。
- `PosOrderQsOprateController`：骑手接单、取餐、送达，使用 `deliveryStatus` 1/2/3。
- `UserOrderController`：用户下单和取消。
- `PosOrderController`：仅 `/addorder`、`/setorderuzt` 和 list 查询仍在使用，主要订单状态流转已经迁出。

推送以当前真实通道为准：`PayPush` 没有 Android FCM；本项目仅有 iOS uni 云函数 `msduser`、`msdrider`、`msdstore`，以及 `PushEvent -> push_message` 入库。`cidType` 当前没有实际区分作用。相关状态见 `specs/012-im-user-integration/code-status.md`。

## Spring Controller 规范

- 需要登录 token 的接口直接声明 `@RequestHeader String token`。不要为了读取 token 注入或使用 `HttpServletRequest`。
- POST 业务参数使用明确 DTO，并显式标注 `@RequestBody`；禁止未标注注解的隐式绑定。
- GET 查询参数逐个显式标注 `@RequestParam`；token 使用 `@RequestHeader`，路径参数使用 `@PathVariable`。
- 禁止用任何 `Map` 作为 Controller 请求方法入参。
- 第三方 `form-urlencoded` 回调也用 DTO（如 `@ModelAttribute`）接收。签名 SDK 必须用 Map 时，只能在 Controller 边界之后由 DTO 转换，不能把 Map 暴露为接口入参。
- DTO 仅承载请求数据，不在 DTO 字段上使用 Bean Validation 注解，也不依赖 `@Valid` / `@Validated` 返回业务校验错误。
- 业务校验放在 Controller 或 Service，并通过 `MessageUtils.message(...)` 等项目国际化机制返回错误，禁止硬编码单一语言错误信息。

## 后端构建和模块边界

- Maven 编译目标为 JDK 21。本机使用 `C:\Users\qmj\.jdks\graalvm-jdk-21.0.7`；只在当前命令环境临时设置 `JAVA_HOME` 和 `PATH`，不要修改用户全局 Java 配置。
- 模块依赖方向必须保持 `ruoyi-admin -> ruoyi-system`。禁止 `ruoyi-system` 反向依赖或导入 `com.ruoyi.app.*`。
- 同时依赖外部 HTTP（httpclient4 + fastjson2）和应用层 Service 的集成代码放在 `ruoyi-admin`，不要放入 `ruoyi-system`。
- Java 块注释或 Javadoc 正文中禁止出现额外的 `*/`。描述 `ATM_*`、`CVS_*` 等通配值时，写成“ATM 系列”“CVS 系列”，避免提前关闭注释。

## 数据库和全栈字段变更

- 不直接执行任何数据库结构或数据迁移操作。所有 `ALTER TABLE`、数据迁移等 SQL 写入 `updatesql/sql.md`，标注日期和用途，由开发者统一手动执行。
- 添加新字段时按顺序检查并更新：Java Entity、MyBatis XML 的 resultMap 和相关 select/insert/update、DTO、Service、Controller、Vue 组件、四个 i18n 文件、SQL 迁移脚本。

## 前端和 i18n

- 平台端和商家端所有新增用户可见文本都必须使用 `$t()`，不得硬编码中文。
- 商家端语言文件位于 `src/lang/zh.js`、`tw.js`、`en.js`、`vi.js`；新增 key 必须四个文件同时添加，名称完全一致。
- i18n key 使用有意义的英文驼峰命名，禁止 `text1`、`text2` 等无意义编号。
- key 必须放进调用路径对应的嵌套对象。例如 `$t('foots.AddCategoryFirst')` 对应的 key 必须位于 `foots` 对象内部。
- 编辑 `foodie-store` 和 `foodie-admin-vue` 时保留 CRLF。先确认原始换行风格，避免字符串替换失败或造成整文件换行变化。

## 商家和订单查询规则

- `InfoUser.userType = 1`（普通商家）：使用 `PosOrder.shId = userId`。
- `InfoUser.userType = 3`（夜市商家）：使用 `PosOrder.shId = userId`。
- 其他摊位商家：先读取 `InfoUser.storeId`，再使用 `PosOrder.mdId = InfoUser.storeId`。
- 字段含义：`InfoUser.userType` 为 0 用户、1 商家、2 骑手、3 夜市；`PosOrder.shId` 是商家 ID，`PosOrder.mdId` 是门店 ID。

## spec-kit 和规格文件

- 用户提到 `spec kit`、`spec-kit` 或 `speckit` 时，指 GitHub `github/spec-kit`；项目配置在 `.specify/`，规格在 `specs/`。
- 新功能默认遵循 `specify -> plan -> tasks -> implement`。
- 已有功能追加或变更时，更新现有 `spec.md`、`plan.md`、`tasks.md` 并顺延任务；除非用户明确要求，不重新启动完整流程。
- OMG 支付相关工作开始前阅读 `specs/016-omg-payment/plan.md`。

## 特定业务约束

- 餐桌码必须覆盖普通商家，不能只按夜市摊主或夜市管理员设计权限；普通商家也能查看自己门店的餐桌码及关联订单。
- 涉及支付、退款、配送和订单状态时，以当前有效入口和最新规格为准；不要把仅修改数据库状态等同于真实支付、退款或配送流程。

## 验证要求

- 根据改动风险运行最小且充分的检查；优先运行受影响模块的编译、单元测试或定向测试。
- 交付前检查 `git diff`，确认没有无关文件、整文件格式化、编码或换行变化。
- 如果受环境或外部服务限制无法完成验证，明确说明未验证项和原因，不把推测描述为已验证结果。
