feat(api,web): fundação de Documentos + EDEN Parceiros/Assinante com login real

Continuação da leva "pelo menos mais 20 etapas" — 2 subagentes em paralelo.

## Documents (apps/api/src/documents/ + migration documents)

Metade "templates + geração" do eden.md módulo 4 (§1.1-1.3): document_templates,
document_template_versions (ciclo draft→publish, no máximo 1 rascunho por
template via índice único parcial, versão publicada imutável), document_generations
(idempotente por (template_version_id, origem), CHECK de origem única). Motor de
merge de variáveis ({{chave}}→valor, nunca lança exceção) como função pura
testável. A metade de Assinatura Eletrônica (envelopes, signatários, OTP,
cadeia de auditoria hash-chain — eden.md §1.4-1.9/§5-7, 9 tabelas satélite)
fica deliberadamente fora — grande e sensível demais para dividir espaço
com esta leva, fica para uma leva própria. PDF real via Chromium também
deferido; document_generations grava rendered_html, pdf_* ficam NULL.

## EDEN Parceiros / EDEN Assinante (apps/reseller-web, apps/subscriber-web)

Replicam o shell autenticado do core-web (leva anterior): login real com
suporte a MFA, sessão, AppShell do Design System — trocando só
applicationKey ("reseller"/"subscriber"), título e chave de localStorage
da sessão. As duas telas "Bootstrap da Fase 1" saem de circulação.

Testado ao vivo contra os containers reais: ciclo completo de template
(criar→draft→409 no segundo draft→editar→publicar→gerar documento com
merge de variáveis funcionando→regeneração idempotente reaproveita o
registro), e login via /v1/auth/login com applicationKey "reseller"/
"subscriber" retornando tokens válidos nos 2 portais reconstruídos.
pnpm turbo run typecheck build (28/28), pnpm --filter @eden/api test
(30/30, sem regressão), trilha de auditoria conferida no Postgres.

Claude-Session: https://claude.ai/code/session_01BcWWuKfykGtUweXmHD6cKx

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-03 17:55:52 -03:00
parent eff515b70d
commit 4d67fe5f1a
42 changed files with 2242 additions and 20 deletions

View File

@@ -268,3 +268,29 @@ Implementado: `infra/docker/Dockerfile.web` agora aceita `ARG VITE_API_BASE_URL`
3. **Não existia `.dockerignore`** no projeto — todo `COPY . .` do `Dockerfile.web`/`Dockerfile.node` estava copiando `node_modules/` (315MB), `.git/` (5.8MB) e `.claude/worktrees/` (345MB, os worktrees de subagentes desta mesma sessão) para dentro do contexto de build a cada vez. Além do desperdício óbvio, isso é parte de por que o bug nº1 passou despercebido no primeiro teste: caches `.turbo/` de dentro de cada pacote também eram copiados para dentro da imagem. Corrigido criando `.dockerignore` (exclui `node_modules`, `.git`, `dist`, `.turbo`, `.claude/worktrees`, `.tmp`, `.env*`, o zip do tema).
Cada correção foi testada isoladamente e a última confirmada abrindo o JS de produção servido pelo container real (`docker compose build --no-cache`) e conferindo que o literal `"/api/v1"` (não mais `"http://localhost:8080/api/v1"`) está no bundle.
---
## Fase 8 (parcial) — Portais Parceiros e Assinante replicam o shell autenticado do Core
Data: 2026-09-03. Subagente `eden-frontend` replicou o mesmo padrão de login/sessão/shell do `core-web` (leva anterior) para `apps/reseller-web` e `apps/subscriber-web` — mesma estrutura de arquivos, mesmo cliente HTTP, mesmo `AuthContext`, só trocando `applicationKey` (`reseller`/`subscriber`), título, e a chave de `localStorage` da sessão (`eden.reseller.session`/`eden.subscriber.session`, isolamento explícito mesmo já sendo origens/portas diferentes).
**Bug de integração (não do agente) encontrado e corrigido**: ao copiar `src/lib/` e `src/routes/` do worktree para `main`, o `cp -r` criou diretórios aninhados (`src/lib/lib/`, `src/routes/routes/`) porque os diretórios de destino já existiam vazios em `main` — mesmo padrão de erro já visto na integração do HR-Timeclock nesta sessão. Corrigido achatando a estrutura antes do typecheck.
Verificado: `pnpm turbo run typecheck build` (28/28) após a correção; containers `eden-parceiros`/`eden-assinante` reconstruídos — títulos corretos (`EDEN Parceiros`/`EDEN Assinante`), texto antigo "Bootstrap da Fase 1" ausente do bundle de produção, formulário de login real presente; login de ponta a ponta testado contra a API real com `applicationKey: "reseller"` e `"subscriber"` — ambos aceitos e retornam tokens válidos.
### Pendências
Idênticas às do `core-web` (rotação de refresh token, enroll de MFA na UI, telas de negócio) — nenhuma tela além do shell autenticado existe em nenhum dos 3 apps ainda.
---
## Fase 3 (parcial) — Fundação de Templates de Documento (sem Assinatura Eletrônica ainda)
Data: 2026-09-03. Subagente construiu a metade "templates + geração" do eden.md módulo 4 (§1.1-1.3) — a metade de Assinatura Eletrônica (§1.4-1.9: envelopes, signatários, OTP, cadeia de auditoria hash-chain, 9 tabelas satélite) foi deliberadamente deixada de fora, por ser criptograficamente/legalmente sensível e grande demais para dividir espaço com esta leva — fica para uma leva própria e dedicada.
`document_templates` + `document_template_versions` (ciclo `draft→publish`, invariante de no máximo 1 rascunho por template via índice único parcial, versão publicada é imutável) + `document_generations` (idempotente por `(template_version_id, origem)`, CHECK garantindo exatamente uma origem). Dependência circular (`document_templates.current_version_id` ↔ `document_template_versions`) resolvida com `ALTER TABLE` depois que as duas tabelas existem. Motor de merge de variáveis (`{{chave}}` → valor do contexto, nunca lança exceção, reporta variáveis ausentes) implementado como função pura testável — o parser Tiptap real e a renderização de PDF via Playwright/Chromium ficam para quando o editor visual e essa infra existirem (simplificação documentada: `editor_content.plainText` como stand-in).
Verificado: `pnpm turbo run typecheck build` (28/28), `pnpm --filter @eden/api test` (30/30, sem regressão). Container `eden-api` reconstruído; testado ao vivo via curl: template criado → draft criado → segundo draft rejeitado (409, invariante confirmada) → draft editado com placeholders → publicado (`current_version_id` atualizado) → documento gerado com merge de variáveis funcionando (`{{empresa}}`/`{{cliente}}`/`{{valor}}` substituídos corretamente) → regeneração com os mesmos parâmetros reaproveita o registro existente (idempotência confirmada, mesmo `id`). Trilha de auditoria conferida no Postgres.
### Pendências
Toda a Assinatura Eletrônica (eden.md §1.4-1.9/§5/§6/§7 — envelopes, signatários, OTP, hash-chain, verificação pública), geração real de PDF (Playwright/Chromium) + sanitização de HTML, editor visual Tiptap real (`renderToHtml`/`resolveDocument` com condicionais e repetição de tabela), seed dos 7 templates reais de produção da Handix, regra de idempotência completa com `force`/`extra_fields`.