Pular para o conteúdo principal

Deploy em Produção

Guia completo para implantar o LJ Velas e Aromas em ambiente de produção na Hostinger.


Sumário

  1. Arquitetura de produção
  2. Pré-requisitos
  3. Configuração do servidor
  4. Variáveis de ambiente de produção
  5. Processo de build e deploy
  6. PM2 para produção
  7. Configuração do NF-e
  8. Domínio e SSL
  9. CI/CD com GitHub Actions
  10. Rollback
  11. Monitoramento
  12. Checklist de go-live

Arquitetura de produção


Pré-requisitos

Plano Hostinger

  • Plano mínimo: Business Hosting ou superior (para apps Node.js)
  • VPS alternativo: KVM 2 ou superior (recomendado para controle total com PM2)
  • Banco de dados MySQL 8.0 (incluído em todos os planos)
  • Suporte a Node.js 20.x

Ferramentas necessárias

FerramentaVersãoObservação
Node.js20.x LTSConfigure no painel Hostinger
npm10.xIncluído com Node.js
PM2latestnpm install -g pm2
Git2.xPara pull do repositório

Configuração do servidor

1. Acesse o servidor via SSH

ssh usuario@seu-servidor.hostinger.com
# ou pela chave SSH configurada no hPanel

2. Crie o banco de dados MySQL

No painel hPanel da Hostinger:

  1. Acesse Bancos de Dados → MySQL
  2. Clique em Criar banco de dados
  3. Preencha:
    • Nome do banco: ljvemasearomas
    • Nome do usuário: ljvemas_app
    • Senha: gere uma senha forte e anote
  4. Clique em Criar

Importante: O banco de dados da Hostinger fica acessível em localhost — a DATABASE_URL deve usar 127.0.0.1 ou o hostname interno fornecido pelo hPanel.

3. Clone o repositório

cd ~/domains/ljvelasearomas.com.br
git clone https://github.com/seu-usuario/ljvemasearomas.git app
cd app

4. Instale as dependências de produção

npm install --omit=dev

O postinstall executa prisma generate automaticamente.

5. Crie o diretório de uploads

mkdir -p ~/domains/ljvelasearomas.com.br/public_html/uploads/products
chmod 755 ~/domains/ljvelasearomas.com.br/public_html/uploads/products

6. Configure o Nginx para servir os uploads

Adicione ao bloco server do Nginx:

# Servir uploads diretamente pelo Nginx (sem passar pelo Node.js)
location /uploads/ {
alias /home/USER/domains/ljvelasearomas.com.br/public_html/uploads/;
expires 30d;
add_header Cache-Control "public, immutable";
}

Variáveis de ambiente de produção

Crie o arquivo .env no diretório da aplicação (~/domains/ljvelasearomas.com.br/app/.env):

nano .env

Variáveis obrigatórias

NODE_ENV="production"

# ─── Banco de dados ───────────────────────────────────────────
# Formato: mysql://USUARIO:SENHA@HOST:PORTA/BANCO
# O host geralmente é localhost ou 127.0.0.1 na Hostinger
DATABASE_URL="mysql://ljvemas_app:SUA_SENHA@localhost:3306/ljvemasearomas"

# Banco sombra (pode ser omitido em produção se não usar migrate dev)
# Se necessário, crie um segundo banco "ljvemasearomas_shadow" no hPanel
SHADOW_DATABASE_URL="mysql://ljvemas_app:SUA_SENHA@localhost:3306/ljvemasearomas_shadow"

# ─── Autenticação ─────────────────────────────────────────────
# OBRIGATÓRIO: gere com: openssl rand -hex 32
JWT_SECRET="sua-chave-producao-de-64-caracteres-aqui"

# ─── Upload de arquivos ───────────────────────────────────────
# Caminho absoluto fora do diretório da aplicação
UPLOAD_DIR="/home/USER/domains/ljvelasearomas.com.br/public_html/uploads/products"

# URL pública base das imagens
UPLOAD_URL_BASE="https://ljvelasearomas.com.br/uploads/products"

# ─── E-mail ───────────────────────────────────────────────────
EMAIL_HOST="smtp.hostinger.com"
EMAIL_PORT="587"
EMAIL_USER="contato@ljvelasearomas.com.br"
EMAIL_PASS="senha-do-email-hostinger"
EMAIL_FROM="LJ Velas e Aromas <contato@ljvelasearomas.com.br>"

# ─── Mercado Pago (PRODUÇÃO — sem o prefixo TEST-) ────────────
# Obtido em: mercadopago.com.br/developers/panel/app
# Use as credenciais de PRODUÇÃO (sem "TEST-" no início)
MERCADOPAGO_ACCESS_TOKEN="APP_USR-0000000000000000-000000-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-000000000"
NEXT_PUBLIC_MP_PUBLIC_KEY="APP_USR-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

# ─── Frete ───────────────────────────────────────────────────
STORE_ORIGIN_CEP="01310-100"

# ─── Aplicação ────────────────────────────────────────────────
NEXT_PUBLIC_APP_URL="https://ljvelasearomas.com.br"

# ─── NF-e ─────────────────────────────────────────────────────
# Gere uma chave aleatória: openssl rand -hex 32
NFE_API_KEY="sua-chave-nfe-secreta"
NFE_SERVICE_URL="http://localhost:8001"

Variáveis de observabilidade (opcionais mas recomendadas)

# HyperDX — APM e logs centralizados
# Crie uma conta em: https://www.hyperdx.io
HYPERDX_API_KEY="sua-chave-hyperdx"
OTEL_SERVICE_NAME="ljvemasearomas-production"

Segurança: O arquivo .env nunca deve ser commitado. Ele está no .gitignore. Em pipelines CI/CD, use os Secrets do GitHub Actions para injetar as variáveis.


Processo de build e deploy

Deploy manual (primeira vez)

# 1. Entrar no diretório da aplicação
cd ~/domains/ljvelasearomas.com.br/app

# 2. Garantir que está na branch correta
git checkout main
git pull origin main

# 3. Instalar dependências
npm install --omit=dev

# 4. Fazer o build de produção
npm run build

# 5. Aplicar migrações do banco de dados
npx prisma migrate deploy

# 6. Iniciar o servidor
npm run start

Deploy de atualização

cd ~/domains/ljvelasearomas.com.br/app

# 1. Parar a aplicação atual (se usando PM2)
pm2 stop ljvemasearomas

# 2. Atualizar o código
git pull origin main

# 3. Instalar novas dependências (se houver)
npm install --omit=dev

# 4. Fazer o novo build
npm run build

# 5. Aplicar novas migrações (se houver)
npx prisma migrate deploy

# 6. Reiniciar com PM2
pm2 restart ljvemasearomas

PM2 para produção

O PM2 é o gerenciador de processos recomendado para garantir que a aplicação seja reiniciada automaticamente após falhas ou reinicializações do servidor.

Instalação

npm install -g pm2

Arquivo de configuração PM2

Crie ecosystem.config.js na raiz do projeto:

module.exports = {
apps: [
{
name: 'ljvemasearomas',
script: 'server.js',
instances: 1, // aumente para usar múltiplos cores
exec_mode: 'fork', // use 'cluster' com instances > 1
env: {
NODE_ENV: 'production',
PORT: 3000,
},
// Reiniciar se o uso de memória ultrapassar 512MB
max_memory_restart: '512M',
// Logs
out_file: './logs/pm2-out.log',
error_file: './logs/pm2-error.log',
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
// Reiniciar automaticamente em caso de falha
autorestart: true,
watch: false,
restart_delay: 5000,
},
],
};

Comandos PM2 essenciais

# Iniciar pela primeira vez
pm2 start ecosystem.config.js

# Ou diretamente com server.js
pm2 start server.js --name ljvemasearomas

# Reiniciar (zero-downtime reload)
pm2 reload ljvemasearomas

# Parar
pm2 stop ljvemasearomas

# Deletar processo
pm2 delete ljvemasearomas

# Ver status
pm2 status

# Ver logs em tempo real
pm2 logs ljvemasearomas

# Ver últimas 200 linhas de log
pm2 logs ljvemasearomas --lines 200

# Monitorar CPU/memória
pm2 monit

Inicialização automática no boot

# Gerar script de startup para o sistema
pm2 startup

# Execute o comando exibido pelo PM2 (começa com "sudo env PATH=...")
# Exemplo:
sudo env PATH=$PATH:/usr/bin pm2 startup systemd -u usuario --hp /home/usuario

# Salvar a lista de processos atual
pm2 save

Configuração do NF-e

O serviço de NF-e é um microserviço PHP independente localizado em /nfe-service/. Ele requer um certificado digital .pfx para assinar notas fiscais.

1. Faça upload do certificado

# Crie o diretório para o certificado (fora do webroot)
mkdir -p ~/certificates

# Copie o certificado .pfx via SCP (da sua máquina local)
scp /caminho/local/certificado.pfx usuario@servidor:~/certificates/

# Defina permissões restritivas
chmod 600 ~/certificates/certificado.pfx

2. Configure o serviço NF-e

No arquivo de configuração do nfe-service (consulte nfe-service/README.md):

# Caminho do certificado
NFE_CERT_PATH="/home/USER/certificates/certificado.pfx"

# Senha do certificado
NFE_CERT_PASSWORD="senha-do-certificado"

# Ambiente (1 = produção, 2 = homologação)
NFE_AMBIENTE="1"

3. Defina permissões do diretório

# O usuário do Apache/PHP-FPM precisa ler o certificado
# Verifique o usuário com: ps aux | grep apache
chown USER:www-data ~/certificates/certificado.pfx
chmod 640 ~/certificates/certificado.pfx

4. Configure as variáveis no .env principal

NFE_API_KEY="chave-secreta-compartilhada-entre-nextjs-e-nfe-service"
NFE_SERVICE_URL="http://localhost:8001"

Domínio e SSL

SSL automático pela Hostinger

A Hostinger gerencia certificados SSL automaticamente via Let's Encrypt para todos os domínios configurados:

  1. No hPanel, acesse Domínios → Gerenciar
  2. Certifique-se de que os nameservers apontam para a Hostinger
  3. Acesse SSL → Gerenciar e ative o SSL Gratuito (Let's Encrypt)
  4. O certificado é renovado automaticamente — nenhuma ação necessária

Redirecionamento HTTP → HTTPS

O header HSTS já está configurado em next.config.ts. Certifique-se de que o Nginx (ou o configurador de proxy da Hostinger) redireciona todo tráfego HTTP para HTTPS:

server {
listen 80;
server_name ljvelasearomas.com.br www.ljvelasearomas.com.br;
return 301 https://$host$request_uri;
}

DNS

TipoNomeValorTTL
A@IP do servidor3600
AwwwIP do servidor3600
CNAMEwwwljvelasearomas.com.br3600

CI/CD com GitHub Actions

O projeto inclui dois workflows em .github/workflows/:

ci.yml — Lint e Type Check

  • Trigger: Push para qualquer branch
  • O que faz: Instala dependências, roda ESLint e verifica tipos TypeScript
  • Objetivo: Bloquear código com erros de lint ou tipo antes do merge

tests.yml — Testes automatizados

  • Trigger:
    • Push para develop ou main → roda testes Jest (unitários + integração)
    • Pull Request para main → roda testes Jest + Playwright E2E (apenas Chromium)
  • Artefatos: Relatórios de teste e cobertura ficam disponíveis por 7 dias

Configurando os Secrets no GitHub

Acesse Settings → Secrets and variables → Actions e adicione:

SecretDescrição
DATABASE_URLURL do banco de teste (pode ser SQLite em memória para CI)
JWT_SECRETQualquer valor aleatório seguro
MERCADOPAGO_ACCESS_TOKENToken de teste (começa com TEST-)
NEXT_PUBLIC_MP_PUBLIC_KEYChave pública de teste
STORE_ORIGIN_CEPCEP qualquer válido
UPLOAD_DIR/tmp/uploads (para CI)
UPLOAD_URL_BASEhttp://localhost:3000/uploads/products

Pipeline completo

Push → develop
└── ci.yml (lint + typecheck)
└── tests.yml (Jest)

Pull Request → main
└── ci.yml (lint + typecheck)
└── tests.yml (Jest + Playwright Chromium)

Merge → main
└── (deploy manual via SSH ou script deploy.bat)

Rollback

Rollback rápido com Git + PM2

cd ~/domains/ljvelasearomas.com.br/app

# 1. Ver histórico de commits
git log --oneline -10

# 2. Voltar para o commit anterior
git checkout HASH_DO_COMMIT_ANTERIOR

# 3. Rebuild na versão anterior
npm run build

# 4. Reiniciar
pm2 restart ljvemasearomas

Rollback de banco de dados (migrações)

# Ver histórico de migrações aplicadas
npx prisma migrate status

# Reverter para uma migração específica (requer Prisma Migrate)
# Atenção: operação destrutiva — faça backup antes
npx prisma migrate resolve --rolled-back NOME_DA_MIGRACAO

Boas práticas: Sempre faça backup do banco antes de aplicar migrações em produção:

mysqldump -u ljvemas_app -p ljvemasearomas > backup_$(date +%Y%m%d_%H%M%S).sql

Monitoramento

HyperDX (APM e logs)

O projeto já inclui @hyperdx/node-opentelemetry via instrumentation.ts. Para ativar:

  1. Crie uma conta em https://www.hyperdx.io
  2. Obtenha sua API Key no painel
  3. Configure no .env:
    HYPERDX_API_KEY="sua-api-key"
    OTEL_SERVICE_NAME="ljvemasearomas-production"
  4. O HyperDX captura automaticamente:
    • Erros não tratados
    • Latência de rotas
    • Queries lentas
    • Logs estruturados

Logs PM2

# Logs em tempo real
pm2 logs ljvemasearomas

# Logs de erro
pm2 logs ljvemasearomas --err

# Limpar logs
pm2 flush ljvemasearomas

Alertas de uptime

Configure um monitor externo para receber alertas se o site ficar fora do ar:


Checklist de go-live

Use esta lista antes de abrir a loja para o público:

Infraestrutura

  • Servidor Node.js 20.x configurado na Hostinger
  • Banco MySQL 8.0 criado e acessível
  • PM2 instalado e configurado para auto-start no boot
  • Diretório de uploads criado com permissões corretas
  • Nginx configurado (proxy reverso + servir uploads)
  • SSL ativado e redirecionamento HTTPS funcionando

Variáveis de ambiente

  • NODE_ENV=production
  • DATABASE_URL apontando para o banco de produção
  • JWT_SECRET gerado com openssl rand -hex 32 (nunca reutilize o de dev)
  • MERCADOPAGO_ACCESS_TOKEN é a chave de produção (não começa com TEST-)
  • NEXT_PUBLIC_MP_PUBLIC_KEY é a chave pública de produção
  • UPLOAD_DIR é um caminho absoluto persistente
  • EMAIL_* configurados e testados com npm run test:smtp
  • STORE_ORIGIN_CEP é o CEP real da loja

Banco de dados

  • npx prisma migrate deploy executado com sucesso
  • Admin criado (via seed ou manualmente)
  • Backup automático configurado no hPanel

Pagamentos

  • Webhook do Mercado Pago apontando para https://ljvelasearomas.com.br/api/webhooks/mercadopago
  • Teste de pagamento realizado com conta real (compra de 1 real)
  • Confirmação de e-mail de pedido recebida

NF-e (se aplicável)

  • Certificado .pfx em /home/USER/certificates/ com permissões 640
  • NFE_API_KEY configurada em ambos os serviços
  • Serviço NF-e em execução e acessível em NFE_SERVICE_URL
  • NF-e de teste emitida com sucesso

Monitoramento

  • HyperDX configurado (ou outra solução de APM)
  • Monitor de uptime ativo (UptimeRobot ou similar)
  • Alertas de e-mail configurados para erros críticos

SEO e performance

  • Domínio com HTTPS sem mixed content
  • Sitemap.xml acessível em /sitemap.xml
  • Robots.txt presente em /robots.txt
  • Lighthouse score ≥ 85 nas páginas principais

Segurança

  • .env não está no repositório Git
  • Senhas de teste (admin123) alteradas
  • Headers de segurança presentes (HSTS configurado em next.config.ts)
  • Rate limiting ativo nas rotas de autenticação