- Auth (apps/api/src/auth/): Argon2id com parâmetros versionados
(ADR-0005), access token JWT de 15min, refresh token opaco de 256 bits
com rotação e detecção de replay (reuso de token já rotacionado revoga
toda a cadeia de sessões do usuário). Endpoints /api/v1/auth/
{login,refresh,logout,me}.
- Permissões resource+action+scope (ADR-0004) via PermissionGuard,
resolvidas do banco a cada request (nunca cacheadas no JWT) — mudança
de papel tem efeito imediato. super_admin com bypass hardcoded,
espelhando a trava já existente no banco.
- Companies (migration + CRUD): leitura aberta a qualquer autenticado,
escrita restrita a companies:manage; validação de CNPJ via
packages/domain-shared (dígito verificador).
- SeedService: cria o primeiro super_admin a partir de
EDEN_SUPERADMIN_EMAIL/PASSWORD só quando `users` está vazia.
- OpenAPI/Swagger em /api/docs; ValidationPipe global com
whitelist+forbidNonWhitelisted (proteção contra mass-assignment).
- packages/database: repositórios (roles/users/sessions/audit/companies)
reutilizáveis por api e worker.
Validado manualmente contra a stack real (não só typecheck): login com
senha errada → 401 genérico; refresh rotaciona e invalida o token
anterior; reuso do token antigo → replay detectado, cadeia revogada;
logout idempotente; audit log com a sequência completa de eventos;
CNPJ inválido rejeitado; mass-assignment rejeitado.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
51 lines
1.8 KiB
TypeScript
51 lines
1.8 KiB
TypeScript
import { Body, Controller, Get, Param, Patch, Post, Query, UseGuards } from "@nestjs/common";
|
|
import { ApiBearerAuth, ApiTags } from "@nestjs/swagger";
|
|
import { CompaniesService } from "./companies.service.js";
|
|
import { CreateCompanyDto } from "./dto/create-company.dto.js";
|
|
import { UpdateCompanyDto } from "./dto/update-company.dto.js";
|
|
import { JwtAuthGuard } from "../auth/jwt-auth.guard.js";
|
|
import { PermissionGuard } from "../auth/permission.guard.js";
|
|
import { RequirePermission } from "../auth/decorators/require-permission.decorator.js";
|
|
import { CurrentUser } from "../auth/decorators/current-user.decorator.js";
|
|
import type { EdenAuthenticatedUser } from "../auth/jwt-auth.guard.js";
|
|
|
|
/**
|
|
* Read is open to any authenticated user (not gated by a resource
|
|
* permission) — company data isn't sensitive and is needed to render
|
|
* contracts/documents from screens any seller/backoffice user can reach,
|
|
* mirroring the legacy (eden.md §1, §6). Write requires companies:manage.
|
|
*/
|
|
@ApiTags("companies")
|
|
@ApiBearerAuth()
|
|
@UseGuards(JwtAuthGuard, PermissionGuard)
|
|
@Controller("v1/companies")
|
|
export class CompaniesController {
|
|
constructor(private readonly companies: CompaniesService) {}
|
|
|
|
@Get()
|
|
list(@Query("includeInactive") includeInactive?: string) {
|
|
return this.companies.list(includeInactive === "true");
|
|
}
|
|
|
|
@Get(":id")
|
|
get(@Param("id") id: string) {
|
|
return this.companies.get(id);
|
|
}
|
|
|
|
@Post()
|
|
@RequirePermission("companies", "manage")
|
|
create(@Body() dto: CreateCompanyDto, @CurrentUser() user: EdenAuthenticatedUser) {
|
|
return this.companies.create(dto, user.id);
|
|
}
|
|
|
|
@Patch(":id")
|
|
@RequirePermission("companies", "manage")
|
|
update(
|
|
@Param("id") id: string,
|
|
@Body() dto: UpdateCompanyDto,
|
|
@CurrentUser() user: EdenAuthenticatedUser,
|
|
) {
|
|
return this.companies.update(id, dto, user.id);
|
|
}
|
|
}
|