br-addon 0.1.69

This is an addon
Documentation
# PROJECT KNOWLEDGE BASE

**Generated:** 2024-02-07 | **Commit:** f339ed6 | **Branch:** main

## OVERVIEW

Rust 插件系统框架,提供 `Addon → Module → Action` 三层运行时分发架构,支持多数据库/缓存/Kafka/邮件集成,自动生成 Swagger 文档和数据库迁移。

## STRUCTURE

```
br-addon/
├── src/
│   ├── lib.rs        # 入口: Plugin trait, ApiResponse, 全局注册
│   ├── addon.rs      # Addon trait + addon_create() 脚手架
│   ├── module.rs     # Module trait + DB helpers
│   ├── action.rs     # Action trait + 参数验证 + UI组件
│   ├── request.rs    # Request/Method/ContentType
│   ├── tools.rs      # Tools 工具集(db/cache/kafka/email)
│   ├── tables.rs     # 表格查询构建器(feature-gated)
│   └── swagger.rs    # OpenAPI 3.0 生成器
├── temp/             # 代码生成模板(14个action模板)
├── examples/         # 完整示例应用(非最小示例)
│   └── addon/api/    # 示例插件实现
└── tests/main.rs     # 脚手架测试(非断言测试)
```

## WHERE TO LOOK

| 任务 | 位置 | 说明 |
|------|------|------|
| 实现新插件 | `examples/addon/` | 参考完整 Addon→Module→Action 实现 |
| 添加新 Action | `temp/action_*` | 选择模板: table/add/del/get/put/select/tree/import |
| 参数验证逻辑 | `src/action.rs:158-468` | `check()` 方法,支持20+字段类型 |
| 数据库操作 | `src/module.rs:111-138` | `db_find/db_select/db_insert/db_update/db_delete` |
| 表格查询 | `src/tables.rs` | `Tables` 构建器,支持分页/排序/联表/树形 |
| Swagger生成 | `src/swagger.rs` | `Swagger::new()` + `add_paths()` |
| 全局状态 | `src/lib.rs:35-52` | `PLUGIN_TOOLS`, `CONFIG`, `GLOBAL_DATA` |

## CODE MAP

| Symbol | Type | Location | Role |
|--------|------|----------|------|
| `Plugin` | trait | lib.rs:64 | 顶层调度: addon/module/action加载, DB初始化 |
| `Addon` | trait | addon.rs:10 | 插件元数据 + module路由 |
| `Module` | trait | module.rs:10 | 模块元数据 + 表配置 + action路由 |
| `Action` | trait | action.rs:9 | 请求处理: run→check→index |
| `ApiResponse` | struct | lib.rs:478 | 统一响应: success/fail/redirect/download |
| `Request` | struct | request.rs:4 | 请求封装: body/query/header/cookie |
| `Tools` | struct | tools.rs:18 | 工具集: db/cache/kafka/email |
| `Tables` | struct | tables.rs:11 | 表格查询构建器 |

## CONVENTIONS

### API 命名
```
{addon}.{module}.{action}  →  dms.task.table
表名自动推导: {addon}_{module}  →  dms_task
```

### Feature 条件编译 (必须)
```rust
#[cfg(any(feature = "mysql", feature = "sqlite", feature = "mssql", feature = "pgsql"))]
fn db_operation() { }
```

### 错误处理
```rust
// Trait 层
fn module(name: &str) -> Result<Box<dyn Module>, String>

// API 层
ApiResponse::fail(900_001, "参数错误")
```

### 命名风格
| 类型 | 风格 | 示例 |
|------|------|------|
| Struct/Enum/Trait | PascalCase | `ApiResponse`, `Action` |
| 函数/方法 | snake_case | `module_name()` |
| 常量 | SCREAMING_SNAKE | `GLOBAL_DATA` |
| 私有方法 | 下划线前缀 | `_name()`, `_table_name()` |

### 中文注释
本项目使用中文注释,保持一致性。

## ANTI-PATTERNS

### 禁止模式
- ❌ 非 feature-gated 代码中直接使用 `self.tools().db`
- ❌ 添加新的全局 `lazy_static!` 变量
- ❌ Action 中直接 panic,应使用 `ApiResponse::fail()`
- ❌ 使用 `.unwrap()` 处理用户输入,应使用 `.unwrap_or()``.unwrap_or_default()`
- ❌ 直接使用 `.leak()` 泄漏字符串,应使用 `Box::leak()` 并添加说明注释

## COMMANDS

```bash
# 开发
cargo build                                    # 构建
cargo build --features "mysql"                 # 指定feature
cargo test                                     # 测试
cargo test -- --nocapture                      # 带输出

# 检查 (提交前必须)
cargo fmt -- --check
cargo clippy --all-targets --all-features -- -D warnings

# 发布
cargo package --list && cargo publish --dry-run && cargo publish
```

**Features**: `mysql` `sqlite` `mssql` `pgsql` `cache` `kafka` `email` (默认全启用)

## GIT COMMIT

```
<类型> <描述>
```
| 前缀 | 含义 |
|------|------|
| A | 新增 |
| U | 更新/优化 |
| F | 修复 |
| D | 删除 |
| R | 重构 |

## NOTES

### 架构特点
- **运行时分发**: API 通过字符串名称动态路由,非编译时绑定
- **反射式命名**: `type_name::<Self>()` 解析模块路径推导名称
- **内置脚手架**: `addon_create()``temp/` 模板生成代码

### 已知问题
- `dev-dependencies` 使用本地路径 `../br-web-server`,CI 需特殊处理
- 无 CI 配置文件,依赖手动执行命令
- 默认 feature 过重,建议按需启用

### 快速开始
```rust
// 1. 实现 Plugin trait
impl Plugin for MyPlugins {
    fn addon(name: &str) -> Result<Box<dyn Addon>, String> { ... }
}

// 2. 实现 Addon/Module/Action
impl Action for MyAction {
    fn title(&self) -> &'static str { "标题" }
    fn index(&mut self, request: Request) -> ApiResponse {
        ApiResponse::success(object! {}, "成功")
    }
}
```