> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lerian.studio/llms.txt
> Use this file to discover all available pages before exploring further.

# Migrações de banco de dados

> Execute as migrações de schema do Midaz Ledger e Tracer com imagens de runner dedicadas, para que as apps subam contra um banco já migrado.

O Midaz aplica as migrações de schema do PostgreSQL por meio de **imagens de runner dedicadas** — uma para o Ledger, outra para o Tracer — desacopladas dos binários das aplicações. As apps não migram mais no boot: elas sobem contra um schema que já foi migrado pelo runner.

<Note>
  Esse modelo é o que roda com `make up` no desenvolvimento local e com o chart de Helm no Kubernetes. Se você usa `make up`, não precisa fazer nada manual — a stack do Compose bloqueia a app até o runner de migração terminar.
</Note>

## Por que um runner dedicado

***

O migrador in-process anterior rodava a cada boot da app a partir do diretório de trabalho. Sob um pod security context endurecido (`distroless:nonroot`, `runAsUser: 1000`, `readOnlyRootFilesystem: true`, `capabilities: drop [ALL]`), esse caminho falhava com `permission denied` e causava crash-loop no pod.

O runner dedicado elimina isso:

* As migrações rodam **uma única vez, como uma etapa separada**, antes da app subir.
* A imagem da app não empacota mais SQL de migração e nunca escreve no schema.
* A própria imagem do runner roda limpa sob o mesmo security context endurecido (veja [Postura de segurança](#postura-de-segurança)).

## Imagens do runner

***

Duas imagens são publicadas por release:

| Imagem                    | Aplica                                | Bancos                            |
| ------------------------- | ------------------------------------- | --------------------------------- |
| `midaz-ledger-migrations` | Migrações de onboarding + transaction | Dois: `onboarding`, `transaction` |
| `midaz-tracer-migrations` | Schema do Tracer                      | Um                                |

As duas imagens compartilham o mesmo formato:

* Base: [`migrate/migrate`](https://github.com/golang-migrate/migrate) `v4.19.1` (pinado).
* Roda como `USER 65532:65532` — não-root, agnóstica ao UID.
* Entrypoint POSIX shell que monta um DSN a partir de variáveis de ambiente, executa `migrate ... up` e sai.
* Não escreve nada em disco — o progresso é rastreado na tabela `schema_migrations` do Postgres, então `readOnlyRootFilesystem: true` é seguro.

O runner do Ledger aplica **onboarding primeiro, depois transaction**, em uma única invocação. O runner do Tracer aplica seu banco único em uma passada.

## Contrato de ambiente

***

Cada entrypoint aceita um override de URL pronto ou as variáveis `DB_*` individuais. **O override de URL tem prioridade quando definido.**

### Runner do Ledger

| Banco       | Override de URL            | Montado a partir de                                                                                                                                                            |
| ----------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| onboarding  | `ONBOARDING_DATABASE_URL`  | `DB_ONBOARDING_HOST`, `DB_ONBOARDING_PORT` (default `5432`), `DB_ONBOARDING_USER`, `DB_ONBOARDING_PASSWORD`, `DB_ONBOARDING_NAME`, `DB_ONBOARDING_SSLMODE` (default `disable`) |
| transaction | `TRANSACTION_DATABASE_URL` | `DB_TRANSACTION_*` (mesmo formato)                                                                                                                                             |

### Runner do Tracer

| Override de URL | Montado a partir de                                                                                           |
| --------------- | ------------------------------------------------------------------------------------------------------------- |
| `DATABASE_URL`  | `DB_HOST`, `DB_PORT` (default `5432`), `DB_USER`, `DB_PASSWORD`, `DB_NAME`, `DB_SSL_MODE` (default `disable`) |

### Formato do DSN

Quando o entrypoint monta o DSN a partir das variáveis `DB_*`, ele produz:

```text theme={null}
postgres://<user>:<encoded-password>@<host>:<port>/<name>?sslmode=<sslmode>
```

A senha é codificada em percent-encoding para que caracteres reservados de URI (`% @ : / ? # & + space [ ]`) não quebrem o DSN. `%` é codificado primeiro para que escapes já inseridos não sejam duplo-codificados.

O entrypoint só registra marcadores de fase (`applying onboarding migrations`, `applying transaction migrations`, `applying tracer migrations`, `migrations complete`). Ele nunca imprime credenciais nem o DSN montado.

## Desenvolvimento local

***

### `make up`

Na raiz do repositório, `make up`:

1. Sobe a infra e aguarda até o Postgres ficar healthy.
2. Executa os serviços one-shot `ledger-migrate` e `tracer-migrate` no Compose.
3. Sobe cada app, que declara `depends_on` do seu serviço de migração com `condition: service_completed_successfully`.

A app nunca sobe contra um banco não migrado.

### Targets `make` no host

Se você quiser rodar migrações direto contra um banco local — por exemplo enquanto desenvolve uma migração nova — cada componente expõe targets Make que usam o CLI pinado do `golang-migrate` e leem as configurações de conexão de `.env`.

Ledger (`components/ledger`):

| Target                     | Efeito                                            |
| -------------------------- | ------------------------------------------------- |
| `make migrate`             | Aplica onboarding e depois transaction (agregado) |
| `make migrate-onboarding`  | Aplica apenas onboarding                          |
| `make migrate-transaction` | Aplica apenas transaction                         |
| `make migrate-down`        | Reverte os dois bancos                            |

Tracer (`components/tracer`):

| Target                 | Efeito                                                    |
| ---------------------- | --------------------------------------------------------- |
| `make migrate`         | Aplica o schema do tracer                                 |
| `make migrate-down`    | Reverte o schema do tracer                                |
| `make migrate-version` | Imprime a versão atual do schema                          |
| `make migrate-force`   | Força a versão do schema (recuperação de um estado dirty) |

### Exemplo: rodar o runner do Ledger manualmente

Você raramente precisa invocar a imagem do runner manualmente — a gate do Compose faz isso por você. Quando precisar, aponte o runner para seus bancos com `DB_*` (ou `*_DATABASE_URL`) e execute uma vez:

```bash theme={null}
docker run --rm \
  --network=infra-network \
  -e DB_ONBOARDING_HOST=postgres \
  -e DB_ONBOARDING_PORT=5432 \
  -e DB_ONBOARDING_USER=midaz \
  -e DB_ONBOARDING_PASSWORD='s3cret!' \
  -e DB_ONBOARDING_NAME=onboarding \
  -e DB_ONBOARDING_SSLMODE=disable \
  -e DB_TRANSACTION_HOST=postgres \
  -e DB_TRANSACTION_PORT=5432 \
  -e DB_TRANSACTION_USER=midaz \
  -e DB_TRANSACTION_PASSWORD='s3cret!' \
  -e DB_TRANSACTION_NAME=transaction \
  -e DB_TRANSACTION_SSLMODE=disable \
  lerianstudio/midaz-ledger-migrations:<tag>
```

O runner sai com `0` em caso de sucesso (incluindo o caso idempotente de no-op) e com não-zero em caso de falha.

## Deploy no Kubernetes

***

Em produção, execute cada runner de migração como um **Job** do Kubernetes (tipicamente um PreSync Job do Argo CD ou um hook do Helm) que termine **antes** do rollout da app. O chart de Helm já conecta isso para você; as seções a seguir cobrem propriedades que você deve manter em mente se escrever seus próprios manifests.

<Note>
  Para deploys multi-tenant, o runner é intencionalmente **agnóstico ao tenant**: ele migra os bancos apontados pelo seu ambiente, uma vez. O fan-out por tenant é responsabilidade do deploy — rode o Job uma vez por banco de tenant, passando os valores `DB_*` (ou o override de URL) correspondentes.
</Note>

### Postura de segurança

O runner foi desenhado para um pod security context endurecido:

* **Não-root** — a imagem fixa `USER 65532:65532`.
* **Agnóstica ao UID** — os arquivos de migração pertencem a root e são de leitura pública, então qualquer UID pode lê-los.
* **Compatível com `readOnlyRootFilesystem`** — `migrate` não escreve estado no filesystem.

A mesma imagem roda limpa sob `runAsNonRoot: true`, `readOnlyRootFilesystem: true` e `capabilities: drop [ALL]`.

### TLS

Os entrypoints honram o `sslmode` do ambiente (`DB_ONBOARDING_SSLMODE`, `DB_TRANSACTION_SSLMODE` ou `DB_SSL_MODE`), com default `disable`. **Deploys de produção devem configurar `require`** (ou mais estrito). O runner shell não reproduz o enforcement de TLS em código, a classificação de erros nem a telemetria que as apps usam para as próprias conexões — o TLS das migrações é controlado inteiramente via `sslmode`, em troca de um runner mínimo e sem dependências.

## Convenções e idempotência

***

* **Pares up/down** — toda migração tem um arquivo `.up.sql` e um `.down.sql`.
* **Idempotente** — rodar `migrate up` quando o schema já está na versão mais recente é no-op. Re-executar o runner após um apply parcial ou completo é seguro.
* **CLI pinado** — as imagens do runner e os targets Make no host pinam `golang-migrate` `v4.19.1`.

## Atualização a partir de versões anteriores

***

Se você vinha de uma release do Midaz em que a app migrava no boot, nenhuma migração manual de dados é necessária — o schema em disco é o mesmo. Para adotar o novo modelo:

1. Traga a release que inclui as imagens do runner.
2. No Kubernetes, adicione os Jobs `midaz-ledger-migrations` e `midaz-tracer-migrations` ao seu pipeline de deploy para rodarem antes do rollout da app. Se você usa o chart oficial de Helm, isso já é feito para você.
3. No desenvolvimento local, `make up` continua funcionando igual — a stack do Compose agora bloqueia as apps nos novos serviços one-shot de migração automaticamente.

## Páginas relacionadas

***

* [Instalando o Midaz](/pt/midaz/midaz-setup) — configuração local completa com `make up`.
* [Atualizando o Midaz](/pt/midaz/updating-midaz) — fluxos de atualização para local e Helm.
* [Estratégias de deployment](/pt/midaz/deployment) — visão geral do deployment BYOC.
* [Variáveis de ambiente do Tracer](/pt/tracer/tracer-environment-variables) — referência completa de configuração do Tracer.
