架构与约束
这一页不是给你背术语的,而是解释 Stratix 为什么强制你按某种方式组织代码。你把这里的规则看懂了,后面写业务时就不容易“代码能跑,但框架没有接住”。
先建立一个正确的心智模型
可以把一个 Stratix 应用理解成四层组合:
- Fastify 负责 HTTP 服务
- Awilix 负责依赖注入
- Stratix Core 负责自动发现、控制器注册和启动流程
- 生态插件负责数据库、缓存、任务等基础设施
对应用开发者来说,最重要的现实是:
- 你主要写的是
controller、service、repository - 你主要配置的是
src/stratix.config.ts - 你主要通过 CLI 创建和扩展项目
启动时到底发生了什么
当应用执行 await Stratix.run() 时,框架大致会做下面这些事:
- 读取运行参数
- 加载环境变量和敏感配置
- 执行
src/stratix.config.ts - 创建根容器和 Fastify 实例
- 按顺序加载配置里的插件
- 扫描应用
src下可发现的类 - 注册控制器、服务、执行器
- 启动 HTTP 服务或其他运行时
这就是为什么你不应该跳过 CLI、乱放目录,或者随便修改配置导出形式。很多“莫名其妙发现不了类”的问题,本质上都是启动链路没接上。
分层规则
controller负责协议层、请求响应和参数转发。service负责业务编排和跨服务协作。repository负责全部数据库访问。
如果你不知道一段代码该放哪里,就先问自己一个问题:
- 它是在处理 HTTP 请求格式吗?放
controller - 它是在组织业务步骤吗?放
service - 它是在读写数据库或持久化状态吗?放
repository
一个最简单的调用链是什么样
HTTP 请求
-> Controller 接收参数
-> Service 组织业务
-> Repository 读写数据
-> Service 返回结果
-> Controller 输出响应
自动发现
Stratix 会自动扫描应用代码并把合适的类接入容器,所以目录约定非常重要。
- 应用默认扫描
src。 src/controllers、src/services、src/repositories、src/executors中的 class 会被优先视为可发现对象。- 不要把普通工具类随意放进这些扫描目录。
对新手来说,最容易踩坑的点是:
- 你在
src/services放了一个“只是想复用一下的工具类”,框架却把它当作 service 注册了 - 你把真正的业务类放到了其他自定义目录,结果框架根本没扫描到
最保守的做法是:只有真正要被框架管理的 class,才放进这些扫描目录。
控制器与路由
@Controller()不接收前缀。- 不要依赖
applicationAutoDI.routing.prefix或插件AutoDIConfig.routing.prefix来定义业务路由前缀。
正确思路是:
@Controller()只标记“这是一个控制器”- 每个方法上的
@Get('/users')、@Post('/users')等装饰器直接写完整业务路径
也就是说,不要写成你在其他框架里常见的:
@Controller('/users')
在当前实现里,这种写法不是推荐主路径。
数据访问
@stratix/database@1.1.0以 repository-first 为主。- 应用侧数据库访问首选
BaseRepository。 - 不要在 service 中直接访问数据库插件或手工拼接跨仓储一致性单元。
这条规则非常关键。你应该把数据库访问理解成“Repository 的职责”,而不是“谁会写 SQL 谁就去写”。
错误做法:
- Controller 直接查数据库
- Service 直接注入数据库插件
- 一个业务流程在多个 service 里分别更新多张表
推荐做法:
- 所有数据库读写都通过 repository
- 多表一致性逻辑优先收敛到 business repository
- service 只调用 repository 提供的业务语义方法
配置约束
新手还需要记住一个关键现实:
src/stratix.config.ts应默认导出函数- 不要把主要配置建立在
Stratix.run({ config })这种调用方式上
最稳妥的形式是:
import type { StratixConfig } from '@stratix/core';
export default function createConfig(
sensitiveConfig: Record<string, string> = {}
): StratixConfig {
return {
server: {
host: '0.0.0.0',
port: Number(process.env.PORT || 3000)
},
plugins: [],
applicationAutoDI: {
enabled: true
}
};
}
插件开发约束
- 插件主入口优先使用“具名插件函数 + withRegisterAutoDI(...) 默认导出”。
- 适配器 token 前缀来自插件函数名,不来自
PluginConfig.name。 - 插件内部如果有持久化逻辑,也保持
controller -> service -> repository分层。
如果你当前只是开发业务应用,这一段先知道即可,不用立刻掌握。
执行器
- 应用
src下的 executor 依赖@stratix/tasks先完成注册。 - 长流程不要长时间持有数据库事务,应使用短事务 + checkpoint 的方式收口状态。
新手最应该死记住的 6 条规则
- 先用 CLI 建项目、生成资源,不要先手写目录。
src/index.ts负责启动,src/stratix.config.ts负责配置。@Controller()不带前缀,路由直接写在方法装饰器上。- service 不直接碰数据库。
- repository 是唯一默认允许承接数据库访问的应用层。
- 不要把普通工具类随便塞进
controllers/、services/、repositories/、executors/。