本指南将教您如何为 DocStudio 配置 Prisma + PostgreSQL。
Prisma 是一个现代化的 TypeScript ORM(对象关系映射)工具,它提供:
- 类型安全:自动生成 TypeScript 类型
- 直观的 API:简洁的数据库操作语法
- 数据库迁移:版本控制数据库 schema
- Prisma Studio:可视化数据库管理工具
cd apps/api
pnpm add prisma @prisma/clientprisma:CLI 工具,用于迁移和生成代码@prisma/client:运行时客户端,用于查询数据库
pnpm dlx prisma init这会创建:
prisma/schema.prisma- 数据库 schema 定义文件.env- 环境变量文件(包含 DATABASE_URL)
# PostgreSQL 连接字符串格式
DATABASE_URL="postgresql://用户名:密码@主机:端口/数据库名?schema=public"
# 本地开发示例
DATABASE_URL="postgresql://postgres:postgres@localhost:5432/docStudio_dev?schema=public"
# 其他环境变量
PORT=3001
NODE_ENV=development
JWT_SECRET=your-secret-key-change-this根据 DocStudio 技术规格文档,我们定义以下模型:
// prisma/schema.prisma
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
// 用户模型
model User {
id String @id @default(cuid())
email String @unique
name String
password String? // 可选:如果使用 GitHub OAuth
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// 关系
ownedSpaces Space[] @relation("SpaceOwner")
spacePermissions SpacePermission[]
@@map("users")
}
// 空间模型
model Space {
id String @id @default(cuid())
name String
ownerId String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// 关系
owner User @relation("SpaceOwner", fields: [ownerId], references: [id], onDelete: Cascade)
documents Document[]
permissions SpacePermission[]
@@map("spaces")
}
// 文档模型
model Document {
id String @id @default(cuid())
spaceId String
parentId String? // 支持层级结构
title String
ydocKey String @unique // Yjs 文档标识符
order Int @default(0) // 排序
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// 关系
space Space @relation(fields: [spaceId], references: [id], onDelete: Cascade)
parent Document? @relation("DocumentHierarchy", fields: [parentId], references: [id], onDelete: Cascade)
children Document[] @relation("DocumentHierarchy")
shareTokens ShareToken[]
@@index([spaceId])
@@index([parentId])
@@index([ydocKey])
@@map("documents")
}
// 空间权限模型
model SpacePermission {
id String @id @default(cuid())
userId String
spaceId String
role Role @default(VIEWER)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// 关系
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
space Space @relation(fields: [spaceId], references: [id], onDelete: Cascade)
@@unique([userId, spaceId]) // 一个用户在一个空间只能有一个角色
@@map("space_permissions")
}
// 分享令牌模型
model ShareToken {
id String @id @default(cuid())
docId String
token String @unique @default(cuid())
permission Permission @default(READ)
expiresAt DateTime?
createdAt DateTime @default(now())
// 关系
document Document @relation(fields: [docId], references: [id], onDelete: Cascade)
@@index([token])
@@map("share_tokens")
}
// 枚举:角色
enum Role {
OWNER
EDITOR
VIEWER
}
// 枚举:权限
enum Permission {
READ
WRITE
}# 创建迁移文件
pnpm dlx prisma migrate dev --name init
# 这会:
# 1. 在数据库中创建表
# 2. 生成 TypeScript 客户端
# 3. 创建迁移历史文件pnpm dlx prisma generate这会生成类型安全的查询客户端。
创建 Prisma 服务:
// src/prisma/prisma.service.ts
import { Injectable, OnModuleInit } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';
@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit {
async onModuleInit() {
await this.$connect();
}
async enableShutdownHooks(app: any) {
this.$on('beforeExit', async () => {
await app.close();
});
}
}创建 Prisma 模块:
// src/prisma/prisma.module.ts
import { Global, Module } from '@nestjs/common';
import { PrismaService } from './prisma.service';
@Global()
export class PrismaModule {
static forRoot() {
return {
module: PrismaModule,
providers: [PrismaService],
exports: [PrismaService],
};
}
}在 AppModule 中注册:
// src/app.module.ts
import { Module } from '@nestjs/common';
import { PrismaModule } from './prisma/prisma.module';
@Module({
imports: [PrismaModule.forRoot()],
// ...
})
export class AppModule {}// 示例:在服务中使用
import { Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
@Injectable()
export class UserService {
constructor(private prisma: PrismaService) {}
// 创建用户
async createUser(email: string, name: string) {
return this.prisma.user.create({
data: { email, name },
});
}
// 查找用户
async findUserByEmail(email: string) {
return this.prisma.user.findUnique({
where: { email },
});
}
// 查找用户的所有空间
async getUserSpaces(userId: string) {
return this.prisma.space.findMany({
where: {
OR: [{ ownerId: userId }, { permissions: { some: { userId } } }],
},
include: {
owner: true,
permissions: true,
},
});
}
}# 格式化 schema.prisma
pnpm dlx prisma format
# 查看数据库结构
pnpm dlx prisma db pull
# 推送 schema 到数据库(开发时快速测试)
pnpm dlx prisma db push
# 打开 Prisma Studio(可视化数据库管理)
pnpm dlx prisma studio
# 重置数据库(⚠️ 会删除所有数据)
pnpm dlx prisma migrate reset
# 查看迁移状态
pnpm dlx prisma migrate status// prisma/seed.ts
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
async function main() {
// 创建测试用户
const user = await prisma.user.create({
data: {
email: 'test@docStudio.com',
name: 'Test User',
},
});
// 创建测试空间
await prisma.space.create({
data: {
name: 'My First Space',
ownerId: user.id,
},
});
}
main()
.catch((e) => console.error(e))
.finally(async () => await prisma.$disconnect());在 package.json 中添加:
{
"prisma": {
"seed": "ts-node prisma/seed.ts"
}
}运行:pnpm dlx prisma db seed
不同环境使用不同的数据库:
# .env.development
DATABASE_URL="postgresql://postgres:postgres@localhost:5432/docStudio_dev"
# .env.test
DATABASE_URL="postgresql://postgres:postgres@localhost:5432/docStudio_test"
# .env.production
DATABASE_URL="your-production-database-url"将 prisma/migrations/ 目录提交到 Git,团队成员运行 prisma migrate dev 同步数据库。
如果还没有 PostgreSQL,可以用 Docker 快速启动:
# docker-compose.yml
version: '3.8'
services:
postgres:
image: postgres:16-alpine
container_name: docStudio-postgres
restart: always
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: docStudio_dev
ports:
- '5432:5432'
volumes:
- postgres_data:/var/lib/postgresql/data
redis:
image: redis:7-alpine
container_name: docStudio-redis
restart: always
ports:
- '6379:6379'
volumes:
postgres_data:启动:docker-compose up -d
A: 运行 pnpm dlx prisma generate 生成客户端
A: 检查 .env 中的 DATABASE_URL 是否正确,确保 PostgreSQL 运行中
A: pnpm dlx prisma migrate reset(
A: 运行 pnpm dlx prisma migrate dev --name 描述 创建新迁移
- ✅ 配置 Prisma
- 🔜 实现 Auth 模块(JWT + Passport)
- 🔜 创建 Space 和 Document CRUD 接口
- 🔜 集成 Yjs + Hocuspocus 协作
更多信息请参考: