feat(mvp): phase 2 - database schema & services layer
Define full Prisma schema (10 models), run initial migration, build core services (auth, user, group, app, board, permission), Zod validators, type definitions, API response envelope, constants, and seed script.
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
import { prisma } from '../prisma.js';
|
||||
import type { CreateGroupInput, UpdateGroupInput } from '$lib/types/group.js';
|
||||
|
||||
export async function findAll() {
|
||||
return prisma.group.findMany({
|
||||
orderBy: { name: 'asc' },
|
||||
include: {
|
||||
_count: { select: { users: true } }
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export async function findById(id: string) {
|
||||
const group = await prisma.group.findUnique({
|
||||
where: { id },
|
||||
include: {
|
||||
_count: { select: { users: true } }
|
||||
}
|
||||
});
|
||||
if (!group) {
|
||||
throw new Error(`Group not found: ${id}`);
|
||||
}
|
||||
return group;
|
||||
}
|
||||
|
||||
export async function findByName(name: string) {
|
||||
return prisma.group.findUnique({
|
||||
where: { name }
|
||||
});
|
||||
}
|
||||
|
||||
export async function findDefaultGroups() {
|
||||
return prisma.group.findMany({
|
||||
where: { isDefault: true }
|
||||
});
|
||||
}
|
||||
|
||||
export async function create(input: CreateGroupInput) {
|
||||
const existing = await prisma.group.findUnique({
|
||||
where: { name: input.name }
|
||||
});
|
||||
if (existing) {
|
||||
throw new Error(`Group with name "${input.name}" already exists`);
|
||||
}
|
||||
|
||||
return prisma.group.create({
|
||||
data: {
|
||||
name: input.name,
|
||||
description: input.description ?? null,
|
||||
isDefault: input.isDefault ?? false
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export async function update(id: string, input: UpdateGroupInput) {
|
||||
await findById(id);
|
||||
|
||||
if (input.name) {
|
||||
const existing = await prisma.group.findFirst({
|
||||
where: { name: input.name, NOT: { id } }
|
||||
});
|
||||
if (existing) {
|
||||
throw new Error(`Group with name "${input.name}" already exists`);
|
||||
}
|
||||
}
|
||||
|
||||
return prisma.group.update({
|
||||
where: { id },
|
||||
data: {
|
||||
...(input.name !== undefined ? { name: input.name } : {}),
|
||||
...(input.description !== undefined ? { description: input.description } : {}),
|
||||
...(input.isDefault !== undefined ? { isDefault: input.isDefault } : {})
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export async function remove(id: string) {
|
||||
await findById(id);
|
||||
await prisma.group.delete({ where: { id } });
|
||||
}
|
||||
|
||||
export async function addUser(groupId: string, userId: string) {
|
||||
const existing = await prisma.userGroup.findUnique({
|
||||
where: { userId_groupId: { userId, groupId } }
|
||||
});
|
||||
if (existing) {
|
||||
return existing;
|
||||
}
|
||||
|
||||
return prisma.userGroup.create({
|
||||
data: { userId, groupId }
|
||||
});
|
||||
}
|
||||
|
||||
export async function removeUser(groupId: string, userId: string) {
|
||||
await prisma.userGroup.deleteMany({
|
||||
where: { userId, groupId }
|
||||
});
|
||||
}
|
||||
|
||||
export async function getGroupMembers(groupId: string) {
|
||||
const memberships = await prisma.userGroup.findMany({
|
||||
where: { groupId },
|
||||
include: {
|
||||
user: {
|
||||
select: {
|
||||
id: true,
|
||||
email: true,
|
||||
displayName: true,
|
||||
role: true,
|
||||
avatarUrl: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return memberships.map((m) => m.user);
|
||||
}
|
||||
|
||||
export async function addUserToDefaultGroups(userId: string) {
|
||||
const defaultGroups = await findDefaultGroups();
|
||||
const results = await Promise.all(
|
||||
defaultGroups.map((group) => addUser(group.id, userId))
|
||||
);
|
||||
return results;
|
||||
}
|
||||
Reference in New Issue
Block a user