# 数据模型：商家门店分管账号

## `info_user` 扩展

| 字段 | 类型 | 可空 | 默认值 | 说明 |
|---|---|---:|---|---|
| `merchant_owner_id` | `BIGINT` | 是 | `NULL` | 类型 5 分管账号所属的商家主账号 ID；其他类型为空 |
| `subaccount_status` | `CHAR(1)` | 是 | `NULL` | 主账号控制状态：`0=启用`、`1=停用`；仅类型 5 使用 |
| `last_login_at` | `DATETIME` | 是 | `NULL` | 商家端最近一次成功登录时间 |

新增索引：

```sql
KEY idx_info_user_merchant_owner (merchant_owner_id, user_type, del_flag)
```

### 类型与状态约束

| 账号 | `user_type` | `merchant_owner_id` | `status` | `subaccount_status` |
|---|---:|---|---|---|
| 普通商家主账号 | `1` | `NULL` | 平台控制 | `NULL` |
| 夜市账号 | `3` | `NULL` | 平台控制 | `NULL` |
| 摊位商家 | `4` | 现有规则 | 平台控制 | `NULL` |
| 商家分管账号 | `5` | 必须为类型 1 主账号 | 平台控制 | 主账号控制 |

类型 5 不创建独立商家钱包，不参与商家审核，不写入商户资质、收款配置或 `store_id` 单店字段。

## `merchant_subaccount_store`

| 字段 | 类型 | 可空 | 说明 |
|---|---|---:|---|
| `id` | `BIGINT AUTO_INCREMENT` | 否 | 主键 |
| `subaccount_user_id` | `BIGINT` | 否 | `info_user.user_id`，必须是类型 5 |
| `store_id` | `BIGINT` | 否 | `pos_store.id` |
| `create_time` | `DATETIME` | 否 | 创建时间 |
| `update_time` | `DATETIME` | 否 | 更新时间 |

索引与唯一性：

```sql
PRIMARY KEY (id)
UNIQUE KEY uk_subaccount_store (subaccount_user_id, store_id)
KEY idx_subaccount_store_store (store_id, subaccount_user_id)
```

不使用软删除。取消授权时删除关联行；权限查询始终同时验证分管账号状态、所属主账号状态和店铺当前所有者。

## 聚合视图

### `MerchantSubaccountView`

- `userId`
- `name`
- `phone`
- `merchantOwnerId`
- `ownerEnabled`：主账号是否启用该分管账号
- `platformEnabled`：平台是否允许该分管账号
- `online`：是否存在有效商家 App 或 PC 会话
- `lastLoginAt`
- `stores[]`：`storeId`、`storeName`

### 可用性判定

```text
subaccount.del_flag = 0
AND subaccount.user_type = 5
AND subaccount.status = 0
AND subaccount.subaccount_status = 0
AND owner.user_type = 1
AND owner.del_flag = 0
AND owner.status = 0
```

通知接收还必须满足目标店铺授权有效、App 会话有效且 CID 非空。

## 数据生命周期

1. 主账号创建分管账号：插入 `info_user` 类型 5，再批量插入授权关系，单事务提交。
2. 调整店铺：验证全部店铺归属后，以事务替换该账号授权集合。
3. 主账号停用：只更新 `subaccount_status=1` 并撤销该账号商家会话。
4. 平台停用：只更新 `status=1` 并撤销该账号商家会话。
5. 删除店铺：同步删除该店铺授权关系；即使清理失败，权限服务也因店铺所有权或有效性不符而拒绝访问。
6. 主商家停用：不批量改写子账号字段；可用性判定通过主账号状态统一阻断，恢复主商家后仍保留原分配关系。
