diff --git a/README.md b/README.md
index 9036554..b006dd7 100644
--- a/README.md
+++ b/README.md
@@ -3072,118 +3072,291 @@ caminho do servidor e o trace inteiro — para **qualquer pessoa** que provocass
---
-🕐 Relógio, restart automático e migrations no boot
+🛠️ 27/08/2026 — Deploy: relógio, arquivos órfãos e tudo que caiu junto
-## O problema relatado
+Um relato só, porque foi **uma corrente**: um problema descoberto expunha o
+seguinte. Vale mais como mapa de diagnóstico do que como changelog.
-> "toda vez que faço o deploy ou reinicio o Docker a data e hora ficam erradas."
-
-São **dois problemas diferentes** que se confundem porque aparecem no mesmo lugar:
-
-| Sintoma | Causa | Onde se resolve |
+| Sintoma na tela | Causa real | Onde se resolveu |
|---|---|---|
-| Hora **sempre 3h adiantada**, todo restart | O container subia em **UTC** | `Dockerfile` (fuso) |
-| Hora **derivando / errada depois de reboot** | Relógio do **host** sem sincronia | `deploy/ntp-seguro.sh` (NTS) |
+| Hora sempre 3h adiantada | Container subia em **UTC** | `Dockerfile` (TZ + `/etc/localtime`) |
+| Hora errada depois de reboot | Relógio do **host** sem sincronia | `deploy/ntp-seguro.sh` (chrony + NTS) |
+| `env file .env not found` | `.env` não é versionado e a pasta foi recriada | recriar no servidor + backup fora da árvore |
+| `Couldn't find Active Storage configuration` | `config/storage.yml` nunca esteve no git | arquivo versionado |
+| `port is already allocated` | Porta 3001 vivia como alteração **local** no compose | `${PORTA_APP:-3001}` |
+| `Blocked hosts: 100.75.222.23:3001` | `config.hosts` ligado só com o domínio | `HOSTS_PERMITIDOS` |
+| `Translation missing … devise.failure` | `fallbacks = true` caía no próprio pt-BR | `fallbacks = [:en]` + traduções |
+| 422 "recusada por verificação de segurança" | `assume_ssl` fixo x acesso por IP em HTTP | gate do `FORCE_SSL` |
+| `URI::InvalidURIError: … SEU_IP` | `DATABASE_URL` com o valor de exemplo | falha rápida no boot |
-### 1. Fuso do container (o "sempre 3h à frente")
+## 1. Relógio: fuso é do container, hora é do host
-A imagem `ruby:3.2.2-slim` sobe em UTC. O Rails até mostrava a hora certa
-(`config.time_zone = "America/Sao_Paulo"`), mas **tudo que era do sistema
-operacional continuava adiantado** — e o pior caso não era visual:
+A imagem `ruby:3.2.2-slim` sobe em UTC. O Rails mostrava a hora certa
+(`config.time_zone`), mas **tudo do sistema operacional** ficava adiantado — e o
+pior caso não era visual:
-> **O cron rodava no horário errado.** `every "*/30 8-18"` no `config/schedule.rb`
-> executava das **05h às 15h** de Brasília, não das 08h às 18h.
+> **O cron rodava no horário errado.** `every "*/30 8-18"` executava das **05h às
+> 15h** de Brasília.
-Agora o `Dockerfile` fixa `TZ=America/Sao_Paulo` **e** o symlink de
-`/etc/localtime` — os dois, porque o cron do Debian lê o arquivo, não a
-variável. O mesmo foi feito no `whatsapp/Dockerfile` (Alpine precisa do pacote
-`tzdata`, que não vem na imagem). Dá para ajustar sem rebuild pelo `TZ` do `.env`.
+O `Dockerfile` agora fixa `TZ=America/Sao_Paulo` **e** o symlink de
+`/etc/localtime` — os dois, porque o cron do Debian lê o arquivo, não a variável.
+Mesmo tratamento no `whatsapp/Dockerfile` (Alpine precisa do pacote `tzdata`).
-### 2. Hora do host — NTP autenticado (NTS)
-
-**Não dá para sincronizar o relógio de dentro do container**: ele lê o clock do
-kernel do host. Rodar NTP lá dentro exigiria `CAP_SYS_TIME` e mudaria a hora do
-servidor inteiro a partir de um processo da aplicação.
-
-No servidor, uma vez:
+**A hora em si não dá para sincronizar de dentro do container**: ele lê o clock do
+kernel do host, e rodar NTP lá dentro exigiria `CAP_SYS_TIME`. Por isso
+`deploy/ntp-seguro.sh`, que roda **uma vez no servidor** e instala **chrony com
+NTS** (RFC 8915): troca de chaves por TLS (TCP 4460) e pacotes NTP assinados.
+NTP comum é UDP sem autenticação, e hora errada aqui muda **o dia da
+consolidação, o recorte do período financeiro e a validade da sessão**. O script
+usa 3 fontes independentes, **desliga as não autenticadas** (deixar o `pool`
+padrão anularia o ganho), desativa o `systemd-timesyncd` e liga o `rtcsync`.
```bash
sudo bash deploy/ntp-seguro.sh
+chronyc tracking # 'System time' na casa dos milissegundos
+chronyc -N authdata # NTS ativo em cada fonte
```
-O script instala e configura o **chrony com NTS** (RFC 8915): a troca de chaves
-é por TLS (TCP 4460) e os pacotes NTP vêm assinados, então uma resposta forjada
-no caminho é descartada. NTP comum é UDP sem autenticação — e hora errada aqui
-não é detalhe: ela muda **o dia da consolidação, o recorte do período financeiro
-e a validade da sessão**.
+## 2. Restart automático e migrations
-O script ainda: usa **3 fontes independentes** (Cloudflare, Netnod, PTB),
-**desliga as fontes não autenticadas** (deixar o `pool` padrão anularia o ganho),
-desativa o `systemd-timesyncd` (não fala NTS e brigaria pelo relógio), liga o
-`rtcsync` (é o relógio de hardware que dá a hora no boot) e mostra a
-conferência no fim. É idempotente e guarda `.bak` da config.
+`restart: unless-stopped` no serviço `app`. Escolhido em vez de `always` porque
+`always` reergue o container até depois de um `stop` deliberado, tirando do
+operador a chance de deixar o sistema fora do ar de propósito.
-Conferir depois, a qualquer momento:
+O boot saiu do `command:` de uma linha e virou **`bin/docker-boot`**:
-```bash
-chronyc tracking # 'System time' deve ficar na casa dos milissegundos
-chronyc -N authdata # NTS ativo em cada fonte (Cook > 0)
+1. **relógio** — imprime hora e fuso (se aparecer UTC, o rebuild não pegou);
+2. **pid órfão**; 3. **gems** (o volume `bundle_cache` sombreia os da imagem);
+4. **migrations** — `db:prepare`, com **espera pelo banco**;
+5. **cron** (best-effort); 6. **Puma**.
+
+A migration é automática a todo restart. A espera do passo 4 existe porque o
+PostgreSQL é externo ao compose: num reboot o Rails pode subir antes de o banco
+aceitar conexão e, com `unless-stopped`, isso viraria **loop de reinício**
+parecendo erro de migration.
+
+**Falha rápida:** `DATABASE_URL` vazia ou com o valor de exemplo não é "banco fora
+do ar" — nenhuma espera resolve. O boot para na primeira tentativa dizendo o que
+preencher, **com a credencial mascarada no log**. Este projeto **não tem
+`config/database.yml`**: a conexão inteira sai dessa variável, e ninguém lê
+`DB_HOST`/`DB_NAME`/`DB_USER`/`DB_PASSWORD`.
+
+## 3. Arquivos que o git não levava — e por isso sumiram juntos
+
+A pasta do deploy foi recriada e levou embora todo arquivo **não versionado**. Dois
+apareceram:
+
+- **`.env`** — está no `.gitignore` por conter senha, e assim deve continuar.
+ Guarde uma cópia fora da árvore do projeto e prefira `git pull`/`reset --hard`
+ na própria pasta a recriá-la (arquivo ignorado sobrevive ao pull).
+- **`config/storage.yml`** — não tinha motivo para estar de fora. O app faz
+ `require "rails/all"`, então o Active Storage sempre carrega e os
+ `config/environments/*.rb` definem `active_storage.service = :local`: com um
+ serviço definido, o Rails **exige** o arquivo no `initialize!` e o servidor não
+ sobe. **Agora é versionado.**
+
+## 4. Configuração do ambiente saiu do `.env` e entrou no compose
+
+A porta do teste (**3001**, porque a 3000 está ocupada por outro stack) vivia como
+alteração **local** no `docker-compose.yml` do servidor — e um `git reset --hard`
+a levou junto, derrubando o ambiente com o proxy apontando para uma porta sem
+ninguém escutando. Agora os valores **não secretos** têm padrão no compose:
+
+```yaml
+ports:
+ - "${PORTA_APP:-3001}:3000"
+environment:
+ TZ: ${TZ:-America/Sao_Paulo}
+ APP_HOST: ${APP_HOST:-teste.reemtransportes.com.br}
+ APP_NAME: "${APP_NAME:-Reem Logística}"
+ WHATSAPP_URL: ${WHATSAPP_URL:-http://whatsapp:3001}
+ HOSTS_PERMITIDOS: ${HOSTS_PERMITIDOS:-100.75.222.23}
```
-> **Firewall:** precisa de saída em **UDP 123** e **TCP 4460**. Sem a 4460 o NTS
-> não fecha e o chrony fica sem fonte.
+`${VAR:-padrão}`: **o `.env` continua mandando**; o padrão só entra quando a
+variável falta. Segredos (`DB_*`, `SECRET_KEY_BASE`, `SIMPLIROUTE_TOKEN`,
+`WHATSAPP_TOKEN`, `SMTP_*`, `NOTIFICACAO_SECRET`) **nunca** vão para o yaml.
-## Restart automático + migrations
+> ⚠️ **`APP_HOST` é só o host, sem `https://`.** O código monta os links como
+> `"https://#{APP_HOST}/motorista"` (`consolidacao_mailer.rb`,
+> `notificacao_service.rb`, `gatilhos.rb`): com o esquema no valor sai
+> `https://https://…` e todo link de e-mail e WhatsApp quebra.
-`docker-compose.yml`, serviço `app`: **`restart: unless-stopped`**. Sobe sozinho
-depois de queda do processo e de reboot do servidor, e só fica parado se alguém
-der `docker compose stop/down`. (`always` foi descartado: ele reergue o container
-até depois de um `stop` deliberado, tirando do operador a chance de deixar o
-sistema fora do ar de propósito.)
+## 5. Produção de verdade: o que só aparece fora do modo development
-O boot saiu do `command:` de uma linha só e virou **`bin/docker-boot`**, com o
-motivo de cada passo comentado:
+O servidor passou a rodar `RAILS_ENV=production`, e três coisas apareceram:
-1. **relógio** — imprime a hora e o fuso no log (se aparecer UTC, o rebuild não pegou);
-2. **pid órfão** — sem limpar, o Puma se recusa a subir depois de uma queda;
-3. **gems** — `bundle check || bundle install` (o volume `bundle_cache` sombreia os gems da imagem);
-4. **migrations** — `db:prepare`, **com espera pelo banco**;
-5. **cron** — `whenever --update-crontab` + daemon, *best-effort*;
-6. **Puma**.
+- **`config.hosts`** — a linha que parecia só liberar o `APP_HOST` na verdade
+ **liga** a verificação e recusa todo o resto. Agora entram também
+ `localhost`/`127.0.0.1` (para o `curl` de dentro do NAS servir de diagnóstico) e
+ a lista `HOSTS_PERMITIDOS`.
+- **`i18n.fallbacks = true`** significa "caia no `default_locale`" — que aqui é o
+ próprio pt-BR. O fallback apontava para si mesmo e chave ausente virava
+ `Translation missing` **na tela do usuário** (tela de login). Agora `[:en]`,
+ igual ao `application.rb`, e o `pt-BR.yml` ganhou as traduções do Devise
+ (`failure`, `sessions`, `passwords`) — o projeto não usa `devise-i18n`.
+- **`assume_ssl`** estava fixo, então `request.base_url` virava `https://` e o
+ `Origin: http://` de quem abre pelo IP não batia: **todo POST voltava 422**
+ ("recusada por uma verificação de segurança") enquanto os GETs passavam e a tela
+ parecia normal. Foi o que quebrou a importação do plano. Um gate `FORCE_SSL=false`
+ devolve o acesso por HTTP para diagnóstico; sem a variável, HTTPS continua
+ obrigatório.
-Ou seja: **a migration é automática a todo restart** — `db:prepare` cria o banco
-se não existir, aplica as migrations pendentes e só faz seed em banco novo
-(idempotente). Não há passo manual depois do deploy.
+> **Proxy reverso:** o destino tem que ser **HTTP** na porta do container. Com
+> `https://` o Puma responde
+> `Are you trying to open an SSL connection to a non-SSL Puma?`.
-> **Por que a espera no passo 4:** o PostgreSQL é externo ao compose. Num reboot
-> do servidor o Rails pode subir antes de o banco aceitar conexão — e agora, com
-> `restart: unless-stopped`, isso viraria um **loop de reinício** parecendo erro
-> de migration. São 10 tentativas × 6s. Se falhar depois disso (migration
-> quebrada, credencial errada), o container sai com erro **de propósito**: melhor
-> do que servir a aplicação contra um schema desatualizado.
+## 6. `db/schema.rb` entrou no `.gitignore`
-## Deploy
+Nunca foi versionado (o schema vive nas migrations). Como o compose monta
+`.:/app`, o `db:prepare` do boot escreve o arquivo **no host** — e um `git add .`
+no meio de um rebase o capturou e virou conflito de deploy. Em
+`RAILS_ENV=production` ele nem seria gerado (`dump_schema_after_migration = false`).
+
+> **Deploy é `git fetch` + `git reset --hard origin/`**, não `pull --rebase`:
+> o container reescreve `Gemfile.lock` e `db/schema.rb` no host, então o checkout
+> produz alteração local sozinho e todo rebase bate de frente com ela.
+
+## ▶️ Deploy
```bash
-# 1. No servidor, uma única vez — relógio com NTP autenticado:
-sudo bash deploy/ntp-seguro.sh
-
-# 2. Rebuild obrigatório (o fuso entra na imagem):
-docker compose up -d --build
-
-# 3. Conferir no log que o container está em -03 e não em UTC:
-docker compose logs app | grep '\[boot\] relógio'
+sudo bash deploy/ntp-seguro.sh # 1x no servidor
+git fetch origin && git reset --hard origin/teste
+docker compose up -d --build # --build: o fuso entra na imagem
+docker compose logs app | grep '\[boot\]'
+curl -I http://127.0.0.1:3001/ # separa "app caiu" de "proxy errado"
```
## 📂 Arquivos
```
-Dockerfile # TZ=America/Sao_Paulo + tzdata + /etc/localtime; CMD -> bin/docker-boot
-whatsapp/Dockerfile # tzdata (Alpine) + mesmo fuso
-docker-compose.yml # restart: unless-stopped, TZ, command: bin/docker-boot
-bin/docker-boot # boot documentado: migrations com espera, cron, Puma — NOVO
-deploy/ntp-seguro.sh # chrony + NTS no host (rodar 1x, como root) — NOVO
-.env.example # TZ=America/Sao_Paulo + aviso "fuso ≠ hora"
+Dockerfile / whatsapp/Dockerfile # TZ + tzdata + /etc/localtime
+docker-compose.yml # restart, PORTA_APP, APP_HOST/NAME, TZ, HOSTS_PERMITIDOS
+bin/docker-boot # boot documentado: espera do banco, cron, Puma — NOVO
+deploy/ntp-seguro.sh # chrony + NTS no host (1x, root) — NOVO
+config/storage.yml # versionado — NOVO
+config/environments/production.rb # hosts, i18n fallbacks, gate do FORCE_SSL
+config/locales/pt-BR.yml # traduções do Devise
+.gitignore # db/schema.rb
+.env.example # TZ, PORTA_APP, HOSTS_PERMITIDOS, APP_HOST sem esquema
+```
+
+
+
+---
+
+
+🚚 Romaneio — a tela recuperou as funções do programa antigo
+
+Referência: o **Romaneiro PDF (GADE Hospitalar)**, o programa em Python que a
+operação usava. O PDF já estava fechado; o que faltava era a **tela**.
+
+## Veículos: lista visível, não um `