整体架构
预计阅读时间: 5 分钟
预计阅读时间: 5 分钟
Summerrs Admin 的核心架构观点只有一句:用插件组合替代脚手架。所有运行时能力都封装为一个 Plugin,在 crates/app/src/main.rs 里按依赖顺序串起来。
请求流转
三大入口域
crates/app/src/router.rs 把整套路由分成 3 个独立域:
pub fn router() -> Router {
let api_router = summer_system::router_with_layers()
.merge(summer_ai_admin::router_with_layers())
.merge(summer_job_dynamic::router_with_layers());
let default_router = auto_grouped_routers().default;
Router::new()
.nest("/api", api_router) // 域 1:JWT
.merge(default_router) // 域 3:default
.layer(CatchPanicLayer::custom(handle_panic))
.merge(summer_ai_relay::router_with_layers()) // 域 2:API key
.layer(ClientIpSource::ConnectInfo.into_extension())
}
关键设计:panic_guard 在 GroupAuthLayer 外层,鉴权阶段的 panic 也会被各家的 flavor 抓住,避免误返成系统级 RFC 7807。
AI Relay 的子路由
crates/summer-ai/relay/src/router/mod.rs 把 relay 内部又拆成三家:
pub fn router_with_layers() -> Router {
let openai = grouped_router(relay_openai_group())
.layer(GroupAuthLayer::new(ApiKeyStrategy::for_group(
relay_openai_group(), ErrorFlavor::OpenAI)))
.layer(middleware::from_fn(openai_panic_guard));
let claude = grouped_router(relay_claude_group())
.layer(GroupAuthLayer::new(ApiKeyStrategy::for_group(
relay_claude_group(), ErrorFlavor::Claude)))
.layer(middleware::from_fn(claude_panic_guard));
let gemini = grouped_router(relay_gemini_group())
.layer(GroupAuthLayer::new(ApiKeyStrategy::for_group(
relay_gemini_group(), ErrorFlavor::Gemini)))
.layer(middleware::from_fn(gemini_panic_guard));
Router::new()
.merge(openai).merge(claude).merge(gemini)
.layer(PropagateRequestIdLayer::x_request_id())
.layer(SetRequestIdLayer::x_request_id(MakeRequestUuid))
}
每家协议的鉴权失败和 panic 都按对应"风味"返回——OpenAI 风格的 {"error": {...}}、Claude 风格的 {"type": "error", "error": {...}}、Gemini 风格的错误 JSON。客户端 SDK 不用改,可以无缝接入。
域之间怎么解耦
每个 crate 自带 router_with_layers(),负责"路由 + 自家中间件"打包,crates/app 只做拼装:
summer-system::router_with_layers() 挂 JWT
summer-ai-admin::router_with_layers() 挂 JWT,合到 /api 下
summer-ai-relay::router_with_layers() 按 flavor 挂三套 ApiKeyStrategy + panic_guard
summer-job-dynamic::router_with_layers() 动态调度器 admin API,挂 JWT
auto_grouped_routers().default 没显式 group 的 handler,无鉴权
这种"自包装"设计的好处:
- 新增业务域只动两个文件:在新 crate 里写好
router_with_layers(),再到 crates/app/src/router.rs 加一行 merge。
- 自家中间件不会污染别人:relay 的
panic_guard 只覆盖 relay 路由,system 域没有。
- app crate 不依赖 relay 内部细节:不用 import
ApiKeyStrategy、ErrorFlavor,黑盒拼装。
数据访问层
summer-sql-rewrite:把鉴权信息(用户、角色、租户、权限)注入到 SQL where 子句。常见用例:行级安全、按租户过滤。
summer-sharding:更上层的 SQL 改写引擎,实现四级租户隔离、分片、加密、脱敏、影子库、CDC。
summer-sea-orm:对 SeaORM 的薄包装,处理连接池配置和 Web 层的分页/排序约定。
详见 多租户。
异步运行时
主二进制用 #[tokio::main](features = ["full"]),关键后台任务:
配置与环境
所有插件用 Summer 的 Configurable derive 从 config/app[-{env}].toml 读取配置,变量用 ${VAR:default} 插值:
[sea-orm]
uri = "${DATABASE_URL:postgres://admin:123456@localhost/summerrs-admin}"
[auth]
jwt_secret = "${JWT_SECRET:change-me-in-local-dev}"
SUMMER_ENV 环境变量决定加载哪个 profile:
下一步