我使用 Prisma 的应用程序有可以创建许多项目的用户。这些项目类似于文本文档,但具有一些有助于组织的附加属性。
这些项目将始终由最初创建它们的用户“拥有”,并且该用户可以控制其他用户的管理访问权限,无论是查看、评论甚至编辑。有权访问其他用户项目的用户在应用程序中被视为“协作者”。
在当前的应用程序架构中,用户可以创建并拥有多个协作者,并且创建用户可以完全控制协作者可以访问其哪些项目以及访问程度——查看、评论、编辑。
应用程序中的用户携带与用户相关的常规元数据,例如姓名和电子邮件。应用程序中的项目携带与项目相关的数据,例如项目名称和其他属性。
我创建了一个存储用户协作者(用户)的表,以便在页面上显示这些协作者的列表,用户可以在该页面上为协作者执行 CRUD 操作。
为了在主页上向用户显示与其关联的项目,我创建了另一个表,该表引用项目及其相关用户并添加一个角色,该角色定义该用户是所有者还是协作者。
这允许我在应用程序的主页上显示用户有权访问的项目,无论用户创建了该项目还是仅仅是一个协作者。
因此,当用户登录并进入其主页时,他们看到的是项目的完整列表,其中他们要么是所有者,要么只是合作者。
对于列表中用户是所有者的项目,我需要显示代表该项目合作者的头像列表。
为什么我应该做其中之一
model User {
id String @id @default(cuid())
name String?
email String? @unique
emailVerified DateTime?
image String?
accounts Account[]
sessions Session[]
collaborator UserCollaborator[] @relation("Collaborator")
userCollaborators UserCollaborator[] @relation("UserCollaborators")
collabInviteReceived UserCollaboratorInvite[] @relation("InviteReceived")
collabInviteSent UserCollaboratorInvite[] @relation("InviteSent")
userProjects UserProject[]
}
model Project {
id String @id @default(cuid())
name String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
things Thing[]
userProjects UserProject[]
}
model UserProject {
projectId String
roleId Int
userId String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
role Role @relation(fields: [roleId], references: [id])
user User @relation(fields: [userId], references: [id])
userCollaboratorProjects UserCollaboratorProject[]
@@id([userId, projectId])
}
model UserCollaborator {
ownerId String
collaboratorId String
roleId Int
status CollaboratorStatusEnum
// this is the user who is the collaborator
collaborator User @relation("Collaborator", fields: [collaboratorId], references: [id])
// this is the user who created the collaborator
owner User @relation("UserCollaborators", fields: [ownerId], references: [id])
role Role @relation(fields: [roleId], references: [id])
userCollaboratorProjects UserCollaboratorProject[]
@@id([ownerId, collaboratorId])
}
model UserCollaboratorProject {
userProjectProjectId String
userProjectUserId String
userCollaboratorOwnerId String
userCollaboratorCollaboratorId String
userCollaborator UserCollaborator @relation(fields: [userCollaboratorOwnerId, userCollaboratorCollaboratorId], references: [ownerId, collaboratorId], onDelete: Cascade)
userProject UserProject @relation(fields: [userProjectUserId, userProjectProjectId], references: [userId, projectId], onDelete: Cascade)
@@id([userProjectUserId, userProjectProjectId, userCollaboratorOwnerId, userCollaboratorCollaboratorId])
}
您的设计中的一个问题是使项目所有者与项目合作者区分开来。这些重叠。例如,当您想要列出用户正在参与的所有项目时。
您可以通过定义一个新实体来解决这个问题,我将其称为“项目参与者”。这是参与该项目的每个人:所有者、管理员、查看者、编辑者等。这就是您想要列出的内容。
另一个问题是让协作者由拥有该项目的用户“拥有”。这就是数据重复。它导致合作者的所有者可能不是项目所有者的可能性。
合作者应该由项目“拥有”。从那里他们可以找到该项目的所有者。这消除了数据重复,协作者所有者不可能与项目所有者不同,并且可以更改谁“拥有”协作者的定义。
业务规则会发生变化,即使您已向您承诺不会发生变化。该模式应努力仅对基本关系进行硬编码。业务规则应该用数据或软件来完成。即使规则没有改变,这也会使您的设计对于附加功能更加灵活。
我将提议这些实体...
参与项目的每个用户都是项目参与者,包括创建者。
每个项目参与者都有一个或多个项目角色。这些将是查看、编辑、评论和所有者。稍后您可以添加更多内容,例如“admin”。
您只需在 ProjectParticipants 中列出用户的条目即可列出所有用户的项目。
角色的作用不是在架构中定义的,而是在软件中定义的。在您的情况下,您只允许该项目中项目角色为“所有者”的 ProjectParticipants 对其他 ProjectParticipants 进行更改。您可以稍后更改此设置,以允许“admin”等对 ProjectParticipants 进行更改。