Pular para conteúdo

0027 — Bump das libs xadm-comum + prefixo de storage s3.* → garage.*

Status: Aprovado · Responsável: Gustavo Madruga · Atualizado em: 2026-08-20 · Decidido em: 2026-08-20

Contexto

Auditoria de defasagem contra o xadm-commons (Forgejo Packages, org xadm): 4 das 5 libs adotadas (0023, 0024, 0025) estavam uma minor atrás. xadm-comum-util já na última (0.1.0).

lib de → para mudança de API
xadm-seguranca 0.3.0 → 0.4.0 aditiva (AuthSettings.getFirebaseJwksUrl)
xadm-comum-web 0.4.0 → 0.5.0 nenhuma (API pública idêntica)
xadm-comum-storage 0.1.0 → 0.2.0 ver abaixo
xadm-comum-teste 0.1.0 → 0.2.0 GarageTestResource.s3Properties() → garageProperties()

O xadm-comum-storage 0.2.0 trouxe duas mudanças que tocam o app:

  1. Interface nova ObjetoStorage (+ impl S3ObjetoStorage): S3ArquivoXlsStorage deixou de receber (S3Client, S3Config) e passou a receber (ObjetoStorage). Refactor interno da lib — DI resolve sozinho (o app não constrói o bean à mão; compileJava do main passou limpo).
  2. Prefixo de config @ConfigurationProperties("s3") → ("garage") no S3Config da lib. O application.yml do app amarrava sob s3:; precisa mover pra garage: ou o binding some (endpoint/credenciais nulos → storage quebra). Os componentes (endpoint, region, accessKey, secretKey, bucket, criarBucket) não mudaram. O modo (app.storage.modo / env S3_FILE_STORAGE) não mudou — o prefixo app.storage foi preservado.

Decisão

Bumpar as 4 libs. Migrar o bloco s3: → garage: no application.yml, mantendo compatibilidade das duas envs (S3_* antigas e GARAGE_* novas) durante a transição no Coolify.

Compatibilidade das duas envs — SEM placeholder aninhado

O reflexo é ${GARAGE_X:${S3_X:default}}. Não funciona no Micronaut: quando o default do placeholder externo contém : (a URL do endpoint, http://…:3900), o resolver quebra o aninhamento — o valor vaza como http://localhost:3900} (URISyntaxException, "Illegal character in authority"). Backtick de escape só cobre um nível; aninhar backtick (`${…`…`}`) também vaza (3900\}`).

Solução adotada — uma env por property, override por prioridade de fonte:

garage:
  endpoint:     ${S3_ENDPOINT:`http://localhost:3900`}
  region:       ${S3_REGION:garage}
  # … demais componentes idem, lendo a env antiga S3_* como default

O YAML lê a antiga S3_* como default; a nova GARAGE_* sobrescreve automaticamente porque a env var vira a property garage.* direto e a fonte de ambiente vence o application.yml no Micronaut. Precedência efetiva GARAGE_* > S3_* > default, verificada com teste discriminante (setar GARAGE_ENDPOINT inválido faz a instanciação do storage falhar citando esse valor — prova que a env chegou na property).

Migração no Coolify (sem downtime)

Cadastrar as GARAGE_* com os mesmos valores das S3_* atuais e só então remover as S3_*:

Novo (cadastrar) Antigo (fallback)
GARAGE_ENDPOINT S3_ENDPOINT
GARAGE_REGION S3_REGION
GARAGE_ACCESS_KEY S3_ACCESS_KEY
GARAGE_SECRET_KEY S3_SECRET_KEY
GARAGE_BUCKET S3_BUCKET
GARAGE_CRIAR_BUCKET S3_CRIAR_BUCKET

S3_FILE_STORAGE (o modo) não muda. Detalhe operacional: operacao/deploy; mapa env→property: projeto/03-object-storage-garage.

Alternativas preteridas

  • Placeholder aninhado ${GARAGE_X:${S3_X:default}} — quebra no Micronaut (colisão do : da URL com o separador de default). Descartada por evidência de teste, não por gosto.
  • Só GARAGE_*, sem fallback — exigiria janela de downtime (renomear todas as envs no Coolify de uma vez). A cadeia de fallback torna a migração sem interrupção.

Consequências

  • Migração de env no Coolify é gradual e reversível; as S3_* seguem válidas até removê-las.
  • Gotcha de stack (vale pra outros apps Micronaut da casa): placeholder aninhado com : no default é furado — preferir uma env por property + override por prioridade de fonte de ambiente.