Compartilhar
Chácara com 3 Quartos à Venda, Locação ou Temporada, 250 m² em Rua Salete Uliana, 624
Rua Salete Uliana, 624
250 m²
3 quartos
1 suíte
3 banheiros
2 vagas
Abra Cadápra
Limite de 450 caracteres nas respostas do fórum e nas mensagens de chat
Contexto
O usuário pediu em 2026-10-06: **"É preciso que tenha um limite de caracteres nas respostas tanto no fórum como na página de parcerias. Permita que a pessoa mande no máximo quatrocentos e cinquenta caracteres."**
Hoje o sistema tem **validação inconsistente**:
- **Resposta do fórum** (PostDetail.jsx): **nenhum limite** nem visual nem backend. O EmojiTextarea da resposta raiz (linha 322) e o da ReplyBar aninhada (linha 464) não recebem maxLength, e o respostaController.js (backend, linha 9) só checa se o campo está presente. A screenshot enviada pelo usuário mostra exatamente isso: o form "Sua resposta" sem contador nem trava.
- **Chat** (Chat.jsx): já tem maxLength=500 no EmojiTextarea e o contador novaMensagem.length/500 na linha 372377. Mas o backend (conversaController.js função enviarMensagem) **não valida tamanho** qualquer requisição direta com mais de 500 chars passa.
A "página de parcerias" mencionada pelo usuário não tem form de resposta próprio quem responde a uma parceria vai pelo **chat que abre a partir do botão "Entrar em contato" / "Enviar mensagem"** da ParceriaDetalhe.jsx. Esse chat usa o mesmo sistema global do Chat.jsx. Logo, padronizar em **450 chars no fórum (respostas) e 450 chars no chat (qualquer conversa)** é o que dá a consistência que o usuário quer.
EmojiTextarea já tem suporte nativo a maxLength com bloqueio real (digitar, colar, inserir emoji, surrogate pair) implementar o limite de 450 é passar a prop e renderizar o contador visual, mesmo padrão usado em CreatePost.jsx:308-314 (maxLength=5000 +
Decisão de produto
- **Limite único: 450 caracteres** (em code units, mesma contagem do EmojiTextarea).
- Aplica em **respostas do fórum** (raiz + reply aninhada) e em **todas as mensagens de chat** (o sistema é global, não dá pra separar "chat de parceria" do "chat de fórum").
- Constante única exportada do frontend: frontend/src/utils/limites.js (ou inline) const LIMITE_RESPOSTA_CHARS = 450, const LIMITE_CHAT_CHARS = 450. No backend, mesma constante inline no controller (sem precisar de arquivo compartilhado valores raramente mudam).
- Backend valida e devolve 400 com mensagem amigável se passar (defesa em profundidade não é só UX, é integridade).
Mudanças
1. Constantes centralizadas (frontend)
Criar frontend/src/utils/limites.js:
js
// Limite único de caracteres em respostas e chat.
// Backend valida o mesmo valor (ver backend/src/controllers/respostaController.js e conversaController.js).
export const LIMITE_RESPOSTA_CHARS = 450
export const LIMITE_CHAT_CHARS = 450
2. frontend/src/pages/PostDetail.jsx resposta raiz
Linha 322329, passar maxLength=LIMITE_RESPOSTA_CHARS e adicionar contador:
jsx
import LIMITE_RESPOSTA_CHARS from '../utils/limites'
...
E ajustar o handleSubmitResposta (linha 7592) adicionar um early return se conteudoFinal.length > LIMITE_RESPOSTA_CHARS (defesa contra bypass de DOM, embora o EmojiTextarea já trave).
3. frontend/src/pages/PostDetail.jsx ReplyBar (reply aninhada)
Linha 464484, o HTML puro recebe maxLength=LIMITE_RESPOSTA_CHARS direto no atributo (HTML nativo funciona em ). Adicionar contador abaixo do form, dentro do mesmo bloco da ReplyBar:
jsx
E no handleSubmitReply (linha 99117) já passa replyConteudo direto sem extractTextFromEmojiHTML (textarea simples); só adicionar o early return por tamanho.
4. frontend/src/pages/Chat.jsx reduzir de 500 para 450
Linha 372: maxLength=500 maxLength=LIMITE_CHAT_CHARS. Linha 377: novaMensagem.length/500 novaMensagem.length/LIMITE_CHAT_CHARS. Linha 173 e 177: trocar 500 por LIMITE_CHAT_CHARS. (Constante importada do mesmo utils/limites.js.)
5. backend/src/controllers/respostaController.js validação de tamanho
Linha 511, depois do if (!postId !conteudo), adicionar:
js
const LIMITE_RESPOSTA_CHARS = 450
if (conteudo.length > LIMITE_RESPOSTA_CHARS)
return res.status(400).json( error: Resposta deve ter no máximo $LIMITE_RESPOSTA_CHARS caracteres. )
6. backend/src/controllers/conversaController.js validação de tamanho
Função enviarMensagem (em torno da linha 258): adicionar o mesmo padrão:
js
const LIMITE_CHAT_CHARS = 450
if (typeof conteudo === 'string' && conteudo.length > LIMITE_CHAT_CHARS)
return res.status(400).json( error: Mensagem deve ter no máximo $LIMITE_CHAT_CHARS caracteres. )
Cuidado: o conteudo do chat pode vir como **JSON serializado** (linha 190 do Chat.jsx: JSON.stringify( texto, anexos )) quando há anexos. A validação conteudo.length > 450 ainda vale o tamanho total (texto + JSON envelope + URLs de anexos) é o que importa. O limite visual no front é só do texto (length do novaMensagem), mas a trava de backend é no payload completo. Vou documentar isso num comentário inline para o próximo que mexer.
Compatibilidade
- **Dados existentes**: respostas/mensagens maiores que 450 chars no banco continuam renderizando (não há truncate de leitura). O limite é só de **escrita**. Nenhuma migração necessária.
- **Backend não trunca**, só recusa (400 Bad Request). Front trava o envio antes mesmo de chamar a API.
- **Surrogate pairs (emoji unicode)**: o EmojiTextarea conta em code units (igual ao atributo HTML maxLength), consistente com o que aparece no contador visual.
Verificação
1. **Build do frontend**: cd frontend && npx vite build zero erros.
2. **Smoke manual (CDP)**: criar backend/scripts/verificarLimiteRespostas.js que:
- Seta o token, navega para um post qualquer (/forum/432d7974-...)
- Clica em "Responder" pra abrir o form
- Tenta digitar > 450 chars no EmojiTextarea (via Runtime.evaluate no data-emoji-editor="resposta") e confere que a trava bloqueia o que passa de 450
- Confere que o contador X/450 aparece e atualiza
- Mesma checagem na ReplyBar (clica "Responder" em alguma resposta, foca o )
- Confere o maxLength=450 no DOM da ReplyBar
3. **Smoke manual do chat**: navegar /mensagens/, tentar digitar > 450 chars no data-emoji-editor="chat-mensagem", confirmar bloqueio + contador.
4. **Backend**: rodar node backend/scripts/testarLimiteResposta.js (script inline, sem persistir): faz um POST /respostas com conteudo de 451 chars, espera 400 com a mensagem "Resposta deve ter no máximo 450 caracteres.". Mesmo script, mas para POST /conversas/:id/mensagens.
5. **Regressão**: rodar backend/scripts/verificarNavegador.js (smoke do fórum) e o backend/scripts/verificarVideos.js ambos devem continuar passando.
Commits e push
Conforme memória push-automatico-github: ao final, commit único em português descrevendo o "porquê" (limites existentes eram inconsistentes respostas sem limite, chat com 500) + git push para ChineSah/forum-06102026.
Arquivos modificados (resumo)
- frontend/src/utils/limites.js (novo, 2 constantes)
- frontend/src/pages/PostDetail.jsx (resposta raiz + ReplyBar)
- frontend/src/pages/Chat.jsx (500 450)
- backend/src/controllers/respostaController.js (validação 450)
- backend/src/controllers/conversaController.js (validação 450)
- backend/scripts/verificarLimiteRespostas.js (novo, smoke CDP)
Não-objetivos
- Sidebar / header / cards do feed (regra nao-alterar-sidebar).
- Limite do **post principal** (continua 5000), da **descrição de parceria** (continua 5000), do **título** (35/56 chars), do **chat entre profissionais** (regra geral).
- Sistema de respostas em ParceriaDetalhe não existe no projeto, e o usuário aceitou que a "resposta" da parceria é via chat (decisão registrada no AskUserQuestion desta sessão).
- Não vou truncar respostas antigas no banco. O limite é só de escrita.
Contexto
O usuário pediu em 2026-10-06: **"É preciso que tenha um limite de caracteres nas respostas tanto no fórum como na página de parcerias. Permita que a pessoa mande no máximo quatrocentos e cinquenta caracteres."**
Hoje o sistema tem **validação inconsistente**:
- **Resposta do fórum** (PostDetail.jsx): **nenhum limite** nem visual nem backend. O EmojiTextarea da resposta raiz (linha 322) e o da ReplyBar aninhada (linha 464) não recebem maxLength, e o respostaController.js (backend, linha 9) só checa se o campo está presente. A screenshot enviada pelo usuário mostra exatamente isso: o form "Sua resposta" sem contador nem trava.
- **Chat** (Chat.jsx): já tem maxLength=500 no EmojiTextarea e o contador novaMensagem.length/500 na linha 372377. Mas o backend (conversaController.js função enviarMensagem) **não valida tamanho** qualquer requisição direta com mais de 500 chars passa.
A "página de parcerias" mencionada pelo usuário não tem form de resposta próprio quem responde a uma parceria vai pelo **chat que abre a partir do botão "Entrar em contato" / "Enviar mensagem"** da ParceriaDetalhe.jsx. Esse chat usa o mesmo sistema global do Chat.jsx. Logo, padronizar em **450 chars no fórum (respostas) e 450 chars no chat (qualquer conversa)** é o que dá a consistência que o usuário quer.
EmojiTextarea já tem suporte nativo a maxLength com bloqueio real (digitar, colar, inserir emoji, surrogate pair) implementar o limite de 450 é passar a prop e renderizar o contador visual, mesmo padrão usado em CreatePost.jsx:308-314 (maxLength=5000 +
formData.conteudo.length/5000
).Decisão de produto
- **Limite único: 450 caracteres** (em code units, mesma contagem do EmojiTextarea).
- Aplica em **respostas do fórum** (raiz + reply aninhada) e em **todas as mensagens de chat** (o sistema é global, não dá pra separar "chat de parceria" do "chat de fórum").
- Constante única exportada do frontend: frontend/src/utils/limites.js (ou inline) const LIMITE_RESPOSTA_CHARS = 450, const LIMITE_CHAT_CHARS = 450. No backend, mesma constante inline no controller (sem precisar de arquivo compartilhado valores raramente mudam).
- Backend valida e devolve 400 com mensagem amigável se passar (defesa em profundidade não é só UX, é integridade).
Mudanças
1. Constantes centralizadas (frontend)
Criar frontend/src/utils/limites.js:
js
// Limite único de caracteres em respostas e chat.
// Backend valida o mesmo valor (ver backend/src/controllers/respostaController.js e conversaController.js).
export const LIMITE_RESPOSTA_CHARS = 450
export const LIMITE_CHAT_CHARS = 450
2. frontend/src/pages/PostDetail.jsx resposta raiz
Linha 322329, passar maxLength=LIMITE_RESPOSTA_CHARS e adicionar contador:
jsx
import LIMITE_RESPOSTA_CHARS from '../utils/limites'
...
novaMensagem.length/LIMITE_RESPOSTA_CHARS
E ajustar o handleSubmitResposta (linha 7592) adicionar um early return se conteudoFinal.length > LIMITE_RESPOSTA_CHARS (defesa contra bypass de DOM, embora o EmojiTextarea já trave).
3. frontend/src/pages/PostDetail.jsx ReplyBar (reply aninhada)
Linha 464484, o HTML puro recebe maxLength=LIMITE_RESPOSTA_CHARS direto no atributo (HTML nativo funciona em ). Adicionar contador abaixo do form, dentro do mesmo bloco da ReplyBar:
jsx
value.length/LIMITE_RESPOSTA_CHARS
E no handleSubmitReply (linha 99117) já passa replyConteudo direto sem extractTextFromEmojiHTML (textarea simples); só adicionar o early return por tamanho.
4. frontend/src/pages/Chat.jsx reduzir de 500 para 450
Linha 372: maxLength=500 maxLength=LIMITE_CHAT_CHARS. Linha 377: novaMensagem.length/500 novaMensagem.length/LIMITE_CHAT_CHARS. Linha 173 e 177: trocar 500 por LIMITE_CHAT_CHARS. (Constante importada do mesmo utils/limites.js.)
5. backend/src/controllers/respostaController.js validação de tamanho
Linha 511, depois do if (!postId !conteudo), adicionar:
js
const LIMITE_RESPOSTA_CHARS = 450
if (conteudo.length > LIMITE_RESPOSTA_CHARS)
return res.status(400).json( error: Resposta deve ter no máximo $LIMITE_RESPOSTA_CHARS caracteres. )
6. backend/src/controllers/conversaController.js validação de tamanho
Função enviarMensagem (em torno da linha 258): adicionar o mesmo padrão:
js
const LIMITE_CHAT_CHARS = 450
if (typeof conteudo === 'string' && conteudo.length > LIMITE_CHAT_CHARS)
return res.status(400).json( error: Mensagem deve ter no máximo $LIMITE_CHAT_CHARS caracteres. )
Cuidado: o conteudo do chat pode vir como **JSON serializado** (linha 190 do Chat.jsx: JSON.stringify( texto, anexos )) quando há anexos. A validação conteudo.length > 450 ainda vale o tamanho total (texto + JSON envelope + URLs de anexos) é o que importa. O limite visual no front é só do texto (length do novaMensagem), mas a trava de backend é no payload completo. Vou documentar isso num comentário inline para o próximo que mexer.
Compatibilidade
- **Dados existentes**: respostas/mensagens maiores que 450 chars no banco continuam renderizando (não há truncate de leitura). O limite é só de **escrita**. Nenhuma migração necessária.
- **Backend não trunca**, só recusa (400 Bad Request). Front trava o envio antes mesmo de chamar a API.
- **Surrogate pairs (emoji unicode)**: o EmojiTextarea conta em code units (igual ao atributo HTML maxLength), consistente com o que aparece no contador visual.
Verificação
1. **Build do frontend**: cd frontend && npx vite build zero erros.
2. **Smoke manual (CDP)**: criar backend/scripts/verificarLimiteRespostas.js que:
- Seta o token, navega para um post qualquer (/forum/432d7974-...)
- Clica em "Responder" pra abrir o form
- Tenta digitar > 450 chars no EmojiTextarea (via Runtime.evaluate no data-emoji-editor="resposta") e confere que a trava bloqueia o que passa de 450
- Confere que o contador X/450 aparece e atualiza
- Mesma checagem na ReplyBar (clica "Responder" em alguma resposta, foca o )
- Confere o maxLength=450 no DOM da ReplyBar
3. **Smoke manual do chat**: navegar /mensagens/, tentar digitar > 450 chars no data-emoji-editor="chat-mensagem", confirmar bloqueio + contador.
4. **Backend**: rodar node backend/scripts/testarLimiteResposta.js (script inline, sem persistir): faz um POST /respostas com conteudo de 451 chars, espera 400 com a mensagem "Resposta deve ter no máximo 450 caracteres.". Mesmo script, mas para POST /conversas/:id/mensagens.
5. **Regressão**: rodar backend/scripts/verificarNavegador.js (smoke do fórum) e o backend/scripts/verificarVideos.js ambos devem continuar passando.
Commits e push
Conforme memória push-automatico-github: ao final, commit único em português descrevendo o "porquê" (limites existentes eram inconsistentes respostas sem limite, chat com 500) + git push para ChineSah/forum-06102026.
Arquivos modificados (resumo)
- frontend/src/utils/limites.js (novo, 2 constantes)
- frontend/src/pages/PostDetail.jsx (resposta raiz + ReplyBar)
- frontend/src/pages/Chat.jsx (500 450)
- backend/src/controllers/respostaController.js (validação 450)
- backend/src/controllers/conversaController.js (validação 450)
- backend/scripts/verificarLimiteRespostas.js (novo, smoke CDP)
Não-objetivos
- Sidebar / header / cards do feed (regra nao-alterar-sidebar).
- Limite do **post principal** (continua 5000), da **descrição de parceria** (continua 5000), do **título** (35/56 chars), do **chat entre profissionais** (regra geral).
- Sistema de respostas em ParceriaDetalhe não existe no projeto, e o usuário aceitou que a "resposta" da parceria é via chat (decisão registrada no AskUserQuestion desta sessão).
- Não vou truncar respostas antigas no banco. O limite é só de escrita.
Negociações e valores
R$ 300.000,00
Compra
R$ 2.700,00
Aluguel
R$ 1.500,00
Temporada
R$ 200,00
IPTU
Características
- Ar condicionado
- Armário Plan. Cozinha
- Armário Plan. Quartos
Veja no mapa interativo