# Migração do Rastro → máquina nova (Gitea + Coolify) Guia para mover a produção do Rastro (hoje em Docker Swarm na VPS 136.0.53.6) para a máquina nova, que usa **Coolify** e um **Gitea interno** (git + registro de imagem Docker). **Escopo:** migra a ESTRUTURA (o stack) + só os DADOS DE USUÁRIO/CONFIG. Documentos, passagens, rotas e mídias NÃO vão (já foram limpos; a base voltou a ~1,6 GB). --- ## Realidade do Rastro (importante) Não é uma imagem única. São **2 imagens custom** + **5 de infra públicas**: | Imagem | Origem | Serviços | |---|---|---| | `rastro-node` | build local → **Gitea** | backend, web, admin, campo, ingestor, processor, dfe-worker, migrate | | `rastro-analytics` | build local → **Gitea** | analytics (Python) | | `rastro-alpr` | build local → **Gitea** | alpr (OCR de placas do Rastro Campo) | | `timescale/timescaledb-ha:pg16` | Docker Hub | db | | `rabbitmq:3-management` | Docker Hub | rabbitmq | | `minio/minio:latest` | Docker Hub | minio | | `gotenberg/gotenberg:8` | Docker Hub | gotenberg | | `osrm/osrm-backend:latest` | Docker Hub | osrm (opcional) | Por isso o deploy no Coolify é via **Docker Compose** (`deploy/coolify-compose.yml`), não "1 app = 1 imagem". **Registro — mesmo Gitea, duas rotas:** - **PUSH** (build de fora, ex.: VPS antiga/seu Mac): `gitea.externo.utic.app.br` — o único que resolve fora da rede da UTIC (o `interno` deu timeout). - **PULL** (Coolify, que é interno): `gitea.interno.utic.app.br` — é o hostname que a máquina do Coolify enxerga, e sem credencial (interno). É o que vai nas `image:` do compose. As imagens já estão publicadas (namespace **ericoalmeida**): `…/ericoalmeida/rastro-node:latest` e `…/ericoalmeida/rastro-analytics:latest`. Veja em `https://gitea.externo.utic.app.br/ericoalmeida/-/packages`. (`docker.bretones.app` que o Leo citou é o registro de OUTRO projeto dele — não é o nosso.) --- ## Pré-requisitos (você faz no navegador) 1. **Usuário no Gitea** em https://gitea.externo.utic.app.br (crie ou use o seu). 2. **Token de escrita de pacote:** Settings → Applications → *Generate New Token* com o escopo de **write:package** (registro Docker). Guarde o token. 3. Anote seu **namespace** (o usuário/organização — ex.: `erico`). As imagens vão para `gitea.externo.utic.app.br//rastro-node:latest`. --- ## Fase 1 — Enviar as imagens para o Gitea De uma máquina que **alcança** `gitea.externo.utic.app.br` e tem o repo (a VPS antiga serve — é amd64 e rápida; ou seu Mac). Na raiz do repo: ```bash make login NAMESPACE= # docker login (usuário + token) make deploy NAMESPACE= # build + push das 2 imagens ``` > `make deploy` = build (`--platform linux/amd64`) + push. Se a máquina nova for **arm64**, > rode `make deploy PLATFORM=linux/arm64` (buildando no Mac, que é ARM nativo). Confirme no Gitea (aba Packages do seu usuário) que `rastro-node` e `rastro-analytics` aparecem. --- ## Fase 2 — Subir o stack no Coolify 1. No Coolify: **New Resource → Docker Compose**. 2. Cole o conteúdo de `deploy/coolify-compose.yml`. 3. **Environment variables:** use `deploy/.env.coolify.example` como base. Preencha os segredos/cert/ONE com os valores reais (copie de `/opt/rastro/.env` da VPS antiga — posso transferir por scp). Ajuste `WEB_DOMAIN`/`ADMIN_DOMAIN` para os domínios novos e `REGISTRY`/`NAMESPACE`. 4. **Registro privado:** aponte o Coolify para o Gitea (Sources/Registries) com o mesmo usuário+token, para ele puxar `rastro-node`/`rastro-analytics`. (Se o Gitea for interno à máquina do Coolify, o pull é direto, sem credencial — como o Leo disse.) 5. **Domínios / roteamento (a parte fina):** o front chama a API em **same-origin** (`/api` e `/health` no MESMO domínio). Configure no Coolify: - `web` → `https://${WEB_DOMAIN}` (porta 39000) - `admin`→ `https://${ADMIN_DOMAIN}` (porta 39020) - `campo`→ `https://${CAMPO_DOMAIN}` (porta 39030) — o /api desse domínio já vai ao backend pela label do Traefik - `backend` → responder `${WEB_DOMAIN}/api`, `${WEB_DOMAIN}/health`, `${ADMIN_DOMAIN}/api`, `${ADMIN_DOMAIN}/health` (porta 39010) — roteamento por PATH. Se o roteamento por path do Coolify complicar, a alternativa é dar ao backend um domínio próprio `api.` e **rebuildar** web/admin com `VITE_API_BASE_URL=https://api.` (o CORS já cobre isso via `CORS_ORIGINS`). 6. Deploy. Na 1ª subida, deixe **ingestor** e **dfe-worker** parados (scale 0) — sobem só quando você quiser puxar dados. O `migrate` roda uma vez (cria o schema) e sai. --- ## Fase 3 — Restaurar os dados de usuário O dump está em `data-migration/rastro-userdata.sql` (2,1 MB — usuários, RBAC, 5.922 pórticos, blacklist, thresholds de calibragem, ncm_ref, cursores). Depois que o `migrate` criar o schema, carregue o dump no container do db (ex.: via terminal do Coolify no serviço `db`, ou `docker exec`): ```bash # copie o arquivo para dentro do container do db, então: psql -U rastro -d rastro -v ON_ERROR_STOP=1 <<'SQL' BEGIN; TRUNCATE app_user, role, permission, role_permission, user_role, user_session, equipment, volante_selection, ingestion_cursor, ingestion_control, ncm_ref, intel_threshold, entity_blacklist, blacklist_event, audit_log, access_request_log, process_lock RESTART IDENTITY CASCADE; SQL psql -U rastro -d rastro -f /caminho/rastro-userdata.sql # tem SET session_replication_role p/ FK circular psql -U rastro -d rastro -c "ANALYZE;" ``` > O `TRUNCATE` antes evita conflito com qualquer linha que o schema-init tenha semeado. > O dump já desabilita os triggers de FK (por causa da FK circular do `app_user`). Login: os mesmos usuários da VPS antiga (ex.: ericoengcomp@gmail.com). Se preferir começar com um admin novo, dá pra semear com `pnpm --filter @rastro/db seed` (variáveis `ADMIN_SEED_*`). --- ## Fase 4 — Certificado A1 e OSRM (quando precisar) - **Certificado A1 (.pfx)** — necessário para a drenagem/consultas SEFAZ. Copie o `.pfx` da VPS antiga (`/opt/rastro/certificado/`) para `CERT_HOST_DIR` na máquina nova e confira `DFE_CERT_PFX_CONTAINER_PATH`/`DFE_CERT_PASSPHRASE`. Sem ele, ingestor/dfe-worker não autenticam no fisco (mas o resto do sistema sobe). - **OSRM (rotas no mapa)** — descomente o serviço `osrm` no compose e leve o grafo do Brasil (`brazil.osrm*`, ~12-15 GB) para `OSRM_DATA_DIR`. Sem ele, o roteamento vira no-op (sem linhas no mapa) — aceitável até haver dado transacional de fato. --- ## Verificação - `web`/`admin` abrem e o login funciona (usuário do dump). - Admin lista os **5.922 pórticos** (equipment) e as **permissões/roles**. - `migrate` terminou como *complete/exited 0*; sem erro novo nos logs dos serviços. - Banco: `SELECT count(*) FROM equipment;` → 5922; `FROM app_user;` → seus usuários. ## Rollback A VPS antiga (136.0.53.6) continua intacta (stack fora do ar, volumes de 84→2,3 GB preservados). Nada aqui a toca — se algo falhar na máquina nova, a origem segue disponível.