Visão Geral da Arquitetura
Visão Geral da Arquitetura
O boilerplate foi concebido como um Monólito Modular baseado em NestJS 11, priorizando simplicidade, limites de domínio claros, segurança por padrão (fail-closed) e mínima fricção de desenvolvimento.
🏛️ Princípios Arquiteturais
- Segurança Fail-Closed: Todo endpoint novo é protegido automaticamente por autenticação JWT via Keycloak, a menos que seja explicitamente marcado com o decorator
@Public(). - Fonte Única de Verdade com Zod: DTOs são declarados usando schemas Zod (
createZodDtodonestjs-zod), garantindo simultaneamente validação de dados em runtime, tipagem estática no TypeScript e geração de especificação OpenAPI (Swagger). - Isolamento de Domínio: Cada módulo funcional (
src/modules/*) encapsula seus próprios controllers, services e DTOs, consumindo o Prisma Client (PrismaService) para persistência. - Respostas e Erros Padronizados: Interceptors e Exception Filters globais garantem que qualquer resposta da API siga um envelope JSON consistente.
- Configuração Validada no Boot: Falhas em variáveis de ambiente obrigatórias interrompem a inicialização imediatamente (fail fast), prevenindo falhas silenciosas em tempo de execução.
🚀 Bootstrap da Aplicação (src/main.ts)
A inicialização da aplicação NestJS ocorre no arquivo src/main.ts:
// src/main.ts
async function bootstrap() {
const app = await NestFactory.create(AppModule);
const configService = app.get(ConfigService);
// 1. Prefixo global da API
app.setGlobalPrefix('cincoders/api');
app.enableCors();
// 2. Filtro de exceção e interceptor de resposta globais
app.useGlobalFilters(new HttpExceptionFilter());
app.useGlobalInterceptors(new TransformInterceptor());
// 3. Documentação Swagger com suporte a Bearer e OAuth2
const swaggerBuilder = new DocumentBuilder()
.setTitle(configService.get('swagger.title', 'cincoders API'))
.setDescription(configService.get('swagger.description', 'API documentation'))
.setVersion(configService.get('swagger.version', '1.0.0'))
.addBearerAuth();
const authServerUrl = configService.get<string>('keycloak.authServerUrl');
const realm = configService.get<string>('keycloak.realm');
if (authServerUrl && realm) {
const issuer = `${authServerUrl.replace(/\/$/, '')}/realms/${realm}`;
swaggerBuilder.addOAuth2({
type: 'oauth2',
flows: {
password: {
tokenUrl: `${issuer}/protocol/openid-connect/token`,
authorizationUrl: `${issuer}/protocol/openid-connect/auth`,
scopes: {},
},
},
});
}
const document = cleanupOpenApiDoc(SwaggerModule.createDocument(app, swaggerBuilder.build()));
SwaggerModule.setup(configService.get('swagger.path', 'api/docs'), app, document);
const port = configService.get<number>('PORT', 3000);
await app.listen(port);
}⚙️ Módulo Raiz e Configurações (src/app.module.ts)
O AppModule orquestra os módulos de infraestrutura e módulos de negócio:
// src/app.module.ts
@Module({
imports: [
// 1. Carregamento de configuração e validação de ambiente
ConfigModule.forRoot({
isGlobal: true,
validate: validateEnv,
load: [databaseConfig, swaggerConfig, keycloakConfig],
}),
// 2. Conexão com PostgreSQL via Prisma (PrismaModule é @Global())
PrismaModule,
// 3. Módulos transversais e de domínio
AuthModule,
HealthModule,
TaskModule,
],
providers: [
// Validação global com Zod
{ provide: APP_PIPE, useClass: ZodValidationPipe },
],
})
export class AppModule {}📁 Estrutura de Diretórios do Projeto
src/
├── common/ # Recursos transversais compartilhados
│ ├── auth/ # Módulo de autenticação (Guards, Keycloak JWKS, Decorators)
│ ├── decorators/ # Decorators globais (@Public)
│ ├── exceptions/ # Hierarquia de exceções de domínio e enum ErrorCode
│ ├── filters/ # HttpExceptionFilter global
│ ├── interceptors/ # TransformInterceptor (envelope de resposta)
│ └── pagination/ # DTOs padronizados de consulta e resposta paginada
├── config/ # Namespaces de configuração e validação de ambiente
│ ├── database.config.ts
│ ├── env.validation.ts
│ ├── keycloak.config.ts
│ └── swagger.config.ts
├── database/ # Integração com Prisma
│ ├── prisma.service.ts # PrismaService (extends PrismaClient, connect/disconnect)
│ └── prisma.module.ts # PrismaModule (@Global())
├── modules/ # Módulos funcionais da aplicação
│ ├── health/ # Health check via @nestjs/terminus + PrismaHealthIndicator
│ └── task/ # Módulo de exemplo com CRUD completo
├── app.module.ts # Módulo raiz
└── main.ts # Ponto de entrada e bootstrap
prisma/
├── schema.prisma # Fonte da verdade do schema (models, relações)
├── migrations/ # Migrations SQL geradas pelo Prisma CLI
└── seed.mjs # Popula tabelas de lookup (status, prioridade, papéis)