Add Groups management and split Admin navigation

- New backend: Group + GroupMembership models, schemas, CRUD router at
  /api/admin/groups (list, create, get detail, update, delete, add/remove members)
- New Alembic migration: groups and group_memberships tables
- Frontend: Admin sidebar item is now an expandable accordion with
  Users and Groups sub-items; AdminPage redirects to /admin/users;
  new AdminUsersPage and AdminGroupsPage with inline member management panel
- API client: 7 new group functions + TypeScript types

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
curo1305
2026-04-17 20:49:54 +02:00
parent 2bb1e03adf
commit 4e9ed97b05
15 changed files with 1035 additions and 191 deletions
+52
View File
@@ -224,6 +224,58 @@ export const updateDocumentLimits = (max_pdf_mb: number) =>
export const getDocumentLimits = () =>
api.get<Record<string, unknown>>("/settings/documents/limits").then((r) => r.data);
// --- Groups (admin only) ---
export interface GroupOut {
id: string;
name: string;
description: string | null;
created_at: string;
member_count: number;
}
export interface GroupMemberOut {
id: string;
email: string;
full_name: string | null;
is_active: boolean;
joined_at: string;
}
export interface GroupDetailOut extends GroupOut {
members: GroupMemberOut[];
}
export interface GroupCreate {
name: string;
description?: string | null;
}
export interface GroupUpdate {
name?: string;
description?: string | null;
}
export const adminListGroups = () =>
api.get<GroupOut[]>("/admin/groups").then((r) => r.data);
export const adminCreateGroup = (data: GroupCreate) =>
api.post<GroupOut>("/admin/groups", data).then((r) => r.data);
export const adminGetGroup = (groupId: string) =>
api.get<GroupDetailOut>(`/admin/groups/${groupId}`).then((r) => r.data);
export const adminUpdateGroup = (groupId: string, data: GroupUpdate) =>
api.patch<GroupOut>(`/admin/groups/${groupId}`, data).then((r) => r.data);
export const adminDeleteGroup = (groupId: string) =>
api.delete(`/admin/groups/${groupId}`);
export const adminAddGroupMember = (groupId: string, userId: string) =>
api.post(`/admin/groups/${groupId}/members/${userId}`);
export const adminRemoveGroupMember = (groupId: string, userId: string) =>
api.delete(`/admin/groups/${groupId}/members/${userId}`);
// --- Services ---
export interface ServiceStatus {
id: string;