- Nx 22.7 monorepo (pnpm 11.1, TypeScript 5.9, Node 24) - apps/api: NestJS 11 (CJS conforme CODING-RULES.md PGD-DB-004) - apps/web: React 19 + Vite 8 (ESM) - libs/shared/api-interface: Zod contract base - Docker Compose dev: Postgres 18, Valkey 8, MinIO, Mailpit - WDS artifacts: - design-artifacts/A-Product-Brief/ (5 docs canônicos + 16 dialogs) - design-artifacts/B-Trigger-Map/ (hub + 4 personas + feature impact) - Stack canon: STACK.md v2.2 + CODING-RULES.md v2.0 + brand.md - AGENTS.md + README.md como entrada para devs/agentes Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
130 lines
12 KiB
Markdown
130 lines
12 KiB
Markdown
# STACK.md — Referência de Tecnologias
|
|
|
|
> Define **o que usar**: tecnologias, versões, estrutura do monorepo e filosofia arquitetural. **Leia antes de decisões de tecnologia ou arquitetura.**
|
|
> Para regras de como escrever o código (invariantes + pegadinhas 🔥), consulte [`CODING-RULES.md`](CODING-RULES.md).
|
|
> **Humano novo?** Este arquivo é projetado para consumo por agente de IA. Comece por [`docs/QUICKSTART.md`](docs/QUICKSTART.md) — 5 min, com TL;DR executável e as 5 decisões arquiteturais-chave.
|
|
|
|
<!--
|
|
FONTE DA VERDADE: stack-jcs/STACK.md (sincronizado com docs/).
|
|
Distribuído por cópia para repos de apps consumidoras. Não editar fora deste repo.
|
|
Versão: 2.2 — última revisão: 2026-05-24.
|
|
Majors acumulados:
|
|
- v2.0 — migração AWS sa-east-1 → Proxmox on-prem (docs/adr/0004-migracao-aws-proxmox.md)
|
|
- v2.1 — master-login substitui Keycloak como IdP (docs/adr/0005-auth-master-login.md)
|
|
- v2.2 — multi-tenancy: BD-por-workspace substitui row-level (docs/adr/0006-multi-tenancy-bd-por-workspace.md)
|
|
-->
|
|
|
|
## 1. O que é e por quê
|
|
|
|
Stack full-stack TypeScript para apps internas da empresa (**Proxmox on-prem no BR** · Docker Compose · MinIO · master-login · Vault · email/CDN via SaaS). Seis decisões que diferenciam de stacks genéricas:
|
|
|
|
1. **Schemas Zod são o contrato.** Tipos derivam de schemas em `libs/shared/api-interface`; mesmo schema valida no Nest e tipa `react-hook-form`. → [§06](docs/06-validacao.md)
|
|
2. **Monorepo Nx · `apps/` + `libs/<scope>/<type>-<nome>`** com 3 tags (`scope:` + `type:` + `domain:`) e ESLint boundaries. Um repo por **produto**, não por serviço. → [§02](docs/02-monorepo-nx.md)
|
|
3. **App stateless · infra stateful self-host no Proxmox.** Postgres, Valkey, MinIO, master-login e Vault rodam em VMs/LXC controladas pelo time — nunca em container efêmero da app. Email (Resend) e CDN (Cloudflare) permanecem SaaS por razões de deliverability / borda global. → [§03](docs/03-backend.md), [§11](docs/11-filas-jobs.md), [ADR 0004](docs/adr/0004-migracao-aws-proxmox.md), [ADR 0005](docs/adr/0005-auth-master-login.md)
|
|
4. **Multi-tenancy via BD-por-workspace.** Cada workspace tem cluster PG próprio registrado no master-login; app cliente resolve `PrismaClient` por request via `get_workspace_connection` + role `app_reader` (senha nunca trafega por HTTP). Sem coluna `tenantId` em modelos; isolamento é físico. → [§03.4](docs/03-backend.md#multi-tenancy), [§23.4](docs/23-autorizacao.md#234-isolamento-por-workspace), [ADR 0006](docs/adr/0006-multi-tenancy-bd-por-workspace.md)
|
|
5. **Tudo que pode esperar vai pra fila (BullMQ).** Email, webhook, processamento, agendado — handler HTTP só faz o mínimo síncrono. Job sempre carrega `workspaceId` no payload; worker recria o CLS. → [§11](docs/11-filas-jobs.md)
|
|
6. **LGPD by design.** Isolamento físico cross-workspace (cluster PG dedicado por cliente), PII criptografada (MinIO SSE + `pgcrypto`), redact agressivo em logs, Art. 18 implementado, hash em targeting de flags. Datacenter próprio elimina exposição ao CLOUD Act (US) sobre dados regulados. → [§07](docs/07-autenticacao.md), [§09](docs/09-observabilidade.md), [§22](docs/22-seguranca-lgpd.md)
|
|
|
|
Princípios canônicos (11 itens) em [`docs/README.md` → Princípios gerais (TL;DR)](docs/README.md#princípios-gerais-tldr). Filosofia arquitetural completa em [§21](docs/21-filosofia-arquitetural.md).
|
|
|
|
## 2. Stack canônica (May 2026)
|
|
|
|
Tabela completa com colunas Versão/Arquivo em [`docs/README.md` → Tabela canônica](docs/README.md#tabela-canônica-de-versões-may-2026). One-liners por camada:
|
|
|
|
- **Runtime:** Node 24 LTS · pnpm 11.1 · TypeScript 5.9 → [§01](docs/01-runtime-tooling.md)
|
|
- **Monorepo:** Nx 22.7 → [§02](docs/02-monorepo-nx.md)
|
|
- **Backend:** NestJS 11.1 (Express 5) · Prisma 7 · PostgreSQL 18 · `nestjs-cls` · `@nestjs/terminus` · `@nestjs/throttler` + `@nest-lab/throttler-storage-redis` → [§03](docs/03-backend.md), [§20](docs/20-praticas-nest-universais.md)
|
|
- **Frontend:** React 19.2 + Compiler · Vite 8 (Rolldown) · Ant Design 6.4 · TanStack Query 5.100 · TanStack Router · Zustand 5.0.13+ → [§04](docs/04-frontend.md)
|
|
- **API:** REST + OpenAPI 3.1 + RFC 9457 Problem Details · Zod 4 (pnpm catalog) + nestjs-zod + react-hook-form (`zodResolver`) → [§05](docs/05-api-design.md), [§06](docs/06-validacao.md)
|
|
- **Auth:** Guards NestJS + `jose` + **master-login** (IdP OAuth2/OIDC próprio em VM Proxmox; HS256 hoje → RS256 roadmap) · argon2id centralizado no IdP → [§07](docs/07-autenticacao.md), [ADR 0005](docs/adr/0005-auth-master-login.md)
|
|
- **Segredos:** **HashiCorp Vault** (KV v2) self-host · Vault Agent injeta env vars no container → [§08](docs/08-secrets-config.md)
|
|
- **Observabilidade:** Pino + nestjs-pino 10.3 · OpenTelemetry (Traces+Metrics GA; Logs Beta) · Grafana Cloud LGTM · Sentry → [§09](docs/09-observabilidade.md)
|
|
- **Flags:** OpenFeature SDK + GrowthBook self-host → [§10](docs/10-feature-flags.md)
|
|
- **Filas:** BullMQ 5.77 + `@nestjs/bullmq` 11 · Bull Board · **Valkey em VM/LXC** Proxmox → [§11](docs/11-filas-jobs.md)
|
|
- **Cache:** `@nestjs/cache-manager` v3 + cache-manager 6 + `@keyv/redis` + `cacheable` (L1) — TTL em **ms** → [§12](docs/12-cache.md)
|
|
- **Real-time:** Socket.IO 4 + `@socket.io/redis-adapter` · SSE via `@Sse()` nativo NestJS → [§13](docs/13-realtime.md)
|
|
- **Uploads:** **MinIO** (S3-compat) presigned **POST policy** + AWS SDK v3 · Uppy + `@uppy/aws-s3` · **ClamAV** em worker BullMQ · sharp 0.34 → [§14](docs/14-uploads.md)
|
|
- **Email:** **Resend** (SaaS — não self-host) + React Email via BullMQ → [§15](docs/15-email-notificacoes.md)
|
|
- **Testes:** Vitest 4.1 · Testcontainers 12 · Supertest 7.2.2 (encapsulado) · Playwright 1.60 → [§16](docs/16-testes.md)
|
|
- **Qualidade:** ESLint 10.4 flat · typescript-eslint 8.59 · Prettier 3.8.3 · eslint-plugin-import-**x** 4.16.2 · Husky 9 + lint-staged 17 · **gitleaks** → [§17](docs/17-qualidade-codigo.md)
|
|
- **CI/Deploy:** GitHub Actions + Nx Cloud · Trivy gate · pin actions por SHA · Docker multi-stage `node:24-alpine` · **Ansible/SSH para VMs Proxmox** com docker-compose rolling (backend) · **Cloudflare + Nginx** servindo SPA estática (frontend, **não containerizar**) → [§18](docs/18-cicd-containers.md)
|
|
|
|
## 3. Quando aplicar este guia
|
|
|
|
- **Greenfield:** obrigatório do dia 0.
|
|
- **Brownfield:** adoção gradual, tópico a tópico.
|
|
- **Spike/POC:** livre até 2 semanas — se virar produto, refatora.
|
|
- **Fora de escopo** (React Native, GraphQL pesado, mobile nativo): exige RFC antes.
|
|
|
|
## 4. Filosofia em 5 bullets
|
|
|
|
Aprofunde em [`docs/21-filosofia-arquitetural.md`](docs/21-filosofia-arquitetural.md).
|
|
|
|
1. **Monólito modular.** Uma única aplicação deployável (`apps/api`), organizada em **um NestJS Module por domínio de negócio** (`ComprasModule`, `VendasModule`, `EstoqueModule`, `FinanceiroModule`).
|
|
2. **Dependências apontam para dentro** (Clean Architecture). Domínio não conhece framework; módulos não importam domínio alheio direto.
|
|
3. **Um domínio = um Module = N libs** (`domain-` / `feature-` / `data-access-`). Boundaries enforçadas pelas três tags Nx ([ADR 0002](docs/adr/0002-tags-nx-canonicas.md)).
|
|
4. **Cross-domínio via fila, read-model ou ACL.** Nunca import direto entre módulos de domínios diferentes. Eventos como substantivo no passado (`OrderPlaced`, `PaymentFailed`).
|
|
5. **Entidade ≠ model Prisma.** Type Prisma é mapeado para entidade em `data-access`; mapper é o único ponto que conhece `Prisma.*`. Entidades com construtor `private` + factories `create()`/`reconstitute()`; mutações por métodos de negócio (`cancel()`, `ship()`). Side-effects (email, webhook, read-model) sempre **após** o `prisma.$transaction`, via BullMQ.
|
|
|
|
## 5. Estrutura do monorepo
|
|
|
|
```
|
|
apps/
|
|
api/ # NestJS HTTP — monólito modular (um Module por domínio)
|
|
api-worker/ # Workers BullMQ (mesma imagem, entrypoint diferente)
|
|
web/ # React + Vite SPA
|
|
web-e2e/ # Playwright
|
|
libs/
|
|
shared/<purpose>/ # usável por api e web
|
|
api/domain-<domínio>/ # entidades, VOs, repositórios abstratos
|
|
api/feature-<domínio>/ # use cases (um arquivo por ação) + Module
|
|
api/data-access-<domínio>/ # Prisma, BullMQ producers, mappers
|
|
api/util-<nome>/ # utilitários sem regra de negócio
|
|
web/<feature|data-access|ui|util>-<nome>/
|
|
```
|
|
|
|
Convenções de naming/branching/code review em [§19](docs/19-padroes-projeto.md); detalhes de tags Nx e `depConstraints` em [§02](docs/02-monorepo-nx.md) e [§21](docs/21-filosofia-arquitetural.md).
|
|
|
|
## 6. Onde aprofundar (mapa por intenção)
|
|
|
|
| Para fazer… | Vá em |
|
|
|---|---|
|
|
| **Invariantes e pegadinhas 🔥 (regras de código)** | [`CODING-RULES.md`](CODING-RULES.md) |
|
|
| Setup zero (runtime, ESM, tooling) | [§01](docs/01-runtime-tooling.md) |
|
|
| Criar/configurar libs Nx, boundaries, tags | [§02](docs/02-monorepo-nx.md), [ADR 0002](docs/adr/0002-tags-nx-canonicas.md) |
|
|
| Modelar backend (Module, Prisma, transação) | [§03](docs/03-backend.md), [§20](docs/20-praticas-nest-universais.md) |
|
|
| Frontend (componente, query, form, router) | [§04](docs/04-frontend.md) |
|
|
| Desenhar endpoint REST (paginação, erro, versão) | [§05](docs/05-api-design.md) |
|
|
| Validar entrada (Zod, DTO, i18n pt-BR) | [§06](docs/06-validacao.md) |
|
|
| Implementar auth (login, refresh, OAuth/PKCE) | [§07](docs/07-autenticacao.md) |
|
|
| Gerir secrets e env vars | [§08](docs/08-secrets-config.md) |
|
|
| Logar, tracear, alertar | [§09](docs/09-observabilidade.md) |
|
|
| Criar feature flag / experimento | [§10](docs/10-feature-flags.md) |
|
|
| Enfileirar job, scheduler, retry, DLQ | [§11](docs/11-filas-jobs.md) |
|
|
| Cachear (app, HTTP, CDN, stampede) | [§12](docs/12-cache.md) |
|
|
| WebSocket / SSE | [§13](docs/13-realtime.md) |
|
|
| Upload de arquivo / imagem | [§14](docs/14-uploads.md) |
|
|
| Enviar email / notificação (web push) | [§15](docs/15-email-notificacoes.md) |
|
|
| Escrever teste (unit, integração, E2E) | [§16](docs/16-testes.md) |
|
|
| Configurar lint / formatter / hook / gitleaks | [§17](docs/17-qualidade-codigo.md) |
|
|
| CI, Docker, deploy Proxmox (Ansible/SSH), rolling | [§18](docs/18-cicd-containers.md) |
|
|
| Dimensionar VMs Proxmox (sizing, HA, capacity) | [§24](docs/24-infra-proxmox.md) |
|
|
| Naming, branching, code review | [§19](docs/19-padroes-projeto.md) |
|
|
| Padrão Nest universal (DI, ciclo de vida, health) | [§20](docs/20-praticas-nest-universais.md) |
|
|
| Filosofia arquitetural (DDD, Clean, BC) | [§21](docs/21-filosofia-arquitetural.md) |
|
|
| LGPD (bases legais, retenção, redact, Art. 18, RoPA) | [§22](docs/22-seguranca-lgpd.md) |
|
|
| Autorização (RBAC + ABAC, BD-por-workspace, anti-IDOR) | [§23](docs/23-autorizacao.md), [ADR 0006](docs/adr/0006-multi-tenancy-bd-por-workspace.md) |
|
|
| Multi-tenancy (factory de PrismaClient, get_workspace_connection, saga de onboarding) | [§03.4](docs/03-backend.md#multi-tenancy), [ADR 0006](docs/adr/0006-multi-tenancy-bd-por-workspace.md) |
|
|
| SLOs default por tipo de endpoint / job / fluxo | [ADR 0001](docs/adr/0001-slo-defaults.md) |
|
|
| ADRs (decisões fora do escopo deste guia) | [`docs/adr/`](docs/adr/) |
|
|
|
|
## Meta-governança
|
|
|
|
- **Adotar em uma app:** copie `STACK.md` e `CODING-RULES.md` para a raiz do repo da app + referencie ambos em `AGENTS.md`. Procedimento completo (cópia, referência, sync, exceções, checklist) em [`docs/README.md` → "Como usar STACK.md em uma app"](docs/README.md#como-usar-stackmd-em-uma-app).
|
|
- **Sync:** PR que altera tabela canônica / princípios em `docs/README.md` **deve** atualizar `STACK.md` no mesmo commit; PR que altera pegadinhas **deve** atualizar `CODING-RULES.md` — enforçado por [`.gitea/workflows/stack-sync-check.yml`](.gitea/workflows/stack-sync-check.yml).
|
|
- **Mudanças de stack:** ADR em `docs/adr/NNN-titulo.md` (sequencial; nunca reescrito — `Superseded by NNN`); RFC via issue com label `rfc`. Bump trimestral de versões.
|
|
- **Mantenedores:** time de plataforma; canal `#plataforma`.
|
|
|
|
---
|
|
**Regra de ouro para o agente:** ao propor tecnologia fora desta tabela, **pergunte antes** e cite a justificativa. Para regras de como escrever o código, consulte [`CODING-RULES.md`](CODING-RULES.md).
|