# 架构审计报告 > 审计时间: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 个变体:`BadRequest`、`Unauthorized`、`Forbidden`、`NotFound`、`Conflict`、`Internal`,带 `#[non_exhaustive]` 防止破坏性变更。 `From` 自动映射:`RowNotFound` → `NotFound`,唯一约束违反 → `Conflict`。 `IntoResponse` impl 将每个变体映射到 HTTP 状态码 + i18n 消息 + 结构化 JSON body。 **缺口:** - **缺少 `TooManyRequests`(429)变体。** 限流中间件(`src/middleware/rate_limit.rs:246-259`)手动构造 JSON 响应,绕过了 `AppError` 管线和 i18n。 - **缺少 `PayloadTooLarge`(413)变体。** `RequestBodyLimitLayer` 产生默认 Axum 响应,不走 `AppError` 格式。 - **缺少 `MethodNotAllowed`(405)和 `ServiceUnavailable`(503)变体。** - **`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 分页一致性 **状态:基本一致,两个端点缺少分页** `PaginationParams`(`src/utils/pagination.rs`)统一用于 6 个列表端点:posts(公开+admin)、comments、media、users。 **不一致:** - **`tag::list`** 和 **`category::list`** 返回 `Vec` 无分页,数据量大时成为性能瓶颈 - Post 列表 handler 手动构造分页参数(`.max(1)` `.clamp()`),其他 handler 直接用 `Query(mut params)` - `PaginatedData` 无 `total_pages` 字段或 `Link` header ### 2.4 输入校验 **状态:强——模式一致,有少量缺口** 所有接受 body 的 handler 统一调用 `validation::validate(&req)?`(`src/errors/validation.rs:42`),DTO 用 `validator` crate 注解。 **缺口:** - Post/Comment 的 `status` 字段无枚举校验,任意字符串(如 `"hacked"`)都会被接受 - `category_id`、`tag_ids[]` 等 UUID 字段无格式校验 - Media 上传无 MIME 类型/扩展名白名单 - `RefreshRequest.refresh_token` 无 `length(min = 1)` 校验 ### 2.5 可观测性 **状态:日志良好,无 metrics,无分布式追踪** **已有:** - `tower_http::TraceLayer` 记录请求/响应(method, URI, status, latency) - 业务逻辑关键点有 `tracing::info!` / `tracing::error!` - `AppError::into_response` 用 `tracing::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 限流 **状态:可用但有限** `RateLimiterSet`(`src/middleware/rate_limit.rs:153`)包含 4 个命名限流器:`global`、`register`、`login`、`comment`,滑动窗口算法。 **限制:** - **纯内存**——多实例部署时限流独立,等效于倍增限额 - **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

` 装饰器(`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_pool`(`src/db/connection.rs:14`)配置 `max_connections`,SQLite 设置 `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.rs`、`src/errors/validation.rs` 无单元测试 ### 2.10 API 版本策略 **状态:单版本,无迁移策略** 所有路由嵌套在 `/api/v1`(`src/server/mod.rs:335`),无版本中间件、无 Accept header 协商、无版本感知序列化。 添加 `/api/v2` 需要复制或重构整个路由注册块(204-315 行)。无版本迁移策略文档。 ### 2.11 Webhook 系统 **状态:基础出站 webhook** `WebhookNotifyHandler`(`src/worker/handlers/webhook.rs`)通过 job queue 发起 HTTP POST,10 秒超时,非 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 级 |