From 8efaa49930c5f4911544c1c120d2db2e354c18a8 Mon Sep 17 00:00:00 2001 From: Thomas Reitz Date: Mon, 9 Mar 2026 22:00:06 +0100 Subject: [PATCH] feat: add user deletion (backend endpoint + frontend with confirmation) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Backend: DELETE /api/v1/users/:id endpoint (PLATFORM_ADMIN only) - Frontend: "Löschen" button with confirmation modal - Cascading deletes handle auth providers, memberships, profiles Co-Authored-By: Claude Opus 4.6 --- .../src/core/users/users.controller.ts | 13 ++++ .../src/core/users/users.service.ts | 15 ++++ .../frontend/src/admin/AdminUsersPage.tsx | 73 +++++++++++++++++++ 3 files changed, 101 insertions(+) diff --git a/packages/core-service/src/core/users/users.controller.ts b/packages/core-service/src/core/users/users.controller.ts index 32599bc..07b989c 100644 --- a/packages/core-service/src/core/users/users.controller.ts +++ b/packages/core-service/src/core/users/users.controller.ts @@ -3,6 +3,7 @@ import { Get, Post, Patch, + Delete, Body, Param, Query, @@ -124,4 +125,16 @@ export class UsersController { ) { return this.usersService.update(id, dto); } + + /** + * DELETE /api/v1/users/:id + * User löschen (nur PLATFORM_ADMIN). + */ + @Delete(':id') + @Roles('PLATFORM_ADMIN') + @UseGuards(RolesGuard) + @ApiOperation({ summary: 'Benutzer löschen (Admin)' }) + async delete(@Param('id', ParseUUIDPipe) id: string) { + return this.usersService.delete(id); + } } diff --git a/packages/core-service/src/core/users/users.service.ts b/packages/core-service/src/core/users/users.service.ts index f678807..e44f3e6 100644 --- a/packages/core-service/src/core/users/users.service.ts +++ b/packages/core-service/src/core/users/users.service.ts @@ -239,6 +239,21 @@ export class UsersService { this.logger.log(`Passwort geändert für User ${user.email}`); } + /** + * User löschen (inkl. Auth-Provider, Memberships, Profil via Cascade). + */ + async delete(id: string) { + const user = await this.prisma.user.findUnique({ where: { id } }); + if (!user) { + throw new NotFoundException('Benutzer nicht gefunden'); + } + + await this.prisma.user.delete({ where: { id } }); + this.logger.log(`User gelöscht: ${user.email}`); + + return { message: 'Benutzer wurde gelöscht' }; + } + /** * Alle User auflisten (für Admin). */ diff --git a/packages/frontend/src/admin/AdminUsersPage.tsx b/packages/frontend/src/admin/AdminUsersPage.tsx index da4129a..13cb9e6 100644 --- a/packages/frontend/src/admin/AdminUsersPage.tsx +++ b/packages/frontend/src/admin/AdminUsersPage.tsx @@ -1,6 +1,7 @@ import { useState } from 'react'; import { useQuery, useQueryClient, useMutation } from '@tanstack/react-query'; import api from '../api/client'; +import { Modal } from '../components/Modal'; import { UserFormModal } from './UserFormModal'; interface User { @@ -48,6 +49,7 @@ export function AdminUsersPage() { const queryClient = useQueryClient(); const [isCreateModalOpen, setCreateModalOpen] = useState(false); const [editingUser, setEditingUser] = useState(null); + const [deletingUser, setDeletingUser] = useState(null); const { data, isLoading, error } = useQuery({ queryKey: ['admin', 'users'], @@ -65,6 +67,14 @@ export function AdminUsersPage() { }, }); + const deleteMutation = useMutation({ + mutationFn: (id: string) => api.delete(`/users/${id}`), + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ['admin', 'users'] }); + setDeletingUser(null); + }, + }); + if (isLoading) return

Laden...

; if (error) return

Fehler beim Laden der Benutzer

; @@ -181,6 +191,20 @@ export function AdminUsersPage() { > {user.isActive ? 'Deaktivieren' : 'Aktivieren'} + @@ -204,6 +228,55 @@ export function AdminUsersPage() { user={editingUser} onSuccess={() => setEditingUser(null)} /> + + {/* Modal: Benutzer löschen — Bestätigung */} + setDeletingUser(null)} + title="Benutzer löschen" + maxWidth="420px" + > +

+ Soll der Benutzer {deletingUser?.firstName} {deletingUser?.lastName} ({deletingUser?.email}) wirklich gelöscht werden? +

+

+ Diese Aktion kann nicht rückgängig gemacht werden. Alle Daten des Benutzers werden unwiderruflich gelöscht. +

+
+ + +
+
); }