CRMEB/backend/modules/README.md
2026-09-23 15:15:02 +08:00

117 lines
6.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# modules/ — 业务扩展层
## 层定位
`modules/` 是 CRMEB v8.0 架构的**业务扩展层**,位于 `app/` 之上,**可以调用 `app/` 和 `crmeb/` 的所有服务**。
本层存放所有可插拔的业务模块,按业务域分类组织。
## 目录结构
```
modules/
├── trade/ 交易域 —— 订单管线扩展(全部实现 TradeModeHandlerInterface)
│ ├── combination/ 拼团 activity_combination
│ ├── seckill/ 秒杀 activity_seckill
│ ├── bargain/ 砍价 activity_bargain
│ ├── integral/ 积分商城 activity_integral
├── product/ 商品域 —— 产品类型(全部实现 ProductTypeHandlerInterface)
│ ├── normal/ 实物商品 product_normal
│ ├── virtual/ 虚拟商品 product_virtual
│ └── cardkey/ 卡密商品 product_cardkey
├── marketing/ 运营域 —— 权益与奖励(纯事件观察者)
│ ├── signin/ 签到 user_signin
│ ├── lottery/ 抽奖 activity_lottery
│ ├── newuser/ 新人专区 marketing_newuser
│ ├── channel_code/ 渠道码 user_channel_code
│ └── recharge/ 充值 user_recharge(已与订单中台解耦,独立充值单)
├── agent/ 分销代理模块
└── channel/ 用户/端渠道扩展(APP/H5/小程序/公众号)
```
> 第三方驱动(支付/短信/上传等)不在 `modules/` 下,统一位于根目录 `driver/{category}/{name}/`,
> 由各 `app/services/driver/*/*DriverServices` 扫描发现,安装时按 plugin.json 的
> `path`(`driver/{category}/{name}`)落位。
`trade/`(怎么卖)× `product/`(卖什么)是两个**正交维度**,可自由组合
(同一商品既能拼团卖也能秒杀卖),各自有独立注册表:
`crmeb/trade/mode/TradeModeRegistry` 与 `crmeb/trade/product/ProductTypeRegistry`。
## 模块内部目录规范
每个模块(`{域}/{type}/`)内部的子目录命名与职责**全 modules 统一**,新增模块必须按下表搭建:
### 根文件(必备)
| 文件 | 职责 |
|------|------|
| `App.php` | 模块注册入口(`register()` 注册处理器,`boot()` 加载 `event.php`) |
| `Installer.php` | 安装/卸载/启用/禁用(建表/菜单/种子,幂等) |
| `plugin.json` | 插件元数据(`key`/`name`/`type`/`path`) |
| `event.php` | 事件监听器注册表 |
| `Handler.php` | 产品类型处理器(**仅 `product/` 域模块**,实现 `ProductTypeHandlerInterface`) |
### 子目录(按需,命名固定)
| 目录 | 命名 | 职责 | 备注 |
|------|------|------|------|
| `controller/` | — | 控制器,固定双端结构:`admin/` + `user/v1/` | |
| `route/` | — | 路由文件:`admin.php` / `user.php`(`manage.php` 可选),自动扫描加载 | |
| `service/` | — | 服务层(类名 `XxxServices`) | |
| `dao/` | — | 数据访问层(类名 `XxxDao`) | 纯事件观察者模块(如 `marketing/newuser`)可缺省 |
| `model/` | — | 模型层 | 同上可缺省 |
| `validate/` | — | 验证器 | 按需 |
| `listener/` | — | 事件监听器(类名 `XxxListener`,与 `event.php` 对应) | |
| `jobs/` | **复数** | 队列任务(继承 `BaseJobs`) | ⚠️ 单数 `job/` 已废弃(2026-08 统一迁移),禁止新建 |
| `handler/` | — | 域内处理器子目录:`trade/` 域放 `{Mode}ActivityHandler`;`product/` 域放 `{Type}OrderAdapter` + `{Type}AfterSaleHandler` | 根 `Handler.php` 为产品类型主处理器(仅 `product/` 域有) |
| `crontab/` | — | 定时任务(如拼团到期、分销员解绑) | 按需 |
### 特殊目录(已有模块使用,新模块按需参照)
| 目录 | 使用方 | 职责 |
|------|--------|------|
| `sdk/` + `notify/` | `channel/wechat_mp`、`channel/wechat_mini` | 第三方 SDK 封装 + 回调处理 |
| `pipeline/` | `product/cardkey`、`product/virtual` | 履约管线 |
| `frontend/dist` | `product/virtual` | 模块内前端构建产物 |
## 边界规则(新模块放哪?)
**一句话:改变一笔订单如何成交的 → `trade/`;决定卖什么形态商品的 → `product/`;
只发放权益、奖励行为、不改变成交的 → `marketing/`。**
"牵扯订单"要拆成三种性质再判断:
| 性质 | 含义 | 判别方法 | 归属 |
|------|------|---------|------|
| **改变成交** | 实现交易契约,订单管线主动调用它 | 实现 `TradeModeHandlerInterface`(定价/下单校验/支付前后/退款/完成等钩子) | `trade/` |
| **决定商品形态** | 决定 SKU 模型、履约方式(发货/发卡/核销)、售后规则 | 实现 `ProductTypeHandlerInterface` + `OrderTypeAdapter` | `product/` |
| **观察订单** | 监听订单事件发权益,移除后订单流程完全不受影响 | 只在 `event.php` 里 listen(如 `OrderPayLottery`) | `marketing/` |
| **自建迷你流程** | 奖品/权益发放挂在活动记录上,不创建订单 | 有自己的发放记录表,不写 `eb_order_center` | `marketing/` |
> 会员订单不在 `trade/`:已独立为 `app/` 层 `eb_member_order` 体系。
## 扩展点一览
| 扩展点 | 目录 | 解决什么 |
|--------|------|---------|
| 交易域 | `trade/` | 怎么卖:交易模式(定价策略、成团/限量规则、订单生命周期钩子) |
| 商品域 | `product/` | 卖什么:产品类型(履约形态、库存方式、售后规则) |
| 运营域 | `marketing/` | 送什么:权益与奖励(签到/抽奖/新人礼/渠道码) |
| 分销代理 | `agent/` | 分销员管理、分销等级、事业部、佣金结算 |
| 用户渠道 | `channel/` | 用户从哪来、如何识别登录、推送消息 |
## 依赖铁律
- `modules/` 内各模块之间**不可互相引用**
- 跨模块通信必须走 `crmeb/` 核心层契约或通过事件机制(`event()`)
- 每个目录都是独立插件包,包含 `plugin.json` + `Installer.php` + `App.php` + 标准 MVC 目录结构
## 自动发现机制
- 路由文件放入 `route/` 目录(`admin.php`/`user.php`/`manage.php`)后自动扫描加载
- 菜单生命周期由 `BaseModuleInstaller` 统一管理
- `plugin.json` 中的 `type` 字段决定插件分类(`mode`→trade、`product`/`product_type`→product、`marketing`→marketing)
> 历史参考:2026-08 由 `trade/mode/*` 拍平为 `trade/*`、`trade/product/*` 提升为 `product/*`,
> 模块 key 不变,plugin.json `path` 已同步。