feat: add paginated project discovery

This commit is contained in:
2026-07-12 01:45:15 +08:00
parent 53d372e29b
commit 816af1abdb
14 changed files with 1505 additions and 237 deletions
+47 -2
View File
@@ -53,6 +53,13 @@ export interface ArchiveFeishuChatBindingInput {
readonly actorFeishuOpenId: string;
}
export interface RenameProjectForActorInput {
readonly organizationId: string;
readonly projectId: string;
readonly actorFeishuOpenId: string;
readonly name: string;
}
export interface CreateFolderInput {
readonly organizationId: string;
readonly name: string;
@@ -131,6 +138,44 @@ export async function moveProjectToFolder(
});
}
export async function renameProjectForActor(
prisma: PrismaClient,
input: RenameProjectForActorInput,
): Promise<{ readonly projectId: string; readonly name: string }> {
const name = requireNonEmpty(input.name, "project name");
const project = await prisma.project.findUnique({
where: { id: input.projectId },
select: { id: true, organizationId: true, name: true },
});
if (project === null) throw new Error(`project not found: ${input.projectId}`);
if (project.organizationId !== input.organizationId) {
throw new Error(`project ${project.id} does not belong to organization ${input.organizationId}`);
}
const actor = await requireProjectManager(prisma, project.id, project.organizationId, input.actorFeishuOpenId);
const updated = await prisma.$transaction(async (tx) => {
await lockActiveOrganization(tx, project.organizationId);
const current = await tx.project.findUniqueOrThrow({
where: { id: project.id },
select: { name: true },
});
const renamed = await tx.project.update({
where: { id: project.id },
data: { name },
select: { id: true, name: true },
});
await tx.auditEntry.create({
data: {
projectId: project.id,
actorUserId: actor.userId,
action: "project.renamed",
metadata: { oldName: current.name, newName: name, actorVia: actor.via },
},
});
return renamed;
});
return { projectId: updated.id, name: updated.name };
}
export async function createProjectFromOrgAdmin(
prisma: PrismaClient,
input: CreateOrgAdminProjectInput,
@@ -494,12 +539,12 @@ async function ensureOrganizationProjectSettingsTx(
async function ensureInboxFolder(prisma: Prisma.TransactionClient, organizationId: string): Promise<{ readonly id: string }> {
const existing = await prisma.folder.findFirst({
where: { organizationId, parentId: null, name: "Inbox", archivedAt: null },
where: { organizationId, kind: "SYSTEM_INBOX", archivedAt: null },
select: { id: true },
});
if (existing !== null) return existing;
return prisma.folder.create({
data: { organizationId, name: "Inbox", sortKey: "000000" },
data: { organizationId, name: "Inbox", kind: "SYSTEM_INBOX", sortKey: "000000" },
select: { id: true },
});
}