0008 — Documentos obrigatórios da Análise de Crédito¶
| Status | CONCLUÍDA |
| Branch | spec/0008-documentos-obrigatorios-analise-credito |
| Criada em | 2026-07-31 |
| Apps afetados | api · web · e2e |
Status:
RASCUNHO→APROVADA→EM IMPLEMENTAÇÃO→CONCLUÍDA
1. Problema¶
Hoje é possível aprovar uma análise de crédito sem um único documento anexado. Nada impede: submit não valida documentos, approve não valida documentos, e DocumentType não tem qualquer noção de obrigatoriedade — só name, group e description. O status PENDING_DOCS existe e o analista tem a ação "Solicitar documentos", mas depende de alguém lembrar de usá-la.
Para uma garantidora é risco de subscrição direto: aprova-se a garantia sem comprovação de renda e o prejuízo só aparece no sinistro.
Dois problemas alimentam o primeiro:
Não se sabe de quem é o documento. A aprovação usa a renda somada de inquilinos e corresponsáveis (total_declared_income → income_to_rent_ratio), e a spec 0003 existe justamente para o corresponsável elevar essa razão. Mas nada relaciona um comprovante de renda à pessoa que o declarou. Uma análise aprovada pela renda de três pessoas pode ter o comprovante de uma só.
O seletor de tipo não separa contexto. A lista de tipos é global do tenant e mistura tudo — são 20 tipos em 7 grupos (Renda, Identificação, Imóvel, Contrato, Jurídico, Residência, Outros). Ao anexar numa análise, o operador vê "Laudo de Vistoria" e "Contrato de Garantia" ao lado de "Comprovante de Renda". É a tela que produz documento classificado errado — e classificação errada torna qualquer conferência inútil.
2. Objetivo¶
Cada garantidora define, por área (inquilino PF, inquilino PJ, corresponsável, imóvel, adicionais), quais tipos de documento são obrigatórios ou opcionais e por quantos dias cada um vale. A análise mostra um checklist do que falta, e a aprovação é bloqueada enquanto faltar obrigatório — com saída registrada para a exceção legítima.
3. Fora de escopo¶
- Coleta guiada dentro do formulário de criação — pedir os documentos ao selecionar inquilino, imóvel e corresponsáveis. É a evolução natural e vai para a 0009. Esta spec entrega a parametrização, o checklist e o bloqueio; o anexo continua pelos painéis de documento que já existem (no inquilino, no imóvel e na análise).
- Outros contextos de anexo fora da análise de crédito (contrato).
- Mudar a lista de Tipos de Documento. Continua como está, fonte única em
/settings/document-types. Esta spec consome essa lista. - Bloqueio no
submit. Barra na aprovação. O operador segue podendo cadastrar o caso e juntar documentos depois — é para isso que existe oPENDING_DOCS. - Validar conteúdo (OCR, autenticidade, valor declarado). A regra é de presença e validade temporal, não de conteúdo.
- Notificar o inquilino sobre o que falta.
4. Regras de negócio¶
Parametrização¶
- RN1. A exigência é definida por área. São cinco:
| Área | A que se refere | Onde o documento fica |
|---|---|---|
LESSEE_PF | inquilino pessoa física | cadastro do inquilino (renter_id) |
LESSEE_PJ | inquilino pessoa jurídica | cadastro do inquilino (renter_id) |
CO_RESPONSIBLE | corresponsável (sempre PF, ver RN4) | cadastro do corresponsável (renter_id) |
PROPERTY | imóvel da análise | cadastro do imóvel (property_id) |
ADDITIONAL | a análise em si | a análise (credit_analysis_id) |
- RN2. Cada par (tipo de documento, área) tem uma exigência:
REQUIREDouOPTIONAL. Ausência de registro = não se aplica — é o padrão. Tipo novo criado em/settings/document-typesnão passa a ser exigido em lugar nenhum sem alguém dizer. - RN3. Cada par tem
validity_days(inteiro, opcional).null= não expira (RG, Contrato Social, Matrícula). Preenchido = o documento só satisfaz o requisito se foi anexado há no máximo esse número de dias — é o que impede um holerite de dois anos atrás sustentar uma análise de hoje.
A contagem é a partir da data de anexo (created_at do documento), não da data do documento em si. Consequência assumida: um holerite de março anexado em julho conta como sendo de julho. O sistema não captura a competência do documento, e capturar exigiria um campo novo no anexo — decidido ficar fora (ver seção 9). Na prática o documento é pedido no momento da análise, então anexo e competência costumam andar juntos; quem quiser margem menor usa um validity_days mais curto.
Por que validade e não "documento desta análise": guardar o documento no cadastro da pessoa é o que permite saber de quem ele é — o
Documentse liga a uma entidade só, então um documento preso à análise perde a autoria, e era exatamente o furo do problema.validity_daysresolve a atualidade sem abrir mão da autoria, e é mais expressivo: cobre "extrato vale 30 dias" e "RG não vence" no mesmo campo.
- RN4. A área
CO_RESPONSIBLEnão se desdobra em PF/PJ: a API já impede corresponsável PJ (CO_RESPONSIBLE_MUST_BE_PF, RN6 da spec 0003). - RN5. Só
ADMIN_TENANTparametriza. Os demais papéis leem — o checklist aparece para quem enxerga a análise. Alinhado ao que já vale paradocument_types:*. - RN6. Excluir um tipo (soft delete) remove junto as suas exigências: some do checklist, sem requisito órfão travando aprovação. O diálogo de exclusão, que já obriga a decidir a reatribuição dos documentos, passa a avisar quando o tipo é exigido em alguma área. Não bloqueia — é decisão do admin, mas informada.
Conferência e bloqueio¶
- RN7. Um documento satisfaz um requisito quando, cumulativamente: está anexado à entidade da área (RN1), tem
document_type_iddo tipo exigido, não está soft-deleted, e está dentro da validade (RN3). Arquivo sem tipo classificado não conta para nada. - RN8. A conferência é por pessoa. Requisito de
CO_RESPONSIBLEprecisa ser satisfeito por cada corresponsável da análise — é o que fecha o furo da renda somada. Idem para o inquilino: cada participanteLESSEEresponde pelos requisitos da sua natureza (PF ou PJ, pelorenter_typede cada um). - RN9.
POST /credit-analyses/{id}/decision/approveé bloqueado se faltar qualquer obrigatório, salvo a exceção da RN10. ErroMISSING_REQUIRED_DOCUMENTS, detalhando o quê e de quem — "faltam documentos" sem nomear obriga o analista a adivinhar. Documento presente mas vencido aparece comoEXPIRED, distinto de ausente: são conversas diferentes com o cliente. - RN10. Exceção com justificativa. Um
ADMIN_TENANTpode aprovar mesmo faltando obrigatório, informandomissing_documents_justification(texto obrigatório, não vazio).ANALYSTnão tem essa saída — precisa escalar. A justificativa e a lista do que faltava vão para o histórico e para a auditoria. - RN11. Snapshot na aprovação. No momento do approve, a decisão guarda os documentos considerados (id, tipo, área, a quem pertencia, data de anexo) e o que faltava. Sem isso, auditar uma aprovação antiga mostraria o cadastro de hoje — e como o documento é reutilizável entre análises (RN3), o cadastro muda.
- RN12. A conferência acontece no approve, sobre o estado corrente. Documento anexado depois do
submitconta normalmente.
Interface¶
- RN13. O seletor de tipo no painel de documentos da análise oferece só os tipos da área
ADDITIONAL. Nos painéis do inquilino e do imóvel, só os tipos das áreas correspondentes. Os demais contextos seguem com a lista completa. - RN14. A tela da análise mostra o checklist agrupado por área e por pessoa: o que é exigido, o que veio, o que falta e o que venceu — visível antes da aprovação, para o bloqueio não ser surpresa no fim do fluxo.
- RN15. Nada é retroativo. A migration nasce sem exigência nenhuma (RN2), então nenhuma análise em andamento passa a ser bloqueada sem alguém ter parametrizado. Análises já
APPROVEDnão são tocadas.
5. Impacto por app¶
apps/api¶
- Enums novos:
DocumentArea(LESSEE_PF,LESSEE_PJ,CO_RESPONSIBLE,PROPERTY,ADDITIONAL) eDocumentRequirement(OPTIONAL,REQUIRED). - Modelo novo:
CreditAnalysisDocumentRequirement(credit_analysis_document_requirements):tenant_id,document_type_id(FK,ON DELETE CASCADE),area,requirement,validity_days(int, nullable). Unicidade em (tenant_id,document_type_id,area).
O
CASCADEnão sustenta a RN6 sozinho — descoberto na implementação: a exclusão de tipo de documento é soft delete (deleted_at), então o cascade nunca dispara. A RN6 é garantida em dois pontos: a consulta de exigências ignora tipos soft-deleted, e oDocumentTypeService.deleteapaga as exigências explicitamente.Por que tabela separada e não colunas em
document_types: manter a lista de tipos neutra é o que deixa barato estender para contrato depois, e evita que a exclusão de tipo (que já tem regra própria de reatribuição) precise entender de exigência.
- Snapshot: coluna
documents_snapshot(JSON, nullable) emdecisions, gravada no approve (RN11), maismissing_documents_justification(Text, nullable) para a RN10. JSON em vez de tabela nova porque é artefato de auditoria, lido inteiro e nunca consultado por partes — eJSONgenérico, nãoJSONB, porque é o que o resto do projeto usa (tenant_settings,channel_integration) e o que funciona no SQLite dos testes. - Endpoints:
GET /api/v1/settings/credit-analysis-documents— todos os tipos do tenant × 5 áreas com a exigência atual, para a tela não cruzar duas chamadas. Permissãocredit_analysis_document_requirements:list.PUT /api/v1/settings/credit-analysis-documents— grava em lote (a tela é uma grade; salvar célula a célula geraria N requisições e estado parcial). Permissãocredit_analysis_document_requirements:update.GET /api/v1/credit-analyses/{id}/document-checklist— checklist resolvido: áreas, pessoas, satisfeito/ausente/vencido. Permissãocredit_analyses:read.- Permissões novas (2) no
rbac_seed+ migration:ADMIN_TENANTcom as duas; demais papéis comlist. - Service:
DecisionService.approvechama o checklist antes de aprovar (RN9/RN10/RN11).AnalysisDecisionRequestganhamissing_documents_justification: str | None— segue o precedente domandatory_clause_confirmed, que mora nesse payload desde a spec 0003. - Migration: tabela + 2 enums + coluna JSONB + 2 permissões e vínculos. Não popula exigência (RN2/RN15).
downgradesimétrico. - Testes: bloqueio por ausência; liberação ao anexar; documento vencido não satisfaz; PF e PJ com conjuntos distintos; cada corresponsável conferido separadamente (RN8);
ADMIN_TENANTcom justificativa;ANALYSTsem a saída; soft-deleted não conta; sem tipo não conta; snapshot gravado.
apps/web¶
- Página nova:
src/pages/settings/credit-analysis-documents/— grade de tipos (agrupados porgroup, como a tela de Tipos de Documento) × 5 áreas, com exigência e validade por célula. App.tsx+components/custom-sider/index.tsx: item novo em ADMINISTRAÇÃO, ao lado de "Tipos de Documento". Os dois arquivos, conforme o CLAUDE.md do web.DocumentsPanel: aceita a lista de tipos permitidos, para respeitar a RN13 sem afetar os outros usos.- Checklist em
credit-analyses/show.tsx: por área e por pessoa, distinguindo ausente de vencido. DecisionPanel: quando falta obrigatório, mostra a lista e — só paraADMIN_TENANT— o campo de justificativa que habilita o botão.- Aviso na exclusão de tipo (
settings/document-types), conforme RN6. - i18n: chaves PT e EN.
data-testid:ca-doc-requirements-form,ca-doc-requirement-{typeId}-{area},ca-doc-validity-{typeId}-{area},ca-doc-requirements-save,credit-analysis-doc-checklist,credit-analysis-doc-missing-{typeId},credit-analysis-doc-expired-{typeId},decision-approve-missing-docs,decision-approve-justification-input.- Responsividade & PWA: a grade tipos × 5 áreas não cabe em 375px como tabela — no mobile vira lista por tipo, com as áreas empilhadas (padrão das specs 0004/0007). O checklist entra em coluna única. Sem impacto de PWA além do cache normal de assets.
apps/e2e¶
- Spec nova
credit-analysis-documents.spec.ts: parametrizar obrigatório; aprovar sem ele e ver o bloqueio nomeando o tipo; anexar e aprovar; documento vencido barrando; PF e PJ distintos; dois corresponsáveis, só um com documento (RN8);ADMIN_TENANTaprovando com justificativa;analista@e2e.testsem a saída. - Rodar em desktop e mobile — a grade de parametrização é o caso crítico em 375px.
- Seeds: aproveitar os tipos que o seed já cria; acrescentar inquilino PJ e um segundo corresponsável em
tests/fixtures/seeds/se necessário.
6. Contrato de API¶
{
"items": [
{ "document_type_id": "uuid", "name": "Comprovante de Renda", "group": "Renda",
"areas": {
"LESSEE_PF": { "requirement": "REQUIRED", "validity_days": 90 },
"LESSEE_PJ": null,
"CO_RESPONSIBLE": { "requirement": "REQUIRED", "validity_days": 90 },
"PROPERTY": null,
"ADDITIONAL": null
} },
{ "document_type_id": "uuid", "name": "RG / Identidade", "group": "Identificação",
"areas": {
"LESSEE_PF": { "requirement": "REQUIRED", "validity_days": null },
"LESSEE_PJ": null,
"CO_RESPONSIBLE": { "requirement": "REQUIRED", "validity_days": null },
"PROPERTY": null,
"ADDITIONAL": null
} }
]
}
PUT /api/v1/settings/credit-analysis-documents
{ "items": [
{ "document_type_id": "uuid", "area": "LESSEE_PF",
"requirement": "REQUIRED", "validity_days": 90 }
] }
{
"areas": [
{ "area": "LESSEE_PF", "renter_id": "uuid", "renter_name": "José da Silva",
"items": [
{ "document_type_id": "uuid", "name": "Comprovante de Renda",
"requirement": "REQUIRED", "status": "SATISFIED",
"document_id": "uuid", "uploaded_at": "2026-06-20T10:00:00Z" },
{ "document_type_id": "uuid", "name": "RG / Identidade",
"requirement": "REQUIRED", "status": "MISSING" }
] },
{ "area": "CO_RESPONSIBLE", "renter_id": "uuid", "renter_name": "Maria Souza",
"items": [
{ "document_type_id": "uuid", "name": "Comprovante de Renda",
"requirement": "REQUIRED", "status": "EXPIRED",
"document_id": "uuid", "uploaded_at": "2025-01-10T10:00:00Z" }
] }
],
"blocking": [
{ "area": "LESSEE_PF", "renter_name": "José da Silva", "name": "RG / Identidade", "status": "MISSING" },
{ "area": "CO_RESPONSIBLE", "renter_name": "Maria Souza", "name": "Comprovante de Renda", "status": "EXPIRED" }
]
}
Erros previstos:
| Código | Quando | HTTP |
|---|---|---|
MISSING_REQUIRED_DOCUMENTS | Falta (ou venceu) obrigatório, sem justificativa válida | 422 |
JUSTIFICATION_REQUIRED | Justificativa vazia ou só espaços | 422 |
FORBIDDEN | ANALYST tentando usar a saída da RN10 | 403 |
7. Critérios de aceite¶
- [x] CA1.
ADMIN_TENANTmarca "Comprovante de Renda" obrigatório emLESSEE_PFcom validade 90, salva, recarrega e a marcação persiste. - [x] CA2.
ANALYSTnão altera a parametrização, mas vê o checklist na análise. - [x] CA3. Análise de inquilino PF sem o comprovante: aprovar falha com
MISSING_REQUIRED_DOCUMENTS, e a mensagem nomeia o tipo e a pessoa. - [x] CA4. Anexado o documento com o tipo correto no cadastro do inquilino, a mesma aprovação passa.
- [x] CA5. Documento do tipo certo, porém anexado há mais dias que a validade, não satisfaz: aparece como
EXPIREDe bloqueia. (A contagem é da data de anexo — RN3.) - [x] CA6. Inquilino PJ com o conjunto de PJ satisfeito aprova, mesmo faltando documento exigido só de PF.
- [x] CA7. Com dois corresponsáveis e obrigatório em
CO_RESPONSIBLE, ter o documento de um não basta — o checklist aponta o outro pelo nome e a aprovação é bloqueada (RN8). - [x] CA8.
ADMIN_TENANTaprova faltando obrigatório informando justificativa; ela fica no histórico e na auditoria com a lista do que faltava. Justificativa vazia é recusada. - [x] CA9.
ANALYSTnão aprova faltando obrigatório, nem enviando justificativa. - [x] CA10. Aprovada a análise, o snapshot registra os documentos considerados; e se depois o documento for trocado no cadastro da pessoa, o snapshot segue mostrando o que sustentou aquela decisão (RN11).
- [x] CA11. No painel de documentos da análise, o seletor mostra só tipos de
ADDITIONAL; no painel do inquilino, só os das áreas de inquilino. - [x] CA12. Excluir um tipo exigido avisa o admin e, confirmado, remove a exigência sem deixar a aprovação travada por requisito órfão.
- [x] CA13. Análises aprovadas antes desta feature seguem íntegras, e nenhuma análise em andamento passa a ser bloqueada sem parametrização (RN15).
- [x] CA14. No mobile (375px), a tela de parametrização é usável sem scroll horizontal e o checklist aparece em coluna única.
- [x] CA15.
make testverde e e2e passando em desktop e mobile.
8. Plano de implementação¶
Ordem obrigatória: api → web → e2e.
- [x]
apps/api— enumsDocumentArea/DocumentRequirement+ modeloCreditAnalysisDocumentRequirement - [x]
apps/api— schemas → repository → service (parametrização + resolução do checklist por área e por pessoa) - [x]
apps/api— routers (GET/PUTsettings,GETchecklist) com Swagger completo - [x]
apps/api—DecisionService.approve: bloqueio, justificativa e snapshot (RN9–RN11) - [x]
apps/api—rbac_seed+ migration (tabela, enums, JSONB, 2 permissões, vínculos) - [x]
apps/api— testes - [x]
apps/web— tela de parametrização (App.tsxecustom-sider), responsiva - [x]
apps/web—DocumentsPanelfiltrado por área, checklist na análise, diálogo de aprovação, aviso na exclusão de tipo - [x]
apps/web— i18n PT/EN - [x]
apps/e2e— spec nova, desktop e mobile - [x]
make teste tsc limpos; sem apontamento novo de lint nos arquivos tocados - [x] Validado no browser em desktop e mobile
9. Decisões em aberto¶
Resolvidas com o usuário (2026-07-31):
- [x] Escopo da parametrização — tela própria da Análise de Crédito, consumindo a lista de Tipos de Documento; por área (inquilino PF/PJ, corresponsável, imóvel, adicionais).
- [x] PF vs PJ — a exigência varia por natureza do inquilino.
- [x] Onde bloqueia — na aprovação, não no envio.
- [x] Exceção —
ADMIN_TENANTaprova com justificativa registrada. - [x] Corresponsável PJ — não existe; a API já impede (
CO_RESPONSIBLE_MUST_BE_PF). Decisão encerrada por fato do código. - [x] Tipo excluído com exigência — a exigência cai junto, com aviso no diálogo de exclusão. Bloquear a exclusão fugiria do padrão já estabelecido para tipos.
- [x] Conferência por pessoa — sim (RN8). Viabilizada por guardar o documento no cadastro da pessoa.
- [x] Atualidade do documento — resolvida por
validity_dayspor tipo/área (RN3), e não por prender o documento à análise. Prender à análise custaria a autoria do documento, que é o que fecha o furo da renda somada. - [x] Auditoria — snapshot no momento da aprovação (RN11).
-
[x] Fatiamento — 0008 entrega parametrização, checklist e bloqueio; a coleta guiada no formulário de criação vai para a 0009.
-
[x] Validade conta de quando? Da data de anexo (
created_at). Sem campo "data do documento" no anexo — ficaria mais preciso, mas mexeria noDocumentsPanele no modelo deDocumentpor um ganho pequeno: na prática o documento é pedido no momento da análise. A imprecisão está registrada na RN3.
Nenhuma decisão em aberto. A spec está pronta para APROVADA.
10. Registro¶
API (2026-07-31)¶
Entregue como planejado: enums, modelo, migration (validada nos dois sentidos), schemas, repository, service com resolução por área e por pessoa, três endpoints com Swagger, bloqueio na aprovação com justificativa e snapshot, permissões no rbac_seed. 14 testes novos, todos passando.
Divergências do planejado:
ON DELETE CASCADEnão sustenta a RN6. A spec afirmava que o cascade da FK garantiria que excluir um tipo levasse junto a exigência. Errado: a exclusão de tipo é soft delete, então o cascade nunca dispara — o testetest_excluir_tipo_remove_a_exigenciapegou isso. A RN6 passou a ser garantida em dois pontos: a consulta de exigências ignora tipos soft-deletados (vale para qualquer caminho) e oDocumentTypeService.deleteapaga as exigências explicitamente (higiene de dados).JSONem vez deJSONBpara o snapshot, seguindo a regra do CLAUDE.md da API: tipos específicos do PostgreSQL quebram os testes, que rodam em SQLite.BusinessRuleErrorganhoudetails(opcional, retrocompatível). A RN9 exige que o erro nomeie o que falta e de quem; sem isso a mensagem seria genérica e o analista teria que adivinhar.
O espelho de permissões do conftest, de novo¶
Os testes novos falharam 12 de 14 na primeira rodada, todos com 403 ao criar tipo de documento. Causa: o tests/conftest.py mantinha cópias manuais do catálogo de permissões e do mapa papel→permissões do rbac_seed, e essas cópias não tinham document_types — nem nunca tiveram. Ou seja, aquela superfície inteira jamais foi exercida por teste.
É a segunda vez que esse espelho custa caro: na spec 0007 ele estava com o recurso decisions no singular, deixando a suíte em 167/173 sem que ninguém percebesse.
Em vez de remendar acrescentando as permissões novas, o conftest passou a importar _PERMISSIONS e _ROLE_PERMISSIONS do rbac_seed. A divergência deixa de ser possível: um papel só tem em teste o que tem em produção. Isso resolveu 8 das 12 falhas.
Vale registrar o que o espelho escondia: como ele era um subconjunto, um papel podia perder permissão real sem nenhum teste falhar — e, pior, podia passar em teste com permissão que não tem em produção.
Bugs meus, encontrados pelos próprios testes: um assert ... or True que nunca falharia (mascarava uma aprovação indevida antes do delete) e um Document.id == str onde a coluna é UUID.
Web (2026-07-31)¶
Divergência de desenho, aprovada pelo usuário: a spec pedia uma grade tipos × 5 áreas. Implementando, isso dava ~200 controles numa tela (20 tipos × 5 áreas × 2 campos) — ilegível no desktop e impossível em 375px. Virou uma aba por área: escolhe-se a área e a lista mostra os tipos com exigência e validade. Resolve o mobile por construção e casa com o trabalho real, que é configurar uma área por vez. Custo assumido: não dá para comparar áreas lado a lado.
Entregue: tela de parametrização (rota, item em ADMINISTRAÇÃO via nav-groups, 23 chaves i18n em PT e EN), checklist na tela da análise distinguindo ausente de vencido, painel de documentos filtrado por área, bloqueio no DecisionPanel com o campo de justificativa só para gestor, e o aviso na exclusão de tipo.
Duas decisões de implementação que a spec não previa:
- Sem parametrização de
ADDITIONAL, o seletor de anexo continua completo. Filtrar para uma lista vazia impediria anexar qualquer coisa num tenant que ainda não configurou nada — o oposto da RN15. documents-file-inputganhoudata-testid. O input era oculto e sem identificação; o CLAUDE.md do web exige testid em elemento interativo, e sem ele não há como exercer o seletor de tipo (que só aparece depois de escolher arquivo).- O seletor de tipo do
DocumentsPanelnão tinha nome acessível. Ao tentar localizá-lo pelo papel ARIA, o snapshot do Playwright mostroucomboboxsem nome: oInputLabelnão estava vinculado aoSelect(faltavamid/labelId). Na prática, um leitor de tela anunciava um campo mudo. Corrigido, mais odata-testid. Foi um defeito pré-existente que só apareceu porque o teste tentou usar a árvore de acessibilidade em vez de um seletor frágil.
E2E¶
credit-analysis-documents.spec.ts, 5 cenários + 1 mobile.
O tenant de e2e não tem tipos de documento. Os 20 tipos padrão nascem na ativação do tenant, e o seed_e2e não passa por ela — a primeira versão do teste dependia do seed e falhou com "nenhum tipo de documento no tenant". Os testes agora criam o tipo de que precisam (idempotente por nome), o que também os torna independentes do ambiente.
Os testes limpam a exigência no finally: a parametrização é global do tenant, e deixar um obrigatório configurado quebraria os outros specs, que aprovam análises sem anexar documento nenhum.
Verificação¶
- API: 187 testes (173 anteriores + 14 novos), zero falhas.
- Migration: aplicada e revertida no PostgreSQL real; o
downgradezera tabela, tipos e permissões sem deixar resíduo. - Permissões no banco:
listpara os seis papéis,updatesó paraADMIN_GLOBAL/ADMIN_TENANT— conferido por query, não por leitura do seed. - Lint: zero apontamento nos seis arquivos novos. Nos arquivos existentes tocados, 78 → 60 (a remoção do espelho de permissões do conftest levou junto várias linhas longas); nenhum apontamento novo.
tscdo web: limpo.- e2e: 6 cenários da 0008 e 54 passed / 2 skipped na suíte inteira, sem falha.
- Browser real: tela de parametrização e checklist a 1440px e 375px,
scrollWidth - clientWidth == 0nas quatro combinações.