122 lines
15 KiB
Markdown
122 lines
15 KiB
Markdown
# 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/` (0001–0012), 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`.
|
||
|
||
### Auth, permissões, Companies e OpenAPI — implementados e testados ao vivo
|
||
|
||
- **Auth** (`apps/api/src/auth/`): Argon2id (parâmetros versionados, ADR-0005), JWT de acesso de 15 min, refresh token opaco (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 `POST /api/v1/auth/{login,refresh,logout}` e `GET /api/v1/auth/me`.
|
||
- **Permissões** (`apps/api/src/auth/permissions.ts`, `permission.guard.ts`): resource+action+scope (ADR-0004), `super_admin` com bypass hardcoded (nunca consulta `role_permissions`, espelhando a trava também existente no banco). Guard resolve permissões do banco a cada request (nunca cacheado no JWT) — mudança de papel tem efeito imediato, mesma filosofia do legado.
|
||
- **Companies** (`apps/api/src/companies/` + migration `1788437478189_companies`): CRUD com leitura aberta a qualquer autenticado e escrita restrita a `companies:manage`; validação de CNPJ (dígito verificador, `packages/domain-shared`) testada com CNPJ válido/inválido conhecidos.
|
||
- **Seed automático**: `SeedService` cria o primeiro `super_admin` a partir de `EDEN_SUPERADMIN_EMAIL`/`PASSWORD` só quando `users` está vazia — testado (log `super_admin inicial criado`).
|
||
- **OpenAPI/Swagger**: `/api/docs` (UI) e `/api/docs-json`, cobrindo todos os endpoints atuais.
|
||
- **Validação/segurança de request**: `ValidationPipe` global com `whitelist`+`forbidNonWhitelisted` (proteção contra mass-assignment) — testado (`id`/`isActive` extras num POST de company são rejeitados com 400).
|
||
|
||
Testes manuais realizados contra a stack real (não só typecheck): login com senha errada → 401 genérico; refresh rotaciona e o token antigo some; reuso do token antigo → 401 + toda a cadeia revogada; logout revoga e é idempotente; audit log com a sequência completa de eventos (`auth.login`, `auth.refresh`, `auth.refresh_replay_detected`, `company.created`).
|
||
|
||
### CRUD de Usuários/Papéis, Products, Resellers, adapters S3/SMTP — implementados via 4 subagentes especializados em paralelo (worktrees isolados) + trabalho direto
|
||
|
||
Estratégia: 4 subagentes (`general-purpose`, atuando com a persona `eden-commercial`/`eden-api-integrations` definida em `.claude/agents/`, já que os subagent types customizados ainda não carregaram nesta sessão) rodaram em paralelo, cada um em `git worktree` isolado, enquanto o CRUD de Usuários/Papéis foi feito diretamente (por tocar peso hierárquico e segurança). Cada agente foi instruído a não editar `app.module.ts` nem `packages/database/src/index.ts` — a integração final (merge das branches, wiring, resolução de conflitos, rebuild, teste ao vivo) foi feita manualmente.
|
||
|
||
- **Users/Roles** (`apps/api/src/users/`, `apps/api/src/roles/`): convite com senha temporária, troca de senha self-service, reset administrativo, grant/revoke de aplicação — tudo com checagem de peso hierárquico (`assertCanAssignRole`/`assertCanActOnUser`, eden.md §1.6). CRUD de papéis e `role_permissions` exclusivo `super_admin` (`SuperAdminGuard`), deliberadamente não generalizado para o modelo de permissão (raiz do próprio sistema de autorização).
|
||
- **Products** (`apps/api/src/products/` + migration `products`): catálogo com as 5 faixas de preço fixas, `product_code` sequencial, flags de rastreamento (estoque/serial/patrimônio/MAC). Leitura aberta, escrita via `products:edit`.
|
||
- **Resellers** (`apps/api/src/resellers/` + migration `resellers`): CRUD operacional + vínculo usuário↔revenda (`users.reseller_id`). Leitura aberta, escrita via `resellers:edit` — desvio deliberado do legado (que travava em `requireAdmin`), documentado em comentário.
|
||
- **Adapters S3/SMTP** (`packages/integrations/`): portados fielmente do legado — S3 falha alto (erro claro se não configurado), SMTP falha silencioso (nunca quebra um fluxo de negócio por causa de e-mail).
|
||
|
||
- **CRM** (`apps/api/src/leads/`, `apps/api/src/opportunities/` + migration `crm`): leads e oportunidades com conversão transacional (`convertLeadToOpportunity`, `FOR UPDATE` + `withTransaction`). Diferente de Companies/Products, leitura também exige permissão (`leads:view`/`opportunities:view`) por conter PII de prospect.
|
||
|
||
**4 bugs reais encontrados em teste manual e corrigidos antes do commit final:**
|
||
1. `assertCanAssignRole`/`assertCanActOnUser` pulavam a validação de existência do papel quando o ator era `super_admin` (o bypass de peso pulava a checagem inteira) — convidar usuário com `role_key` inexistente estourava a constraint FK do banco como 500 não tratado em vez de 400 claro.
|
||
2. `PATCH /v1/resellers/:id/assign-user` aceitava um `resellerId` diferente no corpo, que na prática era o valor usado — o `:id` da URL virava só uma checagem de existência, não o alvo real da atribuição. Corrigido para o `:id` da URL ser a única fonte de verdade; desatribuição virou endpoint próprio (`POST /v1/resellers/unassign-user`).
|
||
3. Os controllers de Leads/Opportunities liam `req.user?.id` em vez de usar `@CurrentUser()`/`request.edenUser` (o padrão real do `JwtAuthGuard`) — todo evento de auditoria de lead/oportunidade estaria gravando `actorId: null` sempre. O agente que os escreveu não tinha o módulo de auth disponível no worktree dele para testar isso de verdade (só stubou e reverteu antes de commitar).
|
||
4. As chamadas `appendAuditEvent()` de leads/opportunities omitiam o campo obrigatório `actorType` (6 ocorrências).
|
||
|
||
Também precisou renomear o timestamp da migration de CRM, que o agente gerou com valor anterior ao da migration de `resellers` (já aplicada por outro agente/merge) — `node-pg-migrate` recusa migration fora de ordem.
|
||
|
||
Todos os módulos testados ao vivo contra a stack real (não só typecheck): convite de usuário, papel inexistente (400 após o fix), CRUD de produto com preços NUMERIC corretos, CRUD de revenda, atribuição/desatribuição de usuário à revenda, lead→oportunidade transacional.
|
||
|
||
### Suíte de testes de integração (agente eden-qa)
|
||
|
||
Vitest + supertest + `@nestjs/testing` (bootstrap real do Nest, sem mock) contra o Postgres real — 5 arquivos, 15 testes, todos verdes: `auth.spec.ts` (anti-enumeração, rotação de refresh, **detecção de replay fim-a-fim**, logout idempotente), `role-weight.spec.ts` (guarda a regressão do bug #1), `companies.spec.ts` (CNPJ), `mass-assignment.spec.ts` (whitelist), `reseller-assignment.spec.ts` (guarda a regressão do bug #2). Achado técnico do agente: o `esbuild` (transform padrão do Vitest) não implementa `emitDecoratorMetadata`, quebrando toda injeção de dependência do Nest silenciosamente sob teste — corrigido trocando para SWC (`unplugin-swc`), abordagem padrão documentada pelo próprio NestJS. Rodar com `pnpm --filter @eden/api test`.
|
||
|
||
### Resumo do lote de agentes paralelos
|
||
|
||
6 subagentes no total (4 + 1 QA + Users/Roles feito diretamente), rodando em `git worktree` isolados, revisados e mesclados manualmente um a um (nunca merge automático sem verificação). **4 bugs reais** encontrados só porque cada módulo foi testado contra a stack viva antes do commit — nenhum deles teria aparecido só com typecheck/build, que todos os agentes já reportavam verde. Padrão validado: delegar implementação para agentes especializados funciona bem para módulos CRUD bem especificados, mas a integração final (merge, wiring, teste ao vivo, revisão) precisa ficar com quem tem visão do sistema inteiro.
|
||
|
||
### Pendências da Fase 1 (não iniciadas)
|
||
- MFA/TOTP (schema já existe — `users.mfa_*` — endpoint ainda não implementado).
|
||
- Extração do Design System a partir do tema DreamsERP (`packages/ui` ainda é placeholder).
|
||
- Wiring dos adapters S3/SMTP em algum módulo consumidor real (hoje só existem como biblioteca em `packages/integrations`, nada os chama ainda).
|
||
- Nota de dado de teste: a empresa "Handix Telecom LTDA" e a revenda "Handix (revenda própria)" criadas durante os testes usam dados de exemplo, não os dados reais da Handix — substituir/remover antes de qualquer ambiente que não seja dev local.
|