Files
raisfast/docs/pocketbase-analysis.md
T

7.9 KiB
Raw Blame History

PocketBase 底层技术架构深度分析

对标项目:PocketBase v0.37.1Go vs raisfastRust 目的:分析 PocketBase 的核心架构设计,识别值得借鉴的特性,制定实施优先级。

一、架构概览

维度 PocketBase (Go) raisfast (Rust)
语言 Go 1.25 Rust 2024
数据库 嵌入式 SQLitemodernc.org/sqlite,纯 Go 无 CGO 嵌入式 SQLitesqlx + libsqlite3-sys
HTTP 框架 自研路由(core.ServeEvent.Router Axum 0.8
二进制体积 ~12MB(单文件可执行) ~28MB
扩展方式 Go 框架 / 内嵌 JS VMgoja Lua / JS / WASM 插件
无状态 JWT 不存储 token,纯 HS256 无状态 存储 refresh token 到 DB
实时推送 SSE 内建
Admin UI 内建(/_/ 无(仅有博客前台)

二、核心设计理念

1. 极简单文件部署

PocketBase 的核心哲学是 "下载即用":单个二进制文件包含所有功能(SQLite、Web UI、API server、Auth、文件上传),零配置启动。Go 的交叉编译特性使其天然适合这个模型。

2. 双数据库架构

PocketBase 使用两个 SQLite 文件:

  • data.db — 业务数据(collections/records
  • auxiliary.db — 日志和临时系统数据

这样做的好处是日志写入不会干扰业务查询的 WAL 锁,值得借鉴。

3. Collection-Driven Schema

PocketBase 的核心抽象是 Collection(等价于 raisfast 的 ContentType)。每个 Collection 有:

  • 字段定义(schema
  • 5 条 API Rulelist/view/create/update/delete
  • 自动的 CRUD REST API

这与 raisfast 的 TOML schema 驱动方式高度一致。

三、值得借鉴的 6 个关键设计

借鉴 1:表达式级 API Rule 系统(高优先级)

这是 PocketBase 最强大的功能。每个 Collection 的 5 条 RulelistRule/viewRule/createRule/updateRule/deleteRule)都是运行时表达式,不是简单的公开/私有标志。

// 示例:只返回已发布且作者为自己的文章
status = "published" && author = @request.auth.id

// 示例:只有管理员可以删除
@request.auth.role = "admin"

// 支持跨 collection 查询
@collection.orders.user ?= @request.auth.id

PocketBase 的 filter 引擎ganigeorgiev/fexpr)支持:

  • 比较:= != > >= < <=
  • 模糊匹配:~ !~LIKE
  • 多值操作:?= ?!= ?~ANY/AT LEAST ONE OF
  • @request.* 上下文:auth user、body、query、headers
  • @collection.* 跨表引用
  • @now 时间宏
  • :isset / :changed / :length / :each 修饰符
  • geoDistance() 地理距离函数
  • strftime() 时间格式化

raisfast 现状check_api_access() 只是简单的枚举(public/authenticated/admin/none),没有表达式级别的过滤。

建议:实现一个 RuleEngine,将 API Rule 解析为 SQL WHERE 子句。可以先支持基础子集:

  • 字段比较:status = "published"
  • 认证上下文:@request.auth.id
  • 逻辑组合:&& / ||

借鉴 2SSE 实时订阅(高优先级)

PocketBase 内建了 Server-Sent Events (SSE) 实时订阅:

GET /api/realtime          → 建立 SSE 连接
POST /api/realtime         → 设置订阅主题
  • 订阅粒度:整个 Collection 或单条 Record
  • 自动权限检查:订阅 Collection 用 listRule,订阅 Record 用 viewRule
  • 5 分钟无消息自动断开(防泄漏连接)

raisfast 现状:没有实时推送能力。

建议:基于 Axum 的 tokio-stream + SSE 实现。架构:

  • EventBus 已存在,可复用
  • 新增 /api/realtime SSE endpoint
  • 客户端发送 POST /api/realtime 设置订阅
  • 每次 CUD 操作后,通过 EventBus 广播 → SSE 推送

借鉴 3:skipTotal 优化(中优先级,低工作量)

PocketBase 的列表 API 支持 ?skipTotal=true 参数,跳过 COUNT(*) 查询,totalItemstotalPages 返回 -1

为什么重要SQLite 的 COUNT(*) 在大数据集上会全表扫描。当用户只是翻页浏览时,第二页开始不需要总数。

raisfast 现状:每次列表查询都执行 SELECT COUNT(*)

建议:在 ContentQueryskip_total: bool 字段,ListParamsskip_total 参数,条件跳过 count 查询。

借鉴 4:Batch API(中优先级)

PocketBase 支持 POST /api/batch,在一个事务中批量执行多个 create/update/upsert/delete 操作:

{
  "requests": [
    { "method": "POST", "url": "/api/collections/posts/records", "body": {"title": "test1"} },
    { "method": "PATCH", "url": "/api/collections/posts/records/xxx", "body": {"title": "test2"} },
    { "method": "DELETE", "url": "/api/collections/posts/records/yyy" }
  ]
}
  • 整个 batch 在单个事务中执行,失败全部回滚
  • 减少 HTTP 往返次数

raisfast 现状:没有批量操作 API。

建议:新增 POST /api/v1/batch endpoint,接收请求数组,在单个 SQLite 事务中执行。

借鉴 5:无状态 JWT(低优先级,架构差异)

PocketBase 不存储任何 JWT token

  • Access tokenHS256 签发后不存 DB
  • 没有 refresh token 机制
  • "登出" = 客户端删除 token
  • authRefresh 接口不废止旧 token,只是返回新 token

raisfast 现状:有完整的 refresh token 机制(存 DB),更安全但也更慢。

建议:这是架构取舍,不需要改。raisfast 的双 token 方案更适合需要强安全控制的场景(企业 CMS),这是差异化优势。

借鉴 6:内置 Admin Dashboard UI(高优先级,差异化机会)

PocketBase 的杀手级特性是开箱即用的 Admin UI(/_/),功能包括:

  • Collection 可视化管理(增删改字段)
  • Record 数据浏览和编辑
  • API Rule 配置界面
  • Auth 用户管理
  • 日志查看
  • 系统设置

raisfast 现状:前端 web/ 是博客前台,不是管理后台。

建议:基于现有的 Next.js + shadcn/ui 搭建 Admin Dashboard,核心页面:

  1. Collection Manager(字段拖拽编辑)
  2. Record Browser(表格 + 筛选)
  3. API Rule Editor(表达式编辑器)
  4. 用户管理

四、性能优化对照

优化项 PocketBase raisfast 现状
SQLite PRAGMA busy_timeout=10000, WAL, synchronous=NORMAL, cache_size=-32000 已优化(Phase 1.1
JWT 缓存 每次解析但 HS256 开销极小 已缓存 DecodingKeyPhase 1.2
Filter→SQL 编译 fexpr 解析为 AST → 直接映射 SQL 尚未实现表达式过滤
列表缓存 无内置缓存(纯 SQL DashMap TTL 缓存(Phase 1.3
并发数据结构 Go map + sync.RWMutex DashMap + ArcSwapPhase 2.1/2.2
Relation 批量化 WHERE IN 批量查询 已实现批量 OneToMany/ManyToManyPhase 2.3

五、PocketBase 核心依赖栈

组件 说明
SQLite 驱动 modernc.org/sqlite 纯 Go,无 CGO
数据库抽象 pocketbase/dbx 自研 query builder
JS 引擎 dop251/goja ECMAScript 2020
表达式解析 ganigeorgiev/fexpr 自研 filter 表达式引擎
JWT golang-jwt/jwt/v5 HS256
密码哈希 golang.org/x/crypto bcrypt
图片处理 disintegration/imaging 缩略图生成
MIME 检测 gabriel-vasile/mimetype 文件类型识别
邮件发送 domodwyer/mailyak SMTP
CLI spf13/cobra 命令行框架
文件监听 fsnotify/fsnotify 热重载

六、实施优先级建议

优先级 功能 工作量 用户价值
P0 skipTotal 优化 1-2h 立即提升列表查询性能
P1 SSE 实时订阅 1-2d 前端实时更新的核心能力
P1 表达式级 API Rule 3-5d 安全模型质变,对标 Strapi
P2 Batch API 1-2d 减少前端 HTTP 往返
P2 Admin Dashboard UI 1-2 周 可用性的关键差异
P3 双数据库分离 0.5d 日志写入不影响业务性能