Files
raisfast/docs/architecture-audit.md
T
2026-04-15 23:46:02 +08:00

13 KiB
Raw Blame History

架构审计报告

审计时间:2026-04-15

基于 Phase 8-14 全部完成后的代码状态。

1. 总体评估

评级:中等偏上——骨架扎实,Schema-driven 扩展能力强,但缺少生产级配套(审计、可观测性、缓存)。

做得好的

领域 评价 关键文件
分层架构 Handler→Service→Repository 三层清晰一致 src/handlers/ src/services/ src/repositories/
Content Type 引擎 TOML 定义即得自动建表 + CRUD API + Admin UI src/content_type/
多租户隔离 tenant_id 贯穿 repo/service/handler 三层,ResolvedTenant 中间件统一解析 src/db/tenant.rs src/middleware/tenant.rs
插件系统 WASM/JS/Lua 三引擎,HookPoint 泛化,VFS 隔离 src/plugins/
错误处理 统一 AppError 枚举 + i18n + JSON envelope src/errors/app_error.rs
输入校验 validator crate + DTO 层一致调用 validation::validate() src/handlers/dto.rs src/errors/validation.rs
事件驱动 EventBus + Worker + Cron 完整闭环 src/eventbus/ src/worker/
RBAC 细粒度权限矩阵,条件权限(author_id == $user.id src/services/rbac.rs src/middleware/permission.rs

成为复杂系统的关键短板

短板 严重度 说明
审计日志 EventBus 有事件但无持久化订阅者,admin 操作无 "谁做了什么" 记录
可观测性 #[instrument]、无 metrics、无 request ID 串联
缓存层不完整 只有 posts 有缓存,worker 缓存失效 handler 是 stub
事务覆盖 media 删除(DB+文件)非原子,options 批量更新无事务
API 版本策略 只有 /api/v1,无 v2 迁移计划
Webhook 不完整 无订阅管理、无 HMAC 签名、无事件过滤
测试覆盖 Options/Plugin/RBAC/Stats/Tenant Admin 无集成测试
限流策略 内存级,无法多实例共享,admin 无独立限流

2. 详细分析

2.1 错误处理

状态:强——设计完善,有少量缺口

AppError 枚举(src/errors/app_error.rs:49)有 6 个变体:BadRequestUnauthorizedForbiddenNotFoundConflictInternal,带 #[non_exhaustive] 防止破坏性变更。

From<sqlx::Error> 自动映射:RowNotFoundNotFound,唯一约束违反 → Conflict

IntoResponse impl 将每个变体映射到 HTTP 状态码 + i18n 消息 + 结构化 JSON body。

缺口:

  • 缺少 TooManyRequests429)变体。 限流中间件(src/middleware/rate_limit.rs:246-259)手动构造 JSON 响应,绕过了 AppError 管线和 i18n。
  • 缺少 PayloadTooLarge413)变体。 RequestBodyLimitLayer 产生默认 Axum 响应,不走 AppError 格式。
  • 缺少 MethodNotAllowed405)和 ServiceUnavailable503)变体。
  • sqlx::Error::RowNotFound 映射到 NotFound("resource")src/errors/app_error.rs:227)丢失了具体资源类型上下文。

2.2 事务支持

状态:关键路径有事务,部分多步操作缺失

已有事务的操作:

文件 行号 操作
src/repositories/sqlx_post.rs 104, 116 Post 创建/更新 + tag 同步
src/services/auth.rs 316 Refresh token 轮换(删除旧 + 插入新)
src/worker/sqlite_queue.rs 113 Job 出队
src/worker/scheduler.rs 370, 633 Cron 清理和种子数据

缺失事务但需要的场景:

  • Media 删除src/services/media.rs)— 先删 DB 记录再删磁盘文件,两步非原子
  • Options 批量更新src/services/options.rs)— 逐条执行,无整体事务
  • Content Type 字段校验 + 写入 — 校验通过后写入,中间无事务保护

2.3 分页一致性

状态:基本一致,两个端点缺少分页

PaginationParamssrc/utils/pagination.rs)统一用于 6 个列表端点:posts(公开+admin)、comments、media、users。

不一致:

  • tag::listcategory::list 返回 Vec<T> 无分页,数据量大时成为性能瓶颈
  • Post 列表 handler 手动构造分页参数(.max(1) .clamp()),其他 handler 直接用 Query(mut params)
  • PaginatedDatatotal_pages 字段或 Link header

2.4 输入校验

状态:强——模式一致,有少量缺口

所有接受 body 的 handler 统一调用 validation::validate(&req)?src/errors/validation.rs:42),DTO 用 validator crate 注解。

缺口:

  • Post/Comment 的 status 字段无枚举校验,任意字符串(如 "hacked")都会被接受
  • category_idtag_ids[] 等 UUID 字段无格式校验
  • Media 上传无 MIME 类型/扩展名白名单
  • RefreshRequest.refresh_tokenlength(min = 1) 校验

2.5 可观测性

状态:日志良好,无 metrics,无分布式追踪

已有:

  • tower_http::TraceLayer 记录请求/响应(method, URI, status, latency
  • 业务逻辑关键点有 tracing::info! / tracing::error!
  • AppError::into_responsetracing::warn!4xx)和 tracing::error!5xx

缺失:

  • #[instrument]——全代码库 0 使用,无法 span 级关联 handler→service→repository 调用链
  • 无 metrics——无 Prometheus / OpenTelemetry,无法追踪请求率、错误率、P95/P99 延迟
  • 无 request ID——TraceLayer 不注入 X-Request-ID,无法跨服务关联
  • 无 pool utilization 监控——无法知道连接池使用率
  • 日志字段不一致——部分用格式化字符串,部分用结构化字段

2.6 限流

状态:可用但有限

RateLimiterSetsrc/middleware/rate_limit.rs:153)包含 4 个命名限流器:globalregisterlogincomment,滑动窗口算法。

限制:

  • 纯内存——多实例部署时限流独立,等效于倍增限额
  • 4 个限流器硬编码——新增需改 struct + from_config() + 中间件函数
  • Admin 端点无独立限流——全局 60 req/min 覆盖,持有 admin token 的攻击者可暴力请求
  • IP 提取信任 X-Forwarded-For——无配置化信任代理
  • 响应无 Retry-After / X-RateLimit-* header
  • RateLimitStore trait 已定义但只有 MemoryStore 实现

2.7 缓存

状态:仅 posts 有缓存,失效 handler 是 stub

CacheStore trait + MemoryCache 实现(src/cache/mod.rs)。CachedPostRepository<P> 装饰器(src/repositories/cached_post.rs)为 posts 提供读穿透缓存 + 写穿透失效,租户感知 cache key。

缺口:

  • InvalidateCacheHandler 是 stub——src/worker/handlers/cache.rs:35 只有 // TODO 注释和日志,不实际删除缓存
  • 只有 posts 有缓存——categories、tags、users、comments、media、options 无缓存
  • Options 缓存无 TTL 刷新——启动时加载到 HashMap,更新时写穿透,但无定期刷新机制
  • MemoryCache 无后台清理线程——过期条目仅在 get/set 时惰性跳过
  • 无 Redis 后端——CacheStore trait 可扩展但只有内存实现

2.8 数据库连接管理

状态:可用但配置最小

init_poolsrc/db/connection.rs:14)配置 max_connectionsSQLite 设置 journal_mode = WAL + foreign_keys = ON

缺失:

  • min_connections 配置
  • acquire_timeout——请求可能无限等待连接
  • idle_timeout / max_lifetime
  • 无连接池利用率监控
  • SQLite WAL 模式仅在启动时设置一次,非 per-connection
  • 无数据库重连逻辑

2.9 测试覆盖

状态:覆盖面广,深度中等

Handler 有集成测试? 测试数
health 1
auth 9
user 7
category 5
tag 4
post 12
comment 8
media 4
rss 2
cron 6
sse 2
tenant_e2e 4
options 0
plugin 0
rbac 0
stats 0
tenant admin 部分(仅 e2e 间接测试)

单元测试总计 422 个,覆盖 content_type、plugins、search、worker 等核心模块。

缺口:

  • Options、Plugin、RBAC、Stats、Tenant Admin CRUD 无集成测试
  • 无负面/边界测试(限流溢出、并发请求等)
  • 无负载/压力测试
  • src/cache/mod.rssrc/errors/validation.rs 无单元测试

2.10 API 版本策略

状态:单版本,无迁移策略

所有路由嵌套在 /api/v1src/server/mod.rs:335),无版本中间件、无 Accept header 协商、无版本感知序列化。

添加 /api/v2 需要复制或重构整个路由注册块(204-315 行)。无版本迁移策略文档。

2.11 Webhook 系统

状态:基础出站 webhook

WebhookNotifyHandlersrc/worker/handlers/webhook.rs)通过 job queue 发起 HTTP POST10 秒超时,非 2xx 触发重试。

缺口:

  • 无 webhook 订阅管理 API(无法动态注册/注销 URL)
  • 无 HMAC 签名(接收方无法验证真实性)
  • 无事件类型过滤(无法订阅特定事件)
  • 无死信队列 UI(永久失败的 webhook 无检查/重放界面)
  • 无出站限流

2.12 审计日志

状态:缺失——无持久化审计轨迹

  • audit_log——所有 migration 中均不存在
  • 无 audit 模块——src/ 中无任何 audit 相关文件
  • EventBus 无持久化订阅者——唯一订阅者转发给插件系统,不做审计持久化
  • Admin 操作无日志记录——用户角色变更、插件启停、配置修改、租户 CRUD、RBAC 变更、Cron 调度变更均无审计记录
  • 无 "谁做了什么、什么时候" 追踪

3. 快速扩展能力评估

能快速扩展的

扩展方向 说明
新 Content Type 创建 TOML 文件即得自动建表 + CRUD API + Admin 页面
新插件 写 plugin.toml + 入口文件,自动加载
新租户 INSERT 一行数据即生效
前端新页面 Admin 页面复用统一 layout + API client
新字段类型 FieldType 枚举加一个变体 + 前端一个组件

扩展时会卡住的

场景 卡点
高并发 缓存不完整 + 无 Redis 后端
多实例部署 限流/缓存全内存不共享
安全合规 无审计日志
运维排查 无分布式追踪、无 metrics
API 演进 无版本策略
外部集成 Webhook 无订阅管理

4. 改进优先级建议

优先级 改进项 工作量估计 收益
P0 审计日志(EventBus 持久化订阅者 + audit_log 表) 2-3 天 安全合规必需
P0 可观测性(#[instrument] + Prometheus metrics + request ID 3-5 天 运维必需
P0 缓存补全(Category/Tag/Options 缓存 + InvalidateCacheHandler 实现) 2-3 天 性能扩展基础
P1 测试补全(Options/RBAC/Stats/Plugin/Tenant 集成测试) 3-5 天 质量保障
P1 Webhook 订阅管理 API + HMAC 签名 2-3 天 外部集成能力
P2 AppError 补全(429/413/405 变体) 0.5 天 一致性
P2 事务补全(media 删除、options 批量、content type 校验+写入) 1-2 天 数据一致性
P2 Redis 缓存/限流后端 3-5 天 多实例部署
P2 API 版本策略文档 + v2 路由架构 1-2 天 长期演进
P3 分页补全(tags/categories 加分页) 0.5 天 性能
P3 输入校验补全(status 枚举、UUID 格式、MIME 白名单) 1 天 安全
P3 DB 连接池配置完善(acquire_timeout、min_connections 0.5 天 稳定性

5. 与同类系统对比

能力 本系统 Strapi WordPress
Schema-driven Content Type TOML → 自动建表/API JSON Schema → 自动建表/API PHP 注册 → 自动建表
插件系统 WASM/JS/Lua 三引擎沙箱 JS 插件(无沙箱) PHP 插件(无沙箱)
多租户 tenant_id 隔离 单租户(Enterprise 有) Multisite
RBAC 细粒度 + 条件权限 细粒度 基于角色
全文搜索 Tantivy(内置) 外部 外部
审计日志 缺失 有插件
可观测性 缺失 有插件
API 版本
Webhook 基础出站 有插件
缓存 仅 posts 内存 + Redis 可选 对象缓存 + Redis
Admin UI Next.js(前后端分离) React SPA PHP SSR
性能(RPS Rust 级(待压测) Node.js 级 PHP 级