In der Nutzerverwaltung kannst du jetzt pro Konto die Rolle, die AG-Zuordnung und die Freigaberollen bearbeiten. Die feste 3er-Freigabelogik bleibt Vorstand A / Vorstand B / Finanz-AG, aber jetzt legst du über die Nutzer fest, wer diese Schritte autorisieren darf. Zusätzlich gibt es unter Nutzer anlegen eine eigene Insel für die Freigabe-Schwelle, und diese Schwelle wird jetzt auch wirklich überall verwendet: in der Erfassungslogik, in den Budgetkarten, im CSV-Backup/-Import und im Audit-Restore. Die Hauptänderungen sitzen in dashboard-shell.tsx, budget-column.tsx, route.ts, schema.prisma und route.ts.
All checks were successful
CI / build-and-deploy (push) Successful in 1m22s

Den Zeitraum-Bereich habe ich dabei gleich mit aufgeräumt: die Auswahl des aktuellen Haushalts ist breiter und sauberer angeordnet, und die Desktop-Nutzerverwaltung ist jetzt wirklich links Anlegen + Schwelle und rechts die Nutzerliste. Seed und Backup/Restore kennen die neuen Felder ebenfalls in seed.ts, route.ts und route.ts.
This commit is contained in:
Jan
2026-04-12 20:09:46 +02:00
parent 92d96ffa27
commit b202fc6c26
20 changed files with 1018 additions and 365 deletions

View File

@@ -3,6 +3,21 @@ import bcrypt from "bcryptjs";
const prisma = new PrismaClient();
const APPROVAL_THRESHOLD = 50;
async function upsertAppSettings() {
await prisma.appSettings.upsert({
where: { id: "global" },
update: {
approvalThreshold: APPROVAL_THRESHOLD
},
create: {
id: "global",
approvalThreshold: APPROVAL_THRESHOLD
}
});
}
async function upsertCurrentPeriod() {
const year = new Date().getFullYear();
const startsAt = new Date(Date.UTC(year, 0, 1));
@@ -36,9 +51,7 @@ async function upsertWorkingGroup(name: string) {
return prisma.workingGroup.upsert({
where: { name },
update: {},
create: {
name
}
create: { name }
});
}
@@ -71,8 +84,44 @@ async function upsertBudget(
});
}
async function upsertUser(input: {
username: string;
role: Role;
passwordHash: string;
workingGroupId?: string | null;
approvalPermissions: ApprovalType[];
}) {
const approvalPreference = input.approvalPermissions[0] ?? null;
await prisma.user.upsert({
where: { username: input.username },
update: {
name: input.username,
username: input.username,
email: null,
passwordHash: input.passwordHash,
role: input.role,
approvalPreference,
approvalPermissions: input.approvalPermissions,
workingGroupId: input.workingGroupId ?? null
},
create: {
name: input.username,
username: input.username,
email: null,
passwordHash: input.passwordHash,
role: input.role,
approvalPreference,
approvalPermissions: input.approvalPermissions,
workingGroupId: input.workingGroupId ?? null
}
});
}
async function main() {
const passwordHash = await bcrypt.hash("demo123!", 12);
await upsertAppSettings();
const currentPeriod = await upsertCurrentPeriod();
const deko = await upsertWorkingGroup("AG Deko");
@@ -83,109 +132,41 @@ async function main() {
await upsertBudget(awareness.id, currentPeriod.id, "Awareness Hauptbudget", 800, "#68A35D");
const technikBudget = await upsertBudget(technik.id, currentPeriod.id, "Technik Infrastruktur", 1500, "#5677F6");
await prisma.user.upsert({
where: { username: "vorstand-a" },
update: {
name: "Admin 1",
username: "vorstand-a",
email: null,
passwordHash,
role: Role.ADMIN,
approvalPreference: ApprovalType.CHAIR_A,
workingGroupId: null
},
create: {
name: "Admin 1",
username: "vorstand-a",
email: null,
passwordHash,
role: Role.ADMIN,
approvalPreference: ApprovalType.CHAIR_A
}
await upsertUser({
username: "vorstand-a",
role: Role.ADMIN,
passwordHash,
approvalPermissions: [ApprovalType.CHAIR_A]
});
await prisma.user.upsert({
where: { username: "vorstand-b" },
update: {
name: "Admin 2",
username: "vorstand-b",
email: null,
passwordHash,
role: Role.ADMIN,
approvalPreference: ApprovalType.CHAIR_B,
workingGroupId: null
},
create: {
name: "Admin 2",
username: "vorstand-b",
email: null,
passwordHash,
role: Role.ADMIN,
approvalPreference: ApprovalType.CHAIR_B
}
await upsertUser({
username: "vorstand-b",
role: Role.ADMIN,
passwordHash,
approvalPermissions: [ApprovalType.CHAIR_B]
});
await prisma.user.upsert({
where: { username: "finanzen" },
update: {
name: "Finanz-AG",
username: "finanzen",
email: null,
passwordHash,
role: Role.FINANCE,
approvalPreference: ApprovalType.FINANCE,
workingGroupId: null
},
create: {
name: "Finanz-AG",
username: "finanzen",
email: null,
passwordHash,
role: Role.FINANCE,
approvalPreference: ApprovalType.FINANCE
}
await upsertUser({
username: "finanzen",
role: Role.FINANCE,
passwordHash,
approvalPermissions: [ApprovalType.FINANCE]
});
await prisma.user.upsert({
where: { username: "deko" },
update: {
name: "Deko Mitglied",
username: "deko",
email: null,
passwordHash,
role: Role.MEMBER,
approvalPreference: null,
workingGroupId: deko.id
},
create: {
name: "Deko Mitglied",
username: "deko",
email: null,
passwordHash,
role: Role.MEMBER,
workingGroupId: deko.id
}
await upsertUser({
username: "deko",
role: Role.MEMBER,
passwordHash,
workingGroupId: deko.id,
approvalPermissions: []
});
await prisma.user.upsert({
where: { username: "technik" },
update: {
name: "Technik Mitglied",
username: "technik",
email: null,
passwordHash,
role: Role.MEMBER,
approvalPreference: null,
workingGroupId: technik.id
},
create: {
name: "Technik Mitglied",
username: "technik",
email: null,
passwordHash,
role: Role.MEMBER,
workingGroupId: technik.id
}
await upsertUser({
username: "technik",
role: Role.MEMBER,
passwordHash,
workingGroupId: technik.id,
approvalPermissions: []
});
const existingExpense = await prisma.expense.findFirst({
@@ -247,4 +228,4 @@ main()
console.error(error);
await prisma.$disconnect();
process.exit(1);
});
});