# 商家门店分管账号任务清单

## 执行状态

- [x] T001 数据模型与账号—店铺关联（提交 `5b910ad`）
- [x] T002 集中式商家门店访问服务（提交 `e63cb3a`）
- [x] T003 商家端分管账号管理接口（提交 `7862f9b`）
- [x] T004 平台分管账号视图与商家列表隔离（提交 `7862f9b`）
- [x] T005 商家登录、退出、双重状态和响应脱敏（提交 `7862f9b`、`5ae3c22`）
- [x] T006 店铺、商品、分类和规格权限收口（提交 `dc595b9`）
- [x] T007 订单、发票、取消和退款权限收口（提交 `4403def`）
- [x] T008 按真实门店路由商家通知（提交 `33005c6`）
- [x] T009 商家端分管账号与角色界面（`foodie-store` 提交 `4d4297d`）
- [x] T010 平台端主商家下属分管账号界面（`foodie-admin-vue` 提交 `27b3d6a`）
- [x] T011 自动化测试、构建和规格回填
- [ ] T011 数据库迁移后的联调、真机推送和完整手工验收（需人工环境）

> **执行要求：** 按任务顺序实施；每个后端任务遵循测试先行，先确认定向测试失败，再写最小实现并复测。提交标题和正文使用中文。

**输入**：[spec.md](spec.md)、[plan.md](plan.md)、[research.md](research.md)、[data-model.md](data-model.md)、[API 契约](contracts/api.md)

## 全局约束

- JDK 使用 `C:\Users\qmj\.jdks\graalvm-jdk-21.0.7`。
- 模块依赖保持 `ruoyi-admin -> ruoyi-system`。
- Controller 请求使用明确 DTO、`@RequestBody`、`@RequestHeader` 和显式查询参数，不使用 `Map`。
- 数据库变更只写入 `updatesql/sql.md`，不直接执行。
- 两个 Vue 仓库新增文案同步维护简中、繁中、英文、越南语并保持 CRLF。
- 保留工作区已有订单状态和推送调整；暂存前逐文件核对，禁止混入 `.claude/homunculus/observations.jsonl`。
- 密码、Token、CID 和支付资料不得出现在日志、错误响应或测试快照中。

---

## Phase 1：数据模型与授权基础

### T001 [US1] 建立分管账号字段和账号—店铺关联模型

**文件：**

- 修改：`ruoyi-system/src/main/java/com/ruoyi/system/domain/InfoUser.java`
- 创建：`ruoyi-system/src/main/java/com/ruoyi/system/domain/constants/MerchantAccountConstants.java`
- 修改：`ruoyi-system/src/main/resources/mapper/infouser/InfoUserMapper.xml`
- 创建：`ruoyi-system/src/main/java/com/ruoyi/system/domain/MerchantSubaccountStore.java`
- 创建：`ruoyi-system/src/main/java/com/ruoyi/system/mapper/MerchantSubaccountStoreMapper.java`
- 创建：`ruoyi-system/src/main/resources/mapper/infouser/MerchantSubaccountStoreMapper.xml`
- 创建：`ruoyi-system/src/main/java/com/ruoyi/system/service/IMerchantSubaccountStoreService.java`
- 创建：`ruoyi-system/src/main/java/com/ruoyi/system/service/impl/MerchantSubaccountStoreServiceImpl.java`
- 创建：`ruoyi-system/src/test/java/com/ruoyi/system/mapper/MerchantSubaccountStoreMapperXmlTest.java`
- 修改：`updatesql/sql.md`

**产出接口：**

```java
public static final String MerchantAccountConstants.SUBACCOUNT_USER_TYPE = "5";

Long InfoUser.getMerchantOwnerId();
String InfoUser.getSubaccountStatus();
Date InfoUser.getLastLoginAt();

List<Long> MerchantSubaccountStoreMapper.selectStoreIdsBySubaccountUserId(Long subaccountUserId);
List<InfoUser> MerchantSubaccountStoreMapper.selectEligibleSubaccountsByStoreId(Long storeId);
int MerchantSubaccountStoreMapper.deleteBySubaccountUserId(Long subaccountUserId);
int MerchantSubaccountStoreMapper.insertBatch(List<MerchantSubaccountStore> relations);
```

- [ ] 写 XML 结构测试，断言 `merchant_owner_id`、`subaccount_status`、`last_login_at` 映射存在，并断言关联表查询使用参数绑定和唯一字段。
- [ ] 运行 `mvn -pl ruoyi-system -Dtest=MerchantSubaccountStoreMapperXmlTest test`，确认因实体、Mapper 或 XML 尚不存在而失败。
- [ ] 为 `InfoUser` 增加三个字段、访问器和 `toString()` 映射；在 `MerchantAccountConstants` 定义类型 1/5 和双重状态常量，禁止在多个 Controller 重复魔法字符串。
- [ ] 实现关联实体、Mapper XML 和 Service；批量插入为空集合时直接返回，不生成非法 SQL。
- [ ] 在 `updatesql/sql.md` 追加 2026-08-28 迁移：三个 `info_user` 字段、所属主账号索引、关联表和两个索引，不执行 SQL。
- [ ] 复跑定向测试并执行 `git diff --check -- ruoyi-system updatesql/sql.md`。
- [ ] 暂存本任务文件并提交：`git commit -m "建立商家分管账号数据模型"`。

### T002 [US2][US4] 实现集中式商家门店访问服务

**文件：**

- 创建：`ruoyi-system/src/main/java/com/ruoyi/system/service/MerchantStoreAccessService.java`
- 创建：`ruoyi-system/src/test/java/com/ruoyi/system/service/MerchantStoreAccessServiceTest.java`
- 按需修改：`ruoyi-system/src/main/java/com/ruoyi/system/mapper/InfoUserMapper.java`
- 按需修改：`ruoyi-system/src/main/java/com/ruoyi/system/mapper/PosStoreMapper.java`

**产出接口：**

```java
public final class MerchantAccessContext {
    Long loginUserId();
    Long ownerUserId();
    boolean owner();
    Set<Long> storeIds();
}

MerchantAccessContext resolve(Long loginUserId);
void requireOwner(Long loginUserId);
Set<Long> getAccessibleStoreIds(Long loginUserId);
void requireStoreAccess(Long loginUserId, Long storeId);
PosOrder requireOrderAccess(Long loginUserId, Long orderId);
PosFood requireFoodAccess(Long loginUserId, Long foodId);
```

- [ ] 写单元测试覆盖：类型 1 主账号获得全部自有店铺；类型 5 只获得授权店铺；类型 5 双重状态任一停用、所属主账号停用、跨商家关系、门店所有者变化均拒绝。
- [ ] 增加订单和商品测试：请求参数中的 `mdId` 与实体真实归属不一致时，以数据库实体的 `mdId` 为准拒绝越权。
- [ ] 运行 `mvn -pl ruoyi-system -Dtest=MerchantStoreAccessServiceTest test`，确认服务尚不存在而失败。
- [ ] 实现服务并使用 `ServiceException` 返回国际化键；每次调用重新读取当前账号和授权，不把 `storeIds` 缓存进 Token。
- [ ] 复跑测试，确认授权取消后无需重新登录即可生效。
- [ ] 暂存本任务文件并提交：`git commit -m "集中商家门店数据权限校验"`。

---

## Phase 2：账号生命周期、平台隔离与登录

### T003 [US1][US4] 实现商家端分管账号管理接口

**文件：**

- 创建：`ruoyi-admin/src/main/java/com/ruoyi/app/user/MerchantSubaccountController.java`
- 创建：`ruoyi-admin/src/main/java/com/ruoyi/app/user/MerchantSubaccountApplicationService.java`
- 创建：`ruoyi-admin/src/main/java/com/ruoyi/app/user/dto/MerchantSubaccountCreateRequest.java`
- 创建：`ruoyi-admin/src/main/java/com/ruoyi/app/user/dto/MerchantSubaccountUpdateRequest.java`
- 创建：`ruoyi-admin/src/main/java/com/ruoyi/app/user/dto/MerchantSubaccountPasswordRequest.java`
- 创建：`ruoyi-admin/src/main/java/com/ruoyi/app/user/dto/MerchantSubaccountStatusRequest.java`
- 创建：`ruoyi-admin/src/main/java/com/ruoyi/app/user/dto/MerchantSubaccountView.java`
- 创建：`ruoyi-admin/src/test/java/com/ruoyi/app/user/MerchantSubaccountControllerTest.java`
- 修改：四个 `ruoyi-admin/src/main/resources/i18n/messages_*.properties`

**接口：**

```text
GET  /merchant/subaccounts
POST /merchant/subaccounts
PUT  /merchant/subaccounts/{subaccountUserId}
PUT  /merchant/subaccounts/{subaccountUserId}/password
PUT  /merchant/subaccounts/{subaccountUserId}/status
```

- [ ] 写 Controller/Service 测试，覆盖手机号全局重复、空姓名、空密码、空店铺、跨商家店铺、非主账号调用、修改他人分管账号、事务中任一授权失败整体回滚。
- [ ] 写状态测试，断言主账号启停只修改 `subaccountStatus`，不能修改平台 `status`；密码重置和停用必须撤销 App/PC Redis 会话。
- [ ] 运行 `mvn -pl ruoyi-admin -am -Dtest=MerchantSubaccountControllerTest -Dsurefire.failIfNoSpecifiedTests=false test`，确认 RED。
- [ ] 实现 DTO 和接口；手机号规范化后同时写入 `user_name` 与 `phone`，固定 `user_type=5`、`audit_status=1`、`status=0`、`subaccount_status=0`，不创建钱包和商户资质。
- [ ] 账号插入与授权批量写入使用同一事务；更新授权先验证完整店铺集合，再替换关系。
- [ ] 四语种补齐账号重复、无权管理、店铺越权、平台停用等业务错误。
- [ ] 复跑测试并提交：`git commit -m "新增商家分管账号管理接口"`。

### T004 [US5] 实现平台下属账号视图并隔离商家管理

**文件：**

- 创建：`ruoyi-admin/src/main/java/com/ruoyi/app/user/MerchantSubaccountAdminController.java`
- 创建：`ruoyi-admin/src/test/java/com/ruoyi/app/user/MerchantSubaccountAdminControllerTest.java`
- 修改：`ruoyi-admin/src/test/java/com/ruoyi/app/user/InfoUserControllerTest.java`
- 按需修改：`ruoyi-admin/src/main/java/com/ruoyi/app/user/InfoUserController.java`

**接口：**

```text
GET /infouser/merchant-subaccounts?merchantUserId={id}
PUT /infouser/merchant-subaccounts/{subaccountUserId}/platform-status
```

- [ ] 写平台接口测试：列表只接受类型 1 主账号；只返回其类型 5 子账号；响应不含密码、CID、Token 和商户资质。
- [ ] 写平台状态测试：只修改 `status`，停用撤销会话；平台恢复不能覆盖 `subaccountStatus=1`。
- [ ] 扩展平台商家列表/导出服务测试，插入或模拟类型 5 后，`userType=1` 结果和总数不包含分管账号；平台通用新增/编辑不能把账号类型写成 5。
- [ ] 运行两个定向测试类确认 RED，再实现 `@PreAuthorize` 列表/编辑权限和类型保护。
- [ ] 复跑测试并提交：`git commit -m "隔离平台商家与分管账号管理"`。

### T005 [US1][US4][US5] 扩展商家登录、退出和会话失效

**文件：**

- 修改：`ruoyi-admin/src/main/java/com/ruoyi/app/user/InfoUserController.java`
- 修改：`ruoyi-admin/src/test/java/com/ruoyi/app/user/InfoUserControllerTest.java`

**行为：**

```java
// shanglodeing 在签发 token 前必须满足
user.getStatus().equals("0");
// 类型 5 还必须满足 subaccountStatus=0 且 owner.status=0
```

- [ ] 写测试覆盖：类型 5 正常登录；自身平台停用、主账号停用、主账号控制停用分别拒绝；类型 1 被平台停用也拒绝；失败分支不能返回成功响应或 Token。
- [ ] 写成功测试，断言更新 CID 和 `lastLoginAt`，使用商家 App/PC token 前缀；退出只删除当前 JTI 会话。
- [ ] 运行 `InfoUserControllerTest` 确认 RED。
- [ ] 将 `shanglodeing` 的类型集合扩展为 1、3、4、5，并在密码验证成功、Token 签发前调用账号可用性校验；修正当前捕获异常后落入成功响应的分支。
- [ ] 新增 `POST /infouser/user/merchantLogout`，使用 `@RequestHeader String token`，验证并删除 JTI，不记录 token。
- [ ] 复跑测试并提交：`git commit -m "完善商家账号登录与停用校验"`。

---

## Phase 3：店铺、商品、订单与退款权限

### T006 [US2] 收口店铺和商品权限

**文件：**

- 修改：`ruoyi-admin/src/main/java/com/ruoyi/app/mendian/PosStoreController.java`
- 修改：`ruoyi-admin/src/main/java/com/ruoyi/app/mendian/PosFoodController.java`
- 修改：`ruoyi-admin/src/main/java/com/ruoyi/app/mendian/PosFenleiController.java`
- 修改：`ruoyi-admin/src/main/java/com/ruoyi/app/mendian/FoodSpecController.java`
- 修改：`ruoyi-admin/src/test/java/com/ruoyi/app/mendian/PosStoreControllerTest.java`
- 创建：`ruoyi-admin/src/test/java/com/ruoyi/app/mendian/PosFoodControllerAccessTest.java`

**必须保护的有效商家端能力：**

```text
店铺：getmystorelist、storelistlist、getstore、addmendian、delemendian、saveMdBusinessHours、营业状态/资料修改
商品：getidlist、getFoodPageList、setposfood、delefood、changerecommend
分类：getfenlei、addfenlei、delefenlei
规格：foodSpecPageList、saveFoodSpec、deleteFoodSpec、changeOpen、changeSpecValueOpen
```

- [ ] 为主账号和类型 5 分别写列表测试：主账号返回全部自有店铺，分管账号返回所有授权店铺且不需要当前店铺。
- [ ] 写越权测试：分管账号新增/删除店铺被拒；可编辑授权店铺；伪造 `userId`、`mdId`、商品 ID、分类 ID 或规格 ID 不能访问未授权店铺。
- [ ] 运行 `PosStoreControllerTest,PosFoodControllerAccessTest` 确认 RED。
- [ ] 为有效写接口补 `@RequestHeader String token` 和明确 DTO/参数；授权使用目标实体真实门店，忽略请求体中的所有者字段。
- [ ] `addmendian` 调用 `requireOwner` 并由后端写入当前主账号 ID；分管账号前端隐藏入口不能替代该校验。
- [ ] 复跑测试并提交：`git commit -m "限制店铺商品操作到授权门店"`。

### T007 [US2] 收口商家订单操作和退款权限

**文件：**

- 修改：`ruoyi-admin/src/main/java/com/ruoyi/app/order/PosOrderShOprateController.java`
- 修改：`ruoyi-admin/src/main/java/com/ruoyi/app/order/PosOrderController.java`
- 修改：`ruoyi-admin/src/test/java/com/ruoyi/app/order/PosOrderShOprateControllerTest.java`
- 按实际有效退款调用修改对应支付 Controller/Service 的授权入口，不改变支付渠道状态机。

**必须保护的能力：**

```text
orderList、getstoreorderlist、订单详情、商家确认/出餐/取消、现金确认、发票查看/作废、现有退款入口
```

- [ ] 写列表测试：类型 5 按授权 `md_id IN (...)` 查询；同主商家的未授权店铺订单不返回。
- [ ] 写操作测试：订单的 `shId` 属于主账号但 `mdId` 未授权时仍拒绝；授权门店订单继续执行现有骑手先接单、支付成功后开放和状态流转规则。
- [ ] 写退款测试：先通过 `requireOrderAccess`，再进入现有渠道退款校验；越权请求不得创建退款记录或改变订单状态。
- [ ] 运行 `PosOrderShOprateControllerTest` 确认 RED。
- [ ] 用集中权限服务替换仅按当前 `userId=shId` 的判断；主账号使用 owner ID，分管账号使用授权门店集合。
- [ ] 复跑订单定向测试及现有支付退款测试，提交：`git commit -m "限制订单退款操作到授权门店"`。

---

## Phase 4：通知路由

### T008 [US3] 将商家通知路由到在线分管账号

**文件：**

- 创建：`ruoyi-admin/src/main/java/com/ruoyi/app/order/MerchantNotificationRouter.java`
- 创建：`ruoyi-admin/src/test/java/com/ruoyi/app/order/MerchantNotificationRouterTest.java`
- 修改：`ruoyi-admin/src/main/java/com/ruoyi/app/order/UserOrderController.java`
- 修改：`ruoyi-admin/src/main/java/com/ruoyi/app/order/PosOrderQsOprateController.java`
- 修改：`ruoyi-admin/src/main/java/com/ruoyi/app/order/PosOrderController.java`
- 修改：`ruoyi-admin/src/main/java/com/ruoyi/app/order/DeliveryOrderNotificationService.java`
- 修改：`ruoyi-admin/src/test/java/com/ruoyi/app/order/DeliveryOrderNotificationServiceTest.java`

**产出接口：**

```java
void sendStoreNotification(Long storeId, Long ownerUserId,
                           String titleKey, String contentKey,
                           String body, String orderNo);
```

- [ ] 写测试覆盖：两个符合条件分管账号全部收到各自消息；主账号不重复；无人具有 App 会话/CID 时主账号兜底；平台或主账号停用的分管账号排除；相同 CID 外部推送去重。
- [ ] 写失败隔离测试：一个接收者推送抛异常，其他账号仍写消息并尝试推送；门店为空时只向 owner 兜底。
- [ ] 运行 `MerchantNotificationRouterTest,DeliveryOrderNotificationServiceTest` 确认 RED。
- [ ] 实现接收者解析、Redis App 会话检查、逐账号 `PushEvent` 入库和 CID 去重；不要新增 Android FCM。
- [ ] 将支付成功/订单开放、骑手接单、订单取消等当前有效商家推送调用替换为路由服务，并保留现有订单状态调整。
- [ ] 复跑通知和订单生命周期测试，提交：`git commit -m "按门店分管账号路由商家通知"`。

---

## Phase 5：商家端与平台端

### T009 [US1][US2] 增加商家端分管账号管理与角色界面

**文件：**

- 创建：`E:/QtwCode/foodie/foodie-store/src/api/subaccount.js`
- 创建：`E:/QtwCode/foodie/foodie-store/src/views/MerchantSubaccount.vue`
- 修改：`E:/QtwCode/foodie/foodie-store/src/router/index.js`
- 修改：`E:/QtwCode/foodie/foodie-store/src/components/Aside.vue`
- 修改：`E:/QtwCode/foodie/foodie-store/src/components/Header.vue`
- 修改：`E:/QtwCode/foodie/foodie-store/src/views/AcidrollingCapacity.vue`
- 修改：`E:/QtwCode/foodie/foodie-store/src/api/store.js`
- 修改：`E:/QtwCode/foodie/foodie-store/src/api/food.js`
- 修改：四个 `E:/QtwCode/foodie/foodie-store/src/lang/*.js`

- [ ] 新增 API 封装，所有分管账号、店铺和商品写请求设置 `isToken: true`；密码沿用现有 RSA 加密工具后提交。
- [ ] 新增管理页：列表、创建、编辑、多店选择、主账号启停和密码重置；平台停用时展示状态且主账号启用按钮不能宣称已恢复。
- [ ] 仅类型 1 显示“分管账号”菜单；类型 5 显示订单、授权店铺和商品入口，隐藏新增/删除店铺、分管账号、账单、支付配置及其他敏感模块。
- [ ] 店铺列表类型 5 不显示新增/删除按钮，但允许编辑授权店铺；退出登录先调用后端退出接口，再清理本地 token。
- [ ] 在 `zh.js/tw.js/en.js/vi.js` 同一嵌套对象增加语义化英文驼峰 key，不新增 `text1` 类编号。
- [ ] 使用 `git diff --check` 和换行检查确认相关 Vue/JS 仍为 CRLF，运行 `npm run build`。
- [ ] 在 `foodie-store` 仓库提交：`git commit -m "增加商家分管账号管理页面"`。

### T010 [US5] 在平台主商家下呈现分管账号

**文件：**

- 修改：`E:/QtwCode/foodie/foodie-admin-vue/src/views/infouser/user/sjuser.vue`
- 修改：`E:/QtwCode/foodie/foodie-admin-vue/src/api/infouser/user.js`
- 修改：四个 `E:/QtwCode/foodie/foodie-admin-vue/src/api/language/language.*.js`

- [ ] 在商家行增加“分管账号”按钮，打开抽屉或对话框并传当前类型 1 主账号 ID，不新增顶级商家行或商家审核入口。
- [ ] 展示姓名、手机号、双重状态、在线/最近登录、负责店铺和创建时间；不展示密码、CID 或资质字段。
- [ ] 平台只提供强制停用/恢复按钮；不提供新增、密码重置和店铺授权编辑。
- [ ] 四语种补齐文案并保持 CRLF，运行 `npm run build:prod`。
- [ ] 在 `foodie-admin-vue` 仓库提交：`git commit -m "在主商家下展示分管账号"`。

---

## Phase 6：集成验证与交付

### T011 全量验证、规格回填与推送

**文件：**

- 修改：`specs/022-merchant-store-subaccounts/tasks.md`（完成状态）
- 按实际结果修改：`specs/022-merchant-store-subaccounts/quickstart.md`

- [ ] 使用 JDK 21 运行 `quickstart.md` 中全部定向测试，记录测试数和结果。
- [ ] 运行 `mvn -pl ruoyi-admin -am -DskipTests package`，再运行项目约定完整回归；如有失败，区分本功能回归与既有失败并记录证据。
- [ ] 构建 `foodie-store` 和 `foodie-admin-vue`，确认四语言文件解析成功。
- [ ] 执行手工验收：多店授权、越权拒绝、授权即时撤销、双重停用、主商家停用、通知全发、CID 去重、主账号兜底、平台商家数量不变。
- [ ] 检查三个仓库 `git diff --check`、换行、编码和暂存清单；后端不得混入 `.claude/homunculus/observations.jsonl` 或其他原有脏文件。
- [ ] 更新任务勾选和验证结果，后端规格/SQL/源码/测试形成中文提交；分别推送三个仓库当前分支。

## 依赖关系

```text
T001 -> T002 -> T003 -> T004 -> T005
                  |       |
                  +------>T006 -> T007 -> T008
                          |             |
                          +-----------> T009
                                        |
T004 --------------------------------> T010
T001..T010 --------------------------> T011
T005..T007 --------------------------> T012
```

- T001、T002 是所有业务故事的阻塞基础。
- T003 完成后可开发商家端页面；T004 完成后可开发平台页面。
- T006、T007 必须先于通知路由最终接入，确保通知目标与实际门店权限一致。
- T009 和 T010 位于不同仓库，可独立构建，但不得在未完成后端契约前联调。

## 需求覆盖

| 需求 | 任务 |
|---|---|
| FR-001、FR-002、FR-003、FR-004、FR-005、FR-006、FR-007、FR-008 | T001、T003、T005 |
| FR-009、FR-010、FR-011、FR-012、FR-013、FR-014、FR-015、FR-016 | T002、T006、T007、T009 |
| FR-017、FR-018、FR-019、FR-020、FR-021、FR-022、FR-023 | T008 |
| FR-024、FR-025、FR-026、FR-027 | T007、T009、T011 |
| FR-028、FR-029、FR-030、FR-031、FR-032、FR-033、FR-034、FR-035 | T004、T005、T010 |
| SC-001、SC-002、SC-003、SC-004、SC-005、SC-006、SC-007、SC-008、SC-009 | T003～T011 |
| FR-036、FR-037、SC-010 | T012 |

---

## Phase 7：统一商家会话认证

### T012 将商家 Redis 会话校验收口到认证层

**文件：**

- 修改：`ruoyi-system/src/main/java/com/ruoyi/system/utils/Auth.java`
- 修改：`ruoyi-system/src/main/java/com/ruoyi/system/utils/AuthAspect.java`
- 修改：`ruoyi-admin/src/main/java/com/ruoyi/app/user/MerchantTokenSessionService.java`
- 修改：当前调用 `MerchantTokenSessionService.requireUserId` 的商家 Controller
- 新增或修改：认证切面、商家店铺和商家订单定向测试

- [x] 先写认证切面测试，覆盖启用会话校验时有效 JTI 放行、缺失 JTI/Redis Key 拒绝，以及默认 `@Auth` 不增加 Redis 会话要求；运行并确认 RED。
- [x] 为 `@Auth` 增加默认关闭的会话校验选项，由 `AuthAspect` 在 JWT 校验通过后检查 JTI 对应 Redis Key，并使用现有国际化登录失效错误。
- [x] 商家业务入口显式启用会话校验，删除 Controller 对 `MerchantTokenSessionService.requireUserId` 的调用；Controller 只从已验证 Token 获取登录用户 ID 并继续执行目标实体归属校验。
- [x] `MerchantTokenSessionService` 删除身份认证职责，只保留退出当前会话、撤销账号全部 App/PC 会话和在线状态查询。
- [x] 运行认证切面、商家登录、店铺和订单定向测试，并使用 JDK 21 构建 `ruoyi-admin` 及依赖模块。
- [x] 检查 `git diff --check`、暂存文件清单和测试结果，形成独立中文提交并推送当前分支。
