feat(auth): add module read/write admin RBAC

Introduce permission catalog, PermissionsGuard, JWT/me payload with
role+permissions, and gate all module controllers. Admins CRUD accepts
role/permissions with safety rules; migrate existing users to super_admin.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-10 15:29:04 +03:30
co-authored by Cursor
parent 4b3a8a1d6c
commit af1e217a68
28 changed files with 532 additions and 75 deletions
+14 -1
View File
@@ -10,36 +10,43 @@ import {
UseGuards,
} from '@nestjs/common';
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
import { PermissionsGuard } from '../auth/permissions.guard';
import { RequirePermissions } from '../auth/permissions.decorator';
import { CurrentUser } from '../auth/current-user.decorator';
import { RenewServerDto, UpdateServerAccountDto } from './dto/server-account.dto';
import { ServersService } from './servers.service';
@Controller('servers')
@UseGuards(JwtAuthGuard)
@UseGuards(JwtAuthGuard, PermissionsGuard)
export class ServersController {
constructor(private readonly serversService: ServersService) {}
@Get('tenants')
@RequirePermissions('servers:read')
listTenants() {
return this.serversService.listTenants();
}
@Get('expiring')
@RequirePermissions('servers:read')
expiring(@Query('limit') limit?: string) {
return this.serversService.getExpiringSoon(Number(limit) || 5);
}
@Post('check-alerts')
@RequirePermissions('servers:write')
checkAlerts() {
return this.serversService.runExpiryAlerts().then(() => ({ ok: true }));
}
@Get('tenants/:id')
@RequirePermissions('servers:read')
getTenantServers(@Param('id') id: string) {
return this.serversService.getTenantServers(id);
}
@Post('tenants/:id/servers')
@RequirePermissions('servers:write')
createServer(
@Param('id') id: string,
@Body() dto: UpdateServerAccountDto,
@@ -50,6 +57,7 @@ export class ServersController {
/** @deprecated prefer PATCH /servers/accounts/:accountId */
@Patch('tenants/:id')
@RequirePermissions('servers:write')
updateAccountLegacy(
@Param('id') id: string,
@Body() dto: UpdateServerAccountDto,
@@ -60,6 +68,7 @@ export class ServersController {
/** @deprecated prefer POST /servers/accounts/:accountId/renew */
@Post('tenants/:id/renew')
@RequirePermissions('servers:write')
renewLegacy(
@Param('id') id: string,
@Body() dto: RenewServerDto,
@@ -69,11 +78,13 @@ export class ServersController {
}
@Get('accounts/:accountId')
@RequirePermissions('servers:read')
getServerAccount(@Param('accountId') accountId: string) {
return this.serversService.getServerAccount(accountId);
}
@Patch('accounts/:accountId')
@RequirePermissions('servers:write')
updateServerAccount(
@Param('accountId') accountId: string,
@Body() dto: UpdateServerAccountDto,
@@ -83,6 +94,7 @@ export class ServersController {
}
@Delete('accounts/:accountId')
@RequirePermissions('servers:write')
deleteServerAccount(
@Param('accountId') accountId: string,
@CurrentUser() user: { id: string },
@@ -91,6 +103,7 @@ export class ServersController {
}
@Post('accounts/:accountId/renew')
@RequirePermissions('servers:write')
renewAccount(
@Param('accountId') accountId: string,
@Body() dto: RenewServerDto,
+2 -1
View File
@@ -1,10 +1,11 @@
import { Module } from '@nestjs/common';
import { AuthModule } from '../auth/auth.module';
import { NotificationsModule } from '../notifications/notifications.module';
import { ServersController } from './servers.controller';
import { ServersService } from './servers.service';
@Module({
imports: [NotificationsModule],
imports: [NotificationsModule, AuthModule],
controllers: [ServersController],
providers: [ServersService],
exports: [ServersService],