Backlog de melhorias
Melhorias levantadas no uso do painel administrativo e na auditoria de
segurança e qualidade do código, em outubro de 2026. Cada
item tem um identificador estável (MF-xx) para ser citado em tarefas, PRs e
conversas com o cliente.
| ID | Melhoria | Tipo | Prioridade | Esforço |
|---|---|---|---|---|
| MF-01 | Corrigir alteração de senha no painel | Bug | Alta | Pequeno |
| MF-02 | Busca e filtros nas tabelas do admin | UX | Alta | Médio |
| MF-03 | Modal de detalhes para dados extensos | UX | Alta | Médio |
| MF-04 | Remover a coluna ID e editar pela coluna Ação | UX | Média | Pequeno |
| MF-05 | Fixar a coluna Ação | UX | Média | Pequeno |
| MF-06 | Itens por página na paginação | UX | Média | Pequeno |
| MF-07 | Placeholder para dados ainda não gerados | UX | Média | Pequeno |
| MF-08 | Contraste e estética das tabelas | Visual | Média | Médio |
| MF-09 | Máscaras de entrada e exibição de dados | UX | Média | Médio |
| MF-10 | Ícones por categoria na seção Diversos | Visual | Baixa | Pequeno |
| MF-11 | Atalho para a documentação nas áreas sobre a Moldapé | Produto | Baixa | Pequeno |
| MF-12 | Reescrever o DataTable sobre o TanStack Table | Arquitetura | Alta | Médio |
| MF-13 | Restringir CORS e rever o SameSite do cookie | Segurança | Crítica | Pequeno |
| MF-14 | Verificar a posse do recurso (IDOR) | Segurança | Crítica | Médio |
| MF-15 | Calcular o valor do pagamento no servidor | Segurança | Crítica | Pequeno |
| MF-16 | Validar o webhook e restringir o token de serviço | Segurança | Crítica | Médio |
| MF-17 | Atualizar dependências vulneráveis (restante) | Segurança | Alta | Médio |
| MF-18 | Migrar para Fastify 5 | Segurança | Média | Médio |
| MF-19 | Respostas de erro sem detalhes internos | Segurança | Alta | Pequeno |
| MF-20 | Endurecer o Better Auth (restante) | Segurança | Alta | Pequeno |
| MF-21 | Headers de segurança (API e CSP) | Segurança | Média | Pequeno |
| MF-22 | Logs sem dados sensíveis e estruturados | Segurança | Alta | Médio |
| MF-23 | Consertar o CI e torná-lo obrigatório | Qualidade | Alta | Médio |
| MF-24 | Cobertura de testes nos fluxos críticos | Qualidade | Média | Grande |
| MF-26 | Reduzir any e ligar o modo estrito |
Qualidade | Média | Grande |
| MF-27 | Migrations automáticas no deploy | Qualidade | Alta | Pequeno |
Correções
Seção intitulada “Correções”Corrigir a alteração de senha de usuários e administradores
Problema
Seção intitulada “Problema”No painel Acessos, editar um usuário ou administrador e preencher uma nova senha não altera a senha. O formulário é salvo sem erro, o que dá a impressão de sucesso.
Causa provável (a confirmar)
Seção intitulada “Causa provável (a confirmar)”O modal UserFormModal envia a senha junto dos demais campos para
authClient.admin.updateUser({ userId, data }). No Better Auth, esse método
atualiza a tabela user; a senha fica na tabela account, com hash, e é
alterada por um método próprio do plugin de admin (setUserPassword).
Proposta
Seção intitulada “Proposta”- Separar a troca de senha: quando o campo vier preenchido, chamar
authClient.admin.setUserPassword({ userId, newPassword }). - Mostrar erro claro se a operação falhar e um toast de sucesso só depois da confirmação.
- Revogar as sessões ativas do usuário após a troca (
revokeUserSessions). - Remover a senha aleatória de reserva (
Math.random()) na criação de usuários: senha passa a ser obrigatória ou o usuário recebe um link de definição de senha.
Critérios de aceite
Seção intitulada “Critérios de aceite”- Depois de alterar, o login com a senha antiga falha e com a nova funciona.
- Vale para usuários e administradores.
- Sessões abertas do usuário são encerradas.
Tabelas do painel administrativo
Seção intitulada “Tabelas do painel administrativo”Barra de busca e filtros nas seções do admin
Problema
Seção intitulada “Problema”As tabelas crescem com o uso (usuários, pedidos, rascunhos) e não há como encontrar um registro sem rolar a página.
Proposta
Seção intitulada “Proposta”- Campo de busca acima de cada tabela, com debounce de 300 ms, buscando nos campos de texto relevantes (nome, e-mail, código do pedido, nome do produto).
- Filtros por coluna onde fizer sentido: status e período em Pedidos; ativo/inativo em Produtos, Peças e Coberturas; perfil em Acessos.
- Estado da busca refletido na URL (
?q=&status=) para poder compartilhar o link filtrado. - Para volumes maiores, busca no servidor (parâmetros na API) em vez de filtrar só a página carregada.
Critérios de aceite
Seção intitulada “Critérios de aceite”- Digitar parte de um e-mail ou código de pedido filtra a tabela em até 1 s.
- “Limpar filtros” volta ao estado inicial.
- A busca funciona junto com a paginação (MF-06).
Modal com o detalhamento de dados extensos
Problema
Seção intitulada “Problema”Colunas como Preços, Reforços de maciez, Configurações de logo e Vetorização exibem listas inteiras dentro da célula. Uma única cobertura ocupa uma tela inteira de altura, e a vetorização de produtos mostra dezenas de URLs. A tabela perde a função de visão geral.
Proposta
Seção intitulada “Proposta”- Na tabela, mostrar só um resumo: contagem e faixa (ex.: “6 preços · R$ 0,00 – R$ 82,30”, “10 arquivos”).
- Um botão Ver detalhes abre um modal (ou painel lateral) com os dados completos organizados em seções, com miniaturas no lugar de URLs.
- Linhas com altura fixa, sem quebra de texto longa.
Critérios de aceite
Seção intitulada “Critérios de aceite”- Nenhuma linha da tabela passa de cerca de 64 px de altura.
- Todos os dados continuam acessíveis em no máximo um clique.
- O modal fecha com
Esce devolve o foco à linha de origem.
Remover a coluna ID e levar a edição para a coluna Ação
Problema
Seção intitulada “Problema”A primeira coluna mostra o ID interno (cuid), que não tem significado para
quem opera o painel e ocupa espaço. Hoje é também o link para editar o
registro, o que não é descobrível.
Proposta
Seção intitulada “Proposta”- Remover a coluna ID das tabelas (o ID pode aparecer no modal de detalhes, com botão de copiar, para suporte técnico).
- Adicionar o botão Editar (ícone de lápis + rótulo acessível) na coluna Ação, ao lado de Desativar e Excluir.
- Onde existir um código legível (ex.:
ORD-…em Pedidos), ele substitui o ID.
Critérios de aceite
Seção intitulada “Critérios de aceite”- Nenhuma tabela do admin exibe
cuidcomo coluna. - Toda linha editável tem o botão Editar na coluna Ação.
Fixar a coluna Ação
Problema
Seção intitulada “Problema”Em tabelas largas (Coberturas, Produtos), a coluna Ação fica fora da área visível e o próprio cabeçalho aparece cortado. Para excluir ou editar é preciso rolar horizontalmente.
Proposta
Seção intitulada “Proposta”Coluna Ação com position: sticky; right: 0, fundo sólido e sombra sutil à
esquerda quando houver conteúdo rolado por baixo. O cabeçalho da tabela também
fica fixo ao rolar verticalmente.
Critérios de aceite
Seção intitulada “Critérios de aceite”- Em 1280 px de largura, as ações de qualquer linha ficam visíveis sem rolagem horizontal.
Seleção de itens por página na paginação
Proposta
Seção intitulada “Proposta”- Seletor com 10, 25, 50 e 100 itens por página, padrão 25.
- Texto “Exibindo 26–50 de 312”.
- Preferência lembrada por tabela no navegador e refletida na URL
(
?pagina=2&porPagina=50).
Critérios de aceite
Seção intitulada “Critérios de aceite”- Mudar a quantidade volta para a página 1 e mantém busca e filtros.
Placeholder nas colunas com dados ainda não gerados
Problema
Seção intitulada “Problema”Em Rascunhos, as colunas Pedido e Imagens criação aparecem em branco quando o rascunho ainda não virou pedido ou não teve imagens geradas. Célula vazia é ambígua: pode ser “ainda não existe”, “falhou” ou “está carregando”.
Proposta
Seção intitulada “Proposta”Um texto padrão discreto por situação, nunca célula vazia:
| Situação | Exibição |
|---|---|
| Ainda não gerado | “Aguardando” em cinza, com ícone de relógio |
| Não se aplica | “—” com aria-label="Não se aplica" |
| Falha ao gerar | “Erro” em vermelho, com dica explicando |
| Carregando | skeleton animado |
Já existe um bom precedente na coluna Logo da cobertura, que mostra “Sem logo”.
Critérios de aceite
Seção intitulada “Critérios de aceite”- Nenhuma célula do admin fica visualmente vazia.
Melhorar o contraste e a estética das tabelas
Problema
Seção intitulada “Problema”Tabelas brancas sobre fundo branco, com divisórias muito claras: o olho não separa a tabela do resto da página nem uma linha da outra.
Proposta
Seção intitulada “Proposta”- Fundo da página em cinza muito claro (
#F7F6F8) e tabela em cartão branco com borda e sombra leve. - Cabeçalho com fundo diferenciado e texto em caixa alta com espaçamento.
- Linhas zebradas sutis e destaque de linha ao passar o mouse.
- Números e valores alinhados à direita; datas e códigos em fonte tabular.
- Cores a partir dos tokens semânticos, respeitando contraste mínimo de 4,5:1.
Critérios de aceite
Seção intitulada “Critérios de aceite”- Contraste entre texto e fundo ≥ 4,5:1 em todas as células.
- Mesma aparência em todas as tabelas (vem do
DataTable).
Reescrever o DataTable sobre o TanStack Table
Problema
Seção intitulada “Problema”O DataTable de packages/ui/src/data-table.tsx é uma implementação própria
(254 linhas): recebe columns (key, header, render) e data, e decide
as ações por uma lista de callbacks fixos (onEdit, onDelete,
onSuspendAccess, onRestoreAccess, onActivateItem, onDeactivateItem,
onChangeStatus, customActions). Ele não sabe ordenar, filtrar, paginar,
fixar colunas nem expandir linhas. Cada uma das 7 telas do admin que o usam
resolve isso (ou não resolve) por conta própria.
Proposta
Seção intitulada “Proposta”Manter o DataTable como componente de apresentação do @moldape/ui e trocar
o motor por @tanstack/react-table
(headless, sem estilo próprio, encaixa no shadcn + Tailwind atual). É o
mesmo caminho do Data Table do shadcn/ui.
| Recurso do TanStack Table | Melhoria que resolve |
|---|---|
getFilteredRowModel + globalFilter / columnFilters |
MF-02 busca e filtros |
getExpandedRowModel ou linha clicável → modal |
MF-03 detalhes |
columnVisibility (ID oculto por padrão) + coluna actions |
MF-04 |
columnPinning: { right: ['actions'] } |
MF-05 coluna Ação fixa |
getPaginationRowModel + setPageSize |
MF-06 itens por página |
cell com estados vazios padronizados |
MF-07 placeholder |
getSortedRowModel |
ordenação por coluna (novo) |
manualPagination / manualFiltering |
paginação no servidor quando a tabela crescer |
Plano de migração:
- Adicionar
@tanstack/react-tableaopackages/uie criarDataTable<TData>tipado comColumnDef<TData>[](acaba com oanydeDataTableRow). - Trocar os 8 callbacks de ação por uma definição de coluna
actions(rowActions: (row) => Action[]), que permite ações condicionais (suspender ou restaurar) sem novas props. - Criar subcomponentes reutilizáveis:
DataTableToolbar(busca + filtros),DataTablePagination(com seletor de itens por página) eDataTableColumnHeader(ordenação). - Migrar as telas uma a uma (
access,products,pieces,coverages,orders,drafts,miscellaneous), mantendo a API antiga como adapter até a última migração e depois removê-la. - Persistir filtro, ordenação e página na URL (
?q=&sort=&page=&size=), para que o admin possa compartilhar e voltar a uma visão.
Critérios de aceite
Seção intitulada “Critérios de aceite”- As 7 telas do admin usam o novo
DataTablee a API antiga foi removida. - Busca, ordenação, itens por página (10/20/50/100) e coluna Ação fixa funcionam em todas elas.
- Colunas tipadas: nenhum
anyemdata-table.tsx. - Teste de componente cobrindo filtro, ordenação, paginação e ação por linha.
- Acessível: cabeçalho ordenável com
aria-sort, ações comaria-label.
Plataforma
Seção intitulada “Plataforma”Máscaras de entrada e de exibição de dados
Problema
Seção intitulada “Problema”Telefones aparecem como 71987148979, e CPF/CNPJ e CEP são digitados sem
formatação. Isso dificulta a leitura e aumenta o erro de digitação.
Proposta
Seção intitulada “Proposta”Um módulo único de formatação (por exemplo, @moldape/ui/format), usado tanto
nos campos quanto nas tabelas:
| Dado | Máscara |
|---|---|
| Telefone | (71) 98714-8979 / (71) 3565-4389 |
| CPF / CNPJ | 000.000.000-00 / 00.000.000/0000-00, com validação de dígitos |
| CEP | 00000-000, com preenchimento de endereço |
| Moeda | R$ 1.234,56 via Intl.NumberFormat('pt-BR') (resolve também UX-04) |
| Data | 20/10/2026 e 20/10/2026 14:32 |
O valor salvo no banco continua sem máscara; a máscara é só de entrada e exibição.
Critérios de aceite
Seção intitulada “Critérios de aceite”- Mesmos formatos no cadastro, no perfil e nas tabelas do admin.
- Colar um valor já formatado ou sem formatação funciona nos dois casos.
- Campos com
inputModeadequado (tel,numeric) para o teclado do celular.
Ícones por categoria na seção Diversos
Problema
Seção intitulada “Problema”Taxa, Itens de suporte, Documentos, Slide show e Cupons usam o mesmo ícone de engrenagem. O ícone deixa de ajudar a localizar a seção.
Proposta (ícones lucide-react, já usado no projeto)
Seção intitulada “Proposta (ícones lucide-react, já usado no projeto)”| Seção | Ícone |
|---|---|
| Taxa | Receipt ou Percent |
| Itens de suporte | LifeBuoy |
| Documentos | FileText |
| Slide show | GalleryHorizontal |
| Cupons de desconto | TicketPercent |

Atalho para a documentação nas áreas sobre a Moldapé
Proposta
Seção intitulada “Proposta”- Em Conta → A Moldapé, um link “Conheça a plataforma” para a documentação e outro para baixar o PDF.
- No menu do painel administrativo, um item “Documentação”.
- Abrir em nova aba e usar a variável
NEXT_PUBLIC_DOCS_URL(não fixar a URL no código).
Segurança e qualidade de software (MF-13 a MF-27)
Os itens MF-13 a MF-27 tratam de correções de segurança e de qualidade do código. Por conterem detalhes técnicos que não devem circular fora da equipe enquanto não forem corrigidos, o detalhamento está apenas na versão online da documentação, de acesso restrito. A tabela acima resume prioridade e esforço.
Segurança (fixes)
Seção intitulada “Segurança (fixes)”Itens levantados na auditoria de código de outubro de 2026 (leitura do código
do monorepo e pnpm audit do lockfile). Onde o problema já está descrito em
Riscos e dívida técnica, o item aponta para o risco
R-xx em vez de repetir o diagnóstico.
Restringir o CORS da API e rever o SameSite do cookie de sessão
Problema
Seção intitulada “Problema”apps/order-lifecycle/src/server.tsregistra o CORS comorigin: trueecredentials: true(comentário: “Temporary: allow all origins to debug the issue”). Isso devolveAccess-Control-Allow-Originigual à origem de qualquer site, com credenciais.- O Better Auth em produção grava o cookie de sessão com
sameSite: 'none'(apps/web/src/lib/auth/auth.ts), eauth-cookies.tsusaNonecomo padrão. - Juntos, permitem que uma página maliciosa aberta pela usuária leia e altere rascunhos, carrinho e pedidos dela (CSRF com leitura de resposta).
- Existe
CORS_ORIGINemconfig.ts, mas a variável não é usada.
Proposta
Seção intitulada “Proposta”origina partir deCORS_ORIGIN(lista:https://moldape.com,https://www.moldape.come, em homologação, o domínio de staging).- Cookie de sessão com
SameSite=Lax. Comomoldape.comeapi.moldape.comsão o mesmo site (mesmo domínio registrável),Laxfunciona;Nonesó é necessário entre domínios diferentes. - Remover o comentário “temporary” e cobrir com teste.
Critérios de aceite
Seção intitulada “Critérios de aceite”- Requisição com
Origin: https://exemplo-malicioso.comnão recebeAccess-Control-Allow-Origin. - Cookie de sessão sai com
Secure; HttpOnly; SameSite=Laxem produção. - Login, checkout e estúdio continuam funcionando em produção e homologação.
Verificar a posse do recurso em rascunhos, carrinho, pedidos e uploads (IDOR)
Problema
Seção intitulada “Problema”Detalha o risco R-11. Vários handlers recebem
um ID na URL ou no corpo e operam sobre ele sem comparar com
request.user.id:
| Controller | Operações sem checagem de posse |
|---|---|
draft-controller |
ler, excluir, adicionar/remover produto, peça, cobertura e observação, trocar lado da peça |
cart-controller |
criar carrinho com userId vindo do corpo, buscar por usuário, adicionar/alterar/remover item, limpar, aplicar/remover cupom e taxa, converter em pedido |
order-controller |
ler pedido |
upload-controller |
excluir plantigrafia (a checagem de path traversal existe, a de dono não) |
Quem souber (ou adivinhar) o ID de um rascunho, carrinho ou pedido de outra pessoa consegue lê-lo ou alterá-lo.
Proposta
Seção intitulada “Proposta”- O
userIdvem sempre da sessão (request.user.id), nunca do corpo ou da query. - Um guard por agregado na camada de aplicação:
assertOwnership(resource, user)nos casos de uso, com exceção explícita paraadmin. - Responder
404(e não403) quando o recurso não é do usuário, para não revelar que o ID existe. - Ativar a regra
route-guarddo revisor de PRs para impedir rotas novas sem guarda.
Critérios de aceite
Seção intitulada “Critérios de aceite”- Teste automatizado com dois usuários (A e B) para cada rota da tabela: B não lê nem altera nada de A.
- Nenhum handler lê
userIddebodyouquery.
Calcular o valor do pagamento no servidor
Problema
Seção intitulada “Problema”payment-controller.createPaymentLink repassa o req.body direto para o
PaymentService e daí para a InfinitePay. Valor, itens e descrição são os que
o navegador mandar: dá para gerar um link de R$ 1,00 para um pedido de
R$ 300,00.
Proposta
Seção intitulada “Proposta”- A rota recebe só o
orderId(oucartId). - O servidor carrega o pedido do usuário logado (ver MF-14), soma itens, cupom e taxa a partir do banco e monta o payload.
- Guardar o valor esperado no pedido e conferir no webhook (MF-16).
- Validar a entrada com schema (Zod ou JSON Schema do Fastify).
Critérios de aceite
Seção intitulada “Critérios de aceite”- Alterar o valor no corpo da requisição não muda o valor cobrado.
- Webhook com valor pago diferente do esperado não marca o pedido como pago.
Validar o webhook da InfinitePay e restringir o token de serviço
Problema
Seção intitulada “Problema”Ver R-01: o webhook marca pedidos como pagos sem
verificar a origem, e o PAYMENT_BYPASS_TOKEN é aceito em qualquer rota.
Proposta
Seção intitulada “Proposta”- Ao receber o webhook, consultar o pagamento na API da InfinitePay pelo ID da
transação e só então atualizar o pedido (conferindo valor e
orderId). - Processamento idempotente (mesmo evento duas vezes não duplica efeitos).
- Token de serviço restrito às rotas internas que precisam dele, com rotação.
Critérios de aceite
Seção intitulada “Critérios de aceite”- Um POST forjado no webhook não muda o status de nenhum pedido.
- O token de serviço é recusado fora da lista de rotas internas.
Atualizar dependências com vulnerabilidades críticas e altas
Já resolvido (2.0 → 2.1.0)
Seção intitulada “Já resolvido (2.0 → 2.1.0)”next14.2.33 → 16.4.2 e React 19;axiosremovido (fetch nativo);vitest1.6 → 5.0.5; Jest ets-jest(que traziam ohandlebarscrítico), TanStack Router (seroval), Uploadcare e Material Tailwind fora do lockfile;zodunificado em uma versão.
Problema (restante)
Seção intitulada “Problema (restante)”| Pacote | Onde | Situação | Versão mínima corrigida |
|---|---|---|---|
better-auth 1.3.30 |
web, @moldape/auth |
avisos críticos incluídos | 1.4.9 (e 1.6.11 para o mais recente) |
jspdf 3.0.3 |
web, order-lifecycle |
avisos críticos incluídos | 4.2.1 |
nodemailer 6.10 |
packages/email |
15 avisos altos | 7.0.11 (ideal: a mais recente) |
fastify 4.29 |
order-lifecycle |
vários corrigidos só na linha 5 | ver MF-18 |
Proposta
Seção intitulada “Proposta”jspdf@^4.2.1enodemaileratuais.better-authpara a linha atual no catálogo do pnpm (vale para web e editor 3D de uma vez), lendo o changelog (a API do pluginadminmudou entre 1.3 e 1.4).- Adicionar
pnpm audit --audit-level=high --prodno CI (MF-23) e Renovate/Dependabot com agrupamento semanal.
Critérios de aceite
Seção intitulada “Critérios de aceite”pnpm audit --prodsem avisos críticos; altos com justificativa registrada.- CI falha quando surge um aviso crítico novo.
Migrar o order-lifecycle para Fastify 5
Problema
Seção intitulada “Problema”O Fastify 4 saiu do suporte (LTS) em 30/06/2025 e não recebe mais
correções: os avisos recentes sobre bypass de validação e de autenticação
por URL malformada só foram corrigidos na linha 5 (>=5.12.2).
Proposta
Seção intitulada “Proposta”Seguir o guia oficial de migração v4 → v5: atualizar fastify,
@fastify/* (cors, multipart, static, swagger, swagger-ui) e
packages/swagger juntos; revisar os pontos que mudaram (schemas completos
em querystring/params, reply.redirect, tipos de request).
Critérios de aceite
Seção intitulada “Critérios de aceite”fastify@5com todos os plugins compatíveis e testes de rota passando.- Health check e Swagger funcionando em homologação antes de produção.
Não expor detalhes internos nas respostas de erro
Problema
Seção intitulada “Problema”O error handler global devolve ao cliente error.message e um objeto
user com id e e-mail do usuário, em qualquer status, inclusive 500.
Mensagens de erro do Prisma e de bibliotecas acabam revelando nomes de
tabela, colunas e caminhos.
Proposta
Seção intitulada “Proposta”- Para 5xx: mensagem genérica e um
requestId; os detalhes ficam só no log. - Para 4xx: mensagem de domínio controlada (erros da aplicação com
code). - Nunca devolver dados do usuário no corpo do erro.
Critérios de aceite
Seção intitulada “Critérios de aceite”- Um erro 500 provocado responde
{ success:false, code, message, requestId }semstack, sem mensagem do Prisma e semuser.
Endurecer a configuração do Better Auth
Já resolvido (2.1.0)
Seção intitulada “Já resolvido (2.1.0)”A configuração foi para @moldape/auth (createMoldapeAuth): log warn em
produção (BETTER_AUTH_LOG_LEVEL para mudar), debugLogs só em debug,
openAPI() só fora de produção e trustedOrigins sem duplicatas, vindo de
BETTER_AUTH_TRUSTED_ORIGINS.
Problema (restante)
Seção intitulada “Problema (restante)”requireEmailVerification: false: qualquer e-mail é aceito sem confirmação.- Sem rate limit nas rotas de login e redefinição.
Proposta
Seção intitulada “Proposta”- Ativar a verificação de e-mail (o SMTP já existe em
packages/email). - Rate limit do próprio Better Auth nas rotas de login e redefinição.
Critérios de aceite
Seção intitulada “Critérios de aceite”- Conta nova só acessa o estúdio depois de confirmar o e-mail.
/api/auth/referenceresponde 404 em produção.- Nenhum log de nível
debugdo Better Auth em produção.
Headers de segurança na API e no site
Problema
Seção intitulada “Problema”O site já envia X-Content-Type-Options, X-Frame-Options,
Referrer-Policy, Permissions-Policy e HSTS (next.config.ts). Faltam a
Content-Security-Policy no site e qualquer header de segurança na API (sem
@fastify/helmet).
Proposta
Seção intitulada “Proposta”@fastify/helmetna API (CSP desligada, já que ela só serve JSON, exceto o Swagger).headers()nonext.configcom CSP em modo report-only primeiro, depois aplicada.- HSTS na Cloudflare.
Critérios de aceite
Seção intitulada “Critérios de aceite”- Nota A em securityheaders.com para
moldape.comeapi.moldape.com.
Tirar dados sensíveis dos logs e adotar log estruturado
Problema
Seção intitulada “Problema”Complementa R-05 e
R-13. Há 294 chamadas a console.log/
console.debug em apps/web/src e apps/order-lifecycle/src (eram 366),
incluindo cookies de sessão no middleware de autenticação da API e o payload
de pagamento (nome, endereço, valor) no checkout. No web, o build de produção
já descarta console.log (compiler.removeConsole); na API, não.
Proposta
Seção intitulada “Proposta”- No
order-lifecycle, usar só o logger do Fastify (pino) comredactparacookie,authorization,password,email,phone,address. - No
web, umloggerpequeno que não imprime nada no navegador em produção. - Regra de lint
no-consolecomo erro (com exceção para scripts) e a regrasecret-in-logdo revisor de PRs ativa.
Critérios de aceite
Seção intitulada “Critérios de aceite”- Zero
console.*emapps/*/srcfora de scripts. - Teste do
redact: um log com cookie sai com[Redacted].
Qualidade de software
Seção intitulada “Qualidade de software”Consertar o CI e fazer dele o portão da main
Problema
Seção intitulada “Problema”Ver R-06 e Implantação:
o passo de health check chama um script que não existe, o build procura um
Dockerfile na raiz e a imagem usa Node 18 (produção usa Node 20). O
pre-commit está com os testes comentados. Na prática nada impede código
quebrado de chegar à main.
Proposta
Seção intitulada “Proposta”Um pipeline com turbo run lint typecheck test build --filter=...[origin/main],
Node 20, cache do pnpm, pnpm audit (MF-17), knip para dependências e
exports sem uso e o revisor de PRs. Proteger a
main exigindo o pipeline verde.
Critérios de aceite
Seção intitulada “Critérios de aceite”- Pipeline verde na
maine obrigatório para merge. - Um PR com erro de tipo, teste falhando ou aviso crítico de dependência é bloqueado.
Medir a cobertura de testes e cobrir o que é crítico
Problema
Seção intitulada “Problema”Há 31 arquivos de teste no monorepo, a cobertura nunca foi medida e não roda no CI. Os fluxos que mais doem quando quebram (posse de recurso, cálculo do carrinho, webhook de pagamento, geração do PDF) não têm teste de ponta a ponta.
Proposta
Seção intitulada “Proposta”vitest --coverageno CI com relatório no PR.- Meta inicial de 60% em
application/edomain/doorder-lifecycle, subindo 10 pontos por trimestre; sem meta para UI no começo. - Testes de integração para as rotas de MF-14, MF-15 e MF-16.
- Um smoke test com Playwright para login → upload → rascunho → checkout
(sem concluir pagamento). A base já existe desde a 2.1.0
(
apps/web/e2e,@moldape/playwright-config): specs públicas, proteção de rotas e telas autenticadas de cliente e admin. Falta o fluxo de compra e rodar no CI com usuários de teste. - Recriar no Vitest a cobertura de login, cadastro e recuperação de senha (as suítes herdadas do Jest, obsoletas, foram apagadas na 2.1.0).
Critérios de aceite
Seção intitulada “Critérios de aceite”- Cobertura publicada a cada PR; a cobertura não pode cair.
Reduzir o uso de any e ligar o modo estrito
Problema
Seção intitulada “Problema”São 589 ocorrências de any, inclusive nos pontos de entrada da API
(req: any, res: any nos controllers) e no DataTable. Os tipos não
protegem justamente onde entra dado externo.
Proposta
Seção intitulada “Proposta”- Tipar
request/replydos controllers com os tipos do Fastify e schemas (MF-15). @typescript-eslint/no-explicit-anycomo aviso agora e erro em arquivos novos (o revisor de PRs aplica só ao diff).- Meta: cortar pela metade em dois ciclos, começando por
presentation/epackages/ui.
Critérios de aceite
Seção intitulada “Critérios de aceite”- Nenhum
anynovo entra em PR; contagem total acompanhada no CI.
Rodar as migrations automaticamente no deploy
Já resolvido
Seção intitulada “Já resolvido”O build do web não roda mais prisma migrate dev e, desde a 2.2.0, existe
pnpm prisma:migrate:deploy (prisma migrate deploy).
Problema (restante)
Seção intitulada “Problema (restante)”Ver R-07: ninguém executa o migrate deploy
automaticamente; as migrations de produção dependem de rodar o comando na mão.
Proposta
Seção intitulada “Proposta”pnpm prisma:migrate:deploy como pre-deploy command do Coolify no
order-lifecycle (dono do schema), com backup antes.
Critérios de aceite
Seção intitulada “Critérios de aceite”- Deploy do
order-lifecyclecom migration pendente aplica a migration antes de subir a nova versão. - Nenhum
migrate devemnixpacks.toml, Dockerfiles ou scripts de deploy.
Fontes da auditoria
Seção intitulada “Fontes da auditoria”- Next.js, Security Update: December 11, 2025.
- Fastify, Long Term Support e guia de migração v5.
- GitHub Advisory Database, avisos citados pelo
pnpm audit(por exemplo GHSA-p293-qw3h-jr36 no Next e GHSA-wfv2-pwc8-crg5 no jsPDF). - OWASP, API Security Top 10 2023 (API1: Broken Object Level Authorization).
Como propor uma nova melhoria
Seção intitulada “Como propor uma nova melhoria”- Dê o próximo ID livre (
MF-29,MF-30…). IDs não são reaproveitados. - Descreva o problema observado, não só a solução.
- Classifique o tipo, a prioridade (Alta: quebra um fluxo ou causa erro; Média: atrapalha o uso diário; Baixa: refinamento; Crítica: falha de segurança explorável ou perda de dinheiro/dados) e o esforço (P: até 1 dia; M: até 1 semana; G: mais que isso).
- Escreva critérios de aceite verificáveis.
- Quando for implementada, troque o status para Concluída e cite o PR.

Desenvolvido e documentado porNós Tecnologia · Desenvolvimento Criativo

