团队里最让人抓狂的技术债,绝对是“改了数据库结构,却从不改文档”。每次新同学在群里问某个表或者某个字段是干什么用的,老员工的回应永远是:“哦,那个字段早就废弃了,现在是用另外一个,文档还没来得及更新。”久而久之,项目里费劲维护的数据库设计文档直接沦为废纸。

靠开发人员的自觉性去手动更新文档是根本行不通的。既然我们项目里用了 Prisma 作为 ORM 框架,数据库的唯一事实来源就是 schema.prisma,那为什么不把文档生成直接做成自动化的 CI/CD 流程?

我们目前的做法是利用 prisma-markdown 这个生成器,配合 huskylint-staged,在开发同学执行 git commit 的瞬间,自动解析 Prisma schema 文件,在本地渲染出最新的 Markdown 格式表结构说明和 Mermaid ER 关系图,并强行将其一起打包提交。

首先,在我们的 schema.prisma 中声明 markdown 文档生成器。这样每次运行 prisma generate 时,就会自动生成对应的文档:

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

generator client {
  provider = "prisma-client-js"
}

// 引入 markdown 生成器
generator markdown {
  provider = "prisma-markdown"
  output   = "../docs/database.md"
  title    = "核心业务系统数据库架构设计"
}

model User {
  id        Int      @id @default(autoincrement())
  email     String   @unique
  name      String?
  role      Role     @default(USER)
  posts     Post[]
  createdAt DateTime @default(now())

  @@map("users")
}

model Post {
  id        Int      @id @default(autoincrement())
  title     String
  content   String?
  published Boolean  @default(false)
  authorId  Int
  author    User     @relation(fields: [authorId], references: [id])
  createdAt DateTime @default(now())

  @@map("posts")
}

enum Role {
  USER
  ADMIN
}

为了确保开发人员在提交代码前一定生成了最新的文档,我们在 package.json 中配置了对应的 npm scripts 以及 lint-staged 规则:

{
  "name": "homework-money-printer-site",
  "version": "1.0.0",
  "scripts": {
    "db:doc": "prisma generate --schema=./prisma/schema.prisma",
    "prepare": "husky install"
  },
  "dependencies": {
    "@prisma/client": "^5.10.0"
  },
  "devDependencies": {
    "husky": "^9.0.11",
    "lint-staged": "^15.2.2",
    "prisma": "^5.10.0",
    "prisma-markdown": "^1.0.9"
  },
  "lint-staged": {
    "prisma/schema.prisma": [
      "npm run db:doc",
      "git add docs/database.md"
    ]
  }
}

最后,在 .husky/pre-commit 钩子文件中,我们只需要添加一行极其简单的指令:

#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

npx lint-staged

这样折腾完以后,任何开发人员只要修改了 schema.prisma 里的任何一个字段或表关联关系,在执行 git commit 时,Husky 就会强行拦截,并在本地启动 Prisma 编译器更新 docs/database.md。紧接着,lint-staged 会自动把这个生成的文档也加入到当前的暂存区(Git Stage)中,随同业务代码一起提交上去。

这套方案跑了几个月,数据库文档再也没有落后过库表结构。唯一需要注意的踩坑点是,prisma-markdown 自动生成的 Mermaid ER 图如果实体太多,在一些低版本的 Markdown 阅读器里可能会因为图表过大导致渲染崩溃。对于超大型项目,建议分模块配置多个 schema 文件。

你们团队是怎么保证数据库定义和设计文档保持一致的?是靠 CI 脚本强行校验,还是干脆直接看数据库实体类代码?