feat: Call Center > Agentes + Telefonia > Dialplan (novo endpoint GET /users)
Fecha a lacuna de backend que travava Agentes: POST /agents exigia um userId de um usuário já existente do tenant, mas não havia nenhum endpoint pra listar usuários. Novo GET /users (gated por users.manage, não agents.manage — listar identidade de login é administração de usuário) via TenantMembership, mesmo padrão de RLS já usado em listUserTenants. Duas telas novas: Call Center > Agentes (criar/listar/remover, seletor de usuário só mostra quem ainda não é agente) e Telefonia > Dialplan (editor estruturado do contexto default — regras com condição/ações dinâmicas, painel de Versões com gerar/ativar, reativar versão antiga = rollback). Testado ponta a ponta contra a API real do tenant Acme, incluindo o ciclo completo de dialplan (criar regra -> gerar v1 -> ativar -> badge "Ativa"). Smoke test de regressão nas 13 telas anteriores do tenant + platform. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BFaBaBSQGhyXGEgtTYZGV8
This commit is contained in:
41
apps/api/src/users/users.controller.ts
Normal file
41
apps/api/src/users/users.controller.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import { Controller, Get, UseGuards } from "@nestjs/common";
|
||||
import { getPrismaClient, withTenantContext } from "@b2bcall/database";
|
||||
import type { AccessTokenClaims } from "@b2bcall/auth";
|
||||
import { JwtAuthGuard } from "../common/guards/jwt-auth.guard";
|
||||
import { PermissionGuard } from "../common/guards/permission.guard";
|
||||
import { RequirePermission } from "../common/decorators/require-permission.decorator";
|
||||
import { CurrentUser } from "../common/decorators/current-user.decorator";
|
||||
|
||||
/**
|
||||
* Usuários do tenant ativo — hoje só o list existe, e só pra alimentar o
|
||||
* seletor de "Call Center > Agentes" (provisionar agente precisa de um
|
||||
* `userId` já existente, secao 45). Convite/criação de usuário continua
|
||||
* só via script (mesma lacuna documentada na PHASE 22 pra tenant/plano).
|
||||
* Gated por `users.manage` (não `agents.manage`) porque listar identidade
|
||||
* de login de outras pessoas é uma ação de administração de usuários, não
|
||||
* de call center — um supervisor com `agents.manage` mas sem
|
||||
* `users.manage` gerencia agentes já provisionados, mas não lista
|
||||
* usuários pra provisionar um novo.
|
||||
*/
|
||||
@UseGuards(JwtAuthGuard, PermissionGuard)
|
||||
@Controller("users")
|
||||
export class UsersController {
|
||||
@RequirePermission("users.manage")
|
||||
@Get()
|
||||
async list(@CurrentUser() user: AccessTokenClaims) {
|
||||
const prisma = getPrismaClient();
|
||||
const tenantId = user.tenantId!;
|
||||
|
||||
const memberships = await withTenantContext(prisma, tenantId, (tx) =>
|
||||
tx.tenantMembership.findMany({
|
||||
where: { tenantId },
|
||||
include: { user: { select: { id: true, email: true, name: true, status: true, deletedAt: true } } },
|
||||
orderBy: { createdAt: "asc" },
|
||||
}),
|
||||
);
|
||||
|
||||
return memberships
|
||||
.filter((m) => m.user.deletedAt == null)
|
||||
.map((m) => ({ id: m.user.id, email: m.user.email, name: m.user.name, status: m.user.status }));
|
||||
}
|
||||
}
|
||||
7
apps/api/src/users/users.module.ts
Normal file
7
apps/api/src/users/users.module.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { Module } from "@nestjs/common";
|
||||
import { UsersController } from "./users.controller";
|
||||
|
||||
@Module({
|
||||
controllers: [UsersController],
|
||||
})
|
||||
export class UsersModule {}
|
||||
Reference in New Issue
Block a user