Commit Graph

9 Commits

Author SHA1 Message Date
18838a9031 feat(api): Quotes, Client Registration e esqueleto de Contratos
Fecha o núcleo comercial da Fase 2/3: motor de precificação de Ofertas
(feito diretamente, dado o risco de erro de arredondamento/regra de
negócio), Cadastro de Cliente e esqueleto de Contratos (via 2 subagentes
em paralelo, salvos manualmente após ambos baterem no limite de gasto
mensal da conta — trabalho não commitado nos worktrees foi revisado
arquivo a arquivo e copiado para main, com as peças faltantes
completadas diretamente).

- Quotes: pricing.ts porta as fórmulas do legado (eden.md §7/§8) —
  needsApproval, faixas de condição de pagamento, efeito legal da
  fidelidade condicionado a approval_status==='approved'. Fluxo
  criar→decidir aprovação→fechar negócio (vinculado a um cadastro de
  cliente, com guarda contra fechamento duplo).
- Client Registration: cadastro direto (eden.md §3), MVP autenticado-only
  (sem token público de autoatendimento, upload ou lookup CNPJ/CEP nesta
  fase — documentado em comentário).
- Contracts: máquina de estados do ADR-0006 imposta via SELECT...FOR
  UPDATE + tabela de transições, com signed_at/activated_at e histórico
  de status; 4 das 11 tabelas do ADR-0006 (as demais adiadas).

2 bugs próprios corrigidos antes do commit: UpdateQuoteInput usava
COALESCE para campos financeiros (undefined do JS apagaria valor em
update parcial) — campos tornados obrigatórios; User.reseller_id/
can_approve_discount faltavam em types.ts apesar das colunas já
existirem no banco desde migrations anteriores.

Verificado: pnpm turbo run typecheck build (28/28), pnpm test (15/15),
e todo o fluxo testado ao vivo via curl contra a stack Docker real,
incluindo cenários de erro (transição de status inválida, FK de produto
inexistente, fechamento duplo, 401 sem token) e trilha de auditoria
conferida no Postgres.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-03 12:25:49 -03:00
e7d3668154 fix: renomeia timestamp da migration de CRM (estava antes de resellers já aplicada)
node-pg-migrate recusa rodar uma migration cujo timestamp precede uma já
aplicada (check-order). O agente gerou 1788439012582 (CRM) antes de
1788439142825 (resellers) já ter sido mesclada e aplicada. Renomeado
para 1788444193993, aplicado com sucesso.
2026-09-03 11:03:39 -03:00
f56c3c9054 Integra módulo de CRM (leads/opportunities); corrige 2 bugs reais do agente
- Wire LeadsModule/OpportunitiesModule em app.module.ts; adiciona os
  exports correspondentes ao barrel @eden/database.

Bugs reais encontrados e corrigidos antes do commit (não pegos pelo
próprio agente porque ele não tinha o módulo de auth disponível no
worktree dele para testar de verdade — só stubado e revertido):

1. Os controllers de Leads/Opportunities liam `req.user?.id`, mas nosso
   JwtAuthGuard real popula `request.edenUser`, nunca `request.user` —
   todo evento de auditoria de lead/oportunidade estaria gravando
   actorId: null sempre, perdendo a atribuição de quem fez a ação.
   Trocado para o padrão real (@CurrentUser() + EdenAuthenticatedUser).
2. As chamadas appendAuditEvent() nos dois services omitiam o campo
   obrigatório `actorType` — corrigido para "user" em todas as 6
   ocorrências.

Também corrigidos: import de guards/decorators via um barrel
"../auth" inexistente (trocado pelos caminhos reais), e os dois módulos
não importavam AuthModule (necessário para o Nest resolver as
dependências do JwtAuthGuard via DI).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-03 11:02:40 -03:00
a8f77e4068 Add CRM leads/opportunities module (Master Prompt §6.2 MVP)
Greenfield for EDEN — eden.md has no CRM module, so this is driven by the
Master Prompt's requirements, not a legacy port.

- Migration 1788439012582_crm.cjs: leads + opportunities tables, free-text
  status/stage (documented via COMMENT ON COLUMN, no CHECK yet — a
  configurable pipeline is a future refinement), indexes on status/owner_id
  and stage/owner_id, set_updated_at triggers reusing the baseline
  schema's trigger function.
- packages/database/src/repositories/{leads,opportunities}.ts: list/get/
  create/update per companies.ts conventions (COALESCE-based partial
  update), plus convertLeadToOpportunity(leadId, input) wrapped in
  withTransaction — inserts the opportunity (lead_id set) and marks the
  lead 'converted' atomically.
- apps/api/src/{leads,opportunities}/: NestJS modules mirroring the
  Companies module structure (controller/service/module/dto). Routes
  v1/leads and v1/opportunities. Because leads/opportunities carry
  prospect PII (unlike the open-read Companies/Products catalog), reads
  are also gated behind @RequirePermission('<resource>', 'view'), not
  just JwtAuthGuard. Writes require '<resource>', 'edit'.
  POST /v1/leads/:id/convert gated by 'leads'/'edit'. Audit events:
  lead.created/updated/converted, opportunity.created/updated.
- Added class-validator/class-transformer to apps/api/package.json
  (needed for the DTOs; not previously a direct dependency).

Known cross-agent dependency gap (by design, not a bug in this code):
this worktree branched before any sibling agent's work landed, so
apps/api/src/auth/ (JwtAuthGuard, PermissionGuard, RequirePermission) and
the Companies module referenced as this task's template do not exist yet
here, and packages/database/src/index.ts / apps/api/src/app.module.ts are
explicitly off-limits for me to edit (merge-conflict avoidance across the
4 parallel agents). `pnpm --filter @eden/database typecheck/build` pass
unconditionally. `pnpm --filter @eden/api typecheck/build` currently fail
with exactly two error classes: "Cannot find module '../auth'" and
"@eden/database has no exported member <leads/opportunities repo fns,
auditRepo>" — both expected to resolve once the auth module and the
index.ts/app.module.ts wiring land at merge time. Verified locally (not
committed) by stubbing both gaps: with the stub in place, both typecheck
and build pass with zero errors, confirming this module's own code is
correct against the documented interfaces.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-03 10:57:28 -03:00
1ff55afd89 Integra módulo de Resellers (agente eden-commercial)
Resolve conflitos de merge (users.ts, audit.ts, br-documents.ts,
pnpm-lock/workspace.yaml — o worktree partiu de uma base anterior à
existência do módulo de auth/companies, então recriou versões próprias
de arquivos que já existiam no main; mantido o conteúdo do main,
incorporando só a função nova assignUserToReseller). Adiciona
resellersRepo ao barrel @eden/database e ResellersModule ao app.module.ts.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-03 09:54:33 -03:00
dca6eb2766 Add operational Resellers module (MVP CRUD, eden.md §1.7/§7)
Migration 1788439142825_resellers.cjs: `resellers` table plus nullable
`users.reseller_id` (scope=reseller per ADR-0004), indexes on
resellers.active and users.reseller_id.

packages/database/src/repositories/resellers.ts: list/get/create/update,
COALESCE-based partial update, mirroring the companies repository
pattern. Also adds repositories/audit.ts (hash-chained appendAuditEvent
over the existing audit_log table) and repositories/users.ts
(assignUserToReseller) - foundational pieces this module depends on that
hadn't landed in this worktree yet; audit.ts mirrors the sibling
worktree's already-built implementation verbatim to minimize merge
friction, and users.ts intentionally contains only the one function the
task asked to append (the fuller users repository belongs to the
auth/identity module being built in parallel).

apps/api/src/resellers/*: controller/service/module/dto mirroring the
Companies module's conventions - read open to any authenticated user,
write gated by @RequirePermission('resellers', 'edit'). Deliberate
deviation from legacy noted in code comments: the legacy hardcoded this
CRUD to requireAdmin and exposed reseller<->user assignment as
`PATCH /users/:id`; EDEN generalizes to the permission model (ADR-0004)
and adds `PATCH /v1/resellers/:id/assign-user` instead. Audits
reseller.created / reseller.updated / reseller.user_assigned.

packages/domain-shared/src/validators/br-documents.ts: CPF/CNPJ
digit-check validators (mirrors the sibling worktree's implementation
verbatim), used for the reseller `document` field the same way Companies
validates cnpj.

Known integration gap (by design, not a bug in this module): this
worktree doesn't yet have apps/api/src/auth/* or the companies-phase
exports in packages/database/src/index.ts - both are being built in
sibling worktrees and are explicitly out of scope here (per the task's
boundaries, app.module.ts and packages/database/src/index.ts are left
untouched for the user to wire up at merge time). @eden/database
typecheck/build pass cleanly; @eden/api typecheck/build currently fail
with exactly ten "cannot find module ../auth/..." /
"no exported member resellersRepo/usersRepo/auditRepo/Reseller" errors,
all attributable to those two integration points and nothing else.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-03 09:44:45 -03:00
e5fd75c44a Add Products/Catalog module (MVP): migration, repository, API
Ports the legacy products table's core shape (eden.md §2 §1.1, Master
Prompt §6.3) faithfully but MVP-scoped: product_code sequence, the 5 fixed
price tiers (price_0/12/24/36/48), impl_unit_price, and stock/serial/
asset-tag/MAC tracking flags. Leaves out legacy telecom-billing specifics
(service_type, metered, tariff_rates, ixc_product_code) for a later phase.

Mirrors the Companies module's structure and conventions exactly: COALESCE
partial updates, JwtAuthGuard/PermissionGuard with open read / gated write
(products:edit) per ADR-0004, product.created/product.updated audit events.
Money fields are validated as non-negative NUMERIC in the DTO only — no
pricing/calculation logic here, that belongs to the future Quotes phase.

Does not touch apps/api/src/app.module.ts or packages/database/src/index.ts
(wiring is left to integration) to avoid conflicting with sibling agents'
concurrent edits to those files; the ProductsService deep-imports the
repository module directly instead of via the shared barrel, noted in a
code comment.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-03 09:38:35 -03:00
8d81cf506b Auth completo (Argon2id + JWT/refresh rotativo), permissões, Companies e OpenAPI
- Auth (apps/api/src/auth/): Argon2id com parâmetros versionados
  (ADR-0005), access token JWT de 15min, refresh token opaco de 256 bits
  com rotação e detecção de replay (reuso de token já rotacionado revoga
  toda a cadeia de sessões do usuário). Endpoints /api/v1/auth/
  {login,refresh,logout,me}.
- Permissões resource+action+scope (ADR-0004) via PermissionGuard,
  resolvidas do banco a cada request (nunca cacheadas no JWT) — mudança
  de papel tem efeito imediato. super_admin com bypass hardcoded,
  espelhando a trava já existente no banco.
- Companies (migration + CRUD): leitura aberta a qualquer autenticado,
  escrita restrita a companies:manage; validação de CNPJ via
  packages/domain-shared (dígito verificador).
- SeedService: cria o primeiro super_admin a partir de
  EDEN_SUPERADMIN_EMAIL/PASSWORD só quando `users` está vazia.
- OpenAPI/Swagger em /api/docs; ValidationPipe global com
  whitelist+forbidNonWhitelisted (proteção contra mass-assignment).
- packages/database: repositórios (roles/users/sessions/audit/companies)
  reutilizáveis por api e worker.

Validado manualmente contra a stack real (não só typecheck): login com
senha errada → 401 genérico; refresh rotaciona e invalida o token
anterior; reuso do token antigo → replay detectado, cadeia revogada;
logout idempotente; audit log com a sequência completa de eventos;
CNPJ inválido rejeitado; mass-assignment rejeitado.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-03 09:25:48 -03:00
44510bd019 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>
2026-09-03 08:01:14 -03:00