Migração de Upload de Imagens para Cloudinary
Resumo das Mudanças
Este documento descreve as mudanças realizadas para migrar o sistema de upload de imagens do backend (Render) para o frontend com Cloudinary, resolvendo definitivamente o problema de perda de arquivos a cada deploy.
Problema Original
- O backend hospedado no Render perdia todas as imagens uploadadas a cada deploy
- Uploads eram feitos diretamente para pastas locais do servidor (
uploads/,public/images/) - Sistema vulnerável a perdas de dados devido ao storage efêmero do Render
- Impossibilidade de manter arquivos entre deploys
Evolução da Solução
Primeira Tentativa: Netlify Functions ❌
- Problema: Complexidade de parsing multipart/form-data
- Limitações: Timeouts, tamanho de arquivos, processamento demorado
- Resultado: Abandonada devido à complexidade desnecessária
Solução Final: Cloudinary Direct Upload ✅
1. Integração Direta com Cloudinary
Serviço Principal: front-end/src/services/netlifyUploadService.js
- Upload direto do frontend para Cloudinary via API REST
- Sem necessidade de Netlify Functions intermediárias
- Suporte a todos os tipos: banners, blog, publicidade, imoveis
- Configuração por variáveis de ambiente
Configuração:
// Upload universal para Cloudinary
const cloudName = process.env.NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME;
const uploadPreset = process.env.NEXT_PUBLIC_CLOUDINARY_UPLOAD_PRESET;
2. Funções Específicas por Tipo de Conteúdo
Arquivo: front-end/src/services/netlifyUploadService.js
- uploadImovelImage() - Upload de imagens de imóveis
- uploadBannerImage() - Upload de banners para carrossel
- uploadBlogImage() - Upload de imagens para artigos do blog
- uploadPublicidadeImage() - Upload de imagens de publicidade
- deleteFromNetlify() - Função para deletar imagens (mantida para compatibilidade)
Características: - Upload direto via FormData para Cloudinary - Organização automática em pastas por tipo - Transformações automáticas (quality: auto, format: auto) - URLs seguras com HTTPS
3. Páginas CMS Completamente Migradas
Páginas atualizadas para Cloudinary:
- front-end/src/app/admin/cms-banner/criar/page.js ✅
- front-end/src/app/admin/cms-banner/editar/[id]/page.js ✅
- front-end/src/app/admin/cms-publicidades/criar/page.js ✅
- front-end/src/app/admin/cms-publicidades/editar/[id]/page.js ✅
- front-end/src/app/admin/cms-publicacoes/criar/page.js ✅
- front-end/src/app/admin/cms-publicacoes/editar/[id]/page.js ✅
- front-end/src/app/admin/cms-imoveis/criar/page.js ✅
- front-end/src/app/admin/cms-imoveis/editar/[id]/page.js ✅
Mudanças implementadas:
- Upload direto para Cloudinary no frontend
- Recebimento de URL segura do Cloudinary
- Envio apenas da URL para o backend via JSON
- Remoção completa de multipart/form-data
- Tratamento de erros robusto
4. Backend Completamente Limpo
Controladores atualizados:
- back-end/src/controllers/bannerController.js ✅
- back-end/src/controllers/blogController.js ✅
- back-end/src/controllers/publicidadeController.js ✅
- back-end/src/controllers/ImagemImovelController.js ✅
Mudanças implementadas:
- Multer removido completamente de todos os controladores
- Controladores recebem apenas url_imagem via JSON
- Remoção de todas as referências a req.file
- Validação atualizada para aceitar URLs do Cloudinary
- Logs de debug limpos
Rotas completamente atualizadas:
- back-end/src/routes/bannerRoutes.js ✅
- back-end/src/routes/blogRoutes.js ✅
- back-end/src/routes/publicidadeRoutes.js ✅
- back-end/src/routes/imagemImovelRoutes.js ✅
Mudanças implementadas:
- Middleware multer removido de todas as rotas
- Rotas aceitam apenas payloads JSON
- Headers Content-Type: application/json
- Remoção de tratamento de upload de arquivos
Estrutura de Pastas no Cloudinary
cloudinary.com/dajy4w5wi/image/upload/
└── imobiliaria/
├── banners/ # Banners do carrossel
├── blog/ # Imagens de artigos
├── publicidade/ # Imagens de publicidade
└── imoveis/ # Imagens de imóveis
Fluxo de Upload Final
Antes (Problemático):
- Frontend → Backend (multipart/form-data)
- Backend salva arquivo localmente com Multer
- Backend salva referência no banco de dados
- ❌ Deploy = perda de todos os arquivos
Primeira Tentativa (Netlify Functions):
- Frontend → Netlify Function (multipart)
- Netlify Function processa arquivo
- Function salva em public/images/
- ❌ Complexidade desnecessária, timeouts
Solução Final (Cloudinary Direct):
- Frontend → Cloudinary (FormData direto)
- Cloudinary retorna URL segura
- Frontend → Backend (apenas URL via JSON)
- Backend salva referência no banco
- ✅ Imagens persistem para sempre no CDN
Benefícios da Migração para Cloudinary
🚀 Performance e Disponibilidade
- ✅ CDN Global: Imagens servidas de pontos próximos ao usuário
- ✅ 99.9% Uptime: Infraestrutura robusta e confiável
- ✅ Cache Automático: Otimização automática de cache
- ✅ Compressão Inteligente: Quality: auto, Format: auto
💾 Persistência e Backup
- ✅ Imagens persistem para sempre (não dependem de deploys)
- ✅ Backup automático gerenciado pelo Cloudinary
- ✅ Versionamento de imagens nativo
- ✅ Redundância geográfica automática
⚡ Performance do Sistema
- ✅ Backend ultrarrápido (sem processamento de arquivos)
- ✅ Menos uso de CPU/RAM no servidor Render
- ✅ Upload paralelo (não bloqueia o backend)
- ✅ Transformações automáticas (WebP, AVIF, etc.)
🔧 Desenvolvimento e Manutenção
- ✅ Código mais limpo (separação de responsabilidades)
- ✅ Menos dependências no backend (sem Multer)
- ✅ Melhor escalabilidade (processamento distribuído)
- ✅ Debugging simplificado (logs centralizados)
Compatibilidade
- ✅ APIs do backend mantêm compatibilidade
- ✅ Estrutura do banco de dados inalterada
- ✅ URLs das imagens mantêm formato original
- ✅ Funcionalidades existentes preservadas
Como Usar o Sistema Atualizado
🔧 Configuração Inicial
Variáveis de Ambiente (Frontend):
# .env.local
NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME=dajy4w5wi
NEXT_PUBLIC_CLOUDINARY_UPLOAD_PRESET=imobiliaria-bortone-upload
Configuração do Upload Preset no Cloudinary: - Signing Mode: Unsigned ✅ - Asset Folder: imobiliaria ✅ - Return Delete Token: Enabled ✅ - Invalidate CDN Cache: Enabled ✅
📤 Uso nas Páginas CMS
Upload de Imagem de Imóvel:
import { uploadImovelImage } from '@/services/netlifyUploadService';
try {
const imageUrl = await uploadImovelImage(file, imovelId, "Descrição da imagem");
// imageUrl = "https://res.cloudinary.com/dajy4w5wi/image/upload/v123/imobiliaria/imoveis/abc123.jpg"
// Enviar apenas a URL para o backend
const response = await axios.post('/api/imoveis', {
...outrosDados,
url_imagem: imageUrl
});
} catch (error) {
console.error('Erro no upload:', error);
}
Upload de Banner:
import { uploadBannerImage } from '@/services/netlifyUploadService';
const imageUrl = await uploadBannerImage(file, "Descrição do banner", usuarioId);
// imageUrl será uma URL completa do Cloudinary
Upload de Blog/Publicidade:
import { uploadBlogImage, uploadPublicidadeImage } from '@/services/netlifyUploadService';
// Para blog
const blogImageUrl = await uploadBlogImage(file, "Título do Post", "Conteúdo...", usuarioId);
// Para publicidade
const pubImageUrl = await uploadPublicidadeImage(file, "Título da Campanha", "Descrição...", usuarioId, true);
Status da Migração ✅
Desenvolvimento:
- ✅ Configuração Cloudinary completa
- ✅ Serviços de upload implementados e testados
- ✅ Todas as páginas CMS migradas
- ✅ Backend limpo (sem Multer/req.file)
- ✅ Build funcionando sem erros
- ✅ CSP configurado para desenvolvimento
- ✅ Upload/exibição funcionando localmente
Para Deploy em Produção:
- 🔄 Configurar variáveis no Netlify
- 🔄 Deploy e teste em ambiente de produção
- 🔄 Monitorar performance do Cloudinary
- 🔄 Verificar URLs em todas as páginas
Especificações Técnicas
🌐 Cloudinary
- Cloud Name:
dajy4w5wi - Upload Preset:
imobiliaria-bortone-upload - Limite por arquivo: 10MB (configurável)
- Formatos suportados: JPG, PNG, JPEG, WebP, GIF
- Transformações: Quality: auto, Format: auto
📁 Estrutura de URLs
https://res.cloudinary.com/dajy4w5wi/image/upload/v{version}/imobiliaria/{tipo}/{filename}
Exemplos:
- Banner: /imobiliaria/banners/banner_1759123456.jpg
- Blog: /imobiliaria/blog/blog_1759123456.jpg
- Publicidade: /imobiliaria/publicidade/publicidade_1759123456.jpg
- Imóvel: /imobiliaria/imoveis/imovel_123_1759123456.jpg
⚙️ Configurações do Next.js
- Content Security Policy: Permite localhost:* em desenvolvimento
- Image Optimization: Desabilitada (unoptimized: true)
- Transpile Packages: Ant Design compatível
- Webpack: Configurado para Leaflet e Ant Design
🔒 Segurança
- Upload preset unsigned para frontend
- Validação de formatos no Cloudinary
- CSP restritivo em produção
- URLs seguras HTTPS obrigatórias
Arquivos de Referência (Deprecated)
Mantidos apenas para referência:
- front-end/netlify/functions/upload-image.js (não usado)
- front-end/netlify/functions/delete-image.js (não usado)
Nota: As Netlify Functions foram substituídas pelo upload direto ao Cloudinary.