Implementação MVP
This commit is contained in:
commit
807b3d72cd
54 files changed
+5241
No files matched your search
@@ -0,0 +1,146 @@
|
||||
# Arquitetura — Gerador de Propostas
|
||||
|
||||
Estado: prompt 01. Baseline oficial: repositório standalone, sem código EloPro legado. Decisão em `adr/ADR-000-standalone-application.md`.
|
||||
|
||||
Não há feature de produto nesta fase: nem tela, nem migration, nem upload, nem PDF real, nem e-mail real.
|
||||
|
||||
## 1. Contexto
|
||||
|
||||
O Gerador de Propostas é um produto EloPro independente. O usuário autenticado opera propostas e, conforme o papel, modelos, dentro de um workspace. CRO, Contratos e Apresentação não são pré-requisito do fluxo.
|
||||
|
||||
```text
|
||||
Pessoa de comercial / Admin / Gestor
|
||||
|
|
||||
v
|
||||
Gerador de Propostas (este repositório)
|
||||
|
|
||||
+--> PostgreSQL (Supabase) estados formais, RLS
|
||||
+--> Redis lock, claim de geração, job efêmero
|
||||
+--> Storage privado arquivo de modelo e PDF formal
|
||||
+--> Sentry erro, com scrub
|
||||
+--> Provider de e-mail port; provider não escolhido (P-011)
|
||||
+--> Motor de ingestão port; motor não escolhido (P-010)
|
||||
+--> CRO port opcional; fonte de cliente aberta (P-002)
|
||||
```
|
||||
|
||||
Auth, workspace, papéis e RLS nascem neste repositório. A UI usa os tokens EloPro V2.1 definidos na source of truth, em componentes locais, a partir do prompt 04.
|
||||
|
||||
## 2. Contêineres
|
||||
|
||||
| Contêiner | Papel nesta fase | Fonte de verdade |
|
||||
| --- | --- | --- |
|
||||
| Next.js 16 App Router | Ainda não criado. Entra no prompt 04. | — |
|
||||
| PostgreSQL via Supabase | Ainda sem migration. Estados formais: modelo, proposta, versão, auditoria, e-mail. | Sim, quando existir |
|
||||
| Redis (`ioredis`) | Ainda sem cliente. Lock de edição, claim de geração, estado efêmero de job. | Não |
|
||||
| Storage | Ainda sem bucket. | O ponteiro formal fica no PostgreSQL |
|
||||
| Sentry | Ainda sem SDK. A política de scrub já existe. | Não |
|
||||
| Claude | Ainda sem SDK. Não lê marcadores. | Não |
|
||||
|
||||
PostgreSQL é a fonte dos estados formais. Redis pode perder dados. Se o processo cair depois do commit e antes de apagar o claim, o retry lê o PostgreSQL e devolve a mesma versão.
|
||||
|
||||
## 3. Camadas
|
||||
|
||||
```text
|
||||
src/ui experiência. Vazia até o prompt 04.
|
||||
src/application casos de uso. Hoje: coordenação da geração e o contrato de autorização.
|
||||
src/domain regras e tipos. Não importa aplicação, ports, infra, UI nem integrações.
|
||||
src/ports interfaces que a aplicação exige da infra.
|
||||
src/infrastructure adapters. Hoje só duplos em memória, para teste.
|
||||
src/integrations/elopro contratos com outros produtos. Sem banco nem sessão compartilhada.
|
||||
src/observability scrub antes de log/Sentry.
|
||||
```
|
||||
|
||||
Regra de dependência, também no ESLint:
|
||||
|
||||
- `domain` não importa as outras camadas.
|
||||
- `ports` importa só `domain`.
|
||||
- `application` não importa `infrastructure` nem `ui`. Teste pode importar duplo.
|
||||
- `infrastructure` não importa `application` nem `ui`.
|
||||
- `integrations` não importa `application`, `infrastructure` nem `ui`.
|
||||
|
||||
`app/` (rotas) fica para o prompt 04 e deve chamar aplicação, não o banco direto a partir de componente cliente.
|
||||
|
||||
## 4. Componentes de domínio
|
||||
|
||||
| Módulo | Responsabilidade | Fora dele |
|
||||
| --- | --- | --- |
|
||||
| Models | Modelos, limite 10, versão de modelo, ativação | Não inicia proposta |
|
||||
| Proposals | Rascunho, status `Rascunho`/`Gerada`, versão formal | Não envia e-mail |
|
||||
| Generation | Commit do PDF, número e versão na mesma transação | Não escolhe o escopo de `PROP` |
|
||||
| Delivery | E-mail do `pdfRef` exibido | Não muda status |
|
||||
| Audit | Eventos mínimos | Retenção é P-007 |
|
||||
| Branding | Logo obrigatório, cores opcionais | Não é o design system da UI |
|
||||
| CRO | Pré-preenchimento quando houver contexto | O standalone funciona com `no-context` |
|
||||
|
||||
Papéis previstos no tipo `WorkspaceRole`: `owner`, `admin`, `gestor`, `agent`. O `WorkspaceAuthorizer` não tem implementação. Não existe adapter que responda `allowed` por omissão. O prompt 03 implementa a matriz, no servidor, com `workspace_id` da sessão.
|
||||
|
||||
Lock de edição: `EDIT_LOCK_TTL_MS` = 10 minutos. A interface `DistributedLockService` não tem tomada forçada.
|
||||
|
||||
## 5. Geração: idempotência e transação
|
||||
|
||||
Entrada: workspace, proposta, rascunho, ator, chave de idempotência, hash do conteúdo, versão do modelo e, se já existir, o número comercial. A chave efetiva no store e no ledger inclui workspace + proposta + chave. Outro workspace não reaproveita o commit.
|
||||
|
||||
Ordem:
|
||||
|
||||
1. Se o PostgreSQL já tem commit da mesma chave e da mesma impressão digital (rascunho, versão do modelo, hash), devolver essa versão com `replayed: true`. Não renderiza de novo e não aloca número.
|
||||
2. Se a mesma chave já tem outra impressão digital, responder `conflict`. Não cria versão.
|
||||
3. Claim efêmero (Redis). Mesma impressão em andamento: `in-progress`. Outra impressão em andamento: `conflict`.
|
||||
4. Renderizar para staging. Falha aqui não abre transação, não aloca número e não grava versão. O claim é liberado para o retry.
|
||||
5. Commit único no store formal:
|
||||
- promove o staging para `pdfRef`;
|
||||
- se a proposta ainda não tem número e esta é a primeira versão, reserva o número dentro dessa mesma unidade;
|
||||
- insere a versão imutável apontando para esse `pdfRef`;
|
||||
- confirma a reserva.
|
||||
6. Se qualquer passo do commit falha, a reserva sofre rollback, o `pdfRef` promovido é desfeito e o staging é descartado. `commercialNumberAssigned` e `formalVersionCreated` ficam falsos. A falha não é gravada como resultado da chave: o retry pode tentar de novo.
|
||||
7. A segunda versão só segue se `existingCommercialNumber` já veio do commit anterior. O coordenador não pede outro número. Quem aloca é só a primeira versão, e só dentro do commit.
|
||||
|
||||
O duplo de teste emite `TEST-######` para deixar óbvio que não é a sequência de produção. O escopo real espera o ADR-001.
|
||||
|
||||
Não há método de update ou delete de versão formal. O objeto commitado é congelado no duplo. A garantia de produção será a ausência de `UPDATE`/`DELETE` na policy e o fluxo, no prompt 02.
|
||||
|
||||
O TTL do claim não é SLO. P-012 segue aberto. Quem ligar o coordinator no futuro passa `attemptTtlMs`.
|
||||
|
||||
## 6. Ports
|
||||
|
||||
| Port | Situação |
|
||||
| --- | --- |
|
||||
| `GenerationCoordinator` | Implementado em `src/application/generation/run-generation.ts` |
|
||||
| `FormalGenerationStore` | Contrato. Duplo em memória nos testes |
|
||||
| `CommercialNumberAllocator` | Contrato transacional (`reserve` / `commit` / `rollback`). Sem adapter de produção |
|
||||
| `ProposalPdfRenderer` | Contrato. Adapter previsto: `@react-pdf/renderer` sobre representação normalizada. Não instalado |
|
||||
| `StagingArtifactStore` | Promote só fica visível se o commit concluir |
|
||||
| `GenerationAttemptLedger` | Contrato do estado efêmero |
|
||||
| `DistributedLockService` | Contrato do lock de edição. Sem force takeover |
|
||||
| `TemplateIngestionService` | Sempre bloqueado: P-006 e depois P-010 |
|
||||
| `ProposalEmailProvider` | Sempre bloqueado: P-001 ou P-011 |
|
||||
| `CroClientPrefillPort` | `no-context` ou `pending-source` |
|
||||
| `WorkspaceAuthorizer` | Só a interface |
|
||||
|
||||
## 7. Sentry e correlação
|
||||
|
||||
`CorrelationContext` carrega `requestId`, `jobId`, `workspaceId` e `actorId`. O `jobId` nasce quando houver job de geração. O `requestId` nasce na borda HTTP se o chamador não enviar um.
|
||||
|
||||
Propagação: a borda cria o contexto, a aplicação repassa aos ports, o job carrega o mesmo `requestId` e preenche `jobId`. Tags previstas no Sentry: esses ids mais `proposalId` ou `modelId` quando a operação for sobre um registro.
|
||||
|
||||
`scrubForTelemetry` roda antes de `captureException` / breadcrumb. Remove, em qualquer profundidade, documento, template, snapshot, análise, e-mail, assunto, corpo, telefone, CPF, CNPJ, logo e nome de arquivo. Não envia o PDF nem o modelo. O SDK do Sentry entra junto com a primeira borda que possa falhar (prompt 14, ou antes se o prompt 04 já expuser erro de runtime). Até lá a função é a política, não um cliente.
|
||||
|
||||
## 8. Stack instalada agora
|
||||
|
||||
TypeScript 5, ESLint 9 e Vitest. O `tsconfig` usa `moduleResolution: Bundler` e strict, alinhado ao App Router que virá.
|
||||
|
||||
Ainda não instalados, de propósito: Next.js, React, Tailwind, Supabase, `ioredis`, Sentry, `@anthropic-ai/sdk`, `@react-pdf/renderer`. Não há uso para eles nesta fase.
|
||||
|
||||
## 9. Pendências que continuam Proposed
|
||||
|
||||
- ADR-001 / P-009 — escopo da sequência
|
||||
- ADR-002 / P-010 — motor de ingestão
|
||||
- ADR-003 / P-011 — provider de e-mail
|
||||
- ADR-004 / P-006 — tamanho, antivírus, sandbox, extração parcial
|
||||
|
||||
P-001, P-002, P-003, P-004, P-005, P-007, P-008 e P-012 também seguem abertos e não têm ADR de decisão.
|
||||
|
||||
## 10. O que o prompt 02 pode fazer sem novas decisões
|
||||
|
||||
Pode criar o schema do workspace, papéis e das tabelas de domínio da source of truth, com RLS por `workspace_id`, desde que não feche os ADRs acima.
|
||||
|
||||
Não criar sequence, unique do número comercial, check de provider, limite de arquivo, job de antivírus nem enum que escolha o motor de ingestão. Detalhe em cada ADR.
|
||||
@@ -0,0 +1,41 @@
|
||||
# Ordem recomendada de execução
|
||||
|
||||
## Pacote A — Fundação
|
||||
1. `prompts/00_repo_discovery_and_guardrails.md`
|
||||
2. `prompts/01_architecture_and_adrs.md`
|
||||
3. `prompts/02_database_schema_rls_migrations.md`
|
||||
4. `prompts/03_auth_workspace_permissions.md`
|
||||
5. `prompts/04_design_system_and_app_shell.md`
|
||||
|
||||
**Gate A:** typecheck/lint/test/build verdes; cross-tenant básico validado; ADRs críticos registrados.
|
||||
|
||||
## Pacote B — Modelos de Proposta
|
||||
6. `prompts/05_models_domain_list_capacity.md`
|
||||
7. `prompts/06_model_upload_analysis_pipeline.md`
|
||||
8. `prompts/07_model_field_review_activation_versioning.md`
|
||||
9. `prompts/08_model_lock_autosave_archive_delete.md`
|
||||
|
||||
**Gate B:** fluxo de Modelos P0/P1 funcional, incluindo 10/10, lock, reprocessamento, ativação e V2+.
|
||||
|
||||
## Pacote C — Propostas
|
||||
10. `prompts/09_proposals_home_and_selection.md`
|
||||
11. `prompts/10_proposal_editor_dynamic_fields_preview.md`
|
||||
12. `prompts/11_proposal_autosave_lock_save_exit_model_switch.md`
|
||||
13. `prompts/12_validate_generate_async_idempotency.md`
|
||||
14. `prompts/13_versioning_history_download.md`
|
||||
|
||||
**Gate C:** 4.1 → 4.2 → 4.3 completo; falhas não criam versões parciais; retry/duplo clique é idempotente.
|
||||
|
||||
## Pacote D — Comunicação, observabilidade e integração
|
||||
15. `prompts/14_email_audit_sentry.md`
|
||||
16. `prompts/15_cro_prefill_integration.md`
|
||||
|
||||
**Gate D:** auditoria ponta a ponta; e-mail usa o PDF exibido; CRO não é dependência do fluxo standalone.
|
||||
|
||||
## Pacote E — Qualidade e release
|
||||
17. `prompts/16_testing_security_accessibility.md`
|
||||
18. `prompts/17_performance_resilience_hardening.md`
|
||||
19. `prompts/18_release_ci_cd_runbook.md`
|
||||
20. `prompts/19_final_gap_audit.md`
|
||||
|
||||
**Gate final:** Definition of Done do MVP atendida, pendências remanescentes explicitamente registradas e nenhum comportamento não aprovado inventado.
|
||||
@@ -0,0 +1,23 @@
|
||||
# Checklist humano entre os pacotes
|
||||
|
||||
## Antes do Pacote B
|
||||
- ADR-001: escopo da sequência PROP decidido?
|
||||
- ADR-002: engine real de ingestão PDF/PPTX/DOCX decidida?
|
||||
- ADR-004: política de tamanho/segurança de arquivo decidida ao menos para staging?
|
||||
|
||||
## Antes do Pacote D
|
||||
- ADR-003: provider de e-mail aprovado?
|
||||
- P-001: comportamento quando workspace não tem Reply-To definido?
|
||||
|
||||
## Antes de produção
|
||||
- P-006: tamanho máximo, antivírus/sandbox/zip-bomb/timeout definidos.
|
||||
- P-007: retenção de auditoria definida.
|
||||
- P-008: lifecycle de entitlements definido.
|
||||
- P-009: sequência PROP aprovada.
|
||||
- P-010: engine de ingestão validada com arquivos reais.
|
||||
- P-011: provider e credenciais de e-mail formalizados.
|
||||
- P-012: pelo menos thresholds operacionais/alertas de produção definidos, mesmo que SLO final venha depois.
|
||||
- Cross-tenant e storage tests aprovados.
|
||||
- Geração idempotente comprovada sob concorrência.
|
||||
- PDF histórico baixado/enviado corresponde exatamente à versão exibida.
|
||||
- QA P0/P1 sem blocker aberto.
|
||||
@@ -0,0 +1,53 @@
|
||||
# Mapa de implementação — Gerador de Propostas
|
||||
|
||||
Estado: prompt 01 concluído no papel. ADR-000 aceito: standalone neste repositório. P-006, P-009, P-010 e P-011 seguem Proposed.
|
||||
|
||||
## Layout
|
||||
|
||||
```text
|
||||
app/ # prompt 04; ainda não existe
|
||||
src/domain/{models,proposals,generation,delivery,audit,branding,cro,shared}
|
||||
src/application/generation # coordinator da geração
|
||||
src/application/access # interface; implementação no prompt 03
|
||||
src/ports/
|
||||
src/infrastructure/memory # somente duplos de teste
|
||||
src/integrations/elopro # CRO e futuros contratos, sem código compartilhado
|
||||
src/ui # prompt 04
|
||||
src/observability
|
||||
supabase/migrations/ # prompt 02; ainda não existe
|
||||
docs/gerador-propostas/adr/
|
||||
```
|
||||
|
||||
PostgreSQL será a fonte de verdade dos estados formais. Redis ficará com lock, claim de geração e job efêmero. Nenhum dos dois clientes está instalado.
|
||||
|
||||
## Mapa por prompt
|
||||
|
||||
| Prompt | Feature | Onde deve morar | Padrão existente |
|
||||
| --- | --- | --- | --- |
|
||||
| 01 | Arquitetura, ADRs P-006/P-009/P-010/P-011, ports | `docs/gerador-propostas/ARCHITECTURE.md`, `docs/gerador-propostas/adr/`, `src/ports/` | Feito. ADRs 001–004 em Proposed. Sem sequence, sem motor, sem provider. |
|
||||
| 02 | Schema, constraints, RLS | `supabase/migrations/` | Nenhum. Toda tabela de domínio tenant-safe por `workspace_id` ou FK + RLS. |
|
||||
| 03 | Auth, workspace, papéis | `src/application/access/` + guards nas actions | Interface `WorkspaceAuthorizer` sem adapter permissivo. `workspace_id` resolvido no servidor. |
|
||||
| 04 | DS V2.1 e app shell | `app/`, estilos Tailwind v4, componentes locais do domínio | Nenhum token no repo. Lacunas de DS (Search, Table, Stepper, Empty, Pagination, Skeleton, Upload, Avatar) ficam locais, não globais. |
|
||||
| 05 | Listagem de modelos e limite 10 | `src/domain/models/` + rota de Modelos | Contar draft/active/archived; versões não ocupam vaga. |
|
||||
| 06 | Upload e análise `[campo]` | porta `TemplateIngestionService`; UI de upload local | P-010 aberto. Sem inferir campo por IA/heurística. |
|
||||
| 07 | Revisão de campos, ativação, V1/V2+ | domínio de modelos | Versão ativada imutável no fluxo normal. Só modelo Ativo inicia proposta. |
|
||||
| 08 | Lock, autosave, arquivar, excluir modelo | Redis lock + PostgreSQL estado | TTL 10 min, sem force takeover. |
|
||||
| 09 | Home 4.1 e seleção | `app/` propostas | Abrir fluxo não cria rascunho vazio. |
|
||||
| 10 | Editor 4.2, campos, preview | uma página, estados Preencher → Validar → Gerar | Tipos Texto e Número/moeda; default Texto; obrigatório = Não. |
|
||||
| 11 | Autosave, lock, salvar, sair, trocar modelo | drafts + lock | Rascunho nasce no primeiro persist. Lock só libera após sucesso de salvar e sair. |
|
||||
| 12 | Validar e gerar, idempotência | `GenerationCoordinator` + job | Falha não cria número, versão formal nem PDF parcial. |
|
||||
| 13 | Versões, histórico, download | `proposal_versions` + storage privado | PDF servido é o da versão exibida. Histórico não é editável. |
|
||||
| 14 | E-mail, auditoria, Sentry | porta de e-mail + `proposal_audit_events` + Sentry | P-011 e P-001 abertos. Sem documento integral nem PII desnecessária em log/Sentry. |
|
||||
| 15 | Pré-preenchimento CRO | `src/domain/cro/` | Opcional. Standalone funciona sem CRO. P-002 aberto (fonte de Cliente). |
|
||||
| 16 | Testes, segurança, a11y | Vitest + testes de RLS/cross-tenant | Ainda sem runner. |
|
||||
| 17 | Performance e resiliência | sem módulo novo obrigatório | P-012 aberto; não inventar SLO. |
|
||||
| 18 | CI/CD e runbook | pipeline no remoto Gitea (não há `.github/`) | Sem pipeline hoje. |
|
||||
| 19 | Auditoria de lacunas | `docs/gerador-propostas/` | Confrontar com `SOURCE_OF_TRUTH.md` §7 e §8. |
|
||||
|
||||
## Fora do MVP (não mapear como entrega)
|
||||
|
||||
USD/i18n, editor rico, modelo do zero, duplicar modelo, assinatura, WhatsApp/CRM, status Enviada/Aceita/Rejeitada, rollback de checkpoint, app nativo, Contrato habilitado (P-005), Apresentação (P-004).
|
||||
|
||||
## Gates
|
||||
|
||||
Ordem e gates humanos: `EXECUTION_ORDER.md` e `HUMAN_REVIEW_CHECKLIST.md`. O próximo passo permitido é o prompt 01, depois de revisão desta discovery.
|
||||
@@ -0,0 +1,107 @@
|
||||
# Discovery do repositório — Gerador de Propostas EloPro
|
||||
|
||||
Data: 2026-10-02
|
||||
Fase: prompt 00 (fundação; nenhuma feature de produto)
|
||||
Raiz: `c:\Users\Usuário\Documents\gerador-proposta`
|
||||
|
||||
## Conclusão
|
||||
|
||||
Este repositório é greenfield. Não há aplicação EloPro pré-existente para reutilizar. A stack descrita no pacote de prompts e na especificação v1.0 ainda não está materializada aqui. O remoto aponta para Gitea (`origin` → `https://gitea.fatorxtech.com/cferraz/gerador-proposta.git`) e o branch `main` ainda não tem commits.
|
||||
|
||||
Decisão de 2026-10-02, registrada no ADR-000: o vazio deste checkout é o baseline oficial. Auth, workspace, papéis, RLS e design system serão criados aqui. Não há outro repositório a importar. A compatibilidade com o restante do EloPro é de produto e de contrato, não de código compartilhado.
|
||||
|
||||
## 1. Inventário da árvore
|
||||
|
||||
| Área pedida | Achado |
|
||||
| --- | --- |
|
||||
| `app/`, `src/`, componentes, `lib` | Ausentes |
|
||||
| Server Actions, Route Handlers | Ausentes |
|
||||
| Supabase (`supabase/`, clients, migrations) | Ausentes |
|
||||
| Testes (`vitest`, `*.test.ts`) | Ausentes |
|
||||
| CI (`.github/`, pipelines) | Ausente |
|
||||
| Sentry (`sentry.*.config.*`, `@sentry/*`) | Ausente |
|
||||
| `package.json`, lockfile, `tsconfig`, Tailwind, ESLint | Ausentes |
|
||||
| `.cursor/rules/` | Criado nesta fase: `elopro-gerador-propostas.mdc` |
|
||||
| `docs/gerador-propostas/` | Criado nesta fase |
|
||||
|
||||
Arquivos versionáveis antes desta fase: nenhum (working tree só com `.git`).
|
||||
|
||||
## 2. Workspace ativo e papéis
|
||||
|
||||
Não há código que resolva workspace ativo nem que represente `owner` / `admin` / `gestor` / `agent`.
|
||||
|
||||
Contrato documental (ainda não implementado), em `SOURCE_OF_TRUTH.md`:
|
||||
|
||||
- Tenant técnico = `workspace_id`, com RLS. CNPJ não é chave de tenant.
|
||||
- Papéis: Superadmin (`profiles.is_superadmin`), Administrador (`owner`/`admin`), Gestor (`gestor`), Usuário (`agent`).
|
||||
- `workspace_id` não pode vir do cliente como autoridade.
|
||||
|
||||
Não existe tabela `profiles`, sessão, helper de impersonação nem superadmin neste repo.
|
||||
|
||||
## 3. RLS, policies e autorização
|
||||
|
||||
Não há migrations, policies, helpers de autorização nem fluxo de impersonação. Nada a reutilizar. A regra do agente exige revalidação server-side e RLS; isso começa no prompt 02, não aqui.
|
||||
|
||||
## 4. Design system e Tailwind v4
|
||||
|
||||
Não há tokens, componentes EloPro, `tailwind` nem consumo de CSS. A especificação visual (EloPro V2.1) está só no texto: Cloud White `#FBFBFE`, Midnight Ink `#071B45`, Primary Blue `#1F6FFF`, Blue 600 `#225EDB`, Bright Blue `#2F8FFF`, Aqua Signal `#00C2A8`, Manrope, raios e motion descritos em `SOURCE_OF_TRUTH.md` §6. Ícones EloPro não estão no repositório; Lucide fica como fallback futuro, não como biblioteca da marca.
|
||||
|
||||
## 5. Redis / ioredis
|
||||
|
||||
Ausente. Não há cliente, URL nem uso de lock.
|
||||
|
||||
## 6. Storage privado e signed URLs
|
||||
|
||||
Ausente. Não há bucket, adapter nem padrão de signed URL.
|
||||
|
||||
## 7. Server Actions, Route Handlers, validação e erros
|
||||
|
||||
Ausentes. Não há convenção local de validação (Zod ou outra) nem de erro de domínio.
|
||||
|
||||
## 8. Sentry
|
||||
|
||||
Ausente nos três runtimes (client, server, edge). Não há DSN nem scrubbing configurado.
|
||||
|
||||
## 9. CI e comandos canônicos
|
||||
|
||||
Não há pipeline. Não há scripts `typecheck`, `lint`, `test` ou `build`.
|
||||
|
||||
### Baseline registrado (2026-10-02)
|
||||
|
||||
| Comando | Resultado |
|
||||
| --- | --- |
|
||||
| `typecheck` | Não existe. Sem `package.json` / `tsc`. |
|
||||
| `lint` | Não existe. Sem ESLint. |
|
||||
| `test` | Não existe. Sem Vitest. |
|
||||
| `build` | Não existe. Sem Next.js. |
|
||||
| Instalação | Não executada. Não há dependências declaradas e o prompt 00 proíbe introduzir dependências sem necessidade. |
|
||||
|
||||
Falhas preexistentes de toolchain: não se aplicam. O baseline é “repositório sem toolchain”. Regressão futura será qualquer falha introduzida depois que esses comandos passarem a existir.
|
||||
|
||||
## Divergências entre stack esperada e o repo
|
||||
|
||||
Stack obrigatória do pacote (ainda não instalada): Next.js 16 App Router, React 19, TypeScript 5, Tailwind CSS v4, Supabase Auth + PostgreSQL (`@supabase/supabase-js`, `@supabase/ssr`), Redis (`ioredis`), TanStack Query v5 só onde houver cache client-side real, `@react-pdf/renderer`, Sentry, `@anthropic-ai/sdk` só para IA aprovada, Lucide só como fallback, `@dnd-kit` só se drag-and-drop for necessário, Vitest, ESLint 9, `postgres` + `tsx` para migrations.
|
||||
|
||||
Premissa do prompt 00 (“integrar ao ecossistema EloPro existente e reutilizar helpers”) **não se confirma neste checkout**. O próximo prompt precisa tratar o app como novo, com boundaries explícitos, em vez de procurar pastas que não existem.
|
||||
|
||||
Entradas externas usadas nesta análise (não estão no Git):
|
||||
|
||||
- `Especificacao_Final_Gerador_de_Propostas_EloPro_v1.0.docx` (02/10/2026)
|
||||
- `Prompt_Pack_Cursor_Gerador_Propostas_EloPro_v1.0.zip`
|
||||
- `elopro-gerador-propostas.mdc`
|
||||
|
||||
## Riscos antes do prompt 01
|
||||
|
||||
1. **Plataforma EloPro ausente.** Resolvido pelo ADR-000: o produto segue standalone neste repositório. Entitlements (P-008) continuam sem lifecycle definido.
|
||||
2. **Pendências P-001..P-012 permanecem abertas.** Não foram preenchidas. P-009, P-010, P-011 e P-006 são o alvo dos ADRs do prompt 01 e devem ficar `Proposed`.
|
||||
3. **Sem baseline executável.** Gates A–E do `EXECUTION_ORDER.md` não podem ficar verdes até existir toolchain. O prompt 01 deve criar o mínimo de projeto só se o escopo dele exigir ports testáveis; o prompt 00 não cria app.
|
||||
4. **Sem commits.** `main` não tem histórico. Convenção de commit ainda não existe no repo.
|
||||
5. **Isolamento multi-tenant ainda é só documento.** Qualquer feature antes de RLS/policies (prompt 02) e auth server-side (prompt 03) não pode ser considerada segura.
|
||||
6. **Spec longa fora do Git.** A fonte normativa operacional copiada é `SOURCE_OF_TRUTH.md`. O docx completo continua em Downloads; se ele mudar, este discovery não acompanha sozinho.
|
||||
|
||||
## O que esta fase não fez
|
||||
|
||||
- Nenhuma feature de negócio (modelos, propostas, PDF, e-mail, CRO).
|
||||
- Nenhuma dependência nova.
|
||||
- Nenhuma migration.
|
||||
- Nenhuma escolha silenciosa sobre P-001..P-012.
|
||||
@@ -0,0 +1,125 @@
|
||||
# Source of Truth — Gerador de Propostas EloPro — MVP
|
||||
|
||||
## 1. Decisões consolidadas
|
||||
|
||||
- Produto standalone dentro do ecossistema EloPro.
|
||||
- Integração com CRO é opcional e serve para pré-preenchimento quando houver contexto explícito de cliente.
|
||||
- Tenant técnico = `workspace_id`; isolamento por RLS. CNPJ é dado comercial, não chave de tenant.
|
||||
- Papéis funcionais: Superadmin, Administrador, Gestor e Usuário. Mapeamento atual EloPro: `profiles.is_superadmin`, `owner/admin`, `gestor`, `agent`.
|
||||
- Modelos são importados por Admin/Gestor a partir de PDF, PPTX ou DOCX.
|
||||
- Marcadores variáveis: `[campo]`. O sistema não infere trechos variáveis.
|
||||
- Limite: 10 modelos por workspace; Rascunho, Ativo e Arquivado contam. Versões internas não ocupam nova vaga.
|
||||
- Status de proposta: apenas `Rascunho` e `Gerada`.
|
||||
- Estados de UI da criação: `Preencher → Validar → Gerar`; são estados da mesma experiência, não status persistidos independentes.
|
||||
- Primeira geração bem-sucedida cria `PROP-######` e `V1`.
|
||||
- Versões formais são imutáveis. Edição posterior cria/retoma o rascunho da próxima versão.
|
||||
- Download e envio por e-mail usam exatamente o PDF da versão exibida.
|
||||
- Lock: um editor por recurso, TTL funcional de 10 minutos, sem force takeover no MVP.
|
||||
- Autosave obrigatório.
|
||||
- Contrato fica visível/desabilitado nesta fase. Apresentação permanece pendente.
|
||||
|
||||
## 2. Regras de negócio
|
||||
|
||||
- RN-001 Standalone — fluxo principal funciona sem Calculadora, Contratos, Planilhas ou outros produtos.
|
||||
- RN-002 Brasil/BRL — pt-BR, BRL; sem seletor obrigatório de moeda.
|
||||
- RN-003 Segurança server-side — permissão, entitlement, limite e estado também no backend/RLS.
|
||||
- RN-004 Autosave — autosave não substitui Salvar/Salvar e sair.
|
||||
- RN-005 Limite de modelos — máximo 10 por workspace; draft/active/archived contam.
|
||||
- RN-006 Modelo ativo — somente modelo Ativo inicia proposta.
|
||||
- RN-007 Marcadores — somente `[campo]` explícito origina campo.
|
||||
- RN-008 Tipos de campo — Texto e Número/moeda; default Texto, obrigatório=Não.
|
||||
- RN-009 Estrutura do modelo — marcador não é criado/excluído/renomeado na tela de validação; correção estrutural exige reenvio.
|
||||
- RN-010 Versão de modelo — primeira ativação V1; alterações V2+ preservam histórico.
|
||||
- RN-011 Criação de rascunho — abrir 4.2 não cria rascunho; nasce no primeiro persist válido.
|
||||
- RN-012 Status — apenas Rascunho/Gerada; edição em andamento é indicador.
|
||||
- RN-013 Fluxo 4.2 — Preencher/Validar/Gerar são estados da mesma página.
|
||||
- RN-014 Salvar — com pendências salva e fica em Preencher; sem pendências cria checkpoint e vai para Validar.
|
||||
- RN-015 Salvar e sair — persiste/checkpoint; libera lock somente após sucesso.
|
||||
- RN-016 Lock — um editor; 10 min; sem tomada forçada; observador vê último persistido.
|
||||
- RN-017 Geração formal — só existe sucesso se PDF formal existir; falha não cria número/versão formal.
|
||||
- RN-018 Numeração — primeira geração cria PROP-###### e V1; escopo da sequência ainda precisa de decisão técnica formal.
|
||||
- RN-019 Imutabilidade — versão formal gerada é imutável.
|
||||
- RN-020 Nova versão — somente com alteração de conteúdo + nova geração bem-sucedida.
|
||||
- RN-021 Histórico — versões antigas podem ser vistas/baixadas/enviadas, nunca editadas/excluídas/usadas como base.
|
||||
- RN-022 E-mail — usa exatamente PDF exibido; não muda status Gerada.
|
||||
- RN-023 Auditoria — autoria e eventos críticos rastreáveis.
|
||||
- RN-024 Logo — logo da empresa obrigatório para identidade da proposta; cores opcionais.
|
||||
- RN-025 Erros — erros são estados das telas existentes, sem criar novas páginas numeradas.
|
||||
|
||||
## 3. Requisitos funcionais
|
||||
|
||||
RF-001 autenticar/resolver workspace; RF-002 listar propostas por escopo; RF-003 listar modelos ativos; RF-004 confirmar seleção sem criar draft; RF-005 abrir 4.2 sem draft vazio; RF-006 prefill CRO quando aplicável; RF-007 campos dinâmicos; RF-008 validação durante edição; RF-009 autosave; RF-010 draft no primeiro persist; RF-011 Salvar; RF-012 Salvar e sair; RF-013 trocar modelo; RF-014 lock; RF-015 validar antes de gerar; RF-016 gerar PDF; RF-017 reconciliar geração assíncrona; RF-018 número comercial; RF-019 versionar; RF-020 detectar ausência de alteração; RF-021 visualizar vigente/histórica; RF-022 baixar PDF; RF-023 enviar e-mail; RF-024 registrar envio; RF-025 excluir draft elegível; RF-026 listar modelos; RF-027 limite 10/10; RF-028 upload PDF/PPTX/DOCX; RF-029 analisar marcadores; RF-030 draft de modelo após upload+análise técnica; RF-031 reprocessar correção no mesmo draft; RF-032 configurar campos; RF-033 autosave/lock de modelo; RF-034 ativar V1; RF-035 versionar modelo V2+; RF-036 arquivar; RF-037 excluir modelo nunca usado (Admin); RF-038 auditoria; RF-039 RLS; RF-040 Sentry.
|
||||
|
||||
## 4. Requisitos não funcionais
|
||||
|
||||
- Segurança: RLS + autorização server-side; fail-closed.
|
||||
- Privacidade: nenhum documento/template cross-tenant; Sentry/logs sem documento integral/PII desnecessária.
|
||||
- Confiabilidade: geração/ativação idempotentes; sem efeitos parciais.
|
||||
- Concorrência: lock TTL 10 min + renovação por atividade; sem force takeover.
|
||||
- Recuperação: autosave e retomada respeitando lock.
|
||||
- Performance: carregamento progressivo; paginação/virtualização quando necessário; metas numéricas ainda abertas.
|
||||
- Acessibilidade: alvo WCAG 2.1 AA, teclado, foco, labels, contraste, status não apenas por cor.
|
||||
- Responsividade: web adaptada; mobile não é mera redução proporcional.
|
||||
- Observabilidade: Sentry client/server/edge + correlação request/job.
|
||||
- Auditabilidade: eventos mínimos imutáveis; retenção ainda aberta.
|
||||
- Manutenibilidade: TS strict recomendado, lint, testes, separação por domínio.
|
||||
- Integridade documental: versão formal referencia versão exata do modelo e artefato.
|
||||
- Segurança de arquivos: MIME/extensão/conteúdo; tamanho/antivírus/sandbox ainda abertos.
|
||||
|
||||
## 5. Modelo de dados proposto
|
||||
|
||||
- `proposal_models`: id, workspace_id, name, status, current_version, created_by, archived_at.
|
||||
- `proposal_model_versions`: id, model_id, version_no, source_file_ref, normalized_template, analysis_json, activated_at, activated_by.
|
||||
- `proposal_model_fields`: id, model_version_id, field_key, display_name, type, required, order.
|
||||
- `proposals`: id, workspace_id, created_by, owner_user_id, status, commercial_number, current_version_no, model_id, client_ref?, created_at.
|
||||
- `proposal_drafts`: id, proposal_id, based_on_version_no?, model_version_id, data_json, content_hash, lock_owner?, updated_at.
|
||||
- `proposal_versions`: id, proposal_id, version_no, model_version_id, content_snapshot, content_hash, pdf_ref, generated_by, generated_at.
|
||||
- `proposal_email_events`: id, proposal_version_id, actor_id, to_email, subject, result, provider_message_id?, created_at.
|
||||
- `proposal_audit_events`: id, workspace_id, proposal_id?, model_id?, actor_id, event_type, metadata, created_at.
|
||||
- locks preferencialmente no Redis.
|
||||
- `workspace_branding`: workspace_id, logo_ref, brand colors opcionais, contact email.
|
||||
|
||||
## 6. Design System EloPro V2.1
|
||||
|
||||
- Base predominante: Cloud White `#FBFBFE`, 65–75% superfícies claras.
|
||||
- Texto/âncora: Midnight Ink `#071B45`.
|
||||
- Primary Blue `#1F6FFF`; botão primário deve usar token de contraste do DS, Blue 600 `#225EDB` quando aplicável.
|
||||
- Bright Blue `#2F8FFF`; Aqua Signal `#00C2A8`; Soft Blue `#DCEBFF`; Warning `#F39A2D`; Error `#E63946`.
|
||||
- Manrope para UI. Source Serif 4 apenas institucional/editorial.
|
||||
- Spacing 4px base; radius input 10, button 18, card 14, panel 18, modal 24.
|
||||
- Motion 120/200/320ms, easing `cubic-bezier(.2,.8,.2,1)`.
|
||||
- Proibido: neon, cyberpunk, holograma, glassmorphism, dark page dominante, grid decorativo, robôs/cérebros futuristas.
|
||||
- Estados sempre por cor + texto + ícone/semântica; nunca cor isolada.
|
||||
- Componentes globais: Button, IconButton, Badge, Tag, Card, Input, Select, Checkbox, Radio, Switch, DateField/DateRangeField, Tabs, CapsuleTabs, ContextGroup, SectionPill, Toast, Tooltip, Dialog.
|
||||
- Preservar quando fizer sentido: ContextLayers, JourneyTrail, OpenFramePanel, SemanticMarker.
|
||||
- `JourneyTrail` não é Stepper genérico.
|
||||
- Lacunas de DS: Search, Table, Stepper, Empty State, Pagination, Skeleton, File Upload, Avatar. Compor localmente usando tokens/primitivos e não promover como componente global sem decisão.
|
||||
- Iconografia EloPro é prioridade; Lucide apenas fallback técnico.
|
||||
|
||||
## 7. Pendências que NÃO podem ser inventadas
|
||||
|
||||
- P-001 fallback de Reply-To sem e-mail comercial.
|
||||
- P-002 fonte definitiva de Cliente no uso independente.
|
||||
- P-003 Tipo no MVP e opções definitivas.
|
||||
- P-004 Apresentação.
|
||||
- P-005 Gerador de Contratos.
|
||||
- P-006 tamanho máximo/antivírus/sandbox/extração parcial de arquivo.
|
||||
- P-007 retenção da auditoria.
|
||||
- P-008 fonte/lifecycle de entitlements.
|
||||
- P-009 escopo definitivo da sequência PROP (recomendação técnica atual: workspace, mas não assumir sem ADR/aprovação).
|
||||
- P-010 motor de ingestão/conversão PDF/PPTX/DOCX.
|
||||
- P-011 provider de e-mail (EloPro documenta Resend, mas formalizar uso no módulo).
|
||||
- P-012 metas quantitativas de performance/SLO/document size/generation time.
|
||||
|
||||
## 8. Critérios críticos de aceite
|
||||
|
||||
- Nenhum P0/P1 bloqueador aberto.
|
||||
- Workspace A nunca acessa B por UI, URL manipulada, API/Action direta ou storage.
|
||||
- Falha de geração não consome PROP nem versão.
|
||||
- Duplo clique/retry não cria duas versões.
|
||||
- Versão formal é imutável.
|
||||
- Lock funcional expira em 10 min e impede edição concorrente.
|
||||
- Usuário Final não acessa Modelos nem por rota direta.
|
||||
- 10/10 bloqueia upload antes do processamento.
|
||||
- PDF baixado/enviado é o mesmo da versão exibida.
|
||||
- UI segue EloPro V2.1 sem inventar regra funcional.
|
||||
@@ -0,0 +1,23 @@
|
||||
# ADR-000 — Aplicação standalone neste repositório
|
||||
|
||||
- Status: Accepted
|
||||
- Data: 2026-10-02
|
||||
- Decisor: produto / engenharia, nesta sessão
|
||||
|
||||
## Contexto
|
||||
|
||||
O discovery da fase 00 encontrou um repositório vazio. A premissa inicial do pacote era reutilizar auth, workspace, RLS e design system de outro checkout EloPro.
|
||||
|
||||
## Decisão
|
||||
|
||||
`gerador-proposta` é um produto standalone novo. O repositório vazio é o baseline oficial.
|
||||
|
||||
Auth, workspace, usuários, papéis e RLS serão implementados aqui, nas fases 02 e 03. O design system nasce aqui no prompt 04, com os tokens EloPro V2.1, pronto para convergir depois sem acoplar código agora.
|
||||
|
||||
A integração com outros componentes EloPro ocorre por ports. Este módulo não assume banco, sessão, componentes ou código compartilhado.
|
||||
|
||||
## Consequências
|
||||
|
||||
- Não há etapa de importar um repositório legado antes do prompt 02.
|
||||
- Contratos externos ficam em `src/integrations/`. O CRO standalone devolve `no-context` ou `pending-source` (P-002), e a geração não depende dele.
|
||||
- Stack alvo: Next.js 16, React 19, TypeScript 5, Tailwind CSS v4, Supabase, Redis, Sentry, Claude e Vitest. Nesta fase só entram TypeScript, ESLint e Vitest, porque ainda não há app, banco, fila nem chamada de modelo.
|
||||
@@ -0,0 +1,49 @@
|
||||
# ADR-001 — Escopo da sequência PROP
|
||||
|
||||
- Status: Proposed
|
||||
- Data: 2026-10-02
|
||||
- Pendência: P-009
|
||||
- Decisão: nenhuma
|
||||
|
||||
## Contexto
|
||||
|
||||
A primeira geração bem-sucedida cria um número comercial no formato `PROP-######` e a versão `V1`. Falha de geração não pode consumir número nem versão. O que permanece aberto é o escopo do contador: o que faz duas propostas receberem números diferentes, e onde a unicidade vale.
|
||||
|
||||
A source of truth registra uma recomendação técnica de escopo por workspace. Esta recomendação não foi aprovada. Este ADR não a converte em regra.
|
||||
|
||||
## Alternativas
|
||||
|
||||
1. Sequência por `workspace_id`. É a recomendação técnica citada na especificação. Continua não adotada.
|
||||
2. Sequência global da plataforma, única entre workspaces.
|
||||
3. Sequência por documento comercial (CNPJ ou equivalente). CNPJ não é chave de tenant; esta alternativa entra só para ficar visível.
|
||||
4. Sequência por usuário criador.
|
||||
|
||||
## Critérios para sair de Proposed
|
||||
|
||||
- Unicidade definida: quem pode ver o mesmo número e quem não pode.
|
||||
- Comportamento em falha: a reserva volta ao contador. Pular número em rollback não atende RN-017.
|
||||
- Concorrência: duas gerações simultâneas no mesmo escopo não recebem o mesmo número.
|
||||
- Efeito em workspace novo, arquivado e reativado.
|
||||
|
||||
## Impacto no código desta fase
|
||||
|
||||
`CommercialNumberAllocator` só pode ser chamado de dentro do commit formal, depois do artefato válido, e só quando a proposta ainda não tem número. O duplo em memória usa o prefixo `TEST-` de propósito. Ele não é a sequência de produção e não escolhe a alternativa 1, 2, 3 ou 4.
|
||||
|
||||
O formato `PROP-######` já está na source of truth. O regex em `src/domain/generation/types.ts` descreve esse formato. Ele não aloca números.
|
||||
|
||||
## Impacto no prompt 02
|
||||
|
||||
A migration pode criar `proposals.commercial_number` como texto anulável.
|
||||
|
||||
Ainda não criar:
|
||||
|
||||
- `CREATE SEQUENCE` ou equivalente
|
||||
- `UNIQUE (commercial_number)` global
|
||||
- `UNIQUE (workspace_id, commercial_number)`
|
||||
- trigger que preencha o número na inserção da proposta
|
||||
|
||||
Qualquer um desses objetos escolheria o escopo antes da aprovação deste ADR.
|
||||
|
||||
## O que aprovar este ADR não muda
|
||||
|
||||
Versão formal continua imutável. Retry com a mesma chave não cria outra versão. A segunda versão reutiliza o número já commitado; não pede outro.
|
||||
@@ -0,0 +1,40 @@
|
||||
# ADR-002 — Motor de ingestão de PDF, PPTX e DOCX
|
||||
|
||||
- Status: Proposed
|
||||
- Data: 2026-10-02
|
||||
- Pendência: P-010
|
||||
- Decisão: nenhuma
|
||||
|
||||
## Contexto
|
||||
|
||||
Admin ou Gestor importa um modelo PDF, PPTX ou DOCX. O campo dinâmico nasce só de um marcador `[campo]` escrito no arquivo. O sistema não infere trecho variável. IA não substitui essa validação.
|
||||
|
||||
O motor que lê o arquivo e devolve texto ou estrutura ainda não foi escolhido. Sem essa escolha, não há parser real nesta fase.
|
||||
|
||||
## Alternativas
|
||||
|
||||
1. Bibliotecas locais por formato, com uma etapa posterior e determinística que só aceita `[campo]`.
|
||||
2. Conversão por processo externo (por exemplo LibreOffice) para um formato intermediário, seguida da mesma detecção determinística.
|
||||
3. Serviço externo de extração de documento, seguido da mesma detecção determinística.
|
||||
4. Modelo de linguagem lendo o arquivo para achar campos. Esta alternativa conflita com a regra de marcador explícito e com a proibição de a IA substituir a validação. Está listada para não reaparecer como atalho. Não é candidata aceitável para descobrir campos.
|
||||
|
||||
As alternativas 1, 2 e 3 continuam abertas. Nenhuma foi escolhida. Claude permanece na stack para capacidades de IA que venham a ser aprovadas; não é o motor de marcadores.
|
||||
|
||||
## Critérios para sair de Proposed
|
||||
|
||||
- Fidelidade dos marcadores em PDF, PPTX e DOCX reais, inclusive repetidos e partidos por formatação.
|
||||
- O que acontece com arquivo sem marcador, arquivo protegido e extração incompleta. O último ponto também depende de P-006.
|
||||
- Isolamento do processo que abre o arquivo, tempo máximo e falha sem criar rascunho de modelo. O limite numérico continua em P-006 e P-012.
|
||||
- O workspace só lê o próprio arquivo.
|
||||
|
||||
## Impacto no código desta fase
|
||||
|
||||
`TemplateIngestionService` devolve `blocked / P-006` enquanto a política de arquivo não existir, e `blocked / P-010` mesmo que um teste marque a política como aprovada. Não há adapter que leia bytes.
|
||||
|
||||
## Impacto no prompt 02
|
||||
|
||||
Pode existir coluna ou objeto para `source_file_ref`, `normalized_template` e `analysis_json`. O conteúdo desses JSON não fica preso a um motor. Não há worker de conversão nesta fase nem na migration.
|
||||
|
||||
## O que este ADR não decide
|
||||
|
||||
Tamanho máximo, antivírus, sandbox e extração parcial continuam no ADR-004.
|
||||
@@ -0,0 +1,41 @@
|
||||
# ADR-003 — Provider de e-mail
|
||||
|
||||
- Status: Proposed
|
||||
- Data: 2026-10-02
|
||||
- Pendência: P-011
|
||||
- Relacionada: P-001
|
||||
- Decisão: nenhuma
|
||||
|
||||
## Contexto
|
||||
|
||||
Download e e-mail usam o PDF da versão formal exibida. O envio não muda o status `Gerada`. A documentação de ecossistema cita Resend em outros contextos. Isso não formaliza o provider deste módulo.
|
||||
|
||||
P-001 também segue aberto: o que fazer quando o workspace não tem e-mail comercial para Reply-To.
|
||||
|
||||
## Alternativas
|
||||
|
||||
1. Resend. Citado fora deste módulo. Não adotado aqui.
|
||||
2. Outro provider HTTP transacional.
|
||||
3. SMTP operado por este produto.
|
||||
4. Não enviar até haver provider e regra de Reply-To. É o comportamento do port hoje, não uma escolha de produto para o MVP.
|
||||
|
||||
## Critérios para sair de Proposed
|
||||
|
||||
- Provider nomeado, conta e ambiente definidos.
|
||||
- O anexo é o `pdfRef` da versão exibida, não uma nova renderização.
|
||||
- Falha de envio não altera status, número nem versão.
|
||||
- Reply-To: ou o e-mail comercial do workspace, ou a regra explícita de P-001. O provider não inventa remetente.
|
||||
- Evento em `proposal_email_events` com resultado e id do provider quando houver.
|
||||
- Corpo, assunto e destinatário não vão para o Sentry.
|
||||
|
||||
## Impacto no código desta fase
|
||||
|
||||
`ProposalEmailProvider` devolve `blocked / P-001` sem Reply-To resolvido e `blocked / P-011` quando o Reply-To existe mas não há provider. Não há cliente HTTP.
|
||||
|
||||
## Impacto no prompt 02
|
||||
|
||||
A tabela `proposal_email_events` pode ser criada com `provider_message_id` anulável e `result` textual. Não gravar um check constraint com o nome de um provider.
|
||||
|
||||
## O que aprovar o provider não decide
|
||||
|
||||
P-001 continua uma pendência separada. Aprovar Resend, ou outro nome, não define o fallback de Reply-To.
|
||||
@@ -0,0 +1,39 @@
|
||||
# ADR-004 — Limites e segurança de arquivo
|
||||
|
||||
- Status: Proposed
|
||||
- Data: 2026-10-02
|
||||
- Pendência: P-006
|
||||
- Decisão: nenhuma
|
||||
|
||||
## Contexto
|
||||
|
||||
O upload do modelo aceita PDF, PPTX e DOCX. A especificação deixa abertos tamanho máximo, antivírus, sandbox e o que fazer com extração parcial. P-012 também deixa abertas as metas numéricas de tempo e tamanho. Este ADR não preenche nenhum desses números.
|
||||
|
||||
## Alternativas
|
||||
|
||||
1. Allowlist de MIME e extensão, com teto de tamanho, sem antivírus no MVP.
|
||||
2. Antivírus síncrono antes de persistir o arquivo.
|
||||
3. Abertura do arquivo só em sandbox, com timeout.
|
||||
4. Rejeitar qualquer extração parcial. A alternativa simétrica, aceitar documento parcial, também fica registrada e não foi escolhida.
|
||||
|
||||
Nenhuma combinação foi aprovada. Não há valor padrão de megabytes, timeout ou lista de assinaturas.
|
||||
|
||||
## Critérios para sair de Proposed
|
||||
|
||||
- Tamanho máximo por arquivo e por workspace, ou a decisão explícita de não ter teto.
|
||||
- Varredura: obrigatória, adiada ou dispensada no MVP, com o risco aceito.
|
||||
- Onde o arquivo é aberto e o que acontece se o conversor não terminar.
|
||||
- Extração parcial: rejeita o upload ou segue com o que foi lido. Isso altera o rascunho de modelo e precisa estar explícito.
|
||||
- Falha de política não cria rascunho de modelo nem dispara o motor do ADR-002.
|
||||
|
||||
## Impacto no código desta fase
|
||||
|
||||
`FileSecurityPolicy` só tem `unapproved` ou `approved` com uma referência de decisão. Não há campos `maxBytes` nem `timeoutMs`. A ingestão bloqueia em P-006 enquanto a política estiver `unapproved`.
|
||||
|
||||
## Impacto no prompt 02
|
||||
|
||||
Pode existir referência de storage privado para o arquivo de origem. Não criar check de tamanho, coluna de status de antivírus com fornecedor escolhido, nem job de varredura. Signed URL e bucket entram quando o fluxo de upload existir, com isolamento por workspace.
|
||||
|
||||
## Relação com os outros ADRs
|
||||
|
||||
P-010 escolhe como ler o arquivo. P-006 escolhe se ele pode ser aceito. Os dois precisam estar Approved antes do upload real do prompt 06. O checklist humano pede essa revisão antes do Pacote B.
|
||||
Reference in new issue
Block a user