Files
OpenFlare/docs/superpowers/specs/2026-08-28-cordis-plugin-layered-architecture-spec.md
T

7.6 KiB
Raw Blame History

Cordis 架构插件标准分层设计规范 (Plugin Layered Architecture Spec)

  • 文档状态: 已敲定 (Approved)
  • 版本: v1.1.0 (2026-08-28)
  • 适用范围: Wavelet 官方插件 (backend/plugins/)、下游定制插件 (downstream/custom_plugins/)

1. 架构总览与统一标准规范 (Architecture & Unified Standard Spec)

在 Wavelet 的 Cordis 微内核架构中,系统通过 微内核 (core/) + 服务契约 (core/contracts/) + 自包含插件 (plugins/ 及 downstream/plugins/) 实现高度解耦与单向依赖。 所有插件统一以 backend/downstream/plugins/custom_example 为基准模板,严格遵循物理子包隔离的分层架构(controller -> service -> dao -> model)。


2. 统一标准分层目录结构 (以 custom_example 为基准)

backend/downstream/plugins/custom_example/ (或 backend/plugins/domain/<plugin_name>/)
├── plugin.go              # [插件根入口] 实现 core.Plugin,装配各子包并向 Cordis 注册
│
├── consts/                # package consts:常量与模块内部错误码定义
│   └── consts.go
│
├── controller/            # package controller:HTTP API 接入层 (参数绑定、会话获取、统一信封响应)
│   └── hello/             # 业务分组/实体子包
│       └── hello.go       # 接口处理 Handler(直接以业务命名,禁止 controller_hello.go)
│
├── service/               # package service:核心业务用例层 (业务用例、事务编排、事件发布)
│   └── hello.go           # 业务用例实现(纯 Go 逻辑,禁止依赖 *gin.Context)
│
├── dao/                   # package dao:数据持久化访问层 DAL (GORM CRUD、SQL 转义防注入)
│   └── hello.go           # 数据访问实现(直接以业务命名,禁止 dao_hello.go)
│
├── model/                 # package model:纯数据实体与传输对象 (零 Web/数据库框架依赖)
│   ├── entity/            # 数据库映射实体 (TableName() 必须带 w_<plugin>_ 前缀)
│   │   └── hello.go
│   └── do/                # 领域对象、请求 Request DTO 与响应 Response DTO
│       └── hello.go
│
└── migrations/            # Goose SQL 独立迁移嵌入目录 (//go:embed)
    ├── postgres/          # PostgreSQL 专属迁移 SQL
    │   └── 20260901000001_init.sql
    └── sqlite/            # SQLite 专属迁移 SQL
        └── 20260901000001_init.sql

⚠️ 严禁规则:严禁在插件根目录下平铺 handlers_*.go、service_*.go、dao_*.go 等前缀文件,子包内文件直接按业务实体命名。严格约束 controller -> service -> dao -> model 单向依赖。 │ ├── auth.go # 认证业务逻辑(直接命名为 auth.go,禁止 service_auth.go) │ ├── user.go # 用户业务逻辑(直接命名为 user.go,禁止 service_user.go) │ ├── config.go # 配置业务逻辑(直接命名为 config.go,禁止 service_config.go) │ └── logs.go # 日志业务逻辑(直接命名为 logs.go,禁止 service_logs.go) │ ├── repository/ # package repository:数据访问持久化层 (DAL) │ ├── repository.go # 仓储通用方法与工厂 │ ├── user.go # 用户仓储实现(直接命名为 user.go,禁止 repository_user.go) │ ├── config.go # 配置仓储实现(直接命名为 config.go,禁止 repository_config.go) │ └── log.go # 日志仓储实现(直接命名为 log.go,禁止 repository_log.go) │ ├── model/ # package model (或 models/):纯领域实体与传输对象 │ ├── entity.go # 数据库映射实体 (TableName() 必须带 w__ 前缀) │ ├── dto.go # 请求入参与响应出参 DTO │ └── events.go # 插件内部/广播事件结构体定义 │ ├── errs/ # package errs:错误常量与错误码定义 (或根目录 errs.go) │ └── errs.go │ └── migrations/ # Goose SQL 独立迁移嵌入文件 (//go:embed) └── 20260828000001_init_<plugin_name>.sql


### 3.2 依赖方向约束 (Strict Dependency Flow)
```mermaid
graph TD
    Plugin[plugin.go 入口] --> Handler[handler/ 接入层]
    Plugin --> Service[service/ 业务层]
    Plugin --> Repository[repository/ 仓储层]
    Handler --> Service
    Handler --> Model[model/ 实体与DTO]
    Handler --> Errs[errs/ 错误常量]
    Service --> Repository
    Service --> Model
    Service --> Errs
    Repository --> Model
  • 单向依赖铁律:
    1. handler/ 依赖 service/、model/、errs/;
    2. service/ 依赖 repository/、model/、errs/,严禁 import gin;
    3. repository/ 依赖 model/ 和数据库底层,严禁反向依赖 service 或 handler;
    4. model/ 纯粹由 Go 结构体组成,严禁依赖上层 handler/service/repository。

4. 各层职责边界与编码守则 (Layer Responsibilities & Guardrails)

4.1 Handler 层 (handler/)

  1. 参数绑定:使用 c.ShouldBindJSON 或 c.ShouldBindQuery。
  2. 上下文提取:从 *gin.Context 提取登录态(如 oauth.GetCurrentUser(c))。
  3. 调用下游:调用 Service 方法,禁止直接调用 Repository 或编写 SQL。
  4. 统一信封响应:
    • 成功:c.JSON(http.StatusOK, response.OK(data)) 或 response.OKNil()。
    • 失败:使用 backend/pkg/response 的 Abort* 系列函数(如 AbortBadRequest、AbortUnauthorized、AbortNotFound、AbortInternal)。
  5. Swagger 注释:每个导出 Handler 必须编写完整的 OpenAPI/Swagger 注解。

4.2 Service 层 (service/)

  1. 纯 Go 逻辑:第一参数必须为 ctx context.Context,返回 (result, error)。
  2. 禁止依赖 Web 框架:严禁 import github.com/gin-gonic/gin,严禁接收 *gin.Context,严禁调用 c.JSON/Abort*。
  3. 事务编排:涉及插件内多表原子操作时,通过 ctx.DB().Transaction(...) 编排。
  4. 事件驱动解耦:跨插件业务通知与状态联动统一通过 ctx.Events().Emit(...) 广播领域事件,杜绝直接跨插件调用私有方法。

4.3 Repository 层 (repository/)

  1. GORM / SQL 操作:统一接收 context.Context,通过 db.WithContext(ctx) 操作数据。
  2. SQL LIKE 防注入:所有含用户输入的模糊查询必须调用 backend/pkg/util.EscapeLike 并显式声明 ESCAPE '\\'。
  3. 表单一所有者原则:仅操作本插件所属表(前缀 w_<plugin>_*),严禁越权 DML/DDL 其他插件所有表。

4.4 Model 层 (model/ 或 models/)

  1. GORM 映射:显式实现 TableName() string 返回带前缀表名。
  2. 零值对齐:Go 结构体字段零值必须与数据库默认值匹配。
  3. 无物理外键:禁止物理外键约束,显式建立单列/复合索引。

4.5 Plugin 入口 (plugin.go)

  1. 实现 core.Plugin 接口(Name() string 与 Apply(ctx *core.Context) error)。
  2. 在 Apply 中完成:
    • 依赖注入与解析(core.Provide / core.Inject / ctx.Using)
    • 路由与中间件声明(ctx.Router().Group(...))
    • 异步与定时任务注册(ctx.Task().Register / ctx.Schedule().RegisterCron)
    • 配置与设置声明(ctx.Settings().Register / ctx.Config().Bind)
    • 数据库迁移注册(ctx.Migrations().Register)