Ambientes e deploy¶
Os ambientes¶
| Ambiente | Aplicação | Documentação | Evolution |
|---|---|---|---|
| Desenvolvimento | kpmentoring.emshome.com.br |
kpdocs.emshome.com.br |
servidor de produção, compartilhado |
| Produção | app.keilladepaula.com.br |
kpdocs.keilladepaula.com.br |
evo.keilladepaula.com.br |
O apex keilladepaula.com.br é um WordPress de terceiro e não faz parte deste sistema.
Dev aponta para o Evolution de produção
Os dois ambientes usam o mesmo servidor Evolution, e o webhook de uma instância tem um destino só. Pedir QR code no dev repointa a instância e deixa a produção surda. Ver Evolution API.
Portas no desenvolvimento¶
Frontend em 3010 e backend em 8010. A porta 3000 é outro aplicativo e responde 404 nas rotas internas.
Fluxo de branches¶
flowchart LR
F[feature] --> D[developer]
D --> M[main]
M -->|timer na VPS| P[produção]
A main deploya sozinha, por timer na VPS. Merge na main é publicar.
Como o deploy roda¶
Não há Docker. A aplicação roda em PHP-FPM com Apache, e o frontend e a fila em PM2.
| Passo | Detalhe |
|---|---|
composer install |
Sem dev, com autoloader otimizado |
| Build do frontend | Antes de derrubar qualquer processo, para que uma falha de build não cause indisponibilidade |
migrate --force |
Só migrations; nunca seed |
| Recarga do PHP-FPM | Obrigatória, porque opcache.validate_timestamps está desligado |
| Restart no PM2 | Frontend e fila |
Permissão nova precisa de migration
O deploy não roda seed. Uma permissão declarada apenas no ProfileSeeder nunca chega à produção. Ver AD-010.
Duas armadilhas de configuração
Ao mexer no .env de produção, rode config:cache de novo, senão a mudança não vale. E NEXT_PUBLIC_API_URL é embutido no bundle: mudá-lo exige rebuild, não restart.
Permissão da mídia¶
O worker da fila grava o anexo do WhatsApp e o PHP-FPM serve. Se os dois não puderem ler o mesmo arquivo, a rota devolve 404, o áudio não toca e o avatar cai nas iniciais, sem erro visível.
Em 12/09/2026 isso era um defeito de produção. O worker herdava o root do daemon do PM2 e os diretórios nasciam root:root 0700, que outro usuário não atravessa.
A correção tem três partes, e nenhuma basta sozinha:
| Parte | Por que é necessária |
|---|---|
uid e gid www-data no bloco da fila no PM2 |
Sem isso o worker é root |
chown -R www-data:www-data storage bootstrap/cache |
Os arquivos já gravados seguiriam ilegíveis |
.env em 0640 root:www-data |
Sem ler o .env, o worker quebra |
pm2 restart não reaplica uid
E o deploy usa restart. Instalar essa mudança numa VPS que já roda exige pm2 delete, pm2 start e pm2 save. A consequência boa é que o deploy também não a desfaz.
O disco local declara permissions para que o diretório nasça 0750 em vez do 0700 padrão do Flysystem. Sem isso o defeito voltaria no próximo diretório criado: cada instância de WhatsApp tem o seu, e um deploy em máquina nova cria a árvore toda.
Banco de testes¶
A suíte usa um banco próprio. Rodá-la sem isolar o banco, enquanto outra sessão roda, produz erros de "relation does not exist" que não têm nada a ver com o código.
Publicar esta documentação¶
cd documentacao
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
mkdocs serve # http://127.0.0.1:8000
mkdocs build # gera ./site
Como a documentação é servida¶
Site estático: o Apache serve a pasta documentacao/site, que é a saída do mkdocs build e não é versionada. Sem build, o domínio responde com erro de diretório vazio.
| Ambiente | Domínio | Estado |
|---|---|---|
| Desenvolvimento | kpdocs.emshome.com.br |
No ar, com certificado válido até 11/12/2026 |
| Produção | kpdocs.keilladepaula.com.br |
DNS criado; vhost ainda não instalado |
O modelo do vhost está em deploy/apache/kpdocs.conf.example. Ele tem só o bloco :80, de propósito: o desafio ACME precisa de HTTP respondendo antes de existir certificado.
# 1. Build, para que o DocumentRoot exista
cd /var/www/kpmentoring/documentacao
python3 -m venv .venv && .venv/bin/pip install -r requirements.txt
.venv/bin/mkdocs build --strict
# 2. Vhost só em :80, e confirmar 200 pelo domínio real
a2ensite kpdocs.conf && systemctl reload apache2
curl -s -o /dev/null -w '%{http_code}\n' http://kpdocs.keilladepaula.com.br/
# 3. Certificado; o certbot escreve o :443 e o redirecionamento sozinho
certbot --apache -d kpdocs.keilladepaula.com.br --redirect
Cloudflare em proxy quebra o desafio HTTP
O desafio ACME precisa alcançar este servidor. Se o registro estiver em modo proxy, desligue o proxy durante a emissão ou use desafio por DNS.
O MkDocs não precisa de rewrite
Ele gera pagina/index.html, então DirectoryIndex resolve as URLs. O ErrorDocument 404 /404.html é o que entrega a página de erro do próprio tema.
Os dois domínios¶
O site_url muda por ambiente, e sem ele o sitemap.xml sai com URLs relativas. São dois arquivos de configuração: o principal aponta para produção, e o de dev herda dele e troca só o que precisa.
mkdocs build # produção, kpdocs.keilladepaula.com.br
mkdocs build -f mkdocs.dev.yml # dev, kpdocs.emshome.com.br
O mkdocs.dev.yml usa a chave INHERIT do MkDocs, então ele tem três linhas e nunca sai de sincronia com a navegação.