Petrichor 技术可视化 · Backend Stack Selection

后端框架技术选型

一张图看清 Petrichor 服务端用了什么、为什么这么选。没有独立后端——Next 16 Route Handlers + Server Actions 就是 API,Drizzle ORM 一份 schema 跨 PostgreSQL / SQLite,鉴权自托管、横切托管。 选型取自 src/serverpackage.json

前端选型 ↗ Agent 架构 ↗
一句话本质:一个 Next 进程装下整个后端,横切能免运维就免运维。

Route Handlers + Server Actions 就是 API,Drizzle 一份 schema 跨 PostgreSQL / SQLite; 鉴权自托管(Better Auth)、缓存与存储走托管(Upstash / S3)。选型来源是仓库里真实的 src/server

Node 22 → Next 16 API → Drizzle/PG → Better Auth → AI 运行时 → 领域服务

01 · 分层全景

六层栈:从运行时底座到接口横切

点步进器或图里的任意一层聚焦;下方详情会列出该层的真实依赖与选它的理由。上层依赖下层,越往上越贴近请求、越薄。

上层依赖下层
接口与横切 Route Handler API · Zod · Upstash Redis · S3 预签名 6 领域服务层 assistant · kb · doc-library · dashboard 5 AI 运行时 Vercel AI SDK · Mastra · MCP(mcp-handler) 4 身份与安全 Better Auth · bcrypt · AES-256 凭据加密 3 数据持久层 PostgreSQL + pgvector · Drizzle ORM · postgres.js 2 运行时底座 Node 22 · TypeScript 5.9 · Next 16 Route Handlers 1

提示:悬停某一层看它的一句话定位,点击则展开该层的依赖清单与选型理由。

键盘 ← → 切层 · P 导览 · Esc 退出聚焦

02 · 选型原则

四条不成文的规矩

这些原则不写在代码里,但决定了上面每一层为什么长这样。

单体优先,无独立后端

Next Route Handlers + Server Actions 同仓同进程,省一层网络与部署;要对外集成再开 MCP / Agent API Key,不为「后端」单独起一套服务。

类型贯通到库

Drizzle schema.ts 即类型源头,Zod 守外部边界,端到端 TypeScript,无 codegen 步骤——改一张表,编译器立刻在调用处报错。

凭据不明文落库

密码 bcrypt、AI 密钥 AES-256 加密后入库、危险操作走确认闸门。安全不靠自觉,靠结构——明文永不落盘。

一份 schema,两处运行

同一份 Drizzle schema:生产走 PostgreSQL、本地走 SQLite,本地零外部依赖起跑;查询避开方言特有语法,靠 ORM 抹平差异。

03 · 关键抉择

六个岔路口,选了什么、放弃了什么

每一条都有真实备选。列出来是为了让「为什么不是那个」也留痕。

ORM

选择Drizzle ORM
备选Prisma
理由SQL-first、无生成步骤、schema 即类型,pg + sqlite 双方言;轻到能塞进 serverless 冷启动。

PostgreSQL 驱动

选择postgres.js
备选node-postgres(pg)
理由更快、标签模板 SQL;prepare:false + max:1 适配连接池 / serverless,不踩预处理语句缓存坑。

API 形态

选择Route Handlers + Server Actions
备选独立 Nest / Express 服务
理由同仓同进程、共享类型、一键部署;对外集成才开 MCP + Agent API Key,不为「后端」单独起一套。

鉴权

选择Better Auth
备选NextAuth / Clerk
理由自托管、drizzle adapter 存库、内置 2FA;无外部依赖与按量计费,账号数据全在自己库里。

数据库迁移

选择手写 SQL 迁移
备选drizzle-kit push(生产)
理由生产用可审计的原生 SQL(含 pgvector / pg_trgm 扩展),drizzle-kit 只在本地开发用。

缓存 / KV

选择Upstash Redis
备选自建 Redis 实例
理由HTTP 协议、serverless 友好、免运维;只做缓存与轻状态,主数据永远以 PostgreSQL 为准。

04 · 完整选型清单

10 个域,一屏看全后端依赖

逐条取自 apps/web/src/serverpackage.json。颜色标出每个依赖在选型里的角色。

后端依赖面板

核心主干是自持的服务端逻辑;托管服务把横切外包;基建类是自托管基础设施与加密;虚线红 是仅本地或可替换项。

运行时 & 语言runtime
Node 22 TypeScript 5.9 Next 16 Server Actions tsx
数据库 & ORMdatabase
PostgreSQL pgvector pg_trgm drizzle-orm postgres.js better-sqlite3 drizzle-kit
鉴权 & 安全auth
better-auth @better-auth/drizzle-adapter two-factor bcryptjs AES-256 · node:crypto
AI 运行时ai-runtime
ai · Vercel AI SDK @ai-sdk/openai @mastra/core @mastra/ai-sdk @modelcontextprotocol/sdk mcp-handler
校验 & 契约contract
zod http 统一响应 分页 pagination
缓存 & KVcache
@upstash/redis
存储 & 上传storage
S3 预签名 local-storage 兜底 uploadthing sharp
领域服务domains
assistant kb doc-library agent dashboard notification public-site
落档 & 可观测observability
thread / run / step 落库 响应头 Thread-Id / Run-Id
工具链tooling
tsx drizzle-kit vitest eslint biome check
主干核心主干 托管托管服务 · SaaS 基建自托管 / 基础设施 / 加密 备选仅本地 · 可替换

选型边界(known tensions)

  • 全部塞进一个 Next 进程:好处是零网络、共享类型;代价是重活(长任务、批处理)只能靠 maxDuration 与外挂队列,量大了要拆服务。
  • 双方言(PG / SQLite)要靠纪律:查询一律走 Drizzle、避开方言特有语法;pgvector / pg_trgm 是 Postgres 独有,SQLite 模式下相关能力降级。
  • 迁移是手写 SQL:可审计但需人肉保证与 Drizzle schema 同步,drizzle-kit 仅辅助本地。
  • 缓存 / 限流依赖 Upstash 可用性:Redis 只做加速与轻状态,主数据永远以 PostgreSQL 为准,Redis 挂了不影响正确性。
  • AI 供应商密钥虽 AES-256 加密,但密钥管理仍在应用层:轮换与泄露响应需要额外流程,当前靠确认闸门 + 全量落档兜底。