Pular para conteúdo

Changelog

Todas as mudanças relevantes deste projeto são registradas aqui.

O formato segue Keep a Changelog e o projeto adota Versionamento Semântico.

0.10.2 - 2026-10-01

Alterado

  • xadm-comum-web 0.10.0 → 0.10.2. O 404 de rota inexistente com Authorization: Basic (scanner de Elasticsearch/Kibana) deixa de abrir issue em ERROR no GlitchTip (issue 1360); só o esquema Bearer conta como credencial na regra do 404 autenticado.
  • Norma X-Adm 2.1.0 e kit 2.0.8. Adota o ADR central 0039 (chamada de app para app pela URL pública, com o xadm-dns do host): o recurso no Coolify leva --dns 10.0.1.1 --dns 1.1.1.1, já aplicado em produção, registrado em docs/decisoes/0035-adota-app-a-app-url-publica-dns-local.md e no runbook de deploy. O pipeline.yml passa a pôr timeout em todo curl, a rodar o gate quando o próprio workflow muda e a reprovar proxy_pass com host literal.

Migração

  • Nada a fazer.

0.10.1 - 2026-09-22

Alterado

  • Uma identidade por app (ADR central 0038). O app_id do docs/app.json passa a ser o próprio slug (central-backend) e o nome de exibição deriva dele. O app_id do POST /api/ci/deploy fica declarado no OpenAPI como o registry_slug que já era na resolução, com o motivo de não validar contra a tabela apps: as stacks compose (PowerSync) ancoram por esse campo e não têm linha no catálogo, então a validação quebraria o único caminho que o usa.
  • Kit X-Adm 2.0.0 → 2.0.1. A skill /xadm-setup foi re-derivada — o POST /api/setup/provision passa a levar o bloco de identidade inteiro do app.json (slug, descricao, stack, toolchain além dos obrigatórios), porque a tabela apps é espelho do app.json e só essa chamada a escreve. Saíram as references de stack Flutter que o kit antigo copiava para todo repo.

Corrigido

  • Upsert do catálogo de apps vira merge. Um /api/setup/provision sem stack, slug ou descricao zerava o valor que um setup anterior tinha gravado — foi o que esvaziou a stack de três apps do catálogo e deixou um sem slug. Campo ausente (ou string em branco) agora preserva o que está lá; nome, grupo e cliente_id seguem obrigatórios pelas guardas, então app novo continua não entrando incompleto.

0.10.0 - 2026-09-16

Adicionado

  • POST /api/auth/refresh (decisão local 0034): troca um JWT de app-user vigente por um novo com o status e o papel atuais, sem a senha. Troca de papel e inativação chegam ao app sem logout. Antes, a sessão pAbast perdia a senha no F5 e o papel ficava congelado até o JWT vencer (24 h). Os tokens de app-user ganham sub_type e auth_time. O teto de sessão AUTH_SESSION_MAX_HOURS (default e máximo 168 h, ADR central 0037) recusa o refresh e corta o exp. Os code de 403 (not_app_user, access_revoked, session_expired, cliente_inactive, auth_method_not_allowed) são contrato com o app.
  • scripts/coolify/limpeza.py: a limpeza das envs sem leitor no Coolify, com gate pelo release servido e git grep da chave antes de apagar, passa a ser versionada no repo dono do CoolifyClient. Roda em dry-run por padrão; o runbook é o docs/operacao/limpeza-envs-coolify.md.

Alterado

  • O reconcile lê int-jar.<cli>.xadm.biz como a instância <cli>. Na troca para native do app multi-instância, o native fica com int.<cli> e o jar vai para int-jar.<cli>. Sem isso, o jar de cada cliente entrava no mapa sem instância, na mesma linha (slug, jar), e um recurso sobrescrevia o outro.
  • Monitor de host: /system/df?type=build-cache. Sem o type, o daemon calcula também imagens, containers e volumes a cada chamada — percorre os volumes do host inteiro, I/O pesado na VM que o monitor observa, e o timeout de 3 s estoura. Pré-requisito para ligar o docker-socket-proxy (allowlist de 3 rotas GET).
  • Deploy só native (ADR central 0033, decisão local 0030). O build.targets do docs/app.json é só native, e o pipeline.yml perdeu o job build_jar e o step de deploy jar. O recurso central-backend-jar-pull fica sem imagem nova: medido em 2026-09-11, o domínio principal já servia 100% native. O rollback é o redeploy da tag imutável <sha>-native.
  • Constituição X-Adm 1.5.0 → 2.0.0, kit 2.0.0.
  • O docs/app.json ganha perfil e kit e perde native e deploy; o projeto do GlitchTip passa para features.glitchtip.project.
  • Foram re-derivados o pipeline, os Dockerfiles, o mkdocs.yml, as skills e o hook, e o bloco de regras do CLAUDE.md troca a linha §6: pela de Feedback:.
  • O deploy passa a exigir gate verde e, em tag, o release-check.
  • O aviso de publicação de docs deriva a URL do CENTRAL_DEPLOY_URL.
  • Entra a página docs/dev/como-rodar.md.
  • xadm-comum-web 0.9.1 → 0.10.0 e xadm-comum-teste 0.3.0 → 0.4.0 (ADR central 0034, decisão local 0031). O DSN do GlitchTip vem só do SENTRY_DSN, e sai o fallback GLITCHTIP_DSN do logback.xml.
  • Locale pt-BR no native (-H:IncludeLocales=pt-BR): no binário, o alerta de silêncio formatava "1.5h" em vez de "1,5h".
  • mavenLocal() no build, depois do registro e só para br.com.xadm (libs, Consumir): a versão da casa ainda não publicada sai do ~/.m2 para testar o app contra a lib; a publicada sempre vem do registro, e a /xadm-release recusa dependência da casa que não está nele.
  • Só o shadowJar produz o build/libs/app.jar: o jar base deixou de usar o mesmo nome.
  • Postgres de teste singleton (xadm-comum-teste 0.4.0). Um container com dados em tmpfs serve a suíte inteira, e o Flyway migra uma vez. Os 26 testes de integração estendem o IntegracaoComPostgres da lib, que esvazia as tabelas antes de cada teste. Sai o jdbc:tc: do application-test.yml, que recriava o banco a cada classe, e com ele o override TEST_DB_URL. A task test caiu de 148 s para 91 s.
  • Travas de teste: 2 min por teste, 15 min para a task test e 5 s para obter conexão. Teste pendurado vira falha em vez de segurar o CI.
  • Services por feature e fronteiras travadas. Sete controllers injetavam repository e tinham regra de negócio inline; a regra passou para services da feature, e os controllers só fazem HTTP e mapeamento. O ArchitectureTest agora trava controller → repository e dependência de controller (regras da RegrasArquitetura da lib) e config/infra na entidade (regra local). Contratos e códigos de erro ficam iguais.
  • Fatias do ArchitectureTest com o nome completo (br.com.xadm.integracao.central.admin.., não ..admin..): a forma curta casaria também um pacote homônimo da lib da casa. A guarda foi provada quebrando de propósito as regras de base, de ciclo e de entidade.
  • POST /test/glitchtip exige xadm_admin (decisão local 0032): sem token responde 401, sem o papel responde 403. O GET /test segue público e mostra o curl com Bearer.
  • Pool do Hikari nas chaves certas. O maximum-pool-size: 5 estava num bloco hikari: aninhado, que o Micronaut ignora — o pool de produção rodava no default de 10. Agora vale maximum-pool-size: 5 com minimum-idle: 2, como a norma pede para um Postgres dividido entre os apps.
  • Job de silêncio com atraso e intervalo por property (CENTRAL_SILENCIO_ATRASO_INICIAL, CENTRAL_SILENCIO_INTERVALO; default 20 min e 15 min, como antes). Só o e2e native encurta, para ver o alerta sair e afirmar o locale pt-BR no binário.
  • Status de acesso pAbast não grava para usuário inexistente: o POST .../status do admin procura o usuário antes de atualizar o acesso; antes gravava e respondia 404.
  • Dois tokens de serviço, um por escopo de rota (decisão local 0033): a separação entre o CENTRAL_API_TOKEN e o shared secret do integrador fica registrada como exceção à regra de um token por app chamado.

Corrigido

  • Docs do rollback e do monitor no estado atual. O runbook de deploy e a decisão 0027 davam a reversão do smoke como automática; o control-plane recusa a tag imutável (400 invalid_image), então a reversão é manual até ele aceitá-la. A decisão 0019 e o runbook do monitor trocam o "mount read-only" pela pré-condição não-root: o Directory Mount do Coolify é bind rw.

Migração

  • Antes do deploy: confira que o recurso central-backend-native-pull no Coolify tem SENTRY_DSN. Se tiver só o GLITCHTIP_DSN, renomeie: sem isso o erro de produção deixa de chegar ao GlitchTip, e a camada do smoke que procura exceção nova passa sem ver nada.
  • Depois do deploy: a variável de repo CENTRAL_DOCS_URL no GitHub deixa de ser lida e pode ser apagada; o recurso central-backend-jar-pull pode ser desligado no Coolify.

0.9.1 - 2026-09-11

Alterado

  • xadm-comum-web 0.9.0 → 0.9.1: a lib passa a embarcar a hint native do SentryAppender (reflect-config com as três entradas: appender, SentryOptions e Level.valueOf). A cópia local registrava só o appender e, no binário native, o <options> do logback.xml era ignorado em silêncio — o evento chegava ao GlitchTip sem environment. A cópia local saiu no mesmo commit (§Migração da lib). De carona, o 404 de negócio (rota que casou) volta a DEBUG; o 404 de rota não casada em request autenticado segue em ERROR.
  • Controllers fora do event loop (micronaut.server.thread-selection: AUTO, default da casa): o default do Micronaut 5 é MANUAL, e sem @ExecuteOn todo método imperativo — JDBC e as chamadas HTTP bloqueantes ao Coolify, Garage, GlitchTip, Metabase e Resend — rodava no event loop do Netty.
  • Beans opcionais por @Requires(pattern = ".+") (Resend, SMTP de teste, validador Firebase): a forma que reprova a property ausente e a vazia; o notEquals = "" só barrava a vazia.
  • Postgres de dev (docker-compose.dev.yml) monta o volume em /var/lib/postgresql, o layout do Postgres 18 (no caminho antigo o volume nomeado ficava vazio e o dado ia para um volume anônimo), e espera com pg_isready -h 127.0.0.1, que não responde "pronto" no servidor temporário do initdb.
  • Constituição X-Adm 1.4.8 → 1.5.0: guardas do pipeline.yml re-derivadas — a defesa anti-vácuo do ArchUnit passa a reconhecer RegrasArquitetura.importNaoVazio(), que o ArchitectureTest usa e que dava aviso eterno; a guarda JTE roda no Windows; entra a guarda de destino de proxy do nginx (aqui se pula) — e as skills /xadm-docs e /x-documentar re-sincronizadas.

0.9.0 - 2026-09-10

Adicionado

  • Heartbeat do integrador-client, com alerta de silêncio por horas úteis: o integrador-client roda on-premise, um por cliente, e quando parava ninguém via — o sintoma chegava dias depois como "a integração parou". O central passa a receber o heartbeat que o integrador-server de cada cliente repassa (POST /api/integrador/heartbeat, token próprio CENTRAL_API_TOKEN), guarda o estado atual por cliente (migração V16, integrador_instancias) e alerta no GlitchTip uma vez por episódio quando uma instalação passa de 6h úteis sem sinal. A aba Deploy do central-ui ganha a lista das instalações, com DELETE idempotente para parar de acompanhar. Ver docs/decisoes/0028-heartbeat-integrador-client.md.

Alterado

  • Produção recusa subir sem os tokens M2M: o central subia healthy com /api/ci/** respondendo 401 a tudo, e o sintoma chegava horas depois como "o deploy da frota parou". Em env=prod o boot passa a ser recusado sem CENTRAL_DEPLOY_TOKEN (e sem CENTRAL_API_TOKEN, do heartbeat) — o rolling deploy do Coolify mantém o anterior no ar; fora de prod (e2e/staging) segue sem token. Ação de operação: cadastrar os dois envs nos recursos do Coolify antes do deploy. Documentação migrada para a constituição 1.4.8.

Corrigido

  • /health volta a provar a identidade da entrega: SOURCE_COMMIT é variável predefinida do Coolify, que em recurso pull-only a injeta em runtime com o literal HEAD por cima do ENV da imagem — a v0.8.0 foi ao ar respondendo "commit":"HEAD", e o smoke pós-deploy passava sem provar identidade (e o rollback seguinte miraria uma tag inexistente). O commit passa ao namespace da casa (XADM_COMMIT), com xadm-comum-web 0.9.0, que trata HEAD como ausente.

0.8.0 - 2026-09-09

Adicionado

  • Smoke de produção pós-deploy, com identidade de entrega e rollback: o /health passa a provar QUAL entrega está no ar — SOURCE_COMMIT vira ARG/ENV nos dois Dockerfiles (declarado tarde, para não invalidar o nativeCompile) e o CI o passa como build-arg. O job smoke roda depois do deploy e confere identidade, rotas críticas do app.json e ausência de exceção nova no GlitchTip; reprovou, reverte para a tag imutável da entrega anterior. Ver docs/decisoes/0027-adota-smoke-de-producao.md.
  • Status de usuário pAbast sem exigir papel: barrar um pAbast exigia antes conceder papel a ele. A rota nova aceita INATIVO/REJEITADO/PENDENTE sem papel (criando a linha de acesso se faltar) e reserva a exigência ao ATIVO, único status de que o token pAbast copia o role — ativar sem papel devolveria sessão sem papel. Inativar preserva o papel.

Alterado

  • CENTRAL_DEPLOY_URL volta a ser flavor-agnóstica: apontava central-backend-jar.xadm.biz — parar o jar numa promoção a native derrubava o POST /api/ci/deploy da frota inteira.
  • xadm-comum-web 0.8.0 (o commit no /health) e ArchitectureTest compondo a RegrasArquitetura do xadm-comum-teste, mantendo local a guarda anti-vácuo e a regra de N destinos que a fábrica ainda não cobre. Documentação migrada para a constituição 1.4.0.

0.7.1 - 2026-09-06

Corrigido

  • Rotas do catálogo de papéis na doc: a modelagem anunciava DELETE /api/admin/apps/{app}/roles quando a rota real é DELETE /api/admin/apps/{app}/roles/{role}, e o runbook de seed conferia o catálogo por uma URL com o slug do app literal no lugar do path param — as duas afirmações que o gate checa-rotas reprovou contra o OpenAPI gerado. O mesmo DELETE errado saiu do javadoc de AppRole.

0.7.0 - 2026-09-06

Adicionado

  • Login social com status×role e auto-governança de acesso: o acesso oauth_firebase passa a ter dois eixos — status (PENDENTE/REJEITADO/ATIVO, lifecycle) e role (papel data-driven por app, catálogo app_roles) — emitidos no token para a sync rule do PowerSync consumir. Abre a superfície self-service /api/app/**: o ADMIN do tenant lista os usuários e atribui papel no seu app, com guarda de auto-lockout do último ADMIN; novo pedido pendente notifica os aprovadores por e-mail (fail-open). @xadm é super-admin implícito. Migrações V11 (split + drop dos grants) e V12 (app_roles). Ver docs/decisoes/0023-login-social-status-role-self-service.md.
  • Acesso unificado pAbast ∪ oauth, com papel por usuário: oauth_access_requests evolui para app_user_access (migração V13) — o acesso de qualquer usuário, social (oauth) ou staff do ERP (pAbast), numa tabela só, com status + role. O login pAbast vira app-user (app_id opcional no login → token com oauth_app_id/role, fail-closed sem papel; o login legado segue inalterado) e o papel é atribuído pela tela unificada de Usuários. Ver docs/decisoes/0024-acesso-unificado-pabast-oauth.md e docs/decisoes/0025-catalogo-de-papeis-declarado-pelo-app.md.
  • Apps compose no control-plane, ancorados no slug do git: stacks build_pack=dockercompose build-from-git (ex. PowerSync) não têm imagem de registry e ficavam fora do reconcile-by-image — sem caminho de deploy gateado e sem auditoria. O POST /api/ci/deploy ganha um segundo modo de âncora: sem imagem, o app_id é o registry_slug e o target é obrigatório (migração V15 abre o CHECK). O caminho por imagem da frota fica byte-idêntico. Ver docs/decisoes/0026-deploy-compose-ancorado-no-git.md.

Corrigido

  • Gate de arquitetura ressuscitado: o ArchUnit 1.3.0 não lê bytecode do JDK 25 (class major 69) e descartava 194 de 388 classes em silêncio — as travas de fronteira passavam vácuas, verdes, desde o bump do Micronaut 5. Sobe para 1.4.1 (piso da norma) e um teste novo falha alto quando o import vem vazio. Junto, o AdminApiCorsFilterTest chamava um construtor que não existe mais, quebrando o compileTestJava e impedindo qualquer teste do repo de rodar.

Alterado

  • Os dois transportes de e-mail passam a ser provados dentro do repo: SmtpEmailSender e ResendEmailSender (o de produção, antes com zero cobertura) ganham prova em JVM pura — SMTP de mentira em ServerSocket local e WireMock —, sem Docker. O endpoint da Resend virou property (RESEND_ENDPOINT, default o de produção) para ter seam de teste. O denominador do JaCoCo deixa de contar código gerado (Serde*, $Intercepted), que escondia os buracos reais.

0.6.1 - 2026-08-31

Alterado

  • CI mais enxuto (GitHub Actions): o pipeline.yml paraleliza a liberação de disco do build native (~5min → ~2min), isola o cache gha por flavor (jar/native) e cacheia as ferramentas de docs (pip/npm); os workflows .forgejo/ remanescentes foram removidos (CI 100% GitHub). Documentação e skills sincronizadas à constituição X-Adm 1.1.2.

0.6.0 - 2026-08-31

Adicionado

  • Poke de docs publicadas (event-driven): POST /api/ci/docs-published (protegido pelo DeployAuthFilter) recebe o aviso do CI quando um app publica docs e cutuca o listener interno do container docs (/cgi-bin/_sync) — elimina o poll de 90s do Garage. Ver docs/decisoes/0022-self-deploy-do-central.md.

Alterado

  • CI 100% GitHub Actions: um pipeline.yml único (decide → gate ∥ docs ∥ build_jar ∥ build_native → release-check → deploy) substitui o build-deploy.yml, zerando a dependência do Forgejo Actions. Alinha o central ao modelo v1.1.0 da casa (ADRs 0027/0028/0026).
  • Self-deploy do central pelo próprio control-plane: o deploy do central passa a usar o mesmo POST /api/ci/deploy da frota, apontando para si; a guarda self_deploy_refused foi removida (o central roda dentro da casa e alcança a API do Coolify — a ponte SSH e a API direta do runner saíram). Ver docs/decisoes/0022-self-deploy-do-central.md.

0.5.4 - 2026-08-30

Adicionado

  • Control-plane de deploy (ADR 0026 / constituição §9): o CI dispara o deploy por API M2M (POST /api/ci/deploy, token dedicado no filtro /api/ci/**) e o central resolve app → recurso Coolify por um mapa auto-curável ancorado na imagem (app_deploy_targets, migração V10, + reconcile-from-Coolify), chamando a API do Coolify — substitui a ponte SSH + allow-list, que ficava órfã a cada cutover blue-green. Ver docs/decisoes/0021-adota-control-plane-deploy.md.
  • Painel de deploy (read-only): GET /api/admin/deploy (JWT xadm_admin) que agrega o mapa de deploy + o último deploy_audit por recurso + o estado vivo do Coolify (reuso do monitor, indexado por uuid), agrupado por app — alimenta a aba Deploy do central-ui.

Alterado

  • Build off-host (jar + native): o jar e o native passam a buildar no CI (GitHub Actions) e o Coolify só puxa a imagem pronta — o build sai do host de produção. Conformidade à constituição 0.37.3.

0.5.3 - 2026-08-28

Alterado

  • Constituição X-Adm sincronizada para 0.36.5: o gate de CI ganha a guarda de paridade Dockerfile/Dockerfile.native (dirs app-writable sob /app) e as skills de release/docs são re-derivadas do template.

Corrigido

  • Deploy native dispara o redeploy sozinho: após publicar a imagem native no registry, o workflow passa a acionar a atualização do recurso no Coolify via ponte SSH (a API do Coolify recusa o IP do runner do GitHub) — antes era publish-only e o recurso só subia a imagem nova num redeploy manual. A leitura da DEPLOY_SSH_KEY foi endurecida contra CRLF: o secret gravado no Windows chegava com \r e o ssh falhava com "error in libcrypto".

0.5.2 - 2026-08-27

Corrigido

  • Build native: título OpenAPI normalizado para ASCII, evitando falha do micronaut-openapi ao criar o arquivo Swagger durante o nativeCompile.

0.5.1 - 2026-08-27

Corrigido

  • Dependência publicada: o central passa a consumir xadm-comum-web:0.6.1, em vez da versão inexistente 0.6.1-SNAPSHOT, permitindo os builds JVM e native.

0.5.0 - 2026-08-27

Adicionado

  • Deploy native: imagem GraalVM native do central-backend buildada no GitHub Actions, publicada no registry e preparada para atualização do recurso native no Coolify.
  • Monitoramento de infraestrutura: endpoints read-only para saúde do host e das aplicações do Coolify, com métricas de recursos e degradação parcial explícita.

Alterado

  • Identidade do serviço: o nome interno passa de auth para central-backend, mantendo auth.xadm.biz como issuer e endpoint JWKS para não quebrar os clientes PowerSync.
  • Health: resposta /health uniformizada para o formato flat {status, versao}, com liveness native explícito.

Corrigido

  • Native liveness: /health/liveness passa a retornar UP também na imagem native.
  • Documentação operacional: rotas do monitor alinhadas ao OpenAPI gerado.

0.4.2 - 2026-08-10

Adicionado

  • Garage — S3 direto para app server: apps server/web (com production_url) passam a receber a write-key do Garage no recurso Coolify (GARAGE_ACCESS_KEY_ID
  • GARAGE_SECRET_ACCESS_KEY, decifrada de secret_ref no ato da injeção), acessando o bucket direto por S3 em vez do round-trip de presign. O presign broker-signed segue valendo para device/mobile (segredo só no auth); o secret entra só no Coolify (mascarado), nunca no app.json. Habilita o gancho deferido na decisão docs/decisoes/0012-garage-arquivos-presign-broker.md.

0.4.1 - 2026-08-10

Corrigido

  • Garage: o provisionamento passa a validar AUTH_CIPHER_KEY (chave AES-256, 32 bytes base64) antes de tocar o broker. Ausente ou inválida, recusa com erro claro em vez de criar bucket + key e só falhar no encrypt final — o que deixava recursos órfãos no Garage e devolvia um 502 opaco ao setup. A chave, antes documentada como legado, volta a ser obrigatória quando a feature de arquivos está ativa (o secret da write-key é cifrado com ela); doc de operação atualizada.

0.4.0 - 2026-07-16

Alterado

  • Central: o DSN de erros é injetado como SENTRY_DSN, não mais GLITCHTIP_DSN. O broker derivava <PROVIDER>_<KEY> para todo env; agora abre exceção explícita quando o consumidor é um SDK de terceiro com nome canônico próprio (glitchtip.dsn → SENTRY_DSN), que é o nome que o SDK do Sentry lê do ambiente por convenção — o mesmo mapeamento que o build Flutter já fazia no --dart-define. Fora da exceção, a derivação segue igual. O logback.xml aceita os dois nomes durante a transição. Ação de operação: após o deploy, renomear o env no Coolify e apagar o GLITCHTIP_DSN órfão à mão — a injeção é upsert e não remove o nome antigo. Ver docs/operacao/injecao-secrets-coolify.md.

Corrigido

  • Setup: app_id e feature ausentes no provision passam a devolver um machine-code estável (app_id_obrigatorio/feature_obrigatoria) em vez do BAD_REQUEST genérico da validação de borda, que a Central não conseguia traduzir em feedback legível.
  • Setup: nome e grupo são validados antes do upsert — provision sem esses campos estourava um 500 opaco (violando o contrato problem+json) em vez de 400 nome_obrigatorio / 400 grupo_invalido.

0.3.10 - 2026-07-10

Corrigido

  • Gate de CI: quebra uma linha longa em MetabaseProvider que estourava o limite do checkstyle (>120 caracteres), restaurando o gate ci.yml verde.

0.3.9 - 2026-07-10

Alterado

  • Constituição X-Adm atualizada para 0.18.4 e adotada cobertura JaCoCo no gate de qualidade (CI).

Corrigido

  • Metabase: o embedding assinado passa a ser best-effort e aplicado após os cards, evitando dashboard vazio quando o embed falha.
  • Analytics: o client_config emite o aptabase_host junto da key.
  • Setup: removida a fórmula do token de serviço da documentação e das respostas da API.

0.3.8 - 2026-07-07

Adicionado

  • Central: links contextuais + embedding assinado do Metabase. A central resolve os links de produção/docs/source por app e embute dashboards do Metabase via signed embedding (JWT HS256), sem expor credenciais. Ver docs/decisoes/0017-metabase-embed.md.

Alterado

  • Contrato de erro único (problem+json): todos os erros do serviço saem em application/problem+json (RFC 7807) com code (machine-code estável), via um processor global; a arquitetura package-by-feature passa a ser travada por gate ArchUnit e o AuthController fica fino (negócio no AuthLoginService). Ver docs/decisoes/0016-contrato-erro-unico.md.

Corrigido

  • Provisão de app de cliente estourava 500 opaco ("Unexpected error" no Sentry) quando o cliente_id do app.json não existia em clientes — ex.: o nome de exibição (Vantroba) no lugar da chave do tenant (vantroba): o FK apps_cliente_id_fkey falhava no PERSIST sem tratamento. O broker passa a validar o cliente_id antes do upsert e responder 400 cliente_desconhecido (problem+json), apontando a chave minúscula esperada.

0.3.7 - 2026-07-04

Corrigido

  • Preflight CORS do admin retornava 401 em produção (Central bloqueada por "No Access-Control-Allow-Origin"): os filtros de /api/admin/** usavam a API @Filter legada, que ordena por getOrder() e ignora @Order — a ordem entre CORS e autenticação ficava indefinida e divergia entre o classpath (teste verde) e o fat jar (produção), onde o auth respondia o OPTIONS com 401 antes do CORS. Migrados para @ServerFilter (honra @Order); o auth passa a eximir OPTIONS. Ver docs/decisoes/0015-filtros-admin-serverfilter.md.

0.3.6 - 2026-07-04

Alterado

  • Constituição X-Adm atualizada para 0.17.26: ci.yml canônico (o env do dind vai na config do act_runner, org-wide) + passo nav-drift (checa-nav.py no gate de código); skills de workflow re-sincronizadas; adiciona scripts/checa-nav.py.

0.3.5 - 2026-07-03

Alterado

  • Metabase organiza por pasta: cada app ganha uma sub-collection própria (X-Adm|cliente → app → dashboard + cards) em vez de tudo solto numa collection compartilhada; os cards voltam ao nome canônico (sem o sufixo · app_id, já isolados).

0.3.4 - 2026-07-03

Corrigido

  • Provisão de analytics (502 em produção): o AptabaseProvider parseava app_key, mas a API serializa em camelCase (appKey) → key nula; e o MetabaseProvider mandava os dashcards com id:-1 repetido → o Metabase rejeitava (400). Corrigidos (lê appKey; id negativo único por card). A idempotência passou a reusar/adotar cards órfãos por nome na collection, sem duplicar — re-rodar o setup auto-cura o estado parcial.

0.3.3 - 2026-07-03

Corrigido

  • Publicação de docs (docs.yml): os links [decisão 00XX](docs/decisoes/…) no CHANGELOG quebravam o mkdocs build --strict — o changelog é embutido em docs/, então o prefixo docs/ não resolvia (virava docs/docs/…). Passam a texto puro (decisão 00XX).

0.3.2 - 2026-07-03

Corrigido

  • Publicação de docs (docs.yml): a geração do Javadoc falhava por 5 erros de doclint pré-existentes (dois {@link} cross-package sem FQN; três <h3> de topo pulando de H1). Corrigido — o pipeline de docs volta a publicar.

0.3.1 - 2026-07-03

Corrigido

  • Pipeline de CI (Testcontainers no runner dind): o gate ficava vermelho porque o mount de /var/run/docker.sock do template era ignorado no runner (dind isolado, sem socket do host). O job passa a alcançar o daemon do dind pelo gateway (DOCKER_HOST=tcp://172.17.0.1:2375), mantendo o isolamento.

0.3.0 - 2026-07-03

Adicionado

  • Provider Garage (arquivos): provisão de bucket + chave e corretor de presign broker-signed (GET /api/apps/garage/presign) com autorização por app (oauth_app_id, 403 cross-app). Ver decisão 0012.
  • Provider Aptabase (analytics — eventos): auto-provisão do app forjando o token de sessão (HS256 com o AUTH_SECRET), sem depender de API de provisão. Ver decisão 0013.
  • Provider Metabase (analytics — BI): auto-provisão de collection → dashboard → cards de BI (queries ClickHouse) via API REST; a feature analytics passa a provisionar Aptabase e Metabase. Ver decisão 0014.

Alterado

  • A injeção do client-grade no Coolify reinicia o recurso para aplicar a env recém-criada.
  • Constituição X-Adm atualizada para 0.17.10 (pipeline de skills x-*; CI com Docker-in-Docker para os Testcontainers).

0.2.1 - 2026-07-03

Corrigido

  • /test/glitchtip aceita application/x-www-form-urlencoded: o submit do botão (form HTML) dava 415 porque o @Post do Micronaut assume application/json.

0.2.0 - 2026-07-03

Adicionado

  • Central de Apps — broker build-time: POST /api/setup/provision provisiona features de infra por app, de forma idempotente, autenticado por token de serviço X-ADM-<código do dia>. Provisão do GlitchTip (DSN) com injeção do client-grade no recurso Coolify do app. Dashboard admin /api/admin/apps (catálogo por app + estado por provider + links).
  • Observabilidade de erros: SDK Sentry/GlitchTip (sentry-logback) reporta os erros do serviço ao GlitchTip; endpoint /test com smoke-tests públicos e inócuos rodáveis em produção (o 1º valida o pipe de erro ponta a ponta). Ver decisão 0011.
  • Documentação migrada para o padrão da constituição X-Adm (seis níveis): Resumo Executivo, Documentação Completa, modelo de dados, decisões (0001–0011), runbooks de operação e guia de desenvolvimento.

Alterado

  • Resposta honesta do /provision: carrega o estado real por provider (state/last_error + injeção injected/motivo) e responde 502 quando nenhum provider liga — nunca mais um 200 mudo escondendo falha. GlitchTip nomeado pelo app_id (slug estável, sem duplicata). Ver decisões 0010/0011.
  • Código reorganizado para package-by-feature (padrão da casa): comum (transversal)
  • login + admin + centralapps, com dependências acíclicas entre features.
  • Constituição X-Adm atualizada para 0.17.2 (skills re-sincronizadas, xadm-setup instalada, app.json com app_id/production_url).
  • Stack migrada para Micronaut 5.0.3 / JDK 25 / Gradle 9.5.1 (decisão 0009). Serde passa a usar Jackson 3; o JWKS é serializado via nimbus. O JVM do Gradle precisa ser 25. Imagens de CI/Docker em ci-java:25 / eclipse-temurin:25.
  • Gate de CI ganhou o checkstyle (./gradlew check), com o código conformado ao padrão de estilo da casa.

Corrigido

  • /acessos expõe o id do pedido e a central tem CORS liberado.
  • gradlew versionado como executável (100755).