# Ingress do tenant `plataforma`. # # ── Por que este arquivo foi escrito, e nao copiado ─────────────────────────── # # O piloto guarda o Ingress dentro de `30-apps-stubs.yaml`, junto com o stub # `backend`. Copiar aquele arquivo traria duas coisas que este tenant nao deve # herdar: # # 1. O proprio stub `backend`, que P0.5 mediu nao atender trafego nenhum (11 # requisicoes externas em 50 dias, todas 401) e que esta em fila para ser # aposentado. Tenant novo nao nasce com divida. # 2. A rota catch-all `/api` -> `backend`. Aqui nao ha catch-all: o que nao # casa com um prefixo conhecido devolve 404, que e a resposta honesta. # # Os nomes de Service tambem divergem de proposito: o piloto publica `frontend`, # e aqui o Service se chama `frontend-spa` (veja `95-frontend-spa.yaml`). Copiar # o do piloto daria um Ingress apontando para um Service inexistente. # # ── Por que o dominio e `.influxdigital.com.br`, e nao `.athleticmap.com` ───── # # O canonico decidido com o usuario em 2026-09-16 (P0.9) e # `.athleticmap.com`. Ele ainda NAO vale, e nascer nele hoje quebraria # justamente o criterio deste card ("login funciona"): # # - `plataforma.athleticmap.com` e `auth-plataforma.athleticmap.com` nao tem # registro A nenhum (conferido em 2026-09-17 por nslookup); # - o apex `athleticmap.com` resolve para 72.61.42.87, que NAO e o cluster — # o cluster e 187.77.37.184; # - cert-manager usa desafio HTTP-01, entao sem o host resolvindo para o # cluster o certificado nao e emitido, e sem certificado nao ha login. # # Ja `*.athleticmap.com` e wildcard para o cluster (conferido: # ate um subdominio inventado resolve para 187.77.37.184). Entao este tenant # sobe hoje e atravessa o corte de dominio junto com os demais, no passo 5 do # `docs/p09-plano-de-corte-dominio.md` — e nao numa migracao propria. # # ── As rotas publicas ──────────────────────────────────────────────────────── # # Duas, e ambas por desenho: # # `/api/public/leads` quem preenche o formulario da landing page # ainda nao e cliente, e portanto nao tem token. # `/api/public/webhooks/asaas` o aviso de pagamento chega dos servidores do # provedor, que tambem nao tem token nosso; quem # autentica e o cabecalho `asaas-access-token`. # # Nenhuma outra rota esta aberta, e nao ha catch-all — o que significa que uma # rota publica NOVA em qualquer servico precisa ser acrescentada aqui a mao, ou # devolve 404. O `scripts/conferir_rotas_publicas.py` existe para isso nao # depender de alguem lembrar. apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: plataforma namespace: plataforma-prod annotations: cert-manager.io/cluster-issuer: letsencrypt-prod traefik.ingress.kubernetes.io/router.middlewares: plataforma-prod-redirect-https@kubernetescrd spec: ingressClassName: traefik tls: - hosts: - plataforma.athleticmap.com - auth-plataforma.athleticmap.com # O host de autenticacao DOS TENANTS. Ver a regra la embaixo. - auth.athleticmap.com secretName: plataforma-tls rules: - host: plataforma.athleticmap.com http: paths: # PUBLICA — sem token, por desenho. Vem primeiro porque o Traefik # ordena por tamanho do prefixo, mas deixar explicito evita que alguem # reordene sem perceber. - { path: /api/public/leads, pathType: Prefix, backend: { service: { name: servico-captacao, port: { number: 80 } } } } # A CONTRATACAO pela landing page: escolher o plano e receber o link # por e-mail. Prefixo cobre tambem `/contratacoes/planos`, que a # pagina le para mostrar o MESMO preco que o checkout vai cobrar. # # Aqui nao ha catch-all: caminho que nao esta escrito nao existe. Foi # por isso que o endpoint respondeu vazio quando a imagem ja estava no # ar — o servico tinha a rota e o Ingress nao. - { path: /api/public/contratacoes, pathType: Prefix, backend: { service: { name: servico-captacao, port: { number: 80 } } } } # PUBLICA — a tela de espera depois do pagamento (P5.8). Quem acabou de # pagar AINDA NAO TEM CONTA, logo nao tem token: se esta rota exigisse # um, a tela que existe para tranquilizar quem pagou seria a primeira a # recusa-lo. # # O que ela entrega e deliberadamente pouco: se a conta ficou pronta e # o endereco do tenant. Nem nome, nem e-mail, nem plano, nem realm — o # id da assinatura na URL e a unica "credencial" da tela, e ha teste # guardando esse limite. Acrescentar um campo aqui e acrescentar o que # um link vazado entrega. # # Estava PREPARADA e nao publicada desde 2026-09-19: o controlador # existe (`EstadoDaContaController`) e a cadeia ja a liberava # (`SecurityConfig`, permitAll), mas sem esta linha o Ingress devolvia # 404 — nao ha catch-all aqui, por desenho. - { path: /api/public/conta, pathType: Prefix, backend: { service: { name: servico-captacao, port: { number: 80 } } } } # LICENCA do tenant: o app do treinador manda a chave (POST) e descobre a escola. # So este caminho EXATO; a emissao (/api/plataforma/licencas) NAO sai na borda. - { path: /api/public/licencas/ativacao, pathType: Exact, backend: { service: { name: servico-captacao, port: { number: 80 } } } } # "Nao tenho a chave" na primeira tela do app: chave nova vai ao e-mail DA COMPRA. - { path: /api/public/licencas/reenvio, pathType: Exact, backend: { service: { name: servico-captacao, port: { number: 80 } } } } # App ja ativado: "minha chave ainda vale?" (revogar a chave derruba os apps). - { path: /api/public/licencas/situacao, pathType: Exact, backend: { service: { name: servico-captacao, port: { number: 80 } } } } # O PAINEL DO COMPRADOR e o PAINEL DO DONO. Sem estas duas linhas as # chamadas caiam no `/` do front, que as repassava a OUTRO servico — o # 401 que voltava parecia o validador de JWT do captacao funcionando, e # era de outro lugar (2026-09-25). A seguranca de cada uma esta no # captacao: JWT do realm `clientes` numa, token de admin na outra. - { path: /api/cliente, pathType: Prefix, backend: { service: { name: servico-captacao, port: { number: 80 } } } } - { path: /api/plataforma/painel, pathType: Prefix, backend: { service: { name: servico-captacao, port: { number: 80 } } } } # PUBLICA — o aviso de ASSINATURA do Asaas (P5.1), que e outra coisa do # `/api/public/webhooks/asaas` logo abaixo: 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 e o que dispara o provisionamento de # um tenant NOVO. Contas diferentes no Asaas, servicos diferentes aqui. # # Chega da internet sem token nosso; quem autentica e o # `PLATAFORMA_WEBHOOK_TOKEN`, conferido no `WebhookDeAssinatura`. Sem o # segredo selado, o endpoint RECUSA tudo de proposito, e o log diz isso. # # Sem esta linha o Ingress devolvia 404: alguem assinaria, pagaria, e # nenhum tenant seria criado — sem erro em lugar nenhum do nosso lado. - { path: /api/public/webhooks/assinatura, pathType: Prefix, backend: { service: { name: servico-captacao, port: { number: 80 } } } } - { path: /api/public/webhooks/subconta, pathType: Prefix, backend: { service: { name: servico-captacao, port: { number: 80 } } } } # PUBLICA — o aviso de pagamento do Asaas, que chega da internet sem # token nenhum (P3.3). NAO casa com /api/financeiro: o controlador # atende em /api/public/webhooks/asaas, e como aqui nao ha catch-all, # a ausencia desta linha daria 404 em todo aviso — a cobranca seria # paga e nunca baixada. Quem autentica e o cabecalho # `asaas-access-token`, conferido no WebhookAsaasController. - { path: /api/public/webhooks/asaas, pathType: Prefix, backend: { service: { name: servico-financeiro, port: { number: 80 } } } } # O resto exige token, como em qualquer tenant. - { path: /bff, pathType: Prefix, backend: { service: { name: servico-bff, port: { number: 80 } } } } - { path: /, pathType: Prefix, backend: { service: { name: frontend-spa, port: { number: 80 } } } } - host: auth-plataforma.athleticmap.com http: paths: - { path: /, pathType: Prefix, backend: { service: { name: keycloak, port: { number: 8080 } } } } # O HOST DE AUTENTICACAO DOS TENANTS. # # O mesmo Keycloak, outro nome. O molde do tenant ja apontava para ca — a # SPA em `ATM_KC_URL` e os tres runtimes em `ATM_ISSUER` — e o host nao # existia: o navegador batia em ERR_CERT_AUTHORITY_INVALID e, passando por # cima, em `404 page not found` do Traefik. Medido em 2026-09-24, no # primeiro login de um tenant provisionado. # # Nao e `auth-plataforma` para o cliente: o endereco aparece na barra do # navegador dele durante o login, e o nome do NOSSO tenant interno nao tem # o que fazer ali. # # O realm de cada tenant recebe `frontendUrl` com este endereco, senao o # Keycloak geraria os links com o `KC_HOSTNAME` global — que continua sendo # o `auth-plataforma`, porque a plataforma depende dele. - host: auth.athleticmap.com http: paths: - { path: /, pathType: Prefix, backend: { service: { name: keycloak, port: { number: 8080 } } } }