# mm_os（超级美眉）框架开发常识

## 一、什么是 mm_os？

| 项目 | 说明 |
|:-----|:------|
| **框架名称** | mm_os（超级美眉） |
| **技术栈** | Node.js + Koa 底层框架 |
| **NPM包** | `mm_os`（当前版本 4.x） |
| **中文名** | 超级美眉（config中 sys.title = "超级美眉"） |
| **用途** | 快速构建网站、小程序、游戏服务端 |
| **核心能力** | 模块化应用、插件系统、挂件系统、事件驱动、模板引擎、多语言、MQTT物联网、RESTful API、前后端分离、任务调度、缓存机制、权限管理 |

## 二、项目目录结构

```
项目根目录/
├── index.js                # 启动入口 → new MM_os(config) → os.run()
├── install.js              # 安装脚本
├── config.json             # 项目配置
├── package.json            # NPM依赖
├── config/                 # 多环境配置
│   ├── local.json          # 本地开发配置
│   ├── development.json    # 开发环境配置
│   ├── test.json           # 测试环境配置
│   ├── production.json     # 生产环境配置
│   ├── tpl.json            # 模板引擎配置
│   └── *.sql               # SQL脚本
├── app/                    # 应用模块目录
│   ├── home/               # 门户应用
│   ├── admin/              # 后台管理
│   ├── cms/                # 内容管理
│   ├── tool/               # 工具应用
│   ├── user/               # 用户管理
│   ├── iot/                # 物联网
│   ├── ai/                 # AI功能
│   ├── wechat/             # 微信
│   └── ...                 # 其他应用
├── com/                    # 公共组件/工具模块
├── static/                 # 静态资源
├── cache/                  # 缓存目录
├── data/                   # 数据目录
├── log/                    # 日志目录
└── doc/                    # 文档目录
```

## 三、App 应用模块结构

每个 App 是独立的功能模块，位于 `app/{模块名}/` 下：

```
app/{模块名}/
├── app.json                # 应用配置（名称/版本/数据库/缓存/排序等）
├── index.js                # 应用主逻辑（含全部生命周期方法）
├── plugin/                 # 插件目录（可选）
├── pendant/                # 挂件目录（可选）
├── event_api/              # 事件API目录（可选，App级事件）
│   ├── client/             # 客户端事件
│   ├── web/                # Web端事件
│   └── manage/             # 管理端事件
└── static/                 # 应用静态资源（可选）
```

**index.js 中的生命周期方法（按触发顺序排列）：**

| 方法名 | 触发时机 | 签名 | 说明 |
|:------|:---------|:-----|:-----|
| `_install` | 首次安装时 | `async _install(option)` | 初始化数据表、创建默认配置 |
| `_init` | 每次启动加载时 | `async _init(option)` | 注册API、初始化模板/挂件/WebSocket/定时任务 |
| `_start` | 应用启动时 | `async _start(option)` | 注册全局钩子（$.hook.addFunc/addAction） |
| `_stop` | 应用暂停时 | `async _stop(option)` | 清理全局钩子 |
| `_update` | 版本更新时 | `async _update(option)` | 执行数据迁移或配置升级 |
| `_destroy` | 销毁时 | `async _destroy(option)` | 释放资源 |
| `_uninstall` | 卸载时 | `async _uninstall(option)` | 清理数据 |
| `_end` | 进程结束时 | `async _end(option)` | 最后的清理 |
| `main` | 手动调用 | `main(param1, param2)` | 主程序入口 |
| `cmd` | 命令行调用 | `cmd(content)` | 指令处理 |
| `help` | 查询帮助时 | `help(item)` | 返回帮助信息 |

> 方法名前带下划线 `_` 的由框架自动触发，不带下划线的需手动调用。

### 生命周期返回值规范

| 返回值 | 含义 |
|:-------|:------|
| `null` 或 `undefined` | ✅ 成功，框架继续后续流程 |
| 非空字符串 | ❌ 错误，框架记录错误并中止当前阶段 |

推荐错误变量使用 `err` 而非 `msg`。

**示例：**
```javascript
module.exports = {
  async _install(option) {
    var db_data = option.db.new('cms_article', 'article_id');
    return null;
  },
  async _init(option) {
    if (!option.db) {
      return '数据库连接未就绪，无法初始化';
    }
    return null;
  }
};
```

### `option` 参数

| 字段 | 类型 | 说明 |
|:-----|:-----|:------|
| `option.db` | object | 框架注入的数据库操作对象 |
| `option.app` | object | 当前 App 配置（来自 app.json） |
| `option.version` | string | 当前/目标版本号 |
| `option.config` | object | 全局配置（来自 config.json） |

**app.json 关键字段：**

| 字段 | 类型 | 必填 | 说明 | 示例值 |
|:----|:----|:----|:-----|:-------|
| `name` | string | ✅ | 应用标识，小写蛇形 | `"sys"`, `"home"` |
| `title` | string | ✅ | 应用中文名 | `"系统"`, `"门户"` |
| `version` | string | ✅ | 版本号 | `"1.0"` |
| `description` | string | | 应用描述 | `"站点系统"` |
| `author` | string | | 作者 | `"qww"` |
| `scope` | string | | 作用域 | `"server"` |
| `main` | string | ✅ | 入口文件路径 | `"./index.js"` |
| `func_name` | string | | 入口函数名 | `"main"` |
| `sort` | number | | 加载顺序 | `10` |
| `state` | number | | 启用：`1`/禁用：`0` | `1` |
| `show` | number | | 菜单显示：`1`/隐藏：`0` | `0` |
| `end` | boolean | | 终止后续模块加载 | `false` |
| `diy_sql` | number | | 独立数据库 | `0` |
| `diy_cache` | number | | 独立缓存 | `0` |
| `sql` | object | | 数据库连接配置 | `{"way":"mysql", ...}` |
| `cache` | object | | 缓存配置 | `{"way":"redis", ...}` |
| `identifier` | string | | 唯一标识符 | `"home"` |
| `lang` | string | | 多语言文件路径 | `"./static/lang/zh.json"` |
| `icon` | string | | 图标URL | `"/sys/img/logo.png"` |
| `game` | object | | 游戏配置 | `{"type":"card_game"}` |

## 四、Plugin 插件系统

插件位于 `app/{模块名}/plugin/{插件名}/` 下：

```
app/{模块名}/plugin/{插件名}/
├── plugin.json
├── index.js
├── api_client/              # 简洁模式，不带模块前缀
│   └── {接口名}/
├── api_{模块名}_client/     # 显式模式，带模块前缀
│   └── {接口名}/
├── api_{模块名}_web/        # Web页面
│   └── index/
├── api_upload/              # 特殊功能目录
├── event_api/               # 插件级事件（可选）
├── static/
└── task/
```

> 同一插件可并存 `api_client` 和 `api_{模块名}_client`。参照 `app/sys/plugin/main/` 和 `app/sys/plugin/tencent/`。

**plugin.json**：name / title / description / version / app / author / main / options / icon / cmd  
**插件生命周期**：_init / install / uninstall / update / start / stop / end / main / cmd / chat / api

## 五、Pendant 挂件系统

挂件位于 `app/{模块名}/pendant/{挂件名}/` 下：

```
app/{模块名}/pendant/{挂件名}/
├── pendant.json
├── pendant.html
└── pendant.js
```

常见类型：文章列表、音频、评论、图库、轮播、二维码、视频、链接列表、排行榜等

## 六、Event 事件系统

> 📖 **详细文档请参阅独立的 `mm_event_system` knowledge。**

Event 是 mm_os 的请求拦截/分发层，分 App 级和 Plugin 级两个层级，覆盖请求生命周期的 5 个阶段（`before` → `check` → `main` → `render` → `after`）。

- **App 级**：`app/{模块名}/event_api/{client|web|manage}/{事件名}/` — 全局拦截
- **Plugin 级**：`app/{模块名}/plugin/{插件名}/event_api/{事件名}/` — 插件内部处理
- **核心模式**：Event 通过 `$.admin.api().run(ctx, db)` 委托给 API 管理器处理具体业务

## 七、API 接口配置（api.json）

### Client 类型

```json
{
  "path": "/api/sys/ls",
  "name": "api_ls",
  "title": "接口标题",
  "method": "ALL",
  "scope": true,
  "cache": 0,
  "param_path": "./param.json",
  "oauth": { "sign_in": false, "vip": 0, "gm": 0, "mc": 0 }
}
```

### Web 类型（额外字段 `type`、`app`、`plugin`）

```json
{
  "path": "/sys/pendant",
  "name": "sys_pendant",
  "title": "挂件管理页面",
  "method": "ALL",
  "type": "web",
  "app": "server",
  "plugin": "sys",
  "scope": true,
  "oauth": { "sign_in": false, "vip": 0, "gm": 0, "mc": 0 }
}
```

| 字段 | 必填 | 说明 |
|:-----|:-----|:------|
| `path` | ✅ | 路由路径，无固定格式 |
| `name` | ✅ | 唯一标识，无固定格式 |
| `method` | ✅ | GET/POST/ALL |
| `type` | Web必填 | `"web"` |
| `app` | Web必填 | 所属 App |
| `plugin` | Web必填 | 所属 Plugin |
| `scope` | | 是否开放 |
| `cache` | | 缓存分钟数 |
| `param_path` | | 参数校验文件 |
| `oauth` | | 权限控制 |

> `name`/`path` 无固定格式，参照 `app/sys/plugin/main/api_client/` 下已有 API。

## 八、API 业务脚本（index.js）

> `db` 由框架注入。生命周期中通过 `option.db` 获取。

Client API：
```javascript
async function main(ctx, db) {
  var { query, body } = ctx.request;
  return $.ret.obj({ success: true, data: result });
}
exports.main = main;
```

Web 页面：
```javascript
async function main(ctx, db) {
  var model = {};
  return db.tpl.view("./index.html".fullname(__dirname), model);
}
exports.main = main;
```

## 九、参数校验（param.json）

| 字段 | 说明 |
|:-----|:------|
| filter | 是否启用过滤 |
| get.query | GET 参数列表 |
| get.query_required | GET 必填 |
| post.body | POST 参数列表 |
| post.body_required | POST 必填 |
| list[].name/type | 参数名/类型 |
| list[].string.min/max | 字符串长度 |

## 十、模板引擎语法

| 语法 | 说明 |
|:-----|:------|
| `${viewBag.xxx}` | 视图数据 |
| `${@view('./xxx.html')}` | 嵌入子视图 |
| `${hookAction('name','pos')}` | 钩子函数 |
| `<!--{ loop data o i }-->` | 遍历 |
| `<!--{ if(条件) }-->` | 条件 |
| `<!-- #main -->` | 挂件插入点 |
| `v-model` / `@click` | Vue 指令 |
| `mm_warp` / `mm_card` | UI 组件 |

## 十一、数据查询语法

```javascript
var db_data = db.new('cms_article', 'article_id');
```

| 后缀 | 含义 | 示例 |
|:-----|:-----|:------|
| _not | 不等于 | `state_not: 0` |
| _gt/_lt | 大于/小于 | `hot_gt: 100` |
| _gte/_lte | ≥/≤ | `hot_gte: 100` |
| _min/_max | 范围 | `hot_min: 10` |
| _like | 模糊 | `title_like: "关键词"` |
| _has | IN | `id_has: [1,2,3]` |

排序：`db_data.get({条件}, "字段 asc/desc")` | 分页：`db_data.size` / `db_data.page` | 联表：`this.sql.run()` | 聚合：count/sum/groupby

## 十二、全局对象 `$`

| 对象 | 说明 |
|:-----|:------|
| $.sql | 数据库连接 |
| $.log | 日志（.info/.error/.warn） |
| $.run_path | 运行路径 |
| $.ret.obj(data) | 返回成功 |
| $.ret.error(code, msg) | 返回错误 |
| $.dir.copy(src, dest) | 目录复制 |

字符串扩展：`loadJson()` / `fullname()` / `hasFile()` / `saveText()`

## 十三、配置文件体系

| 配置 | 位置 | 用途 |
|:-----|:-----|:------|
| 环境配置 | config/{env}.json | 多环境 |
| 模板配置 | config/tpl.json | 模板参数 |
| 应用配置 | app/{模块名}/app.json | 应用/数据库/缓存 |
| 插件配置 | app/{模块名}/plugin/{插件名}/plugin.json | 插件/版本/选项 |
| 挂件配置 | app/{模块名}/pendant/{挂件名}/pendant.json | 挂件/模板/数据源 |

## 十四、常见开发场景

| 场景 | 推荐方式 | 对应技能 | 对应 work | 说明 |
|:-----|:---------|:---------|:----------|:------|
| 新增功能模块 | 创建 App | `mm_app_development` | `develop_mm_app` / `config_mm_app` / `script_mm_app` | 独立功能模块 |
| 扩展已有App功能 | 创建 Plugin | `mm_plugin_development` | `develop_mm_plugin` / `config_mm_plugin` / `script_mm_plugin` | 热插拔扩展 |
| 在Plugin中提供API | 创建 API 接口 | `mm_api_development` | `develop_mm_api` / `script_mm_api` | 必须依附 Plugin |
| 页面片段复用 | 创建 Pendant | `mm_pendant_development` | `develop_mm_pendant` / `config_mm_pendant` / `script_mm_pendant` | 可复用 UI |
| 页面展示 | 开发 Template | `mm_template_development` | `develop_mm_template` / `syntax_mm_template` | 前端模板 |
| 定时任务 | 创建 Task | `mm_task_development` | `develop_mm_task` / `config_mm_task` / `script_mm_task` | 周期执行 |
| 请求拦截/分发/预处理 | 配置 Event | `mm_api_event_development` | `develop_mm_api_event` / `config_mm_event` / `script_mm_event` | 📖 详见 `mm_event_system` |
| 代码复用 | 封装 Com | `mm_com_script` | `script_mm_com` | 全局共享 |
