feat: add organization tenant model

This commit is contained in:
2026-07-09 23:37:20 +08:00
parent 5d315fff21
commit 2b7aa3294f
20 changed files with 900 additions and 116 deletions
+22 -5
View File
@@ -10,6 +10,10 @@ export interface ActorInput {
readonly chatId?: string | undefined;
}
export interface PrincipalResolutionScope {
readonly organizationId: string;
}
export type PrincipalSource =
| "actor-user"
| "context-chat"
@@ -25,19 +29,20 @@ export interface ResolvedPrincipal {
export interface PrincipalResolution {
readonly actor: ActorInput;
readonly organizationId: string;
readonly userId?: string | undefined;
readonly principals: readonly PrincipalRef[];
readonly resolved: readonly ResolvedPrincipal[];
}
export interface PrincipalResolver {
resolveActor(actor: ActorInput): Promise<PrincipalResolution>;
resolveActor(actor: ActorInput, scope: PrincipalResolutionScope): Promise<PrincipalResolution>;
}
export class PrismaPrincipalResolver implements PrincipalResolver {
constructor(private readonly prisma: PrismaClient) {}
async resolveActor(actor: ActorInput): Promise<PrincipalResolution> {
async resolveActor(actor: ActorInput, scope: PrincipalResolutionScope): Promise<PrincipalResolution> {
const resolved = new PrincipalCollector();
resolved.add({ type: "USER", id: actor.feishuOpenId }, "actor-user");
if (actor.chatId !== undefined && actor.chatId !== "") {
@@ -51,7 +56,11 @@ export class PrismaPrincipalResolver implements PrincipalResolver {
if (user !== null) {
const memberships = await this.prisma.teamMembership.findMany({
where: { userId: user.id, revokedAt: null, team: { archivedAt: null } },
where: {
userId: user.id,
revokedAt: null,
team: { organizationId: scope.organizationId, archivedAt: null },
},
select: { teamId: true },
});
for (const membership of memberships) {
@@ -59,7 +68,14 @@ export class PrismaPrincipalResolver implements PrincipalResolver {
}
const externalMemberships = await this.prisma.externalPrincipalMembership.findMany({
where: { userId: user.id, revokedAt: null },
where: {
userId: user.id,
revokedAt: null,
connection: {
organizationId: scope.organizationId,
revokedAt: null,
},
},
select: { principalType: true, principalId: true },
});
for (const membership of externalMemberships) {
@@ -75,7 +91,7 @@ export class PrismaPrincipalResolver implements PrincipalResolver {
const bindings = await this.prisma.teamExternalBinding.findMany({
where: {
revokedAt: null,
team: { archivedAt: null },
team: { organizationId: scope.organizationId, archivedAt: null },
OR: externalPrincipals.map((principal) => ({
principalType: principal.type,
principalId: principal.id,
@@ -94,6 +110,7 @@ export class PrismaPrincipalResolver implements PrincipalResolver {
return {
actor,
organizationId: scope.organizationId,
...(user !== null ? { userId: user.id } : {}),
principals: resolved.principals(),
resolved: resolved.entries(),