Branch: test-202609v2(按用户要求不单独开分支) | Date: 2026-09-08 | Spec: spec.md
Input: Feature specification from /specs/029-merchant-self-delivery/spec.md
商家在门店信息开启自配送(全天/按星期自定义时段);下单时按快照判定(即时单按下单时刻、预约单按预约送达时间,区间 [开始,结束)),命中的外送单标记 self_delivery=1、不进骑手抢单池;商家接单/出餐后自行配送,可选"开始配送"、必点"确认送达"完成订单;运费全额(不抽成)入账 user_id=sh_id(普通商家=商家、夜市摊位单=夜市主),到付归因同步;夜市由夜市主在夜市主门店行统一配置、对旗下摊位生效;用户端与商家端显示"商家自配送/自配送"标识(四语言)。合并订单/同一配送人多单机制明确排除(另立需求)。
技术方案:pos_store 2 列 + 新表 pos_store_self_delivery_hours(镜像营业时段模式)+ pos_order 1 列快照;新增 SelfDeliveryUtil(时段判定,不复用边界语义不符的 isLegalTime)与 SelfDeliveryService(配置解析/入账);配送操作端点加在 PosOrderShOprateController;结算分支挂 OrderLifecycleService.completeSideEffects;骑手池过滤 + 三操作直调拒绝。详见 research.md、data-model.md、contracts/api.md。
Language/Version: Java 21(Spring Boot + MyBatis-Plus);前端 Vue2 + Element UI(foodie-store)
Primary Dependencies: MyBatis-Plus(新表 BaseMapper)、Redisson(配送操作并发锁)、PayPush/MerchantNotificationRouter(推送)、merchantStoreAccessService(022 门店权限)
Storage: MySQL(DDL 见 data-model.md,写入 updatesql/sql.md 由开发者手动执行)
Testing: JUnit5(SelfDeliveryUtil 边界单测、SelfDeliveryService 判定/入账单测、Controller 契约测试——仓库已有 PosOrderQsOprateControllerTest/PosOrderShOprateControllerTest 先例);接口级冒烟按 quickstart.md
Target Platform: Linux 服务器部署(Windows 开发机,JDK 用 C:\Users\qmj\.jdks\graalvm-jdk-21.0.7 临时设置 JAVA_HOME)
Project Type: web-service(后端)+ 商家端管理前端(外部路径 E:\QtwCode\foodie\foodie-store,CRLF 文件用 Python 脚本编辑)
Performance Goals: 无特殊要求(判定为 O(时段数) 纯内存计算;配置读取随下单批量查表)
Constraints: 模块依赖 admin→system 不可反向;Controller 参数规范(token/DTO/@RequestParam);i18n 后端 5 个 properties + 前端 4 个语言文件;不触碰废弃代码清单
Scale/Scope: 后端 ~8 个文件改动 + 4 个新文件;前端 1 个设置区块 + 订单标识 + i18n;1 张新表 + 3 列
GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.
.specify/memory/constitution.md 为未填写的占位模板,无项目级 gates。以 CLAUDE.md 项目规范替代检查:
| 规范 | 状态 |
|---|---|
| Controller 参数规范(token/DTO/显式 @RequestParam/禁 Map) | ✅ contracts/api.md 全部 DTO 化 |
| 模块边界 admin→system | ✅ 实体+Mapper 在 system,业务服务在 admin(data-model.md) |
| DDL 入 updatesql/sql.md 不直接执行 | ✅ data-model.md 已给出待登记 SQL |
| 前端 i18n 四语言、key 有意义、按对象层级插入 | ✅ contracts §5/§6;CRLF 用 Python 编辑 |
| 废弃代码不触碰 | ✅ research.md「涉及的废弃代码」节 |
Java 注释禁 */、主要注释规范 |
✅ 实现阶段遵守 |
| 餐桌码先例:功能覆盖普通商家 | ✅ 配置/判定/操作均含普通商家路径 |
specs/029-merchant-self-delivery/
├── plan.md # This file
├── research.md # Phase 0 output(现状事实 F1-F16 + 决策 D1-D10)
├── data-model.md # Phase 1 output(DDL + 状态机 + 校验)
├── quickstart.md # Phase 1 output(8 个验证场景)
├── contracts/
│ └── api.md # Phase 1 output(接口契约 + i18n 清单)
└── tasks.md # Phase 2 output (/speckit-tasks - NOT created yet)
foodie_server/
├── ruoyi-system/src/main/java/com/ruoyi/system/
│ ├── domain/
│ │ ├── PosStore.java # +selfDeliveryEnabled/selfDeliveryMode
│ │ ├── PosOrder.java # +selfDelivery
│ │ └── PosStoreSelfDeliveryHours.java # 新实体
│ └── mapper/
│ └── PosStoreSelfDeliveryHoursMapper.java # 新 BaseMapper(无 XML)
├── ruoyi-admin/src/main/java/com/ruoyi/app/
│ ├── utils/SelfDeliveryUtil.java # 新:[start,end) 按星期判定
│ ├── order/
│ │ ├── SelfDeliveryService.java # 新:配置解析(摊位→夜市主门店)/判定/运费入账
│ │ ├── UserOrderController.java # createOrderChild 判定快照
│ │ ├── PosOrderShOprateController.java # 商家端 createOrder 判定;requireRiderAssigned 放行;+selfDeliveryStart/Complete;chuCan 骑手推送跳过
│ │ ├── PosOrderQsOprateController.java # newTask 过滤;三操作直调拒绝
│ │ ├── OrderLifecycleService.java # completeSideEffects 增自配送运费分支
│ │ └── OrderService.java # setSelfDeliveryFreightBilling(type="5")
│ ├── mendian/PosStoreController.java # +get/saveMdSelfDeliveryHours
│ └── order/dto/
│ ├── SelfDeliveryConfigInput.java # 新(含 SelfDeliveryHourInput)
│ └── SelfDeliveryOperateInput.java # 新
├── ruoyi-admin/src/main/resources/i18n/ # 5 个 properties 加 key
├── ruoyi-admin/src/test/java/... # SelfDeliveryUtilTest / SelfDeliveryServiceTest / 契约测试
└── updatesql/sql.md # DDL 登记
foodie-store/(商家端 PC,E:\QtwCode\foodie\foodie-store)
├── src/views/...门店信息页 # 自配送区块(复用营业时段编辑交互)
├── src/views/...订单列表/详情 # "自配送"标签
└── src/lang/{zh,tw,en,vi}.js # selfDelivery.* keys
Structure Decision: 复用现有分层(system 实体 / admin 业务),新表走 MyBatis-Plus BaseMapper 不建 XML;前端仅 foodie-store,foodie-admin-vue 与客户端 uni-app 不在本功能改动范围(research D10、assumptions)。
无 Constitution Check 违规需要辩护。
| Violation | Why Needed | Simpler Alternative Rejected Because |
|---|---|---|
| — | — | — |