数据库配置
使用 Postgres 与 Drizzle ORM 为 Better Auth 和业务表搭建数据层。
数据库是现代 SaaS 的中心。几乎所有能力——认证、计费、积分、存储、用量追踪,甚至演示模块——都会落到数据库。我们有时自嘲是“CRUD 工程师”:增删改查是日常工作。随着 schema 变大,把数据库当作地基,能让应用保持可预期。
本文将数据库放在首位:先讲表如何映射到功能,再讲如何用 Drizzle 做类型安全的 CRUD,最后讲连接、迁移与验证。
为什么数据库要先行
- 事实来源:auth、计费、文件、任务都持久化在此,并在服务/API 层做关联查询。
- 模型 → 类型 → UI:
src/db/schema.ts
中的 Drizzle 模型产出的类型会在模型与路由中共享。 - CRUD 即产品界面:大多数页面本质上是列表/详情的读写。表设计得好,UI 就容易交付。
关键域(表 → 功能)
- 认证:
users
、sessions
、accounts
、verifications
(Better Auth)。 - 计费与积分:
orders
、credits
记录购买与积分流水。 - 存储:
files
保存 S3/R2 对象元数据与生命周期(uploading → active → deleted)。 - 用量与任务(AI):
tasks
记录 queued/running/completed,并以credits_trans_no
关联到积分账本。 - 内容:
posts
。 - 增长与反馈:
affiliates
、feedbacks
。 - 演示:
reservation_services
、reservations
展示排期/订金支付模式。
代码中的 CRUD 优先模式
- 模型位于
src/models/*
,提供类型化的 helper:src/models/file.ts
:insertFile
、findFileByUuid
、updateFileByUuid
、listFilesByUser
、softDeleteFile
。src/models/task.ts
:insertTask
、findTaskByUuid
、getTasksByUserUuid
、updateTaskStatus
。
- 服务与 API 路由调用这些 helper;尽量集中数据库访问,避免散落查询。
- 新功能路径:在
src/db/schema.ts
建表/加列 →pnpm drizzle-kit generate
→pnpm drizzle-kit migrate
→ 添加src/models/<domain>.ts
→ 在src/services/*
与路由中使用。
1. 什么是 Drizzle ORM?
Drizzle ORM 是连接 TypeScript 与 Postgres 的类型安全层。src/db/schema.ts
中的定义就是唯一数据源,它让我们可以:
- 通过
drizzle-kit
生成迁移 SQL - 将迁移执行到 Postgres
- 在项目中共享类型(例如
users.$inferSelect
)
无需手写 SQL,直接修改 schema 文件,再让 Drizzle 负责生成和执行迁移即可。
2. 选择你的数据库方案
根据实际情况更新 .env
。
场景 | 建议 |
---|---|
仅本地开发 | 使用 Docker 启动 Postgres(如 docker run ... postgres:16 ),DATABASE_URL 指向 postgres://postgres:postgres@localhost:5432/postgres 。 |
托管 Postgres(Neon、Supabase、Railway 等) | 使用服务商提供的连接串,并允许执行迁移的 IP 访问。 |
不同环境使用不同数据库 | .env 保留本地配置,生产环境在部署平台中配置相同的环境变量。 |
已有数据库并含其它表 | Drizzle 只会修改 src/db/schema.ts 声明的表。确认没有命名冲突,必要时可以使用独立 schema。 |
注意:Drizzle 不会自动创建数据库,请先手动创建空库再执行迁移。
3. 配置环境变量
设置连接字符串和 Better Auth 的密钥。项目默认读取 .env
、.env.local
、.env.development
。
DATABASE_URL="postgresql://user:password@host:5432/db?sslmode=require"
BETTER_AUTH_SECRET="$(openssl rand -base64 32)"
BETTER_AUTH_URL="http://localhost:3000"
修改后务必重启 pnpm dev
,确保进程读取最新值。
4. 理解相关文件
src/db/schema.ts
– 定义 Better Auth 的核心表(users
、sessions
、accounts
、verifications
)以及业务表:orders
、credits
、files
、tasks
、posts
、affiliates
、feedbacks
、reservation_services
、reservations
。src/db/config.ts
– drizzle-kit 的配置(schema 路径和 Postgres 连接)。src/lib/auth.ts
– Better Auth 字段与 Drizzle 列的映射。如果重命名了users
的列,这里也要调整。
添加列或表时,先改 schema.ts
,再同步更新 auth.ts
中的映射。建议在 schema.ts
中为高频查询添加索引(uniqueIndex
/index
),以便数据增大后仍能保持读取性能。
5. 代码变更后生成迁移
每次修改 schema.ts
都需要执行:
pnpm drizzle-kit generate --config src/db/config.ts
示例输出:
Reading config file 'src/db/config.ts'
...
[✓] Your SQL migration file ➜ src/db/migrations/0002_add_user_flag.sql 🚀
会生成:
src/db/migrations/<timestamp>_*.sql
src/db/migrations/meta/_journal.json
请把它们都提交到版本库。
6. 将迁移应用到 Postgres
执行生成好的 SQL:
pnpm drizzle-kit migrate --config src/db/config.ts
成功输出示例:
Applying migrations from src/db/migrations
Migration 0002_add_user_flag.sql executed in 380 ms
All migrations applied!
如遇认证失败,检查 DATABASE_URL
;若超时或卡住,确认网络权限或数据库是否启动。
7. 验证结果
使用任意 Postgres 客户端检查表和列。psql
示例:
\dt
SELECT * FROM sessions LIMIT 1;
SELECT email_verified FROM users LIMIT 1;
你应该能看到 Better Auth 的表以及核心业务表。做一个最小 CRUD 烟测:通过一个模型 helper 插入并读取一行(例如,调用 POST /api/storage/uploads
创建一条 files
记录,然后 SELECT * FROM files LIMIT 1;
)。
8. 体验认证流程
迁移完成后,重启 pnpm dev
,打开 /zh/signup
(或其它语言路径)注册账号。成功注册后会跳回首页,并能在 users
、sessions
表中看到新记录。
9. 常见问题排查
- Error: model "userss" not found – 确认
src/lib/auth.ts
中引用的是users
表,移除旧示例里的usePlural
。 - 缺少列 – 修改了
schema.ts
却没有执行generate
和migrate
。请重新执行。 - 连接失败 – 确认数据库存在、账号密码正确、SSL/网络策略允许访问。
- 需要清空数据 – 手动删除表或使用 drizzle-kit 生成的 SQL 回滚,然后重新
generate
→migrate
。
遵循「修改代码 → 生成迁移 → 执行迁移 → 验证」的流程,就能避免认证接口返回 500 错误。