Í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 (com No TLS Verify) 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 (os valores
${OPENAI_API_KEY},${ANTHROPIC_API_KEY},${GEMINI_API_KEY}); só olitellmas recebe. Uma variável do consumidor com nome de provedor que recebe${LITELLM_MASTER_KEY}(ex.:OPENAI_API_KEY=${LITELLM_MASTER_KEY}no Open WebUI) é a chave do proxy e é válida. 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.
notificacoes¶
| Campo | Valor |
|---|---|
| Provedor | n8n (workflow notificar, arquivo ansible/files/n8n/notificar.json); coletores: Grafana Alerting (ansible/templates/grafana/alerting/*.yml.j2), blackbox-exporter, diun |
| Aplica-se a | todas |
| Arquivos | ansible/templates/prometheus.yml.j2 (job blackbox_http); compose do consumidor (webhook nativo, se houver) |
| Páginas | página da aplicação; 01-manual-implementacao/09-painel-notificacoes.md |
| Manual | webhook configurado na interface da aplicação (NTF-3), quando ela não aceita configuração por arquivo ou variável |
Entrada única: POST /webhook/notificar no n8n com Authorization: Bearer <NOTIFICACOES_WEBHOOK_TOKEN> — interna http://n8n:5678/webhook/notificar (stack apps), externa https://n8n.<domínio>/webhook/notificar. A regra bypass do Authelia para n8n.{{ base_domain }} com resources: ["^/webhook/.*$"] é parte desta integração (não é desvio de AUT-3/AUT-4). Alertas globais (disco, RAM, CPU, ZFS, hosts, certificados, logins falhos no Authelia) ficam no provedor, em ansible/templates/grafana/alerting/rules.yml.j2, e não são por aplicação.
Regras¶
- NTF-1 — disponibilidade: aplicação com Exposição
publica/protegidatem alvo pela URL interna do serviço principal (ex.:http://n8n:5678/healthz; a URL pública passa pelo Authelia e não mede a aplicação) comlabels: {app: <id>}no jobblackbox_http; o alvo dotraefikusa o módulotls_traefik(mede também o certificado). Dasinterna, sólitellm(http://<ai_desktop_vm_ip_var>:4000/health/liveliness) eloki(http://loki:3100/ready) têm alvo — as demaisinterna→—. Evidência:prometheus.yml.j2. - NTF-2 — atualizações: existe um serviço do
diunna mesma VM da aplicação (Stack/VM dodiun× da aplicação). Evidência: catálogo e composes. - NTF-3 — eventos: aplicação com webhook nativo (
radarr,sonarr,homeassistant,jellyfinvia plugin) tem na sua página o passo "apontar o webhook para o n8n"; sem o passo documentado →✋. Demais →—. - NTF-4 (sobra) — nenhum alvo do
blackbox_httpnem regra de alerta comappque não exista no catálogo. Evidência:prometheus.yml.j2erules.yml.j2.
Ao adicionar (por consumidor)¶
- Alvo no
blackbox_http(NTF-1), se aplicável. - Se a VM ainda não tem
diun: apontar a lacuna no plano (NTF-2) e propor ao usuário. - Se a aplicação tem webhook nativo: passo manual na página dela (NTF-3).
Ao remover (por consumidor)¶
- Retirar o alvo do
blackbox_httpe o passo de webhook da página.
Ao remover o provedor¶
Desativar os coletores (contato n8n do Grafana, webhook do Diun e do scripts/notify.sh), remover ansible/files/n8n/notificar.json, a regra bypass de /webhook/ no Authelia e as variáveis TELEGRAM_*/NOTIFICACOES_WEBHOOK_TOKEN; avisar que as notificações param.
painel¶
| Campo | Valor |
|---|---|
| Provedor | homepage |
| Aplica-se a | Exposição ≠ interna |
| Arquivos | ansible/templates/homepage/services.yaml.j2; .env da Homepage (chaves HOMEPAGE_VAR_*) |
| Páginas | página da aplicação; 01-manual-implementacao/09-painel-notificacoes.md |
| Manual | gerar a chave de API na interface da aplicação e gravá-la no vault (PNL-2) |
Aplicação interna entra com +painel em Ajustes (atalho para a URL da LAN).
Regras¶
- PNL-1 — a aplicação tem entrada no
services.yaml.j2(nome = id do catálogo), no grupo da sua Categoria, comhrefhttps://<Subdomínio>.{{ base_domain }}(ou URL da LAN para+painel) e status: nacore-services-vm,server: coreecontainer: <container_name>(estado do container); em outra VM,siteMonitorpela URL da LAN (a URL pública passa pelo Authelia). Evidência: template. - PNL-2 — aplicação com widget oficial da Homepage (
jellyfin,radarr,sonarr,qbittorrent,nextcloud,homeassistant,grafana,prometheus,portainer) temwidgetna entrada; credenciais só como{{HOMEPAGE_VAR_<APP>_...}}, com valor vindo do vault (homepage_widget_keys.<app>, ougrafana_admin_initial_password) pelo playbook. Otraefikfica sem widget (a API só existe atrás do Authelia). Evidência: template, compose da Homepage e playbook. - PNL-3 (sobra) — nenhuma entrada no
services.yaml.j2sem aplicação correspondente no catálogo. Evidência: template.
Ao adicionar (por consumidor)¶
- Entrada no
services.yaml.j2(PNL-1); se houver widget: entrada, variávelHOMEPAGE_VAR_*no compose da Homepage,.env.template, chave emhomepage_widget_keysnovault.yml.examplee emissão no playbook (PNL-2); passo manual da chave na página 09.
Ao remover (por consumidor)¶
- Retirar a entrada, a variável
HOMEPAGE_VAR_*, a chave do vault e a emissão.
Ao remover o provedor¶
Remover homepage, docker-socket-proxy (se não usado por outro), os templates ansible/templates/homepage/ e as variáveis HOMEPAGE_VAR_*.
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 (para a reestruturação): a stack apps é um compose único, mas recebe cinco .env separados (hoje unidos à mão num apps.env, ver página 07); portas publicadas pelo Docker (ex.: Loki 3100, LiteLLM 4000) contornam o UFW — a restrição real é a LAN. Os demais itens registrados na auditoria inicial foram corrigidos em 2026-10-13.