import { Injectable, Logger } from "@nestjs/common"; import { WorkspaceMemberRole } from "@prisma/client"; import { PrismaService } from "../prisma/prisma.service"; import type { WorkspaceResponseDto } from "./dto"; @Injectable() export class WorkspacesService { private readonly logger = new Logger(WorkspacesService.name); constructor(private readonly prisma: PrismaService) {} /** * Get all workspaces the user is a member of. * * Auto-provisioning: if the user has no workspace memberships (e.g. fresh * signup via BetterAuth), a default workspace is created atomically and * returned. This is the only call site for workspace bootstrapping. */ async getUserWorkspaces(userId: string): Promise { const memberships = await this.prisma.workspaceMember.findMany({ where: { userId }, include: { workspace: { select: { id: true, name: true, ownerId: true, createdAt: true }, }, }, orderBy: { joinedAt: "asc" }, }); if (memberships.length > 0) { return memberships.map((m) => ({ id: m.workspace.id, name: m.workspace.name, ownerId: m.workspace.ownerId, role: m.role, createdAt: m.workspace.createdAt, })); } // Auto-provision a default workspace for new users. // Re-query inside the transaction to guard against concurrent requests // both seeing zero memberships and creating duplicate workspaces. this.logger.log(`Auto-provisioning default workspace for user ${userId}`); const workspace = await this.prisma.$transaction(async (tx) => { const existing = await tx.workspaceMember.findFirst({ where: { userId }, include: { workspace: { select: { id: true, name: true, ownerId: true, createdAt: true }, }, }, }); if (existing) { return { ...existing.workspace, alreadyExisted: true as const }; } const created = await tx.workspace.create({ data: { name: "My Workspace", ownerId: userId, settings: {}, }, }); await tx.workspaceMember.create({ data: { workspaceId: created.id, userId, role: WorkspaceMemberRole.OWNER, }, }); return { ...created, alreadyExisted: false as const }; }); if (workspace.alreadyExisted) { return [ { id: workspace.id, name: workspace.name, ownerId: workspace.ownerId, role: WorkspaceMemberRole.OWNER, createdAt: workspace.createdAt, }, ]; } return [ { id: workspace.id, name: workspace.name, ownerId: workspace.ownerId, role: WorkspaceMemberRole.OWNER, createdAt: workspace.createdAt, }, ]; } }