Índice de Integrações¶
Cada integração liga uma aplicação provedora (ex.: Traefik) às aplicações consumidoras que satisfazem a regra "Aplica-se a", avaliada sobre os fatos do Catálogo de Aplicações. Este índice é lido e aplicado por agentes de IA por meio das skills audit-integrations, add-app, remove-app, add-integration e remove-integration (veja AGENTS.md).
Legenda¶
Aplica-se a usa as colunas do catálogo:
<Coluna> = <valor>/<Coluna> ≠ <valor>— ex.:Exposição ≠ interna,Métricas = sim.todas— toda aplicação do catálogo.+<id>— integração opcional: só se aplica a quem tem+<id>em Ajustes.-<id>em Ajustes sempre exclui a aplicação, mesmo que a regra se aplique.- A aplicação provedora não é consumidora da própria integração, salvo indicação na seção.
Regras têm id <PREFIXO>-<n>. Regras marcadas (sobra) verificam o inverso: algo que ficou para trás e não deveria existir.
Status da auditoria: ✅ ok · ❌ <REGRA> falta · ⚠️ <REGRA> sobra · ✋ passo manual pendente · — não se aplica · ? depende de valor ? no catálogo.
Uma seção pode ter subseções extras de referência (ex.: ### Origem dos valores) depois das cinco obrigatórias; as skills as seguem ao corrigir ou adicionar.
Serviço principal é o primeiro da coluna Serviços. Regras de roteamento e autenticação valem para ele; aplicações ansible:<role> têm a evidência nas tasks/labels do role, não em compose.
roteamento¶
| Campo | Valor |
|---|---|
| Provedor | traefik |
| Aplica-se a | Exposição ≠ interna |
| Arquivos | docker/stacks/<stack>/docker-compose.yml (labels do serviço principal); para ansible:<role>, ansible/roles/<role>/tasks/main.yml; routers definidos por arquivo em ansible/roles/infra/traefik-config/templates/*.yml.j2 |
| Páginas | página da aplicação; 01-manual-implementacao/05-rede-segura.md |
| Manual | — |
Regras¶
- ROT-1 — o serviço principal tem
traefik.enable: "true"e um router com regraHost(`<Subdomínio>.${BASE_DOMAIN_FROM_VAULT}`)(ouHost(`<Subdomínio>.{{ base_domain }}`)em role Ansible;${N8N_SUBDOMAIN}conta como o subdomínion8n). Aplicação em outra VM que não a do Traefik: em vez das labels, um router no file provider (ansible/roles/infra/traefik-config/templates/*.yml.j2) com essa regra, apontando parahttp://<ip da VM>:<porta publicada no compose>. Evidência: labels do serviço ou template do file provider. - ROT-2 — o serviço principal está na rede
proxy; aplicação em outra VM, roteada pelo file provider, publica a porta no IP da VM (${<VM>_IP}:<porta>:<porta do container>). Evidência:networks:/ports:do serviço (para role Ansible:networksdo task do container). - ROT-3 (sobra) — nenhum router (por label ou por arquivo do file provider) pertence a aplicação
interna, a serviço fora do catálogo, ou usa subdomínio diferente do catálogo. Evidência: labels de todos os composes e roles, eansible/roles/infra/traefik-config/templates/*.yml.j2.
Ao adicionar (por consumidor)¶
- Labels no serviço principal:
traefik.enable, router<app>com a regra Host,entrypoints/tlsiguais aos vizinhos,loadbalancer.server.portcom a porta interna. - Rede
proxy(externa) no serviço principal.
Ao remover (por consumidor)¶
- Remover as labels
traefik.*do serviço (ou o serviço inteiro, se a aplicação sai). - Remover a rede
proxyse o serviço continuar existindo comointerna.
Ao remover o provedor¶
Todas as aplicações com Exposição ≠ interna perdem acesso externo: remover roteamento, autenticacao e acesso-externo de todas, ou substituir o provedor antes.
autenticacao¶
| Campo | Valor |
|---|---|
| Provedor | authelia |
| Aplica-se a | Exposição ≠ interna |
| Arquivos | labels do serviço principal; ansible/roles/infra/authelia-config/templates/configuration.yml.j2 |
| Páginas | página da aplicação; 01-manual-implementacao/05-rede-segura.md (bloco literal do configuration.yml.j2) |
| Manual | — |
Regras¶
- AUT-1 — Exposição
protegida: o router do serviço principal inclui exatamente o middlewareauthelia-forwardauth@docker(pode haver outros na lista; nomes parecidos comoauthelia@dockernão valem). Evidência: labeltraefik.http.routers.<r>.middlewaresoumiddlewares:do router no template do file provider. - AUT-2 — Exposição
protegida: o subdomínio é coberto por uma regratwo_factoremaccess_control.rules— a regra curinga"*.{{ base_domain }}"→two_factorsatisfaz. Evidência:configuration.yml.j2. - AUT-3 — Exposição
publica: existe regradomain: "<Subdomínio>.{{ base_domain }}"compolicy: bypassantes da regra curinga, e o router não usa o middleware do Authelia. Evidência:configuration.yml.j2e labels. (O próprioautheliacumpre isso com a regra deauth.) - AUT-4 (sobra) — nenhuma regra
bypass/one_factorespecífica para subdomínio que não exista no catálogo. Evidência:configuration.yml.j2.
Ao adicionar (por consumidor)¶
protegida: acrescentarauthelia-forwardauth@dockeraos middlewares do router; conferir que a curinga continuatwo_factor.publica: adicionar a regrabypassno bloco literal doconfiguration.yml.j2(página 05) antes da curinga →dev.py sync.
Ao remover (por consumidor)¶
- Retirar a regra específica do subdomínio do
configuration.yml.j2(via página 05), se houver. - Retirar o middleware das labels (ou o serviço).
Ao remover o provedor¶
Toda aplicação protegida ficaria exposta sem login: bloquear até que cada uma vire interna ou outro provedor de autenticação seja adicionado.
acesso-externo¶
| Campo | Valor |
|---|---|
| Provedor | cloudflared |
| Aplica-se a | Exposição ≠ interna |
| Arquivos | — (configuração do túnel é remota, no painel da Cloudflare) |
| Páginas | 01-manual-implementacao/05-rede-segura.md (seção Public Hostnames) |
| Manual | Public Hostname <Subdomínio> → https://traefik:443 no túnel, ou hostname curinga * já configurado |
Regras¶
- EXT-1 — a página 05 documenta o Public Hostname curinga
*ou a página da aplicação registra o hostname específico a criar. Se nenhum dos dois:✋(passo manual pendente), não❌. Evidência: texto das páginas.
Ao adicionar (por consumidor)¶
- Se não houver curinga: registrar na página da aplicação o passo manual "criar Public Hostname
<Subdomínio>" e listá-lo nos passos manuais do plano.
Ao remover (por consumidor)¶
- Se havia hostname específico: passo manual "remover Public Hostname
<Subdomínio>" no plano; retirar a menção da página.
Ao remover o provedor¶
Nenhuma aplicação fica acessível pela internet; tratar como remoção de acesso-externo de todos os consumidores (passos manuais) e avisar o usuário.
metricas¶
| Campo | Valor |
|---|---|
| Provedor | prometheus |
| Aplica-se a | Métricas = sim |
| Arquivos | ansible/templates/prometheus.yml.j2; playbook ansible/playbooks/setup-monitoring-stack-volumes.yml (renderiza o template) |
| Páginas | página da aplicação; 01-manual-implementacao/07-deploy-apps.md |
| Manual | — |
Regras¶
- MET-1 — existe um
job_nameemprometheus.yml.j2cujo target aponta para um serviço da aplicação (<serviço>:<porta>). O próprioprometheuscumpre com o jobprometheus(localhost:9090). Evidência:scrape_configs. - MET-2 (sobra) — todo job aponta para um serviço do catálogo com Métricas = sim, exceto jobs
node_exporter_*, que monitoram hosts/VMs (não aplicações). Evidência:scrape_configs.
Ao adicionar (por consumidor)¶
- Confirmar na documentação oficial a porta/caminho de métricas; adicionar o job em
prometheus.yml.j2(template estrutural) e citar na página da aplicação.
Ao remover (por consumidor)¶
- Remover o job do consumidor de
prometheus.yml.j2.
Ao remover o provedor¶
Remover prometheus.yml.j2 e as tarefas que o renderizam no setup-monitoring-stack-volumes.yml (via wiki); colocar Métricas = não em todas as aplicações; avaliar o grafana (datasource Prometheus).
logs¶
| Campo | Valor |
|---|---|
| Provedor | loki (coleta pelo promtail) |
| Aplica-se a | todas |
| Arquivos | compose do consumidor; ansible/templates/promtail-config.yml.j2 (renderizado por setup-monitoring-stack-volumes.yml e, na VM de IA, por setup-ai-volumes.yml) |
| Páginas | 01-manual-implementacao/07-deploy-apps.md; 01-manual-implementacao/08-stack-ia.md (promtail_ai) |
| Manual | — |
Regras¶
- LOG-1 — nenhum serviço da aplicação sobrescreve
logging:(o Promtail lê os logs JSON padrão do Docker em/var/lib/docker/containers). Evidência: compose do serviço. - LOG-2 — há um
promtailrodando na mesma VM da aplicação (hoje nacore-services-vm, serviçopromtailda stackapps, e naai-desktop-vm, serviçopromtail_aida stackai, que envia ao Loki pela porta 3100 publicada no IP dacore-services-vm). Evidência: catálogo (Stack/VM dopromtail) × Stack/VM da aplicação.
Ao adicionar (por consumidor)¶
- Não definir
logging:no compose. - Se a VM ainda não tem
promtail: apontar a lacuna no plano (LOG-2) e propor ao usuário.
Ao remover (por consumidor)¶
Nada a fazer.
Ao remover o provedor¶
Remover loki/promtail e promtail-config.yml.j2/loki-local-config.yaml.j2 (via wiki); avisar que os logs deixam de ser centralizados; revisar datasources do grafana.
dados¶
| Campo | Valor |
|---|---|
| Provedor | infra (ZFS no host Proxmox, exportado por NFS) |
| Aplica-se a | Dados ≠ nenhum |
| Arquivos | compose do consumidor (volumes:); playbook ansible/playbooks/setup-<stack>-volumes.yml correspondente |
| Páginas | página da aplicação; 04-manutencao-recuperacao/02-backup-restore-estrategia.md |
| Manual | — |
Regras¶
- DAD-1 — Dados =
nfs: os volumes de dados persistentes usam${VM_NFS_MOUNT_BASE_PATH}/…ou uma variável*_PATHcriada pelo playbook de volumes da stack (que a aponta para o NFS). Binds de sistema (/var/run/docker.sock,/etc/localtime, logs do Docker) não contam. Evidência:volumes:+ playbook. - DAD-2 — Dados =
local: a página da aplicação tem aviso de que os dados ficam fora dos snapshots ZFS e a página de backup lista a aplicação. Evidência: as duas páginas. - DAD-3 — o playbook
setup-<stack>-volumes.ymlcria os diretórios usados pela aplicação. Evidência: tasksansible.builtin.filedo playbook.
Ao adicionar (por consumidor)¶
nfs: diretórios no playbook de volumes e variável*_PATH(vervariaveis).local: diretório local no playbook, aviso na página e entrada na página de backup.
Ao remover (por consumidor)¶
- Remover os diretórios/variáveis da aplicação do playbook; não apagar dados — registrar no plano um passo manual de arquivamento/remoção dos dados no NFS ou disco.
- Retirar a aplicação da página de backup.
Ao remover o provedor¶
Não se aplica (infraestrutura base).
variaveis¶
| Campo | Valor |
|---|---|
| Provedor | infra (Ansible gera os .env; Portainer os carrega) |
| Aplica-se a | todas (exceto ansible:<role>) |
| Arquivos | docker/stacks/.env.template; ansible/playbooks/setup-*-volumes.yml e setup-core-networking.yml (geração do .env/environment); ansible/templates/portainer_stack_env.j2 |
| Páginas | 01-manual-implementacao/00-preparacao-planejamento.md (bloco literal do .env.template) |
| Manual | — |
Regras¶
- VAR-1 — toda
${VAR}(inclusive${VAR:-padrão}) usada em qualquer serviço da aplicação existe no.env.template. Evidência: compose ×.env.template. - VAR-2 — toda
${VAR}usada em qualquer serviço da aplicação é produzida por um playbook (tarefa que gera o.envouenvironment:do deploy). Variável compartilhada que não é produzida falha em todas as aplicações que a usam. "Produzida" = emitida com o mesmo nome; emissão condicional ({% if X is defined %}) só conta se algum playbook defineX. Evidência:grepda variável emansible/playbooks/eansible/templates/portainer_stack_env.j2. - VAR-3 (sobra) — nenhuma variável do
.env.templatedeixou de ser usada por todos os composes. Evidência:grepemdocker/stacks/*/docker-compose.yml.
Ao adicionar (por consumidor)¶
- Variáveis novas no bloco literal do
.env.template(página 00) →dev.py sync. - Geração no playbook da stack.
Ao remover (por consumidor)¶
- Remover do
.env.templatee do playbook somente as variáveis que nenhum outro serviço usa (grepem todos os composes antes). Variáveis compartilhadas comoSYSTEM_TIMEZONE,DOCKER_PUID,DOCKER_PGID,BASE_DOMAIN_FROM_VAULTpermanecem.
Ao remover o provedor¶
Não se aplica.
Origem dos valores¶
Toda variável é emitida pelo playbook da stack, com o nome exato usado no compose, a partir de uma fonte versionada — nunca com valor fixo no playbook. A tabela descreve as stacks implantadas pelo Portainer (apps, ai), que usam stack_configs; na stack core toda variável — inclusive as comuns e os segredos — é uma entrada em environment: do deploy em ansible/playbooks/setup-core-networking.yml.
| Tipo | Como reconhecer | Fonte do valor | Como o playbook emite |
|---|---|---|---|
| Comum | DOCKER_PUID, DOCKER_PGID, SYSTEM_TIMEZONE, BASE_DOMAIN_FROM_VAULT, VM_NFS_MOUNT_BASE_PATH, ZFS_*_DATASET_NAME |
vault / group_vars/all/main.yml |
já emitidas por ansible/templates/portainer_stack_env.j2 — nada a fazer |
| Segredo | senha, chave, token (*_PASSWORD*, *_KEY, *_SECRET*, *_TOKEN*) |
vault.yml, chave snake_case (ex.: litellm_master_key); placeholder obrigatório em vault.yml.example; valor sem $, #, aspas ou espaços (o .env não usa aspas) |
entrada { name: 'VAR', value: "{{ chave_vault }}" } em stack_configs; o playbook carrega o vault (vars_files) e a tarefa que grava o .env usa mode: '0600' |
| IP de host/VM | *_IP, *_IP_VAR |
[all:vars] do hosts.ini (core_services_vm_ip_var, ai_desktop_vm_ip_var, proxmox_host_ip_var) |
entrada em stack_configs com a variável do inventário |
| Caminho | *_PATH |
group_vars/all/main.yml (vm_nfs_mount_base_path, zfs_*_dataset_name) ou caminho local declarado no playbook |
entrada em stack_configs concatenando as variáveis |
| Configuração | demais (subdomínios, nomes, flags) | group_vars/all/main.yml |
entrada em stack_configs |
Playbook de cada stack: core → environment: do deploy em ansible/playbooks/setup-core-networking.yml; apps → setup-productivity-automation-volumes.yml (nextcloud, homeassistant), setup-media-stack-volumes.yml (mídia), setup-monitoring-stack-volumes.yml (monitoramento), setup-n8n-volumes.yml (n8n); ai → setup-ai-volumes.yml.
Segredo novo (sem chave no vault): proponha snake_case derivado do nome da variável e confirme com o usuário antes de criar.
llm¶
| Campo | Valor |
|---|---|
| Provedor | litellm |
| Aplica-se a | +llm |
| Arquivos | compose do consumidor (environment:); ansible/templates/litellm_config.yaml.j2 |
| Páginas | 01-manual-implementacao/08-stack-ia.md; 02-visao-geral-arquitetura/08-apis-llm-estrategia.md |
| Manual | — |
Regras¶
- LLM-1 — o consumidor aponta para o LiteLLM (variável com
http://litellm:4000) e depende do serviçolitellm. Evidência:environment:edepends_on:. - LLM-2 — o consumidor não recebe chaves de provedores externos (
OPENAI_API_KEY,ANTHROPIC_API_KEY,GEMINI_API_KEY); só olitellmas recebe. Evidência:environment:. - LLM-3 — consumidor e
litellmcompartilham uma rede (ai_network). Evidência:networks:.
Ao adicionar (por consumidor)¶
- Variável de base URL do LiteLLM,
depends_on: [litellm], redeai_network; modelos novos emlitellm_config.yaml.j2, se necessário.
Ao remover (por consumidor)¶
- Retirar variáveis,
depends_one a rede (se não usada por outro motivo); remover dolitellm_config.yaml.j2modelos usados só por ele.
Ao remover o provedor¶
Consumidores ficam sem LLM: remover +llm de todos e decidir com o usuário se eles saem ou passam a usar APIs diretas.
documentacao¶
| Campo | Valor |
|---|---|
| Provedor | wiki |
| Aplica-se a | todas |
| Arquivos | — |
| Páginas | 02-visao-geral-arquitetura/09-catalogo-aplicacoes.md; página da aplicação; INDEX.md (seção Aplicações) |
| Manual | — |
Regras¶
- DOC-1 — a aplicação tem linha no catálogo com todas as colunas preenchidas (sem
?). - DOC-2 — a página indicada na coluna Página existe e cita a aplicação (nome, serviço principal ou subdomínio).
- DOC-3 — o
INDEX.mdlista a aplicação na seção Aplicações. - DOC-4 (sobra) — todo serviço dos composes pertence a exatamente uma aplicação do catálogo. Evidência:
services:de cada compose × coluna Serviços. - DOC-5 (sobra) — todo serviço listado no catálogo existe no compose da stack (ou no role, para
ansible:<role>).
Ao adicionar (por consumidor)¶
- Linha no catálogo; seção na página da stack; skill
update-index.
Ao remover (por consumidor)¶
- Retirar a linha do catálogo e a seção/menções da página; skill
update-index.
Ao remover o provedor¶
Não se aplica.
Pendências da auditoria inicial¶
Desvios encontrados na primeira auditoria (2026-10-13) que dependem de decisão ou de refatoração. Os mecânicos (VAR-2 e DAD-3) foram corrigidos pela skill fix-integrations.
Nenhuma pendência de regra em aberto: LOG-2, ROT-3 e MET-2 foram decididas em 2026-10-13 (Promtail na VM de IA, Open WebUI protegida, job glances removido).
Fora das regras (registrados para a refatoração): LiteLLM aponta o Ollama para ai_desktop_vm_ip_var:11434, mas o Ollama escuta só em 127.0.0.1 (usar http://ollama:11434); cloudflared sem --metrics para o job cloudflared:2000; sobras do Plex em setup-media-stack-volumes.yml; MONITORING_GRAFANA_PROVISIONING_PATH gerada e não usada; authentication_backend comentado no configuration.yml.j2; full-deploy.yml não importa os playbooks de monitoramento e produtividade; a stack apps é um compose único, mas recebe cinco .env separados (hoje unidos à mão num apps.env, ver página 07); n8n com N8N_BASIC_AUTH_ACTIVE=true além do forward-auth do Authelia (login duplo); Public Hostname do túnel: o índice (acesso-externo) diz https://traefik:443 e a página 05 manda http://traefik:80; a página 08 cita o Ollama em http://ai-desktop-ip:11434, mas ele só escuta em 127.0.0.1, e o exemplo de config.yaml do LiteLLM na página difere do template; Open WebUI recebe LITELLM_API_BASE, que não parece ser variável reconhecida (o Open WebUI usa OPENAI_API_BASE_URL/OPENAI_API_KEY; validar); Grafana não monta a pasta de provisioning, então os datasources gerados pelo playbook não carregam; litellm publica 4000 em todas as interfaces sendo interna; portas publicadas pelo Docker (ex.: Loki 3100) contornam o UFW — a restrição real é a LAN; middleware nextcloud-headers em nextcloud_middleware.yml.j2 usa a chave pass: true, que não parece ser opção válida de headers no Traefik (validar).