Commit Graph

413 Commits

Author SHA1 Message Date
ATM Platform 97e0aeecd4 feat(P0.9): fase issuer - o issuer passa para athleticmap.com 2026-09-23 12:30:41 +00:00
ATM Platform eeda1e90da Revert "feat(P0.9): fase issuer - o issuer passa para athleticmap.com"
This reverts commit f4747712ad.
2026-09-23 12:22:02 +00:00
ATM Platform f4747712ad feat(P0.9): fase issuer - o issuer passa para athleticmap.com 2026-09-23 12:21:47 +00:00
ATM Platform 5e1bf3a00b feat(P0.9): fase realm - o realm passa a aceitar os dois dominios 2026-09-23 12:14:17 +00:00
deploy 440ade90f5 feat(P0.9): fase HOSTS — os cinco tenants passam a atender os DOIS dominios
Aditiva de proposito: nenhum endereco antigo sai. Quem esta usando
<tenant>.athleticmap.influxdigital.com.br continua entrando, e o cert-manager
passa a emitir tambem o certificado de <tenant>.athleticmap.com.

Foi possivel porque o dono criou o curinga hoje: *.athleticmap.com resolve para
187.77.37.184, conferido com um nome ALEATORIO — demo. ou www. responderiam
mesmo sem curinga, e a conferencia passaria por engano.

9 arquivos, 28 trocas, 317 insercoes e 4 remocoes. As 4 sao as linhas de TLS em
fluxo, reescritas com os dois dominios na mesma lista.

Cada regra de Ingress foi DUPLICADA com os mesmos paths, e nao trocada: uma
regra com host: X so atende X.

`platform/` (ArgoCD e Grafana) fica FORA: mexer no Ingress do ArgoCD no meio de
uma migracao de dominio e perder o instrumento de rollback.

Conferido antes de aplicar: YAML valido em todos os Ingress, e ZERO host sem
entrada de TLS.

O que NAO muda aqui: ATM_ISSUER, ATM_KC_URL e as URLs do Garmin. Ninguem e
deslogado nesta fase.
2026-09-23 11:35:48 +00:00
deploy 80489672b0 fix(plataforma): o initContainer entrega a posse da copia de trabalho
O clone e feito como root e o container principal roda como o usuario app
(uid 999). Sem o chown, a copia de trabalho fica so-leitura para ele, e a etapa
MANIFESTOS_GERADOS falharia ao escrever tenants/<nome> — medido de dentro do pod
logo depois do primeiro deploy: "escrita: NEGADA".

chown, e nao fsGroup: fsGroup ajusta o GRUPO e depende de o diretorio ter
permissao de grupo, o que o git nao garante arquivo a arquivo. Entregar a posse
e explicito e nao depende de umask.
2026-09-22 22:13:27 +00:00
deploy 6ca712c619 feat(plataforma): a etapa MANIFESTOS_GERADOS ganha o molde e a copia de trabalho
Era a primeira etapa do provisionamento e a unica bloqueada por algo MEU, nao
por credencial do dono: o pod nao enxergava o molde nem o repositorio GitOps, e
as tres propriedades ficavam vazias. Falhar fechado, nomeando a propriedade, era
o comportamento certo — o que faltava era o material chegar.

Um initContainer clona o repositorio em /gitops na subida. Dentro dele,
moldes/consolidado e o molde e tenants/<nome> e onde a etapa escreve: UM volume
serve aos dois, e por isso o molde foi para o repositorio GitOps no commit
anterior.

Tres decisoes que valem registro:

- CLONE ANONIMO. O Gitea aceita leitura sem credencial neste repositorio, e
  leitura e tudo o que a etapa 1 precisa. Empurrar e a etapa ARGO_SINCRONIZADO,
  que depende de credencial e continua bloqueada — esta mudanca nao a destrava e
  nao tenta;
- emptyDir, e nao PVC. A copia e descartavel por desenho: se o pod morrer no
  meio de um provisionamento, o que ficou pela metade some junto. Melhor do que
  um clone velho e divergente sobrevivendo entre reinicios;
- a imagem e a do act_runner, que JA esta no no e tem git 2.45.2. Nao ha
  registry aqui, entao construir uma imagem so para ter git custaria mais do que
  reusar esta.

O endereco e o interno (gitea-http.gitea.svc:3000), o mesmo do ApplicationSet.
Depende do 19-netpol-gitea.yaml do commit anterior.
2026-09-22 22:10:39 +00:00
deploy efc9d35f94 feat(plataforma): o provisionamento passa a LER o repositorio GitOps
A etapa MANIFESTOS_GERADOS renderiza o molde para tenants/<nome> numa copia de
trabalho, e o pod obtem essa copia clonando o Gitea na subida. Clonar e leitura.

Escrever continua fora de alcance, de proposito: empurrar no ramo padrao E o
deploy, e depende de uma credencial que ainda nao existe.

O Gitea aceita clone ANONIMO deste repositorio (conferido com git ls-remote sem
credencial), entao a etapa 1 funciona antes de a credencial de escrita existir.

A MESMA armadilha de rede, pela TERCEIRA vez. De dentro do pod, antes desta
politica: HTTP 000, exit 7. O ipBlock 10.43.0.0/16 da deny-cross-tenant cobre o
ClusterIP do Gitea e nao adianta — o k3s avalia DEPOIS do DNAT, e ali o destino
ja e o IP do POD.

Aconteceu com a API do Kubernetes em 20/09, com o sealed-secrets hoje mais cedo,
e agora aqui. E regra deste cluster, nao coincidencia.

Estreita: so o servico-captacao, so o POD do Gitea por rotulo (namespaceSelector
sozinho abriria a 3000 do namespace inteiro, onde tambem vivem o Valkey e o
runner de CI), so a 3000, so saida.
2026-09-22 22:08:45 +00:00
deploy f6aeb233a7 feat(moldes): o molde do tenant novo entra no repositorio GitOps
Ate aqui ele vivia SO no monorepo, e o provisionamento roda DENTRO do cluster —
o pod do servico-captacao nao tinha como enxerga-lo. A etapa MANIFESTOS_GERADOS
falhava por configuracao vazia, e falhar fechado era o comportamento certo; o
que faltava era o molde chegar.

Pondo-o aqui, o pod precisa de UM volume em vez de dois: o mesmo clone do GitOps
serve de molde (moldes/consolidado) e de copia de trabalho (tenants/<nome>).

Os tres marcadores — TENANT, REALM e PLANO — batem com o RenderizadorDeMolde. Os
arquivos NAO sao YAML valido antes de renderizados, e isso e de proposito: um
`{{PLANO}}` literal aplicaria sem reclamar e criaria um tenant cujo plano se
chama "{{PLANO}}", com a barreira negando tudo depois.
2026-09-22 22:07:34 +00:00
deploy 713db06a7b fix(plataforma): o frontend tambem precisava de FQDN, e so ele ficou de fora
Os quatro tenants foram corrigidos mais cedo hoje; o plataforma nao. O defeito
so apareceu agora, e por um motivo que vale registrar: ele e o unico SEM
catch-all /api. Nos outros, uma rota sem linha propria era engolida pelo
backend legado; aqui ela cai no frontend — e e ali que o bug estava esperando.

Medido no log do proprio pod:

  servico-bff could not be resolved (3: Host not found)
  request: "POST /api/plataforma/provisionamentos"

O resolver do nginx nao aplica os search do /etc/resolv.conf, entao nome curto
nao resolve. As cinco variaveis estavam vazias, e toda ausente cai em
ATM_API_URL, que cai no nome curto `servico-bff`.

Aqui nao ha runtime consolidado: os destinos apontam para o BFF, que ja era o
padrao — a diferenca e so o FQDN.

Achado ao conferir o PLATAFORMA_ADMIN_TOKEN recem-ligado: a consulta de estado
devolvia 502 em vez de 401, e o 502 era isto.
2026-09-22 21:28:16 +00:00
deploy 4024c27f1b feat(plataforma): o captacao passa a ler os dois tokens
Vai DEPOIS do commit que selou os Secrets, e nao junto: secretKeyRef de Secret
ausente impede o pod de subir. Os dois ja materializaram no cluster.

PLATAFORMA_WEBHOOK_TOKEN destrava a etapa que recebia o aviso de assinatura e
recusava tudo por falta de configuracao. Falta CADASTRAR o mesmo valor no painel
do Asaas, na conta da Athletic Map — quem for cadastrar le uma vez com:

  kubectl -n plataforma-prod get secret plataforma-webhook-token \
    -o jsonpath='{.data.token}' | base64 -d

PLATAFORMA_ADMIN_TOKEN destrava a consulta de estado do provisionamento, que e
interina e vive no cabecalho x-atm-admin-token.
2026-09-22 21:26:14 +00:00
deploy 1bc58f2927 fix(plataforma): os dois tokens regerados, porque os primeiros vazaram
Ao conferir que os Secrets tinham materializado, o comando imprimiu o campo
`.data` inteiro — ou seja, parte do valor em base64 dos dois tokens foi parar na
conversa. Curto, e o bastante para nao dar por confiavel.

Regerados. Custo zero: nada os referenciava ainda (nenhum Deployment, e o
webhook nao estava cadastrado no Asaas), entao nao houve janela de uso.

A licao, que ja valia para senha e vale igual para Secret: conferir existencia
com `-o name`, e nunca com `-o custom-columns=...:.data` nem `-o yaml`. O que se
quer saber e SE existe, nao O QUE e.
2026-09-22 21:25:43 +00:00
deploy 9f3360038a feat(plataforma): os dois tokens que sao NOSSOS, selados
PLATAFORMA_ADMIN_TOKEN e PLATAFORMA_WEBHOOK_TOKEN. Os dois sao gerados aqui, ao
contrario da api-key do Asaas, que vem do painel do provedor.

O valor nasceu, foi selado e morreu dentro de um unico shell no servidor: nao
foi ecoado, nao foi para arquivo, nao entrou no historico e nao apareceu em ps.
O que se commita e o cifrado, que e publico por natureza.

Vao SOZINHOS neste commit, sem a referencia no Deployment: secretKeyRef de
Secret ausente impede o pod de subir. Primeiro o Secret materializa, depois o
env aponta para ele.

O webhook-token precisa ser CADASTRADO no painel do Asaas com o mesmo valor. Ele
pode ser lido uma vez, por quem for cadastrar:

  kubectl -n plataforma-prod get secret plataforma-webhook-token \
    -o jsonpath='{.data.token}' | base64 -d
2026-09-22 21:24:56 +00:00
deploy 4c338c0eda feat(piloto,acme,escolinha): o Ingress simplificado, como no demo (P4.6)
Mesma mudanca do commit anterior, agora nos tres restantes. O demo foi primeiro
e ficou conferido de fora: os 13 contextos em 200, /bff em 200, /inicio e
/lp-escolinhas em 200, e — o que mais importava — /api/nao-mapeado continua
devolvendo 401, como antes. O comportamento visivel nao mudou.

Catorze linhas saem de cada um. O destino do /api passa de backend (o legado)
para frontend-spa; a decisao "401 ou 404" segue aberta e intacta.
2026-09-22 19:54:40 +00:00
deploy d81f45b62c feat(demo): o Ingress para de rotear /bff e os treze /api/<contexto> (P4.6)
Catorze linhas saem. Quem conhece a topologia interna passa a ser o
frontend/nginx.conf.template, que viaja junto com a imagem — antes, cada
mudanca de topologia obrigava a editar o Ingress de todos os tenants.

O destino do /api mudou de backend (o legado) para frontend-spa. O que o
visitante ve NAO muda: caminho nao mapeado continua recebendo 401 — antes do
backend legado, agora do BFF, para onde o nginx manda o /api que sobra. A
decisao "401 ou 404" segue aberta e intacta; isto so tira o legado do caminho
do trafego.

Pre-condicao resolvida hoje: as cinco variaveis de destino do nginx estavam
vazias e, mesmo apontadas, precisavam de FQDN (o resolver do nginx nao aplica os
search do resolv.conf). Sem isso, esta mudanca derrubaria os treze contextos e o
/bff de uma vez.

ORDEM: /api/public e /api/public/webhooks/asaas vivem no
96-ingress-garmin-public.yaml e tem prefixo mais longo, entao vencem o /api — o
Traefik ordena por tamanho.

Primeiro tenant. Os outros tres so depois de conferido.
2026-09-22 19:52:26 +00:00
deploy 1dda8d518d fix(tenants): o webhook de PAGAMENTO do Asaas morria no BFF
O arquivo 96-ingress-garmin-public.yaml foi criado para o callback do Garmin e
leva TODO o /api/public para o servico-bff. O BFF relaya o Garmin de proposito
(GarminBffController), mas NAO tem controlador para /api/public/webhooks/asaas —
so o financeiro tem (WebhookAsaasController).

Resultado nos quatro tenants: o aviso de pagamento do Asaas chegava ao BFF e
parava ali. O sintoma seria o pior possivel — a cobranca e paga e NUNCA baixada,
sem erro nenhum do nosso lado; o provedor so registra uma entrega recusada.

Esta dormente hoje porque nenhum dos quatro tem asaas-credentials (cada cliente
traz a propria chave, decisao de 19/09). Passaria a morder no primeiro cliente
que ligasse a cobranca — e o diagnostico comecaria pelo lado errado, olhando o
financeiro, que nunca recebeu nada.

O Traefik ordena por TAMANHO do prefixo, entao a rota nova vence a generica
sozinha; fica escrita primeiro mesmo assim, para ninguem reordenar sem perceber.

Achado a partir do scripts/conferir_rotas_publicas.py, que acusou o piloto. A
acusacao estava certa no problema e errada no alcance: ele le a copia PARCIAL do
monorepo, que nao tem o Ingress de nenhum dos quatro, e concluiu sobre um.
Medido no cluster, os quatro eram identicos e os quatro estavam quebrados.
2026-09-22 15:02:05 +00:00
deploy 2a4b387e37 feat(plataforma): duas rotas publicas que existiam no codigo e nao no Ingress
O Ingress do plataforma nao tem catch-all, por desenho: rota publica nova
precisa ser acrescentada a mao, ou devolve 404. Duas estavam faltando, as duas
achadas por scripts/conferir_rotas_publicas.py.

/api/public/conta (P5.8) — a tela de espera depois do pagamento. Quem acabou de
pagar AINDA NAO TEM CONTA, logo nao tem token. O controlador existia
(EstadoDaContaController) e a cadeia ja liberava (permitAll), mas o Ingress
devolvia 404: a tela que existe para tranquilizar quem pagou nao respondia.

/api/public/webhooks/assinatura (P5.1) — e outra coisa do webhooks/asaas que ja
estava la: aquele avisa que uma COBRANCA de cliente foi paga e vai para o
financeiro do tenant; este avisa que alguem assinou a Athletic Map, e dispara o
provisionamento de um tenant NOVO. Contas diferentes no Asaas, servicos
diferentes aqui. Sem esta linha, alguem assinaria, pagaria, e nenhum tenant
seria criado — sem erro em lugar nenhum do nosso lado.
2026-09-22 14:56:43 +00:00
deploy a6d1f36d67 fix(tenants): o roteamento interno do nginx precisa de FQDN, e nunca funcionou
Ao conferir o P4.6, o nginx do frontend devolveu 502 em TODOS os caminhos
internos, inclusive /bff. O log diz o porque:

    servico-bff could not be resolved (3: Host not found)
    runtime-saude could not be resolved (3: Host not found)

O "resolver" do nginx NAO aplica os "search" do /etc/resolv.conf: ele consulta o
nome exatamente como esta escrito. O comando "getent hosts servico-bff", de
dentro do MESMO pod, resolve — porque usa o resolv.conf, que tem
"search escolinha-prod.svc.cluster.local ...". O nginx nao usa.

Isso e PREEXISTENTE e estava invisivel: o Ingress roteia /bff e as treze linhas
de /api/<contexto> direto para os Services, entao o nginx nunca foi exercitado
nesses caminhos. Quem removesse as linhas do Ingress — que e exatamente o que
P4.6 quer — derrubaria os treze contextos E o /bff de uma vez, com 502 e nenhuma
pista no Ingress para explicar.

As cinco variaveis passam a usar FQDN. Conferido depois, batendo no nginx por
dentro (sem passar pelo Ingress): os 13 contextos respondem 200, e o /bff
tambem. De fora, os quatro tenants seguem em 200 — nada regrediu.
2026-09-22 13:53:06 +00:00
deploy 6dd1fbc24e feat(tenants): o roteamento interno do nginx, por grupo de contextos (P4.6)
As tres variaveis estavam VAZIAS nos quatro tenants, e render-config.sh faz toda
ausente cair em ATM_API_URL, que cai em http://servico-bff. O nginx mandaria
/api/cadastro para o BFF, que responde 401 em vez da resposta do contexto.

Nada quebrava porque o INGRESS atende antes, com uma linha por contexto — e sao
justamente essas linhas que P4.6 quer remover. Sem isto, remove-las quebraria os
treze caminhos de uma vez.

Aditivo: enquanto o Ingress existir, o trafego nem chega a este nginx.
2026-09-22 13:49:10 +00:00
deploy 8e0a2a8f18 feat(plataforma): o certificado de selagem vem do controlador, pela URL
O ipBlock da deny-cross-tenant nao vale para destino em outro namespace (o k3s
avalia depois do DNAT), entao a variavel sozinha daria FalhaTemporaria. Vai
junto a netpol estreita: so o servico-captacao, so o pod do controlador, so a
porta 8080, so saida.
2026-09-22 13:07:28 +00:00
deploy 84293e4176 chore(plataforma): servico-captacao:1.5-realm 2026-09-22 12:43:21 +00:00
deploy 2a7292455d feat(escolinha): BFF e frontend novos (P4.3-P4.9) 2026-09-22 12:28:46 +00:00
deploy 63889b64f9 feat(escolinha): contextos do runtime-saude passam a responder por ele (P4.3-P4.9) 2026-09-22 12:27:55 +00:00
deploy ea6c08797e feat(escolinha): runtime-saude no ar (P4.3-P4.9) 2026-09-22 12:27:52 +00:00
deploy 0ca5a3bdfa feat(escolinha): contextos do runtime-operacao passam a responder por ele (P4.3-P4.9) 2026-09-22 12:26:49 +00:00
deploy 492acaf0fa feat(escolinha): runtime-operacao no ar (P4.3-P4.9) 2026-09-22 12:26:47 +00:00
deploy 1343b52278 feat(escolinha): contextos do runtime-core passam a responder por ele (P4.3-P4.9) 2026-09-22 12:26:19 +00:00
deploy ccd98c252c feat(escolinha): runtimes consolidados ao lado dos servicos (P4.3-P4.9) 2026-09-22 12:25:30 +00:00
deploy a2d8644595 chore(tenants): frontend-spa:2.67-csp-script 2026-09-22 12:17:44 +00:00
deploy 4eedae4c78 chore(tenants): frontend-spa:2.67-csp-script 2026-09-22 12:17:05 +00:00
deploy a67efba9de fix(tenants): ATM_PLANO=institucional (sem ele a barreira cai em bronze e os modulos pagos dao 403) 2026-09-22 11:06:09 +00:00
deploy 6faa9c8ab7 fix(tenants): ATM_PLANO=institucional (sem ele a barreira cai em bronze e os modulos pagos dao 403) 2026-09-22 11:06:05 +00:00
deploy feb721ccee fix(tenants): ATM_PLANO=institucional (sem ele a barreira cai em bronze e os modulos pagos dao 403) 2026-09-22 11:05:59 +00:00
deploy cde7d9bd02 fix(tenants): ATM_PLANO=institucional (sem ele a barreira cai em bronze e os modulos pagos dao 403) 2026-09-22 11:05:26 +00:00
deploy 27065a4274 chore(tenants): frontend-spa:2.66-lp-css 2026-09-22 02:00:29 +00:00
deploy 22412c40aa feat(backup): envio para fora do servidor (atm-pg-backup:1.2 com rclone) 2026-09-22 01:57:55 +00:00
deploy 76fd9fd270 chore(tenants): frontend-spa:2.66-lp-css 2026-09-22 01:49:39 +00:00
deploy ac40b21768 chore(tenants): frontend-spa:2.66-lp-css 2026-09-22 01:41:27 +00:00
deploy 7301899084 chore(platform): sincroniza platform/ com o monorepo 2026-09-21 23:30:21 +00:00
deploy 019bf6707e feat(backup): envio para fora do servidor (atm-pg-backup:1.2 com rclone) 2026-09-21 23:17:51 +00:00
deploy e666b8e045 feat(backup): envio para fora do servidor (atm-pg-backup:1.2 com rclone) 2026-09-21 23:15:59 +00:00
deploy 5cae175d97 feat(backup): envio para fora do servidor (atm-pg-backup:1.2 com rclone) 2026-09-21 23:13:35 +00:00
deploy 07682c2859 chore(tenants): servico-bff:2.0-exportacao 2026-09-21 22:31:53 +00:00
deploy 6aed5291a6 chore(tenants): servico-bff:2.0-exportacao 2026-09-21 22:27:36 +00:00
deploy 5e467f768a chore(tenants): runtime-operacao:1.2-auditoria 2026-09-21 22:24:14 +00:00
deploy a7b6e7c2c2 chore(tenants): runtime-operacao:1.2-auditoria 2026-09-21 22:22:10 +00:00
deploy b0374ac0a0 chore(tenants): runtime-core:1.2-auditoria 2026-09-21 22:18:05 +00:00
deploy e056b7295a chore(tenants): runtime-core:1.2-auditoria 2026-09-21 22:16:40 +00:00
deploy 95eb3b93c8 chore(plataforma): servico-captacao:1.4 2026-09-21 22:09:06 +00:00
deploy b3762496f8 chore(platform): sincroniza platform/ com o monorepo 2026-09-21 21:58:09 +00:00