refactor(erp): integração direta com banco ERP — schema sar
Revoga ADR 0006 (BD-por-workspace separado). O SAR agora conecta ao banco PostgreSQL do ERP (módulo SIG) e usa o schema `sar` para tudo. PRISMA - Remove: Client, Product, Order, OrderItem, OrderStatusHistory, RepTarget, RepDiscountLimit, PushSubscription (modelos isolados) - Adiciona: Pedido, PedidoItem, HistoricoPedido, AlcadaDesconto, MetaRepresentante, PushSubscription (mapeados para sar.*) - IDs: id_cliente/cod_vendedor/id_empresa são INTEGER (ERP) - situa: Int (1=Pendente 2=Aprovado 3=Cancelado 4=Faturado) - JWT: workspace_id:string → id_empresa:number - URL: inclui ?schema=sar para Prisma rotear ao schema ERP SERVICES - ClientsService: $queryRawUnsafe contra sar.vw_clientes + sar.pedidos - CatalogService: $queryRawUnsafe contra sar.vw_produtos + sar.vw_estoque - OrdersService: Prisma models Pedido/PedidoItem/HistoricoPedido/AlcadaDesconto - DashboardService: MetaRepresentante + queries raw para inativos - NotificationsService: PushSubscription com codVendedor + idEmpresa CONTRATOS (api-interface) - client.contract: campos ERP (idCliente, nome, cgcpf, cod_vendedor…) - order.contract: PedidoSummary/PedidoDetail/CreatePedido + SITUA_LABEL - product.contract: ProdutoSummary/ProdutoDetail (vw_produtos) - auth.contract: workspaceId:string → idEmpresa:number WEB - Todos os cockpits e queries atualizados para os novos tipos Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -10,8 +10,9 @@ class DevTokenRequestDto extends createZodDto(DevTokenRequestSchema) {}
|
||||
|
||||
// Dev-only stub — emite JWT HS256 para smoke tests locais.
|
||||
// CODING-RULES PGD-SEC-002: retorna 404 em produção.
|
||||
// CODING-RULES PGD-AUTHZ-002: workspace_id vem do body aqui APENAS porque
|
||||
// CODING-RULES PGD-AUTHZ-002: id_empresa vem do body aqui APENAS porque
|
||||
// este endpoint É o gerador do token — nenhum outro handler pode fazer isso.
|
||||
// ADR 0006 revogado: workspaceId → idEmpresa (Int da empresa no ERP)
|
||||
|
||||
@Public()
|
||||
@Controller({ path: 'auth/dev' })
|
||||
@@ -32,7 +33,7 @@ export class DevAuthController {
|
||||
if (this.isProd) throw new NotFoundException();
|
||||
|
||||
const accessToken = await new SignJWT({
|
||||
workspace_id: dto.workspaceId,
|
||||
id_empresa: dto.idEmpresa,
|
||||
role: dto.role,
|
||||
})
|
||||
.setProtectedHeader({ alg: 'HS256' })
|
||||
|
||||
@@ -10,9 +10,10 @@ import { WorkspacePrismaPool } from '../workspace/workspace-prisma-pool.service'
|
||||
import type { JwtPayload } from './jwt.types';
|
||||
import { IS_PUBLIC_KEY } from './public.decorator';
|
||||
|
||||
// Guard global (APP_GUARD). Valida Bearer HS256 e atualiza CLS com workspace real.
|
||||
// CODING-RULES PGD-AUTHZ-002: workspaceId sempre do JWT, nunca de body/param.
|
||||
// Ordem NestJS: middleware CLS (workspace default) → este guard (workspace real).
|
||||
// Guard global (APP_GUARD). Valida Bearer HS256 e atualiza CLS com idEmpresa real.
|
||||
// CODING-RULES PGD-AUTHZ-002: idEmpresa sempre do JWT, nunca de body/param.
|
||||
// Ordem NestJS: middleware CLS (idEmpresa default) → este guard (idEmpresa real).
|
||||
// ADR 0006 revogado: workspace_id → id_empresa; URL inclui ?schema=sar
|
||||
|
||||
@Injectable()
|
||||
export class JwtAuthGuard implements CanActivate {
|
||||
@@ -44,16 +45,18 @@ export class JwtAuthGuard implements CanActivate {
|
||||
|
||||
(req as Request & { user: JwtPayload }).user = payload as JwtPayload;
|
||||
|
||||
// Sobrescreve CLS com workspace real do JWT (corre depois do middleware).
|
||||
const workspaceId = payload.workspace_id;
|
||||
this.cls.set('workspaceId', workspaceId);
|
||||
// Sobrescreve CLS com idEmpresa real do JWT (corre depois do middleware).
|
||||
const idEmpresa = payload.id_empresa;
|
||||
this.cls.set('idEmpresa', idEmpresa);
|
||||
this.cls.set('userId', payload.sub);
|
||||
this.cls.set('role', payload.role);
|
||||
|
||||
const dbUrl =
|
||||
// URL inclui ?schema=sar para o Prisma rotear ao schema correto no ERP
|
||||
const baseUrl =
|
||||
process.env['DATABASE_URL'] ??
|
||||
`postgresql://sar:sar_dev_password@localhost:5432/sar_workspace_${workspaceId}`;
|
||||
this.cls.set('prisma', this.pool.getOrCreate(workspaceId, dbUrl));
|
||||
'postgresql://sar:sar_dev_password@localhost:5432/sar_workspace_dev';
|
||||
const dbUrl = baseUrl.includes('?') ? `${baseUrl}&schema=sar` : `${baseUrl}?schema=sar`;
|
||||
this.cls.set('prisma', this.pool.getOrCreate(idEmpresa, dbUrl));
|
||||
|
||||
return true;
|
||||
} catch {
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
// Claims do JWT emitido pelo master-login. Fonte da verdade para req.user.
|
||||
// CODING-RULES PGD-AUTHZ-002: workspace_id vem sempre do token, nunca do body.
|
||||
// CODING-RULES PGD-AUTHZ-002: id_empresa vem sempre do token, nunca do body.
|
||||
// ADR 0006 revogado: workspace_id → id_empresa (Int, empresa no ERP).
|
||||
|
||||
export type JwtRole = 'rep' | 'supervisor' | 'manager' | 'admin';
|
||||
|
||||
export interface JwtPayload {
|
||||
sub: string; // userId
|
||||
workspace_id: string;
|
||||
sub: string; // userId / cod_vendedor como string
|
||||
id_empresa: number; // empresa no ERP (era workspace_id)
|
||||
role: JwtRole;
|
||||
iat?: number;
|
||||
exp?: number;
|
||||
|
||||
Reference in New Issue
Block a user