Bootstrap EDEN: Fase 0 (arquitetura) e Fase 1 (monorepo + infra)

Fase 0 — descoberta e arquitetura:
- Inventário do projeto, glossário de domínio, arquitetura com bounded
  contexts e topologia de containers, threat model inicial.
- 12 ADRs cobrindo modular monolith, topologia de containers (Postgres
  isolado + eden-core/parceiros/assinante em containers e portas
  distintos), auth/sessões, modelo de permissões, criptografia/segredos,
  contrato first-class, stock ledger, separação billing/finance/fiscal,
  outbox transacional, adapters SaperX e Focus NFe, e identidade
  compartilhada entre as 3 apps.
- 14 subagentes e 7 skills especializados por domínio em .claude/.
- Hooks de segurança (PreToolUse/PostToolUse/Stop) testados via pipe.

Fase 1 — plataforma (em andamento):
- Monorepo pnpm workspaces + Turborepo: apps/{api,worker,core-web,
  reseller-web,subscriber-web} + 9 packages compartilhados.
- apps/api: NestJS mínimo com /health/live e /health/ready (checando
  Postgres real via @eden/database).
- 3 frontends Vite + React + TypeScript + Tailwind, com o favicon
  oficial do EDEN.
- packages/database: migration baseline (node-pg-migrate) criando
  roles/role_permissions/applications/users/user_applications/sessions/
  audit_log — audit log append-only com hash-chain, testado ao vivo
  (UPDATE/DELETE bloqueados pelo trigger).
- compose.yaml implementando a topologia da ADR-0002, validada de ponta
  a ponta: os 6 containers sobem e ficam saudáveis com um único
  `docker compose up`.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-03 08:01:14 -03:00
commit 44510bd019
149 changed files with 13006 additions and 0 deletions

View File

@@ -0,0 +1,18 @@
# ADR-0001: Modular Monolith como estilo arquitetural do backend
## Status
Aceito
## Contexto
O EDEN precisa cobrir 14+ domínios de negócio (CRM, contratos, estoque, financeiro, billing, fiscal, telecom, suporte, RH, etc.) servindo 3 aplicações web distintas. O legado OrçaFácil é um monolito simples (Express + Postgres) sem separação de módulo forte. Microserviços trariam isolamento de falha e escalabilidade independente, mas custam operacionalmente caro (deploy, observabilidade, transação distribuída, N bancos ou schemas) num estágio em que o time e o volume ainda não justificam esse custo — e o Master Prompt (§4.2) explicitamente pede para evitar microserviços prematuros.
## Decisão
Construir `apps/api` como **modular monolith** em NestJS: um processo, módulos por bounded context (ver `docs/architecture.md` §2) com fronteiras de import explícitas (lint/arquitetura impede um módulo importar internals de outro), comunicação entre módulos via serviço de aplicação exposto ou evento de domínio (outbox) — nunca acesso direto a tabela de outro módulo.
Candidatos naturais a extração futura para serviço próprio, se/quando o volume justificar: **Billing** (processamento em lote, alta carga periódica) e **Fiscal** (chamadas externas longas/assíncronas). Nenhuma extração é feita nesta fase.
## Consequências
- Positivo: deploy único mais simples, transação ACID cross-módulo quando necessário (ex.: fechar oferta + criar cadastro), menor custo operacional inicial.
- Positivo: fronteiras de módulo desde o dia 1 tornam uma futura extração mecânica, não uma reescrita.
- Negativo: falha de um módulo (ex.: bug de memória em geração de PDF) pode afetar o processo inteiro — mitigado por `apps/worker` separado para jobs pesados/assíncronos (PDF, billing run, fiscal) desde o início.
- Negativo: todos os módulos compartilham o mesmo pool de conexão de banco — dimensionar pool e monitorar por módulo via métricas/labels.

View File

@@ -0,0 +1,35 @@
# ADR-0002: Topologia de containers — Postgres isolado + 1 container por aplicação web
## Status
Aceito (decisão explícita do operador)
## Contexto
O EDEN tem 3 aplicações web (`core-web`, `reseller-web`, `subscriber-web`) mais a API e um worker assíncrono, além do Postgres 18 exigido pelo Master Prompt (§4.3). O operador determinou explicitamente: o banco de dados deve subir em container separado; `eden-core`, `eden-parceiro` e `eden-assinantes` devem ser containers distintos, cada um em porta própria.
## Decisão
Topologia de containers via Docker Compose (um `compose.yaml` por ambiente — dev/staging/prod usando overrides), com os seguintes serviços:
| Serviço | Container | Porta exposta ao host | Fala com Postgres? |
|---|---|---|---|
| `eden-postgres` | Postgres 18 | Não (produção) / porta alta não-padrão (dev) | — |
| `eden-redis` | Redis (quando houver job real) | Não | — |
| `eden-api` | API principal (NestJS) | `EDEN_API_PORT` (env, default 8080) | Sim — único serviço com credencial de banco |
| `eden-worker` | Jobs assíncronos (BullMQ) | Não | Sim (mesma credencial de app, escopo próprio se possível) |
| `eden-core` | Frontend ERP interno | `EDEN_CORE_PORT` (env, default 3001) | Não — só HTTP para `eden-api` |
| `eden-parceiros` | Frontend portal revenda | `EDEN_PARCEIROS_PORT` (env, default 3002) | Não — só HTTP para `eden-api` |
| `eden-assinante` | Frontend portal assinante | `EDEN_ASSINANTE_PORT` (env, default 3003) | Não — só HTTP para `eden-api` |
Regras adicionais:
1. Rede docker interna dedicada (`eden_net`); só a API tem credencial de Postgres — as 3 apps web nunca recebem `DATABASE_URL`.
2. Portas configuráveis via `.env`, nunca hardcoded no `compose.yaml`, para permitir múltiplas instâncias (dev + staging) na mesma máquina.
3. `healthcheck` obrigatório em cada serviço; `depends_on` usa `condition: service_healthy`, não apenas ordem de start.
4. Volume nomeado `eden_pgdata` para dado do Postgres; nunca bind mount direto de produção sem estratégia de backup validada.
5. Build multi-stage; imagens de produção sem devDependencies/toolchain de build.
6. Backup lógico (Master Prompt §6.15) roda a partir do container do worker (ou de um job dedicado), nunca do host diretamente — mantém a regra de "streaming, nunca materializar em disco local" também em containers.
## Consequências
- Positivo: isolamento de falha por aplicação — um crash no frontend do assinante não derruba o core nem a API.
- Positivo: cada app pode escalar/atualizar independentemente (ex.: deploy do `eden-assinante` sem tocar no `eden-core`).
- Positivo: superfície de acesso ao banco reduzida a um único serviço, simplificando auditoria de acesso a dado.
- Negativo: mais serviços para orquestrar/monitorar do que um único container "tudo junto" — mitigado por healthchecks e observabilidade centralizada (Master Prompt §16).
- A definir na Fase 1: se `eden-core`/`eden-parceiros`/`eden-assinante` são servidos como SPA estática (nginx) ou com SSR — não muda a topologia de containers, só a imagem base de cada um.

View File

@@ -0,0 +1,21 @@
# ADR-0003: Autenticação e gestão de sessão
## Status
Aceito
## Contexto
O legado usa JWT HS256 com payload mínimo (`sub`, `ver`), expiração fixa de 30 dias, sem refresh token, invalidação via `token_version` incremental (derruba todas as sessões de uma vez, nunca uma só). O Master Prompt (§5.3) pede explicitamente uma evolução: access token curto + refresh token rotativo (ou sessão server-side segura), refresh tokens armazenados em hash, histórico de sessões/dispositivos, "encerrar todas as sessões", MFA/TOTP preparado.
## Decisão
- **Access token**: JWT de vida curta (15 min), payload mínimo (`sub`, sessão id), assinado (algoritmo a confirmar em ADR de criptografia geral — HS256 mantém paridade com o legado, RS256 fica em aberto se houver necessidade de verificação por serviço externo).
- **Refresh token**: opaco, alta entropia (≥256 bits), **rotativo a cada uso** (um novo é emitido e o antigo invalidado), armazenado só como hash no banco (nunca em claro) — mesma filosofia do token de link público do legado.
- **Tabela `sessions`** (não só um contador `token_version`): permite listar sessões/dispositivos ativos e revogar individualmente **ou** todas de uma vez (superset da capacidade do legado, que só permitia "todas").
- **Vínculo por aplicação**: uma sessão registra explicitamente para qual aplicação (`core`/`reseller`/`subscriber`) foi emitida — nunca inferir pelo papel do usuário (Master Prompt §5.1).
- **MFA/TOTP**: schema preparado desde a Fase 1 (tabela de fator, secret cifrado), ativação opcional para todos, indicada como obrigatória por política para `super_admin`/`admin` assim que a UI existir.
- Senha: Argon2id (ADR-0005 detalha parâmetros/versionamento), não bcrypt.
## Consequências
- Positivo: revogação granular por sessão/dispositivo, alinhado ao pedido explícito do Master Prompt.
- Positivo: access token de vida curta reduz janela de uso de token vazado sem exigir consulta ao banco a cada request (mesma vantagem de performance que o legado tinha com JWT, mas com menor exposição).
- Negativo: mais complexidade que o modelo legado (rotação de refresh token exige lógica de "replay detection" — se um refresh token já usado for reapresentado, é sinal de token roubado; a sessão inteira deve ser revogada nesse caso).
- Migração: nenhuma — é um sistema novo, não há sessões legadas para migrar.

View File

@@ -0,0 +1,20 @@
# ADR-0004: Modelo de permissões — RBAC + peso hierárquico + escopo de dados
## Status
Aceito
## Contexto
O legado tem um sistema de feature keys com 2 níveis (`view`/`edit`) por papel, mais peso hierárquico (`role weight`) que impede um ator de administrar papel/usuário de peso maior, mais um caso especial hardcoded de "próprio vs. todos" (`ofertas`/`ofertas_others`) repetido manualmente por feature quando necessário. O Master Prompt (§5.2) pede evolução: cada permissão deve expressar recurso/ação (`view`/`create`/`edit`/`delete`/`approve`/`export`/`manage`) e escopo (`own`/`team`/`reseller`/`legal_entity`/`all`) — generalizando o padrão "próprio vs. todos" em vez de repeti-lo campo a campo.
## Decisão
- Preservar o conceito de **role weight** exatamente como no legado (nunca um ator administra papel/usuário de peso maior; `super_admin` sempre no teto, nunca editável).
- Substituir o mapa plano `{feature_key: 'view'|'edit'}` por uma matriz `role_permissions(role, resource, action, scope)` — cada linha concede uma ação sobre um recurso com um escopo. Isso generaliza o caso `ofertas`/`ofertas_others` sem precisar de uma segunda feature key por recurso: o escopo `own` já cobre "só minhas ofertas", `all`/`reseller` cobre "todas"/"da revenda".
- Papel novo nasce sem nenhuma linha (zero acesso) — replica a regra do legado de nunca herdar permissão por padrão.
- `super_admin` continua **hardcoded fora da tabela** (nunca consultado via `role_permissions`), com bypass total mas sempre auditado.
- UI de gerenciamento de papel permite configurar, por menu/módulo, ação e alcance — conforme pedido explícito do Master Prompt §5.2.
## Consequências
- Positivo: elimina a necessidade de duplicar feature key para cada distinção "próprio vs. todos" que aparecer no futuro (o legado já tinha um caso day-1, `ofertas_others` — outros vão aparecer em Contratos, Chamados, etc.).
- Positivo: mapeamento direto do padrão de autorização do legado (`requireFeatureOrSuperAdmin`) para um middleware `requirePermission(resource, action, scopeResolver)` equivalente.
- Negativo: migração de mental model para quem vai configurar papéis (matriz maior que o mapa binário do legado) — mitigado com UI que agrupa por módulo/menu como já era.
- Todo endpoint continua resolvendo escopo no servidor a partir da sessão (nunca aceitar `reseller_id`/`customer_id` do cliente) — reforça Master Prompt §12.

View File

@@ -0,0 +1,20 @@
# ADR-0005: Criptografia e gestão de segredos
## Status
Aceito
## Contexto
O legado usa bcrypt custo 10 para senha, JWT HS256 sem rotação, AES-256-GCM para o único segredo reversível identificado (senha de equipamento Control iD), HMAC-SHA256 para OTP. O Master Prompt (§5.4) pede Argon2id para senha e AES-256-GCM (ou equivalente autenticado) com versionamento de chave para todo segredo operacional reversível (API keys de IA, tokens SaperX, credenciais Control iD, secrets de gateway), com chave raiz nunca no banco.
## Decisão
- **Hash unidirecional** (senha, refresh token, tokens públicos sem necessidade de recuperação): Argon2id, parâmetros iniciais conservadores e revisáveis (memory cost, iterations, parallelism documentados em `packages/auth`), com **versionamento de parâmetro** por hash armazenado (permite aumentar custo no futuro sem invalidar hashes antigos — eles são re-hasheados no próximo login bem-sucedido).
- **Criptografia reversível de campo**: AES-256-GCM, IV de 96 bits aleatório por operação, tag de autenticação verificada na decriptação (falha se adulterado) — mesmo formato de armazenamento do legado (`iv:tag:ciphertext`, base64), reaproveitando padrão já validado em produção pela Handix.
- **Versionamento de chave**: todo campo cifrado grava também qual versão de chave raiz foi usada (`key_version`), permitindo rotação de chave raiz sem re-cifrar tudo de uma vez (re-cifra sob demanda/job de rotação).
- **Chave raiz**: nunca no banco nem na imagem do container — variável de ambiente/secret store, injetada no container em runtime. Rotação de chave raiz é operação registrada e auditada (runbook próprio).
- **OTP**: manter HMAC-SHA256 com segredo de servidor (nunca hash simples — espaço pequeno de 10⁶ valores exige resistência a rainbow table via segredo), TTL curto, uso único, máximo de tentativas com bloqueio — replicar fielmente o padrão do legado (validado em produção).
- **Cartão de crédito**: nunca armazenar CVV; tokenização via gateway/PSP; nenhum cofre de cartão caseiro (Master Prompt §5.4).
## Consequências
- Positivo: Argon2id é hoje o padrão recomendado (OWASP) sobre bcrypt, resistente a ataque por GPU/ASIC.
- Positivo: versionamento de chave/parâmetro evita "big bang" de rotação — rotação é incremental e auditável.
- Negativo: Argon2id é mais pesado computacionalmente que bcrypt custo 10 — dimensionar parâmetros considerando throughput de login esperado (não copiar cegamente defaults de biblioteca sem medir).

View File

@@ -0,0 +1,23 @@
# ADR-0006: Contrato como agregado de primeira classe
## Status
Aceito
## Contexto
No legado, "contrato" não é uma tabela — é a junção em tempo de consulta de `client_registrations` (ativos) com a `quotes` que os originou. Isso funciona para o caso simples de uma oferta = um contrato, mas não suporta amendments, renovações, múltiplas versões, ou itens/partes de contrato como entidades consultáveis. O Master Prompt (§6.6) exige transformar contrato em agregado de primeira classe.
## Decisão
Criar as tabelas: `contracts`, `contract_items`, `contract_parties`, `contract_versions`, `contract_documents`, `contract_amendments`, `contract_renewals`, `contract_status_history`, `contract_assets`, `contract_services`, `contract_billing_rules`.
Estados: `draft → pending_signature → active → suspended/cancelled/terminated/expired → renewed`.
Regras preservadas do legado (nunca perder):
- **`contract_period` (faixa de preço) permanece distinto de `fidelity_period` (permanência efetiva)** — vigência/vencimento/multa sempre calculados pela fidelidade **resolvida** (`fidelity_period` se aprovado, senão `contract_period`), nunca pela faixa de preço bruta.
- Contrato assinado grava **snapshot** dos valores jurídicos/comerciais relevantes no momento da assinatura (via `contract_versions`) — uma alteração futura de produto/preço nunca muda retroativamente um contrato já assinado (invariante nº4 do Master Prompt §24).
- Fluxo de fechamento de oferta → geração de contrato preserva a "trava" equivalente (oferta travada do legado vira, no EDEN, transição de estado do contrato que também impede edição desconforme, exceto por papel com permissão de correção auditada equivalente ao `super_admin` do legado).
## Consequências
- Positivo: permite amendments/renovações/múltiplas partes sem gambiarra de "reabrir a oferta".
- Positivo: relatórios de vencimento/MRR (equivalente ao `GET /contracts/report` do legado) passam a consultar uma tabela real em vez de uma junção calculada, com melhor performance de índice.
- Negativo: mais complexidade de schema/migração do que o legado; mitigado por ser green-field (sem dado legado a migrar automaticamente — Handix decide se há import histórico do OrçaFácil, fora do escopo desta ADR).
- Depende de: Customer 360 (Fase 2) e Commercial/Ofertas (Fase 2) já existirem — ver `docs/architecture.md` §2.

View File

@@ -0,0 +1,20 @@
# ADR-0007: Estoque como ledger de movimentos, nunca saldo editável
## Status
Aceito
## Contexto
O legado não tem módulo de estoque real — produtos têm preço e flags, mas nenhuma tabela de movimento/saldo. O Master Prompt (§6.8, §11.5) exige estoque com ledger de movimentos, ativos serializados (serial/patrimônio/MAC) e rastreabilidade completa warehouse↔cliente↔warehouse.
## Decisão
Modelar: `warehouses`, `warehouse_locations`, `stock_items`, `stock_lots` (quando necessário), `stock_movements` (ledger append-only), `stock_reservations`, `serialized_assets`, `asset_assignments`, `inventory_counts`, `transfers`, `receipts`, `issues`, `returns`, `rma`, `asset_maintenance`.
Saldo de estoque é **sempre calculado** a partir de `stock_movements` (soma de entradas/saídas), nunca uma coluna editável diretamente. Cada `serialized_asset` tem um único estado ativo por vez (nunca dois ativos "ativos" com o mesmo serial/MAC/patrimônio simultaneamente — constraint de banco, não só validação de aplicação).
Fluxo de instalação (fechamento de oferta/contrato com equipamento): reserva → seleção de unidade serializada → vínculo a contrato/cliente → movimento para instalado/comodato → rastreabilidade até devolução/baixa (Master Prompt §6.8).
## Consequências
- Positivo: auditoria completa de estoque (invariante nº7 do Master Prompt §24 — rastrear do warehouse até o cliente e de volta).
- Positivo: elimina classe de bug "saldo dessincronizado" comum em campo editável.
- Negativo: toda operação de estoque precisa passar por um serviço de domínio que grava o movimento — nenhum caminho de escrita direta em "saldo".
- Depende de: Organization (warehouses por unidade legal) já existir.

View File

@@ -0,0 +1,22 @@
# ADR-0008: Separação entre Billing, Financeiro (AR/AP) e Fiscal
## Status
Aceito
## Contexto
O legado não tem billing recorrente nem contas a receber/pagar como módulo — só a oferta/contrato com valores. O Master Prompt (§6.9, §6.10, §6.11) exige três motores distintos e explicitamente adverte: "nunca confundir faturamento, documento fiscal e recebimento: são eventos relacionados, porém distintos."
## Decisão
Três motores com dados e responsabilidades separadas:
1. **Billing** (`billing_accounts`, `billing_cycles`, `subscriptions/services`, `charge_components`, `usage_charges`, `invoices`, `invoice_items`, `invoice_adjustments`, `billing_runs`): responsável por **calcular o que é devido** (mensalidade, pró-rata, implantação, consumo) e gerar a fatura interna (`invoice`). Fechamento de billing run é idempotente e reexecutável com segurança **antes** da consolidação; depois de consolidada, uma invoice não é editada silenciosamente — usa ajuste/nota de crédito/débito ou refaturamento controlado.
2. **Finance/AR-AP**: responsável por **cobrar e receber/pagar** — títulos, parcelas, boletos (provider abstraction), dunning, conciliação, contas a pagar. Um título de AR nasce a partir de uma invoice de billing, mas é uma entidade própria (permite negociação, baixa parcial, estorno, sem tocar no billing).
3. **Fiscal**: responsável por **emitir o documento fiscal** correspondente a um item de billing já classificado (fiscal profile) — nunca hardcoded por tela. Documento fiscal é consequência do item de faturamento, não do clique de um usuário numa tela específica.
Cada camada guarda `external_id`/referência para a anterior, nunca duplica o cálculo.
## Consequências
- Positivo: permite reconciliar valor da origem (billing) até o recebimento (finance) e até o documento fiscal (fiscal) — invariante nº5 e nº6 do Master Prompt §24.
- Positivo: mudança de gateway de cobrança (Finance) não afeta o cálculo de billing; mudança de regra tributária (Fiscal) não afeta o cálculo comercial.
- Negativo: mais tabelas e mais pontos de integração entre módulos do que uma solução monolítica "fatura única" — mitigado por eventos de domínio (`invoice.created`, `payment.received`, `fiscal_document.authorized`) documentados no Master Prompt §9.2.
- Depende de: Contracts (Fase 3) e Inventory/consumo (para usage_charges) parcialmente.

View File

@@ -0,0 +1,18 @@
# ADR-0009: Outbox transacional para eventos de integração
## Status
Aceito
## Contexto
O EDEN precisa publicar eventos de domínio (`lead.created`, `contract.signed`, `invoice.overdue`, etc. — catálogo no Master Prompt §9.2) para consumo por n8n/webhooks/outros módulos, sem perder evento em caso de falha entre o commit da transação de negócio e a publicação. O legado não tem esse problema porque não publica eventos externos.
## Decisão
Toda operação que precise emitir um evento relevante grava a linha do evento na mesma transação SQL da mudança de negócio, numa tabela `outbox_events` (payload normalizado, tipo do evento, status `pending/delivered/failed`, tentativas, correlation id). Um processo separado (`apps/worker`) lê a outbox e entrega (webhook assinado HMAC, ou fila interna para o próprio módulo consumidor), marcando como entregue só após confirmação — com retry/backoff e dead-letter após esgotar tentativas.
Consumidores (internos ou externos via n8n) devem ser idempotentes por `event_id` — reentrega nunca duplica efeito.
## Consequências
- Positivo: garante "at-least-once" delivery sem depender de o processo de aplicação sobreviver após o commit (invariante nº9 do Master Prompt §24 — webhook repetido não duplica efeito, aplicado também no sentido saída).
- Positivo: replay manual de evento é trivial (reprocessar linha da outbox).
- Negativo: exige limpeza/arquivamento periódico da tabela de outbox (retenção configurável) para não crescer indefinidamente.
- Negativo: consumidores precisam de lógica de idempotência — custo replicado em cada integração, mitigado por uma camada compartilhada em `packages/integrations`.

View File

@@ -0,0 +1,19 @@
# ADR-0010: Adapter SaperX isolado
## Status
Aceito
## Contexto
SaperX é o sistema de telecom/billing externo com o qual o EDEN precisa se integrar (circuitos, DIDs, consumo/CDR, faturas). O legado (`eden.md`) não documenta integração automática com sistemas de telecom externos (a única "integração IXC" citada é manual, campo de texto livre) — SaperX é uma integração nova para o EDEN, sem precedente de código a herdar, só requisitos do Master Prompt §6.12.
## Decisão
Módulo `integrations/saperx` como adapter/port isolado (padrão do Master Prompt §13): configuração por ambiente, token criptografado (AES-256-GCM, ver ADR-0005), suporte a IP allowlist se a API exigir, timeout + retry seguro + rate limiting local + circuit breaker, correlation id em toda chamada, logs nunca com token, healthcheck de integração próprio (não derruba o `/health/ready` geral do EDEN por indisponibilidade do SaperX).
Nunca acoplar entidades internas ao payload bruto do SaperX — todo dado externo vira DTO normalizado antes de entrar no domínio, com `external_id` + snapshot de origem quando necessário para auditoria/reconciliação.
Se um endpoint necessário não estiver disponível/documentado no momento da implementação: implementar interface + mock + TODO explícito, nunca inventar resposta.
## Consequências
- Positivo: se a API do SaperX mudar ou a Handix trocar de provider de telecom no futuro, só o adapter muda — domínio (contratos, billing, customer 360) permanece intacto.
- Positivo: consistente com o mesmo padrão usado para Focus NFe e Control iD — um único modelo mental de integração externa no projeto inteiro.
- Risco conhecido: sem acesso à documentação/sandbox do SaperX nesta fase — endpoints exatos e formato de payload serão confirmados na Fase 6; até lá, contrato do adapter fica desenhado a partir dos objetivos de negócio (Master Prompt §6.12), não de um payload real.

View File

@@ -0,0 +1,18 @@
# ADR-0011: Adapter Focus NFe isolado
## Status
Aceito
## Contexto
O EDEN precisa emitir NFCom, NFS-e e recibo de locação via Focus NFe (Master Prompt §6.11). O legado tem toda a camada de **catálogos** fiscais (NCM, CFOP, municípios, cClass NFCom, cTribNac/cTribMun, IBS/CBS) e **configuração fiscal de produto** (`product_fiscal_profiles`) já madura e testada em produção, mas **não tem motor de emissão** (`fiscal_rules` existe só como schema, sem lógica) — é o ponto de partida a herdar, não a integração de emissão em si, que é nova.
## Decisão
- Portar fielmente o modelo de catálogos fiscais e `product_fiscal_profiles` do legado (índice único parcial "um profile ativo por componente de faturamento", proteção contra inativação em massa no upsert, importação automática vs. manual com dry-run obrigatório) — é infraestrutura validada, não reinventar.
- Construir `integrations/focus-nfe` como adapter/port novo: referência única/idempotente por documento, emissão, consulta, cancelamento, webhooks autenticados, persistência do request normalizado (nunca com segredo), retries com backoff, dead-letter/retry manual.
- Emissão fiscal é sempre consequência de um item de billing já classificado por fiscal profile — nunca lógica hardcoded numa tela (mesmo princípio do Master Prompt §6.11).
- `fiscal_rules` (motor de resolução automática de regra fiscal): portar como schema preparado, sem implementar motor de resolução nesta fase — mesma decisão consciente já tomada no legado ("não implementar resolução automática completa agora"), reavaliar na Fase 6.
## Consequências
- Positivo: reaproveita ~19 tabelas de catálogo fiscal já desenhadas e testadas contra fontes reais (Siscomex/IBGE), reduzindo risco de erro em modelagem tributária brasileira (área de alto custo de erro).
- Positivo: separação nítida entre "classificação fiscal do produto" e "documento fiscal emitido" evita duplicar regra tributária em múltiplos lugares (Master Prompt §6.11).
- Negativo: sem motor de resolução automática, a escolha de código fiscal por operação continua dependendo de configuração manual do fiscal profile — aceito como escopo da Fase 6; motor completo fica como trabalho futuro explícito, não "silenciosamente esquecido".

View File

@@ -0,0 +1,18 @@
# ADR-0012: Três aplicações web, identidade e backend compartilhados
## Status
Aceito
## Contexto
O EDEN precisa de 3 frontends (Core interno, Parceiros/Revenda, Assinante) com níveis de acesso e dados completamente diferentes, mas compartilhando o mesmo ecossistema de API e identidade (Master Prompt §7, §8, missão §0). O legado é uma aplicação única (OrçaFácil) sem essa separação — todo controle de acesso é por papel/feature dentro do mesmo frontend.
## Decisão
- **Uma identidade pode ter acesso a uma ou mais aplicações** (`core`/`reseller`/`subscriber`), modelado explicitamente (tabela de vínculo identidade↔aplicação), nunca inferido pelo nome do papel (Master Prompt §5.1) — evita o erro de assumir "todo `reseller_admin` só acessa `reseller`", o que impediria, por exemplo, um funcionário Handix logar como suporte em nome de uma revenda no futuro, se o negócio pedir.
- **Cada aplicação é um frontend React+Vite próprio** (`apps/core-web`, `apps/reseller-web`, `apps/subscriber-web`), cada uma em seu container (ADR-0002), consumindo a mesma API (`apps/api`) via REST versionada (`/api/v1`).
- **Isolamento de dado por escopo, nunca por frontend**: a separação de app não substitui a checagem de escopo no backend (§5.2/ADR-0004) — um usuário `reseller` autenticado contra a API nunca deve conseguir, mesmo manipulando requests, ver dado de outra revenda; isso é reforçado por teste automatizado explícito (Master Prompt §15.2, item 12).
- **Design System único** (`packages/ui`) compartilhado pelas 3 apps, derivado do tema DreamsERP, garantindo consistência visual sem duplicar componente.
## Consequências
- Positivo: onboarding de nova aplicação futura (ex.: app mobile) reaproveita a mesma API/identidade sem redesenho.
- Positivo: bug de isolamento fica mais fácil de testar (mesma API, 3 conjuntos de credenciais de teste, casos invariantes automatizados).
- Negativo: qualquer mudança de contrato de API precisa considerar as 3 apps simultaneamente — versionamento de API (`/api/v1`) e testes de contrato (Master Prompt §15.1) mitigam quebra silenciosa.

102
docs/architecture.md Normal file
View File

@@ -0,0 +1,102 @@
# EDEN — Arquitetura (Fase 0)
## 1. Estilo arquitetural
**Modular monolith** em monorepo TypeScript (pnpm workspaces + Turborepo), conforme Master Prompt §4. Um único processo de API (`apps/api`) organizado por bounded contexts internos, com fronteiras de módulo explícitas e comunicação interna via eventos de domínio (outbox) — nunca chamada direta cross-módulo que quebre a fronteira. Ver ADR-0001.
Motivo de não usar microserviços desde o início: custo operacional de dezenas de serviços não se paga no estágio atual; o modular monolith permite extrair um bounded context para serviço próprio no futuro (ex.: billing/fiscal, que já são os candidatos naturais por volume/isolamento) sem reescrever o domínio.
## 2. Bounded contexts
| Contexto | Núcleo de dados | Depende de | Agente responsável |
|---|---|---|---|
| **Identity & Access** | users, roles, permissions, sessions, resellers (vínculo) | — (fundacional) | `eden-security` |
| **Organization** | legal entities, companies, branches, warehouses, cost centers | Identity | `eden-architect` |
| **Commercial (CRM)** | leads, opportunities, quotes, pricing tiers, approval workflow | Identity, Organization | `eden-commercial` |
| **Customer 360** | client accounts (PF/PJ), reseller accounts, partners/QSA | Commercial | `eden-commercial` |
| **Contracts** | contracts, versions, amendments, renewals, status history | Customer 360, Commercial | `eden-commercial` |
| **Documents & E-signature** | templates, versions, generations, envelopes, signers, audit hash-chain | Contracts, Organization | `eden-frontend` (editor) + domínio próprio |
| **Inventory & Assets** | warehouses, stock ledger, serialized assets, RMA | Contracts (instalação) | `eden-inventory` |
| **Finance (AR/AP)** | receivables, boletos, dunning, payables, reconciliation | Contracts, Billing | `eden-finance` |
| **Billing** | billing accounts, cycles, subscriptions, invoices, billing runs | Contracts, Inventory (consumo) | `eden-finance` |
| **Fiscal** | catálogos fiscais, fiscal profiles, documentos fiscais emitidos | Billing | `eden-fiscal` |
| **Telecom (SaperX)** | circuitos, DIDs, consumo/CDR, conciliação | Customer 360, Billing | `eden-telecom` |
| **Support (Service Desk)** | tickets, SLA, OS | Customer 360, Contracts, Inventory | `eden-support` |
| **HR/Timeclock** | devices, employees, AFD, apuração, banco de horas | Organization (isolado do resto) | `eden-hr-timeclock` |
| **Integrations/Events** | outbox, webhooks, API clients, delivery log | transversal | `eden-api-integrations` |
Regra de dependência: setas só "para trás" na tabela acima (uma linha não depende de uma que a segue) — evita ciclo entre módulos. HR/Timeclock é deliberadamente isolado (só depende de Organization) — pode ser paralelizado/adiado sem travar o núcleo comercial, replicando a recomendação do próprio `eden.md`.
## 3. Estrutura do monorepo
Conforme Master Prompt §4.2:
```text
apps/
api/ # API principal (modular monolith)
worker/ # jobs assíncronos (BullMQ)
core-web/ # EDEN Core (ERP interno)
reseller-web/ # EDEN Parceiros
subscriber-web/ # EDEN Assinante
packages/
database/ # schema, migrations, query layer
contracts/ # DTOs/schemas/event contracts compartilhados
ui/ # Design System (derivado do tema DreamsERP)
auth/ # SDK de auth client-side comum às 3 apps
observability/
config/
testing/
integrations/ # adapters Focus NFe, SaperX, Control iD, S3, SMTP
domain-shared/
infra/
docker/
migrations/
docs/
.claude/
```
## 4. Topologia de deployment / containers
**Decisão explícita solicitada pelo operador**: Postgres roda em container próprio, separado dos containers de aplicação; cada uma das três aplicações web roda em seu próprio container, cada uma em porta distinta. Detalhamento completo em `docs/adr/0002-container-topology.md`. Resumo:
```text
┌─────────────────────────────────────────────────────────────┐
│ docker compose (rede interna "eden_net") │
│ │
│ ┌───────────────┐ ┌───────────────┐ ┌─────────────────┐ │
│ │ eden-postgres │ │ eden-redis │ │ eden-api │ │
│ │ :5432 (int) │ │ :6379 (int) │ │ :8080 → host │ │
│ └───────┬───────┘ └───────┬───────┘ └────────┬────────┘ │
│ │ │ │ │
│ └─────────────┬─────┴─────────────────────┘ │
│ │ (api é o único que fala com o banco) │
│ ┌───────────────┐ ┌──▼────────────┐ ┌─────────────────┐ │
│ │ eden-worker │ │ eden-core │ │ eden-parceiros │ │
│ │ (sem porta) │ │ :3001→host │ │ :3002→host │ │
│ └───────────────┘ └───────────────┘ └─────────────────┘ │
│ ┌────────────────┐ │
│ │ eden-assinante │ │
│ │ :3003→host │ │
│ └────────────────┘ │
└─────────────────────────────────────────────────────────────┘
```
Princípios:
1. **Nenhuma aplicação web fala direto com o Postgres** — todas as 3 (core/parceiros/assinante) consomem exclusivamente a API (`eden-api`), que é a única com credencial de banco. Isso preserva o requisito do Master Prompt de "nascer preparado para ser consumido por essas três aplicações" sem triplicar a superfície de acesso a dados.
2. **Postgres nunca expõe porta ao host em produção** — só rede interna do compose; em dev, opcionalmente mapeada para uma porta alta não-padrão para acesso de ferramenta local (ex. `55432:5432`), nunca `5432:5432` direto.
3. **Cada app web em porta própria e distinta**, definida em `.env` (`EDEN_CORE_PORT`, `EDEN_PARCEIROS_PORT`, `EDEN_ASSINANTE_PORT`, `EDEN_API_PORT`) — nenhuma hardcoded no compose, para permitir múltiplos ambientes na mesma máquina (dev/staging) sem colisão.
4. **Build multi-stage por app** (`infra/docker/Dockerfile.api`, `Dockerfile.web` parametrizado por app via build-arg) — imagens enxutas, sem devDependencies em produção.
5. **Healthcheck obrigatório em todo container** (Postgres via `pg_isready`, API via `/health/ready`, apps web via HTTP 200 na raiz) — `depends_on: condition: service_healthy`, não apenas ordem de start.
6. **Volumes nomeados** para dados do Postgres (`eden_pgdata`) — nunca bind mount direto de dado de produção para o filesystem do host sem estratégia de backup (backup lógico via `pg_dump` streaming para S3, Master Prompt §6.15, roda **de dentro** do container/worker, não do host).
7. Redis (cache/fila BullMQ) entra como container próprio (`eden-redis`) só quando o primeiro job assíncrono real precisar dele — não subir vazio "por precaução" (Master Prompt §4.1: "somente quando houver benefício real").
## 5. Identidade compartilhada entre as 3 apps
Uma única API de autenticação/autorização (dentro de `eden-api`) emite sessão para as 3 aplicações. Uma identidade pode ter acesso a `core`/`reseller`/`subscriber` de forma explícita (tabela de vínculo, não inferida pelo nome do papel) — ver ADR-0012 e Master Prompt §5.1.
## 6. Próximos documentos
- `docs/security/threat-model.md`
- `docs/adr/*` (decisões referenciadas acima)
- `docs/implementation-plan.md` (backlog por fase)
- `docs/data-model/*` (ERD por domínio — produzido ao entrar em cada Fase)

13
docs/assumptions.md Normal file
View File

@@ -0,0 +1,13 @@
# EDEN — Registro de Assunções (não bloqueantes)
Conforme Master Prompt §2.3 — cada item aqui é uma decisão tomada para não bloquear o progresso, com a alternativa mais segura/coerente escolhida. Revisar com o operador quando possível.
| # | Assunção | Alternativa escolhida | Revisitar quando |
|---|---|---|---|
| 1 | Retenção/eliminação de dados pessoais (LGPD) ainda não tem política definida pela Handix | Modelar coluna/config de retenção desde já no schema de Identity/Customer 360, mas manter processo de eliminação manual/auditado até jurídico definir política | Início da Fase 2 (Customer 360) |
| 2 | Ambiente de execução não tinha Docker/Node/pnpm instalados | Provisionar via gerenciador de pacote do SO no início da Fase 1, versão LTS atual do Node | Início da Fase 1 |
| 3 | Portas dos containers das 3 apps + API | Definidas via `.env` (`EDEN_CORE_PORT=3001`, `EDEN_PARCEIROS_PORT=3002`, `EDEN_ASSINANTE_PORT=3003`, `EDEN_API_PORT=8080`), não hardcoded — ver ADR-0002 | Se o operador já tiver portas reservadas em uso, ajustar `.env` |
| 4 | Projeto não estava sob controle de versão Git | Assumir que Git será iniciado no começo da Fase 1 (monorepo) — não iniciar prematuramente na Fase 0 para não versionar `tema_do_Eden.zip` (360MB) sem `.gitignore` pronto | Início da Fase 1 |
| 5 | `super_admin` inicial do EDEN | Seguir o padrão do legado (promoção via seed/migration com e-mail vindo de env `EDEN_SUPERADMIN_EMAIL`, nunca hardcoded no código) — Master Prompt §2.2 já define isso | Bootstrap da Fase 1 |
| 6 | Overtime multiplier (Art. 59 CLT) no módulo de ponto | Legado tem os campos (`overtime_multiplier`, `apply_multiplier_to_time_bank`) mas não os aplica no motor de cálculo — EDEN preserva os campos como metadado e registra decisão explícita (implementar ou não a multiplicação) só quando a Fase 9 (RH/Ponto) for iniciada | Início da Fase 9 |
| 7 | Extensão Postgres `btree_gist` para exclusão de conflito de horário (Agenda) | Legado evita a extensão deliberadamente (nunca usada em produção) e resolve conflito via transação + `SELECT ... FOR UPDATE`. EDEN preserva essa escolha por padrão — reavaliar `EXCLUDE`/GiST só se performance exigir | Início da Fase 9 (Agenda) |

58
docs/glossary.md Normal file
View File

@@ -0,0 +1,58 @@
# EDEN — Glossário de Domínio
Vocabulário Handix/telecom/ERP, preservado do legado OrçaFácil (`eden.md`) sempre que possível — não inventar sinônimos novos para conceitos já nomeados.
## Identidade e acesso
- **super_admin**: papel com bypass total, hardcoded (nunca passa por `role_permissions`), peso hierárquico fixo 100, nunca editável via UI.
- **role weight (peso de papel)**: inteiro 099 (super_admin = 100, fixo) que impede um ator de administrar/atribuir papel com peso maior que o seu, mesmo tendo a feature de gestão liberada.
- **feature key**: chave de tela/recurso gateável (`ofertas`, `clientes_todos`, `fiscal`, etc.), com dois níveis de acesso (`view`/`edit`) por papel.
- **scope (escopo de dados)**: no EDEN, evolução do padrão "próprio vs. todos" do legado para `own`/`team`/`reseller`/`legal_entity`/`all`.
- **token_version**: mecanismo legado de invalidação de sessão (incrementa a cada logout/reset de senha). No EDEN, substituído por refresh tokens revogáveis (ver ADR-0003), mas o *conceito* de "derrubar todas as sessões de um usuário" deve ser preservado.
## Comercial
- **contract_period (faixa de preço)**: período (0/12/24/36/48 meses) que determina qual coluna de preço do produto foi usada. Não é necessariamente o prazo de permanência real.
- **fidelity_period (fidelidade efetiva)**: prazo de permanência realmente assinado pelo cliente, quando **menor** que `contract_period`. Só produz efeito legal (vigência, multa, vencimento) depois de **aprovado**.
- **condição especial (`proposed_monthly_total`)**: valor mensal negociado diferente do total de tabela. Desconto exige aprovação; acréscimo (markup) não.
- **needsApproval**: `isDiscount OR hasReducedFidelity` — uma única aprovação cobre as duas exceções quando coexistem.
- **rateio proporcional**: distribuição de uma condição especial entre os itens da oferta, proporcional ao peso de cada item no total de tabela — nunca abate um item isolado.
- **oferta travada**: estado de uma oferta (`quotes`) após o cadastro de cliente ser iniciado (`client_registration_id` setado) — não editável exceto por `super_admin`.
- **deal_status**: estado do negócio (`orcamento`/`fechado`/`perdido`), distinto de `status` (estado do documento/proposta).
- **contrato (legado)**: no OrçaFácil não é tabela própria — é a junção de `client_registrations` ativos + `quotes`. No EDEN, torna-se agregado de primeira classe (`contracts`) — ver seção 6.6 do Master Prompt e ADR-0006.
## Cadastro / Cliente / Revenda
- **client_registrations**: cadastro completo (PF/PJ) de um cliente final, nascido de uma oferta fechada (ou "direto").
- **registration_status**: máquina de estados `rascunho → pendente_validacao → ativo ⇄ bloqueado/inativo`.
- **reaproveitar cadastro ativo**: atalho que copia identidade/endereço/contato de um cadastro já `ativo` para uma nova oferta, sem passar pelo formulário público de novo.
- **sócio assinante**: sócio (QSA) de uma PJ marcado como signatário — substitui inteiramente o bloco "Representante da Empresa".
- **Programa de Canais**: módulo de aprovação de revendas (`reseller_registrations`), com dois tipos: `finder` (pontual) e `recorrente` (com Termo de Adesão).
## Documentos e assinatura
- **document_template_versions**: versionamento imutável de template (Tiptap JSON); só 1 draft por vez; publicar é irreversível para aquela versão.
- **merge field**: variável de documento inserida via catálogo fechado (whitelist), nunca texto livre `{{...}}` no editor visual novo.
- **signature_envelope**: pacote de assinatura (documentos + signatários) com máquina de estados de 19 estágios (DRAFT → ... → COMPLETED).
- **hash-chain de auditoria**: cadeia SHA-256 append-only de eventos do envelope, com verificação em duas camadas (linkage + conteúdo).
- **OTP**: código de 6 dígitos, HMAC-SHA256 com segredo de servidor, TTL de 5 min, uso único.
## Fiscal
- **NFCom**: Nota Fiscal de Serviços de Comunicação (telecom).
- **NFS-e**: Nota Fiscal de Serviço eletrônica (ISS municipal).
- **fiscal profile (`product_fiscal_profiles`)**: liga um produto ao(s) código(s) fiscal(is) aplicável(is), separado por componente de faturamento (`RECURRING`/`IMPLEMENTATION`) — nunca duplicado dentro de `products`.
- **IBS/CBS**: tributos do "IVA dual" da reforma tributária brasileira — catálogos já modelados no legado, ainda sem motor de emissão.
## Ponto eletrônico
- **AFD**: Arquivo Fonte de Dados — formato legal (Portaria MTP 671/2021) de marcações de ponto, imutável uma vez importado.
- **NSR**: Número Sequencial de Registro — chave de idempotência por marcação, nunca inventado se ausente.
- **banco de horas**: livro-razão (crédito/débito em minutos) sem coluna de saldo persistida.
- **fechamento de período**: veto (não histórico paralelo) — mês `FECHADO` bloqueia recálculo/aprovação/lançamento manual até reabertura auditada.
## Plataforma / Infraestrutura
- **EDEN Core / Parceiros / Assinante**: as três aplicações web do ecossistema (ERP interno, portal de revenda, portal do assinante), compartilhando o mesmo backend de identidade/API.
- **outbox transacional**: padrão de persistência de eventos de domínio na mesma transação do negócio, para publicação confiável a integrações (n8n, webhooks) sem perda em caso de falha pós-commit.
- **adapter/port**: padrão de integração externa (Focus NFe, SaperX, Control iD) isolando domínio de detalhes de protocolo/provider.

View File

@@ -0,0 +1,83 @@
# EDEN — Plano de Implementação por Fase
Backlog macro conforme Master Prompt §18. Cada fase só inicia com o gate da fase anterior verde (build/typecheck/lint/testes críticos + doc/ADR necessária atualizada — Definition of Done, Master Prompt §20).
## Fase 0 — Descoberta e arquitetura (CONCLUÍDA — ver docs/progress.md)
- [x] Ler `eden.md` integralmente (4597 linhas, 7 módulos).
- [x] Inventariar projeto/tema/assets (`docs/project-inventory.md`).
- [x] `docs/glossary.md`.
- [x] `docs/architecture.md` (bounded contexts + topologia de containers).
- [x] `docs/security/threat-model.md`.
- [x] ADRs 00010012.
- [x] `.claude/agents/` (14 agentes).
- [x] `.claude/skills/` (7 skills mínimas).
- [x] Hooks (`PreToolUse`/`PostToolUse`/`Stop`), testados via pipe.
- [x] `docs/implementation-plan.md` (este arquivo).
- [x] Revisão cruzada final (self-review contra critérios eden-architect + eden-security + eden-database) — ver `docs/progress.md`.
**Gate de saída**: VERDE. Fase 1 pode começar quando autorizada.
## Fase 1 — Plataforma
- Monorepo (pnpm workspaces + Turborepo), `git init`.
- Docker: provisionar Docker/Node LTS/pnpm no ambiente; `compose.yaml` com topologia da ADR-0002 (Postgres separado + eden-core/parceiros/assinante em containers/portas distintas).
- Postgres 18 + migrations versionadas (`packages/database`).
- Config/env (`.env.example` completo — DB, JWT/session, SMTP, S3, chaves de criptografia).
- Logging estruturado + correlation id.
- Auth (ADR-0003), Users, Roles/Permissions/Scopes (ADR-0004).
- Companies/Legal Entities (Organization).
- S3 adapter, SMTP adapter.
- Audit log append-only (hash-chain reforçado por trigger).
- API/OpenAPI 3.1 base (`/api/v1`).
- Design System inicial (`packages/ui`) a partir do inventário do tema DreamsERP.
- Seed: entidade Handix + superadmin via env (`EDEN_SUPERADMIN_EMAIL`/`PASSWORD`).
## Fase 2 — Comercial
- CRM (leads, oportunidades, pipeline).
- Produtos/grupos/subgrupos/marcas (evoluindo `products` do legado).
- Pricing tiers (faixas 0/12/24/36/48) + fidelidade reduzida com aprovação (ADR de negócio herdada do legado, seção 6.4 do Master Prompt).
- Ofertas + approval workflow genérico.
- Customer 360 (clientes PF/PJ, cadastro público com token, sócios/QSA).
- Revendas (cadastro/aprovação + operacional).
## Fase 3 — Contratos/documentos
- Contracts first-class (ADR-0006).
- Templates de documento (Tiptap, versionamento, publicação) + PDF server-side (Playwright/Chromium, sem navegação de rede).
- Assinatura eletrônica (envelope, OTP, hash-chain, certificado, verificação pública) — portar fielmente do legado (Master Prompt §6.7).
- Portal de cadastro público (cliente/revenda).
## Fase 4 — Estoque/ativos
- Warehouse, ledger de movimentos (ADR-0007).
- Serial/patrimônio/MAC, reserva/instalação/comodato/RMA.
## Fase 5 — Billing/financeiro
- Subscription/billing engine (ADR-0008).
- Invoices, AR/AP.
- Boletos (provider abstraction), dunning, conciliação.
- Dashboards financeiros (MRR, ARR, churn, aging).
## Fase 6 — Fiscal/telecom
- Catálogos fiscais + `product_fiscal_profiles` (portados do legado).
- Adapter Focus NFCom/NFS-e (ADR-0011).
- Adapter SaperX (ADR-0010) — circuitos, DIDs, consumo, conciliação.
## Fase 7 — Suporte
- Service desk, SLA, OS, integração com portais.
## Fase 8 — Portais
- EDEN Parceiros completo (isolamento cross-reseller testado).
- EDEN Assinante completo (isolamento cross-customer testado).
## Fase 9 — RH/Ponto + backoffice legado restante
- Control iD + AFD (Portaria 671) — imutabilidade do dado bruto (Master Prompt §6.14).
- Banco de horas, fechamento de período.
- Agenda (salas/carros), backup (streaming S3), dashboards restantes.
## Fase 10 — Hardening
- E2E completos (15 fluxos mínimos do Master Prompt §15.2 + casos invariantes §15.3).
- Performance, security review, access-control review.
- Migration rehearsal, backup/restore drill.
- Runbooks (`docs/runbooks/`).
- Release readiness contra os critérios de aceitação global (Master Prompt §21).
## Dependências entre fases (resumo)
Fase 1 → 2 → 3 → 4 → 5 → 6 (fiscal depende de billing) → 7 → 8 (depende de 27 existirem parcialmente) → 9 (paralelizável a partir da Fase 1, isolada) → 10.

83
docs/progress.md Normal file
View File

@@ -0,0 +1,83 @@
# EDEN — Progresso
## Fase 0 — Descoberta e Arquitetura: CONCLUÍDA
Data: 2026-09-03.
### Entregáveis
- `docs/project-inventory.md`, `docs/glossary.md`, `docs/architecture.md`, `docs/assumptions.md`, `docs/security/threat-model.md`, `docs/implementation-plan.md`, `docs/progress.md` (este arquivo).
- 12 ADRs em `docs/adr/` (00010012), cobrindo: modular monolith, topologia de containers (Postgres isolado + eden-core/parceiros/assinante em containers/portas distintas — decisão explícita do operador), auth/sessões, modelo de permissões, criptografia/segredos, contrato first-class, stock ledger, separação billing/finance/fiscal, outbox transacional, adapter SaperX, adapter Focus NFe, três apps com identidade compartilhada.
- 14 subagentes em `.claude/agents/`: eden-architect, eden-database, eden-security, eden-commercial, eden-finance, eden-fiscal, eden-inventory, eden-telecom, eden-support, eden-hr-timeclock, eden-frontend, eden-api-integrations, eden-qa, eden-code-reviewer.
- 7 skills em `.claude/skills/`: eden-domain, eden-security, eden-finance, eden-fiscal, eden-inventory, eden-telecom, eden-timeclock — cada uma com `SKILL.md` + `references/`.
- Hooks em `.claude/settings.json` + `.claude/hooks/*`: `PreToolUse` (guarda de comandos Bash destrutivos/externos e de acesso a arquivo fora do projeto/`.ssh`/`/etc`/segredo), `PostToolUse` (lint/typecheck incremental, fail-open enquanto pnpm não existir), `Stop` (checagem advisória de segredo/TODO crítico no diff, silenciosa até existir repositório git). Testados via pipe com payloads sintéticos — todos os cenários (allow/ask/deny/fail-open) se comportaram como esperado.
### Revisão cruzada (self-review contra os critérios dos agentes eden-architect / eden-security / eden-database, criados nesta mesma fase)
**eden-architect**: bounded contexts (`docs/architecture.md` §2) têm direção de dependência consistente (nenhum ciclo); HR/Timeclock corretamente isolado; candidatos a extração futura (Billing, Fiscal) identificados sem extração prematura. Nenhuma feature de negócio foi implementada antes deste gate — consistente com o Master Prompt §18.
**eden-security**: threat model cobre as superfícies do legado (rotas públicas, auth, autorização, integrações, upload, PDF, auditoria, infraestrutura) mais os invariantes de teste obrigatórios (§15.3). Hooks `PreToolUse` já impõem, a nível de ferramenta, várias regras de §2.1/§2.2 (fora do projeto, `.ssh`/`/etc`, impressão de `.env`, SSH/SCP externo, remoção ampla de volume/prune). Pendência real registrada (não bloqueante): política de retenção/eliminação LGPD ainda não definida pela Handix (`docs/assumptions.md` #1).
**eden-database**: princípios de modelagem (§11) já refletidos nas ADRs de contrato/estoque/billing (nunca saldo editável, nunca CASCADE indiscriminado, JSONB só para snapshot/metadata). Nenhum schema físico foi criado ainda nesta fase — corretamente adiado para a Fase 1, quando o Postgres 18 realmente subir.
**Nota**: esta revisão foi feita pela própria sessão orquestradora aplicando os critérios definidos nos arquivos de agente recém-criados. Os subagentes dedicados (`eden-architect`, `eden-security`, `eden-database`) ficam disponíveis para revisões reais em sessões futuras assim que o Claude Code os carregar como subagent types.
### Pendências não bloqueantes (ver `docs/assumptions.md`)
1. Política de retenção/eliminação de dados pessoais (LGPD) — Handix ainda não definiu.
2. Docker/Node/pnpm precisam ser provisionados no ambiente antes da Fase 1.
3. Portas dos containers definidas via `.env` (não fixas) — ver ADR-0002.
4. Git ainda não iniciado no projeto — planejado para o início da Fase 1.
5. Inventário fino do `tema_do_Eden.zip` (extração de componentes) adiado para o início de `eden-frontend`.
## Gate de saída da Fase 0: VERDE
Todos os itens do checklist da seção 22 do Master Prompt (“Primeira Execução”) estão completos.
---
## Fase 1 — Plataforma: EM ANDAMENTO
Data de início: 2026-09-03.
### Ambiente provisionado
- Docker CE 29.7.2 + Compose v5.5.0 (repositório oficial Docker, não o `docker.io` do Debian) instalados via apt.
- Node.js 22.23.2 LTS (NodeSource) + pnpm 11.25.0 (via corepack).
- Git 2.47.3. Repositório inicializado (`main`), remoto `origin` = `https://git.falehandix.com.br/Matheus/eden.git` (nenhum push feito ainda).
### Monorepo
- pnpm workspaces + Turborepo. 5 apps (`api`, `worker`, `core-web`, `reseller-web`, `subscriber-web`) + 9 packages, todos com `package.json`/`tsconfig.json` válidos.
- `pnpm install`, `pnpm turbo run typecheck` e `pnpm turbo run build` passam 100% (15/15 e 14/14 tarefas, respectivamente) em todo o monorepo.
- `apps/api`: NestJS mínimo com `/health/live` e `/health/ready` (este último checando Postgres de verdade via `@eden/database`).
- `apps/worker`: placeholder que confirma conectividade com o banco; sem BullMQ/Redis ainda (conforme ADR-0002 — só entra quando houver job real).
- `apps/core-web`, `apps/reseller-web`, `apps/subscriber-web`: Vite + React + TS + Tailwind, cada um com favicon oficial do EDEN.
- `packages/database`: migrations via `node-pg-migrate` (formato `.cjs`), client de query (`pg` Pool).
### Banco de dados
- Migration baseline aplicada com sucesso contra Postgres 18.6 real (container `eden-postgres`): `roles`, `role_permissions`, `applications`, `users`, `user_applications`, `sessions`, `audit_log` — cobrindo Identity & Access (ADR-0003/ADR-0004) e um audit log append-only com hash-chain (testado: `UPDATE`/`DELETE` são efetivamente bloqueados pelo trigger, só liberados via `SET LOCAL eden.allow_audit_mutation`).
- Seeds: 4 papéis do sistema (pesos idênticos ao legado) + as 3 aplicações (`core`/`reseller`/`subscriber`).
- Organization (empresas/entidades legais), Commercial e demais bounded contexts **ainda não têm migration** — ficam para quando cada fase começar, por design (ver ADR-0001).
### Docker Compose — topologia ADR-0002 validada de ponta a ponta
`docker compose --env-file .env up -d` sobe os 6 serviços com sucesso:
| Serviço | Status observado |
|---|---|
| `eden-postgres` | healthy — porta dev 55432, nunca 5432 direto |
| `eden-api` | healthy — único serviço com `DATABASE_URL`; `/health/ready` confirma Postgres via rede interna |
| `eden-worker` | up — conecta ao Postgres, sem porta exposta |
| `eden-core` (:3001) | healthy — HTTP 200 |
| `eden-parceiros` (:3002) | healthy — HTTP 200 |
| `eden-assinante` (:3003) | healthy — HTTP 200 |
Bugs de bootstrap corrigidos nesta sessão (documentados aqui para não se repetirem):
1. Imagem oficial `postgres:18-alpine` mudou o layout do volume — precisa montar `/var/lib/postgresql` (não `.../data`).
2. `apps/api/package.json` tinha `"type": "module"` incompatível com o `tsconfig` (saída CommonJS) — Node falhava com `exports is not defined`.
3. `node-pg-migrate --envPath` não carregava o `.env` corretamente nesta versão — trocado por `bash -c 'source .env; ...'` nos scripts `migrate:up`/`migrate:down`.
4. Healthcheck dos 3 frontends usava `wget http://localhost/...`, que resolve para `::1` (IPv6) dentro do container — nginx só escuta IPv4; trocado para `127.0.0.1`.
### Pendências da Fase 1 (não iniciadas)
- Módulo de autenticação real (Argon2id, JWT curto + refresh rotativo, MFA) — ADR-0003 desenhada, implementação ainda não começou.
- Companies/Legal Entities (Organization).
- Adapters S3/SMTP.
- OpenAPI 3.1.
- Extração do Design System a partir do tema DreamsERP (`packages/ui` ainda é placeholder).
- Nenhum commit git feito ainda — aguardando solicitação explícita do operador.

59
docs/project-inventory.md Normal file
View File

@@ -0,0 +1,59 @@
# EDEN — Inventário do Projeto
Estado em: 2026-09-03 (Fase 0 — Descoberta e Arquitetura).
## 1. Arquivos de origem (raiz do projeto)
| Arquivo | Tamanho | Papel |
|---|---|---|
| `EDEN_MASTER_PROMPT_CLAUDE.md` | 45.8 KB | Fonte de verdade nº1 — missão, regras operacionais, arquitetura alvo, ordem de implementação. |
| `eden.md` | 325.5 KB / 4597 linhas | Fonte de verdade nº2 — especificação funcional completa do legado OrçaFácil (engenharia reversa). Índice de 7 módulos, ver seção 3 abaixo. |
| `tema_do_Eden.zip` | 360 MB | Tema visual comprado: **DreamsERP v1.0.1** (Angular + Bootstrap). Base para o Design System do EDEN — não copiar JS/Angular, extrair componentes visuais para React/Tailwind. |
| `Eden_logo_horizontal.png` | 454 KB | Logo oficial — uso em headers/documentos. |
| `Eden_logo_vertical.png` | 432 KB | Logo oficial — uso em telas de login/splash. |
| `eden_fav_ico.png` | 573 KB | Favicon oficial — precisa ser convertido/otimizado para tamanhos padrão de favicon (16/32/180px) antes do uso web. |
## 2. Conteúdo do `tema_do_Eden.zip`
- Raiz: `dreamserp-v1.0.1/`.
- Contém: `angular.zip` (build/fonte Angular do template), `documentation/` (HTML de documentação do tema, com assets próprios — Bootstrap, fontes Nunito/Poppins, imagens de banner/logo/tecnologia).
- Total de 2198 entradas no arquivo.
- **Decisão registrada em ADR-0012 pendente de detalhamento**: nenhuma regra de negócio do EDEN deve depender de HTML/JS do tema; extrair apenas tokens visuais (cores, tipografia, espaçamento, componentes) para `packages/ui`.
- Inventário completo de componentes reaproveitáveis fica pendente para quando o Design System (`eden-frontend`) for iniciado na Fase 1 — extrair o zip para pasta temporária dentro do projeto (`.tmp/theme-inventory/`, git-ignorada) só nesse momento, para não versionar 360MB de asset de terceiro sem necessidade.
## 3. Índice de módulos do `eden.md` (legado OrçaFácil)
| # | Módulo | Linhas aprox. | Mapeia para (EDEN) |
|---|---|---|---|
| 1 | Auth, Usuários, Papéis, Permissões, Segurança | 11450 | `eden-security`, IAM (Fase 1) |
| 2 | Produtos, Ofertas (Quotes), Faixas de Preço/Fidelidade, Contratos | 6901450 | `eden-commercial` (Fase 2), `eden-commercial`→Contratos first-class (Fase 3) |
| 3 | Cadastro de Cliente e Cadastro/Gestão de Revendas | 14512206 | `eden-commercial` (Customer 360, Revendas) (Fase 2/8) |
| 4 | Templates de Documentos, PDF, Assinatura Eletrônica | 22072822 | módulo Documentos (Fase 3) |
| 5 | Módulo Fiscal (NCM, CFOP, Municípios) | 28233143 | `eden-fiscal` (Fase 6) |
| 6 | Módulo de Ponto Eletrônico (Timeclock) | 31444141 | `eden-hr-timeclock` (Fase 9) |
| 7 | Backoffice diverso (Backup, Agenda, Welcome Page, Empresa, Dashboard) | 41424597 | plataforma/backoffice (Fase 1/9) |
Leitura completa registrada — nenhuma seção pulada.
## 3.1 Controle de versão
- Repositório git inicializado em `/opt/eden` na Fase 1 (branch `main`).
- Remoto `origin`: `https://git.falehandix.com.br/Matheus/eden.git` (servidor git próprio da Handix, definido pelo operador).
- Nenhum push realizado ainda — commits/push só ocorrem quando explicitamente solicitados.
## 4. Ambiente de execução observado
- Sistema operacional: Linux (Debian 13), sem systemd de usuário próprio visível além do host.
- **Não instalados neste ambiente**: `docker`, `docker compose`, `node`, `pnpm`. Precisam ser provisionados antes da Fase 1 (bootstrap de plataforma).
- Não é um repositório Git (`git status` não aplicável) — decisão pendente sobre iniciar `git init` no início da Fase 1.
## 5. Decisões já tomadas nesta Fase 0
- Topologia de deployment: Postgres em container próprio + um container por aplicação web (`eden-core`, `eden-parceiros`, `eden-assinante`), cada um em porta distinta — ver `docs/adr/0002-container-topology.md`.
- Demais decisões arquiteturais: ver `docs/adr/`.
## 6. Pendências explícitas (não bloqueantes, registradas conforme regra 2.3 do Master Prompt)
- Extração/inventário fino do `tema_do_Eden.zip` (componentes reaproveitáveis) — adiado para o início de `eden-frontend`.
- Provisionamento de Docker/Node/pnpm no ambiente — parte da Fase 1.
- Definição de qual gerenciador de containers/orquestração (Docker Compose simples vs. outra ferramenta) — assumido Docker Compose por ser o que o Master Prompt (seção 4.3) já pede; ver ADR-0002.

View File

@@ -0,0 +1,82 @@
# EDEN — Threat Model (Fase 0)
Modelo inicial, por bounded context, método STRIDE simplificado. Revisar a cada fase (§18 do Master Prompt) com o agente `eden-security`.
## 1. Ativos críticos
1. Credenciais de autenticação (senhas, refresh tokens, OTP, tokens de link público/assinatura).
2. Dados pessoais PF/PJ (CPF/CNPJ, endereço, contatos) — LGPD.
3. Segredos de integração (Focus NFe, SaperX, Control iD, SMTP, S3, chaves de IA) — sempre cifrados em repouso (AES-256-GCM), chave raiz fora do banco.
4. Registros financeiros/fiscais (títulos, faturas, documentos fiscais emitidos) — integridade e auditabilidade.
5. Cadeia de auditoria de assinatura eletrônica (hash-chain) — valor probatório/legal.
6. Dado bruto de ponto (AFD) — valor legal, imutabilidade.
7. Dump de backup do Postgres (contém tudo acima) — acesso altamente restrito.
## 2. Superfícies de ataque e mitigação por camada
### 2.1 Rotas públicas sem autenticação
Existem por necessidade de negócio (cadastro de cliente/revenda, assinatura eletrônica, verificação pública, ViaCEP/CNPJ lookup client-side). Mitigação obrigatória em toda rota pública nova:
- Token opaco ≥96 bits de entropia como capacidade de acesso, nunca sequencial/adivinhável.
- Rate limiting por IP **e** por token/identidade quando aplicável (duas dimensões, nunca uma só).
- Revalidação total de regra de negócio no backend — o cliente é sempre não confiável.
- 404/409 sem vazar existência de recurso quando aplicável (mensagens genéricas para "não existe" vs. "já usado").
### 2.2 Autenticação e sessão
- Herdar do legado: `token_version`-like mecanismo de invalidação global, MAS evoluir para refresh token rotativo hashado (ADR-0003) — não repetir JWT de 30 dias sem revogação.
- Argon2id (não bcrypt) para novo hash de senha — custo a definir em ADR de segurança/config, revisável sem quebrar hashes existentes (versionamento de parâmetro).
- MFA/TOTP obrigatório para `super_admin`/`admin` assim que o módulo existir.
- Lockout progressivo por conta + rate limit por IP (duplo, como no legado) — nunca só um dos dois.
### 2.3 Autorização
- Nunca confiar em `role`, `customer_id`, `reseller_id`, `legal_entity_id` vindos do cliente — resolver sempre a partir da sessão/token no servidor.
- `super_admin` mantém bypass total mas toda ação sensível permanece auditada (bypass de autorização ≠ bypass de auditoria).
- Testar isolamento cross-reseller e cross-subscriber explicitamente em CI (casos invariantes do Master Prompt §15.3).
### 2.4 Dados em trânsito/repouso
- TLS obrigatório ponta a ponta (terminação em proxy reverso — nunca assumir rede interna "confiável" sem TLS entre containers quando trafegar dado sensível entre hosts distintos; dentro do mesmo compose/host, aceitável por rede docker isolada, mas revisar se algum dia sair para múltiplos hosts).
- Campos de alto risco (ver Master Prompt §5.4) cifrados com AES-256-GCM, chave raiz via secret manager/env fora do banco, versionamento de chave.
- Nenhum arquivo (documento, anexo, backup) exposto por URL pública direta — sempre proxy autenticado pelo backend (padrão herdado do legado, preservar).
### 2.5 Integrações externas (Focus NFe, SaperX, Control iD, n8n)
- Adapter/port isolado por provider (Master Prompt §13) — nunca acoplar domínio ao payload bruto externo.
- Timeout + retry com backoff + circuit breaker — indisponibilidade externa nunca corrompe o ERP nem trava a request HTTP do usuário (usar fila/worker).
- Webhooks sempre autenticados (assinatura HMAC) e idempotentes (event id + delivery log).
- n8n nunca acessa o Postgres diretamente — só via API/eventos com service accounts escopados.
### 2.6 Upload de arquivo
- Validação de MIME real (não só extensão), limite de tamanho por rota, scan hook preparado para malware, armazenamento fora do webroot, nunca executável a partir do storage.
### 2.7 Geração de documento/PDF
- Sanitização de HTML em duas camadas (allowlist estrita de tags/atributos/estilos/schemes de URL) antes de qualquer renderização — herdar do legado.
- Renderer (Chromium/Playwright) sem navegação de rede (`page.setContent` apenas, bloquear qualquer request de rede) — elimina SSRF por construção, herdar do legado.
### 2.8 Auditoria
- Append-only reforçado em nível de banco (trigger que recusa UPDATE/DELETE fora de uma escotilha administrativa explícita e ela própria auditada) — não confiar só em "a aplicação nunca faz UPDATE".
- Ordem de eventos por sequência monotônica (serial/bigserial), nunca por timestamp (timestamps podem colidir dentro de uma transação).
- Nunca gravar segredo em claro no audit log (nem em metadata JSON).
### 2.9 Infraestrutura/containers
- Postgres nunca exposto publicamente (ver `docs/architecture.md` §4).
- Segredos de ambiente via `.env`/secret store, nunca em imagem de container ou repositório.
- Cada container roda com usuário não-root quando a imagem base permitir.
- Backup: dump em streaming (nunca materializado em disco/memória local), acesso de restauração com fricção deliberada (confirmação explícita da chave do backup, como no legado).
## 3. Casos invariantes de segurança (a testar sempre — Master Prompt §15.3)
- Desconto pendente nunca vira valor legal aprovado sem `approval_status = approved`.
- `fidelity_period` não aprovado nunca altera vigência/multa/vencimento legal.
- Mesmo serial/MAC/patrimônio nunca alocado duas vezes simultaneamente.
- Webhook repetido nunca duplica pagamento; billing run repetido nunca duplica fatura; mesma referência fiscal nunca emite documento fiscal duplicado.
- Usuário de revenda nunca acessa dado de outra revenda alterando UUID na URL; assinante nunca acessa documento de outro customer account.
- AFD bruto nunca é alterável por nenhuma rota administrativa.
- Audit log crítico nunca é mutável pela aplicação em uso normal.
## 4. LGPD — pontos de atenção específicos
- Minimização: cadastro público de cliente/revenda já segue esse princípio no legado (só pede o necessário por PF/PJ) — preservar.
- Direito de exportação/eliminação do titular: não existe hoje no legado — **gap a suprir no EDEN**, registrar ADR quando o módulo de Identity/Customer 360 for implementado.
- Retenção configurável: não existe hoje no legado (dados nunca expiram automaticamente) — decisão de produto a tomar com jurídico/DPO da Handix antes da Fase 2, registrar assunção em `docs/assumptions.md` enquanto isso.
## 5. Revisão
Este documento deve ser revisitado ao final de cada fase (Master Prompt §18) e sempre que um novo adapter de integração externa for adicionado.