managarten/services/mana-core-auth/src/admin/user-data.controller.ts
Till-JS a2e2a5b73c feat(admin): add user data dashboard for cross-project data visualization
Add comprehensive admin dashboard to view and manage user data across all projects:

Backend:
- Add admin endpoints to Chat, Todo, Contacts, Calendar, Picture, Zitare, Presi
- Each backend exposes GET/DELETE /api/v1/admin/user-data/:userId
- Service-to-service auth via X-Service-Key header

Aggregation (mana-core-auth):
- GET /api/v1/admin/users - Paginated user list with search
- GET /api/v1/admin/users/:userId/data - Aggregated data from all backends
- DELETE /api/v1/admin/users/:userId/data - GDPR deletion across all projects

Frontend (ManaCore web):
- New User Data tab in admin navigation
- User search page at /admin/user-data
- User detail page with ProjectDataCard components
- GDPR deletion dialog with email confirmation

Presi:
- Migrate user_id from UUID to TEXT for Better Auth compatibility
- Add SQL migration script
2026-02-11 14:59:18 +01:00

66 lines
2 KiB
TypeScript

import {
Controller,
Get,
Delete,
Param,
Query,
UseGuards,
Logger,
HttpCode,
HttpStatus,
} from '@nestjs/common';
import { UserDataService } from './user-data.service';
import { AdminGuard } from './guards/admin.guard';
import { UserDataSummary, DeleteUserDataResponse, UserListResponse } from './dto/user-data.dto';
/**
* Admin controller for cross-project user data management
* All endpoints require admin authentication (role=admin or in ADMIN_USER_IDS)
*/
@Controller('api/v1/admin')
@UseGuards(AdminGuard)
export class UserDataController {
private readonly logger = new Logger(UserDataController.name);
constructor(private readonly userDataService: UserDataService) {}
/**
* List all users with pagination and search
* GET /api/v1/admin/users?page=1&limit=20&search=email
*/
@Get('users')
async getUsers(
@Query('page') page?: string,
@Query('limit') limit?: string,
@Query('search') search?: string
): Promise<UserListResponse> {
const pageNum = parseInt(page || '1', 10);
const limitNum = Math.min(parseInt(limit || '20', 10), 100);
this.logger.log(
`Admin request: getUsers page=${pageNum} limit=${limitNum} search=${search || ''}`
);
return this.userDataService.getUsers(pageNum, limitNum, search);
}
/**
* Get aggregated user data from all projects
* GET /api/v1/admin/users/:userId/data
*/
@Get('users/:userId/data')
async getUserData(@Param('userId') userId: string): Promise<UserDataSummary> {
this.logger.log(`Admin request: getUserData for userId=${userId}`);
return this.userDataService.getUserDataSummary(userId);
}
/**
* Delete all user data across all projects (GDPR right to be forgotten)
* DELETE /api/v1/admin/users/:userId/data
*/
@Delete('users/:userId/data')
@HttpCode(HttpStatus.OK)
async deleteUserData(@Param('userId') userId: string): Promise<DeleteUserDataResponse> {
this.logger.log(`Admin request: deleteUserData for userId=${userId}`);
return this.userDataService.deleteUserData(userId);
}
}