想去哪里?

首页 页面 关于 页面 项目 页面 简历 页面 技术 页面 随笔 页面 联系 页面 隐私政策 页面 Terminal Spike 隐私政策 页面 用 Astro 构建文档与职业个人网站 技术 通过 tmux、Mosh、Termius 与 Tailscale 随处使用 Codex 技术 用 Langfuse 观察 Codex 的 MCP 工具调用 技术 产品应用中的本地化 技术 把 MCP 作为安全的 AI 集成边界 技术 用 Zod、OpenAPI 与 Swagger 维护 API 契约 技术 用 pg-boss 运行持久后台任务 技术 通过真实知识工作流理解 pgvector 与 RAG 技术 Pi Edge:让 Pi 待在 Obsidian 笔记旁 技术 为真实排序任务设计拖放交互 技术 Prisma 与 PostgreSQL:产品状态的事实来源 技术 把 Ralph Loop 当作计划队列 技术 用 React Router 组织全栈产品工作流 技术 把 shadcn 风格组件变成自己的产品系统 技术 用表格与编辑器承载密集业务操作 技术 Terminal Spike:原生 Android 终端 技术 在 Linux 上用 fcitx 输入带声调的拼音 技术 在 Linux 上配置 DEFT Pro 轨迹球 技术 在 KOReader 上使用 Pocket 稍后读 技术 为 Vercel AI SDK 设置明确的工具边界 技术 垂直切片架构与 dependency-cruiser 技术 用 Vitest 与 Playwright 测试产品工作流 技术 我的随处工作流:Herdr、code-server、Obsidian 与 Pi Edge 技术 Zod 不只是校验 技术 《卡拉马佐夫兄弟》是我看过最好的小说 随笔 基督徒口述1960劳改历史 随笔 圣经中的“道”与言语 随笔 我们爱,因为神先爱我们,而不是空洞的“自爱” 随笔 妈妈,让我来承担爸爸的过错吧 随笔 我与神的故事 随笔 世界远离上帝,接近中国 随笔 “爱的五种语言”和内外向,只存在于语言中 随笔 人格类型不存在,你在世界而非概念中生活 随笔 危险的词语:为什么心理学是不可能的 随笔 2000 年,一个深圳打工者的故事 随笔 阿联酋Ras al Khaimah见闻录 随笔 沙甸:1975 年的一场冲突 随笔 关于中国的纪录片 随笔
← 技术/工程实践

Prisma 与 PostgreSQL:产品状态的事实来源

持久状态为何属于数据库,以及如何避免 Prisma 渗透应用各处。

我不把 PostgreSQL 只当作基础设施。对于产品,它是记住发生过什么的地方。

因此数据库设计也是产品决策。用户创建请求后,系统应知道创建者、当前状态、修改时间,以及后续流程允许做什么。界面可以展示状态,却不应成为事实来源。

Prisma 让数据模型在代码中可见,并提供有类型的数据库访问:

export async function createRequest(input: CreateRequestInput) {
  return db.request.create({
    data: {
      title: input.title,
      status: "draft",
      createdById: input.userId,
    },
  });
}

这只是简化示例。重点是边界:后续工作流应读取数据库里的持久状态,而不是从页面、缓存或客户端对象猜测。

Prisma 很方便,容易出现在路由、组件、后台 worker 和测试的每个角落,产品规则也随之悄悄散开。

例如请求只有具备标题且用户有权限时才能提交。这条规则不应复制到三个路由 action 中,应该放在服务后面:

export async function submitRequest(input: SubmitRequestInput) {
  const request = await requestRepo.findForUpdate(input.requestId);
  assertCanSubmit(request, input.userId);
  return requestRepo.updateStatus(request.id, "submitted");
}

repository 仍可使用 Prisma,服务负责规则。

PostgreSQL 也不只是存储。一次流程修改多个对象时需要事务;必须杜绝坏状态时需要约束;产品增长后常用页面仍要快,就需要索引。

代价是必须认真设计数据库。迁移和权限都需要谨慎。今天看似无害的字段,明天可能成为公开行为的一部分,之后改名或删除会比想象困难。

Prisma 让 schema 更容易审查,生成类型能抓住许多简单错误,却不能消除这些设计工作。如果忘记底层数据库,也容易忽略查询成本。

我偏好的分工是:PostgreSQL 存持久状态;Prisma 提供类型访问和迁移;服务承载产品规则;路由与 worker 调用服务;测试在规则所在处验证规则。

这并非适用于所有项目。特殊 SQL、重分析或 Prisma 不擅长表达的数据库特性,可以直接用 SQL。小原型也可以先接受更直接的 Prisma 调用,直到流程确实需要更强的边界。

重点不在 Prisma 本身,而在于把持久状态当作产品契约。用户一旦依赖它,就应该有清楚的归属。