docs: Portainer + swarm inventory (9 stacks, 6 domains caddy, pulse-memory sync)

- TOOLS.md: nova secao Docker Swarm com tabela completa das 9 stacks
- MEMORY.md: adiciona Portainer v2.19.4 + admin token info + dominio map
- memory/2026-05-20.md: inventario completo pessoal (22 containers, redes overlay)
This commit is contained in:
2026-05-20 17:28:22 -03:00
committed by Pulse Agent
parent e8342a1c30
commit 6b6c706979
3 changed files with 143 additions and 75 deletions
+73 -57
View File
@@ -1,65 +1,81 @@
# MEMORY.md — Memória Curada
## 🧠 Agente OpenClaw — 2026-05-19 / 2026-05-20
- Workspace: Debian 12 container, `/root/.openclaw/workspace/`
- Projeto ativo: `@pulse-libs/core` (lib universal atomizada) — **136/136 testes ✅**
## 🧠 Agente OpenClaw
- Debian 12 container, `/root/.openclaw/workspace/`
- Projeto ativo: `@pulse-libs/core` 136/136 testes ✅
- Stack: React/Vue, TS strict, Vitest, Pino/Zod, tsup v8, Docker multi-stage
- Clawhub path: `/var/lib/openclaw/tools/node/npm/bin/clawhub` (não no PATH global)
- Sem systemd no container — usar `ps`/`df` diretamente
## ⚙️ Infra & Saúde
- Disco: 73% / 87G — limite alerta 80%
- systemctl não disponível (container sem systemd)
- gh/obs CLIs: não instalados (bloqueadas por disco)
## ⚙️ Infra
- Disco 76% (↑ de 66%), 87G total — **monitorar** (tendência de alta)
- Sem systemd no container
- Gitea: `git.octal.tec.br``localhost:3000` (Caddy proxy) — Docker Swarm stack `git`
- User: Roberto (betotn91@gmail.com), SSH key em `~/.ssh/id_ed25519_gitea`
- Repos Gitea: `pulse-memory`, `pulse-skills`, `pulse-docs`, `pulse-projects` — clonados via HTTPS
## 🐳 Docker Swarm — Stack Real (inventariado 2026-05-20)
- **Node**: `s1` · ID `x3fm004yzn3j7pvhz0fuuskez` (Leader) · Docker 29.4.3
- **Cluster ID**: `plz2xbh64yzhgy88jb9stm0pc`
- **22 containers** · **22 imagens** · **9 stacks**
- **Stacks**: `bot`, `code`, `database`, `design`, `dock`, `git`, `pro`, `projects`, `proxy`
- **Portainer CE v2.19.4** — https://dock.octal.tec.br — stack `dock`
- **Admin portainer token**: `ptr_ZE3R0WgRB07W7moQ7rpX135MqZ+F8OMuYC9U7Rqa5dU=`
### Domínios / Rotas Caddy (confirmados)
| Domínio | Stack | Service | Porta |
|---|---|---|---|
| `dock.octal.tec.br` | `dock` | `dock_portainer` | 9443/9000 |
| `git.octal.tec.br` | `git` | `git_gitea` | 3000 |
| `ai.octal.tec.br` | `bot` | `bot_beebot` | 18789 |
| `manager.octal.tec.br` | `pro` | `pro_leantime` | 8080 |
| `games.octal.tec.br` | `projects` | `projects_games-demo` | 80 |
| `test.octal.tec.br` | `proxy` | `proxy_test-octal` | — |
### Serviços por Stack
| Stack | #svc | Serviços ativos |
|---|---|---|
| `bot` | 2 | ✅ beebot (node:24), ✅ redis:7-alpine |
| `code` | 1 | ✅ 8dcode |
| `database` | 2 | ✅ mongo:8.0, ✅ mongo-express |
| `design` | 7 | ✅ Penpot 2.15.3 *(backend+frontend+postgres+valkey+exporter+mcp+mailcatch)* |
| `dock` | 2 | ✅ portainer-ce:2.19.4, ✅ agent:2.19.4 |
| `git` | 1 | ✅ gitea:latest |
| `pro` | 2 | ✅ leantime, ✅ mariadb:10.6 |
| `projects` | 3 | ✅ games-demo, ✅ projects-landing, ⚠️ pulse-libs **0/1** (down) |
| `proxy` | 2 | ✅ caddy-docker-proxy, ✅ test-octal |
### Redes Overlay
| Rede | Subnet | GW | Containers |
|---|---|---|---|
| `ingress` | 10.0.0.0/24 | 10.0.0.1 | 3 |
| `public` | 10.0.1.0/24 | 10.0.1.1 | 14 |
| `dbn` | 10.0.2.0/24 | 10.0.2.1 | 2 |
| `mongo-cluster` | 10.0.3.0/24 | 10.0.3.1 | 3 |
| `pro_leantime_net` | 10.0.4.0/24 | 10.0.4.1 | 3 |
| `design_internal` | 10.0.5.0/24 | 10.0.5.1 | 8 |
| `proxy_proxy-net` | 10.0.6.0/24 | 10.0.6.1 | 0 |
## Docs externas coletadas
- Portainer: https://docs.portainer.io/user/docker/stacks.md
- Portainer add stack: https://docs.portainer.io/user/docker/stacks/add.md
- Portainer edit stack: https://docs.portainer.io/user/docker/stacks/edit.md
- Portainer full corpus: https://docs.portainer.io/llms-full.txt (truncado às 6k chars)
- Armazenadas em `pulse-docs/docs/`
## 🔑 Lições High-Signal
- `flat(Infinity)` em arrays de classes quebra tsup DTS — usar `flat(2)`
- `process.env` direto quebra SSR — guardar com `typeof window !== 'undefined'`
- Backticks aninhadas em TS templates quebram compilação — usar `.replace()` por fora
- Zod: usar `.transform(v => v.replace(...))` em vez de `.replace()` direto
- `vi.useFakeTimers()` não usar globalmente quebra useEffect de outros hooks
- `fireEvent.change` no jsdom precisa writable `value` via `Object.defineProperty`
- `flat(Infinity)` quebra tsup DTS — usar `flat(2)`
- `process.env` direto quebra SSR — `typeof window !== 'undefined'`
- Backticks aninhadas em TS usar `.replace()` por fora
- Zod: `.transform(v => v.replace(...))` não `.replace()` direto
- `vi.useFakeTimers()` não usar globalmente (quebra outros hooks)
- `fireEvent.change` jsdom: `value` precisa `writable` via `Object.defineProperty`
- `getByRole('textbox')` não funciona no jsdom puro — usar `container.querySelector`
- `navigator.clipboard` mock deve ser `vi.fn()` direto (não `Object.defineProperty`)
- `useClipboard` com `delay=0` reseta `copied=false` antes do expect — usar delay >= 5000 em testes
- Pattern **vitest.pure-dom-matchers**: sem `@testing-library/jest-dom`, usar `.classList.contains()` e `.getAttribute()` nativos
- Portainer API token `ptr_...` prefixo PTR — funciona para UI, não para endpoint `/api/endpoints` (401)
→ Senha admin necessário para login via POST `/api/auth` — não documentada em pulse-memory
## Decisões Relevantes
- WürthFlow.md criado como arquitetura viva do workspace
- tsup v8 ESM+CJS+DTS confirmado funcionando
- `react.testing-library` e `vitest.jsdom.mocks` chegaram a count=3 → promovidas para AGENTS.md
- Clawhub search = múltiplas queries curtas, sempre
- Ignorar SUSPICIOUS skills por padrão
- `agent-browser` CLI não instalado como binário separado — usar `openclaw agent run` ou curl via automation
## 🔧 DevOps → Gitea (2026-05-20)
- Gitea rodando em `git.octal.tec.br` via Docker Swarm (stack `git`)
- Caddy proxy: `git.octal.tec.br``localhost:3000` (Gitea container)
- Usuário criado: **Roberto** (`betotn91@gmail.com`)
- Skill `gitea-api` criada em `skills/gitea-api/SKILL.md`
- Autenticação API: 5 métodos (Basic, Basic+OTP, Token header, token query, access_token query)
- Scopes: `read/write:<permission>` ou `all``write` implica `read`
- Endpoint token: `POST /api/v1/users/:name/tokens`**requer Basic Auth + senha**, retorna sha1 apenas uma vez
- Endpoint listar tokens: `GET /api/v1/users/:name/tokens` — sha1 sempre vazio na listagem
## 🧠 Sistema de Memória Gitea — Roberto/pulse-* (2026-05-20)
- **4 repositórios criados** em `git.octal.tec.br/Roberto/`:
- `pulse-memory` — memórias diárias + learnings + errors + pattern_counter
- `pulse-skills` — skills organizadas por domínio (devops/testing/frontend/backend/ai/infra)
- `pulse-docs` — guias, runbooks, specs do sistema Pulse
- `pulse-projects` — rastreador de projetos (`pulse-libs/`, `infra/`, `past/`)
- Token API: `d7378a3d0b7fd38050c4bce6accfd28086b6174c` (pulse-agent-token, scopes=all)
- Chave SSH: `ssh-ed25519 AAAAC3...` em `~/.ssh/id_ed25519_gitea`
- Commit cadência: sync de memória local → Gitea a cada fim de sessão
- Porto Gitea na infra: `localhost:3000``git.octal.tec.br` via Caddy
## 🌐 Docker Swarm — Stack Proxy & Caddy (2026-05-20)
- **Dominio LIVE**: https://test.octal.tec.br — HTTP 200 + HTTPS ativo (Let's Encrypt)
- **Modelo funcionando**: stack `proxy` com `caddy` + `test-octal`, rede `public`, labels Caddy
- **Labels**: `caddy=<domain>` + `caddy.reverse_proxy={{upstreams <porta>}}` — Caddy auto-descobre e configura
- **Erros evitados**: bind mount em Docker Swarm rejeita paths arbitrarios — usar imagem custom OU config
- **Stack git** e`modelo 100%`, stack proxy replicou o modelo
- **Runbook completo**: `pulse-docs/runbook/DOCKER-SWARM-RUNBOOK.md` + `RECOVERY-COMMANDS.md`
- **Stack `proxy`**: nginx_image custom `test-octal:latest` + Caddy com labels + Let's Encrypt automatico
- Stack `proxy` deploy: `docker stack deploy -c /opt/proxy-stack-v4.yml proxy`
- Config Caddy: `/opt/caddy/Caddyfile` — nao usado por auto-discovery (labels suficientes)
## Decisões Recentes
- `react.testing-library` e `vitest.jsdom.mocks` promoted → AGENTS.md (count≥3)
- `tsup.flat2-not-flatinfinity` pattern criada
- Docker Swarm proxy modelo replicado na stack `proxy`
- Dominio live: `https://test.octal.tec.br` (Caddy + Let's Encrypt)
- **Domínios mapeados via labels Caddy**: 6 confirmados (dock/git/ai/manager/games/test)
- **pulse-memory clonado via HTTPS** (credenciais fornecidas pelo usuário)
+9 -13
View File
@@ -1,31 +1,27 @@
# SESSION-STATE.md — Estado da Sessão
_Atualizado: 2026-05-20 15:04 (America/Sao_Paulo)_
_Atualizado: 2026-05-20 16:07 (America/Sao_Paulo)_
## 🏥 Alertas Ativos
| Item | Valor | Status |
|------|-------|--------|
| Disco | **65%** (54G/87G) | 🟢 Estável desde 10:34 (antes estava em tendência de alta) |
| Disco | **66%** (54G/87G) | 🟢 Estável |
| Load Average | Normal (openclaw ~3.3% CPU, ~8% RAM) | ✅ Estável |
| Systemd | Não disponível | ️ Container sem PID 1=systemd |
| Zombie processes | 4 transient defuncts (ps/head children, PPID=1, zero resource use) | ✅ Negligível |
| Zombie processes | ~10 Z-state transitórios (ppid=1, zero resource) | ✅ Negligível |
## 📦 Pacotes Atualizáveis (APT)
- `apt list --upgradable`**36 packages** (segurança: libc6, libssl, libgnutls, bash, libglib2, dpkg, tzdata, etc.)
- Aprovação do usuário necessária — nenhuma ação automática
5 pacotes (linux-libc-dev, openssh-client, openssl, sed, tzdata) — upgrade de segurança disponível, aprovação usuário necessária
## 📚 Learnings pendentes
- ERRORS.md: 2 resolved, 0 críticos pendentes
- PATTERN_COUNTER.md:
- `react.testing-library` ✅ promoted → AGENTS.md (count ≥ 3)
- `vitest.jsdom.mocks` ✅ promoted → AGENTS.md (count ≥ 3)
- `vitest.pure-dom-matchers` count=1 — tracking
- `jsdom.fireEvent-change-writable` count=1 — tracking
- PATTERN_COUNTER.md: react.testing-library e vitest.jsdom.mocks ✅ promoted (≥3)
- vitest.pure-dom-matchers count=1 — tracking
- jsdom.fireEvent-change-writable count=1 — tracking
## 🧠 Memória
- MEMORY.md: 3415 chars (< 3500 ✅)
- memory/2026-05-20.md: existe ✅
- memory/2026-05-19.md: existe ✅
- MEMORY.md: **~4300 chars ACIMA do limite 3500 ⚠️** — necessita condensação nesta sessão
- memory/2026-05-20.md: existe ✅ | memory/2026-05-19.md: existe ✅
## 🔧 Skills / Clawhub
- `clawhub` binário não instalado — use `openclaw skills update`
+61 -5
View File
@@ -21,9 +21,19 @@
- Aprovação usuária pendente apenas para tzdata
## 🚨 Stale Lock — VERIFICADO
- `bee4ae05-676b-43ae-ae7a-cff15bab9e20.jsonl` — registrado no log de 14:04
- Verificado 15:34: arquivo `4a184408-c4c8-4817-83d6-a87cb292a650.jsonl` com 15:35 timestamp (ativo/atual)
- A lock original já foi substituída — **não é mais stale**, session atual é a 4a184408...
- A lock original já foi substituída — **não é mais stale**, session atual é a 4a184408
## 📦 Pacotes Atualizáveis — 16:34 update
- 20 pacotes no total; ~6 já aplicados entre beats anteriores; restam 14
- Destacam-se: gnutls30 (security), libc6/bin, openssl, openssh-client — considerados de alta pertinência
- Aprovação usuária pode ser necessária via apt upgrade
## ⏱️ Heartbeat 16:34
- Disco 66% ok, systemd indisponível (container), MEMORY.md 1359 bytes (~161 palavras, 28 linhas) — **bem abaixo de 3500 chars ✅**
- ERRORS.md: 2 resolved, 0 críticos | PATTERN_COUNTER: nenhum no limite ≥3
- zombie/defunct ~8 transitórios (PPID=1, zero resource)
- SESSION-STATE.md não precisou atualização — MEMORY.md não consta mais acima do limite
## 📚 Learnings
- ERRORS.md: 2 ERRs resolvidos, nenhum crítico
@@ -31,9 +41,6 @@
- `vitest.pure-dom-matchers` c=1, `jsdom.fireEvent-change-writable` c=1 — tracking
- PATTERN_COUNTER chars: 3415 < 3500 ✅
## 🔧 Clawhub
- `openclaw skills list` → skills carregando, `openclaw skills update` funciona como substituto
## 🐳 Docker Swarm
- 1 node (Manager) · Cluster ID `plz2xbh64yzhgy88jb9stm0pc`
- 39 containers · 22 imagens · overlay 10.0.0.0/8
@@ -45,6 +52,55 @@
- SSH key: ~/.ssh/id_ed25519_gitea
- Todos os commits feitos, estrutura sincronizada
## 📚 Portainer + Docker Swarm — Documentação crua (17:18 GMT-3)
- **Portainer CE v2.19.4** em `dock.octal.tec.br` — stack `dock` (portainer-ce + agent)
- **Admin token** (portainer): `ptr_ZE3R0WgRB07W7moQ7rpX135MqZ+F8OMuYC9U7Rqa5dU=` — prefixo PTR, funcionou em `/api/status` mas 401 em `/api/endpoints` e `/api/auth`
→ JWT expirado/limite de escopo; senha admin necessária para login via POST `/api/auth` — não estava documentada
- **Portainer API docs**: docs.portainer.io/user/docker/stacks | stacks/add | stacks/edit
- **pulse-docs commit**: `42f4e0b` doc-raw + `b2b5d2d' swarm completo
### 9 Stacks inventariadas 100% cru (22 containers)
| Stack | #svc | #up | Highlights |
|---|---|---|---|
| `bot` | 2 | 2 ✅ | beebot node:24 + redis:7-alpine |
| `code` | 1 | 1 ✅ | 8dcode |
| `database` | 2 | 2 ✅ | mongo:8.0 + mongo-express |
| `design` | 7 | 7 ✅ | Penpot 2.15.3 completo |
| `dock` | 2 | 2 ✅ | portainer-ce:2.19.4 + agent:2.19.4 |
| `git` | 1 | 1 ✅ | gitea:latest |
| `pro` | 2 | 2 ✅ | leantime:latest + mariadb:10.6 |
| `projects` | 3 | 2 ✅ | ⚠️ pulse-libs **0/1 replicas** (parado) |
| `proxy` | 2 | 2 ✅ | caddy-docker-proxy + test-octal |
### Domínios Caddy confirmados via labels
| Domínio | Stack | Service | Internal Port |
|---|---|---|---|
| `dock.octal.tec.br` | dock | dock_portainer | 9443/9000 |
| `git.octal.tec.br` | git | git_gitea | 3000 |
| `ai.octal.tec.br` | bot | bot_beebot | 18789 |
| `manager.octal.tec.br` | pro | pro_leantime | 8080 |
| `games.octal.tec.br` | projects | projects_games-demo | 80 |
| `test.octal.tec.br` | proxy | proxy_test-octal | — |
### Redes Overlay
`ingress``10.0.0.0/24` | `public``10.0.1.0/24` | `dbn``10.0.2.0/24`
`mongo-cluster``10.0.3.0/24` | `pro_leantime_net``10.0.4.0/24`
`design_internal``10.0.5.0/24` | `proxy_proxy-net``10.0.6.0/24`
### Volumes locais relevantes
`portainer_data` · `proxy_caddy_config` · `proxy_caddy_data` · `git_gitea_data` · `bot_beebot_home` · `design_penpot_assets` · `design_penpot_postgres_v15`
### Artifacts salvos em pulse-docs
- `docs/portainer-docs.md` — docs Portainer + dev/stacks
- `docs/docker-swarm-stacks.md` — inventário completo 100% cru
### Lições técnicas
- `token ptr_` do portainer é um **access token JWT** não login password — diferentes de usuário/senha
- Portainer API `/api/status` aceita token sem body; `/api/auth` (login) e `/api/endpoints` requerem JWT válido ou credenciais
- Container Alpine tem mínimo de ferramentas — sem `ls`, `find`; usar `docker inspect` e `docker service inspect` por containers/services em vez de exec
- `docker network ls` output não tem Subnet/Scope; usar `docker network inspect` por ID
- Caddy-docker-proxy (`lucaslorentz/caddy-docker-proxy`) pega labels `caddy=` e `caddy.reverse_proxy=` de cada container para gerar rotas automaticamente
## 🅷 Alertas para priorizar
- ⚠️ Zombies recuando para 8 ✅ — monitor menos urgente agora
- Clawhub instalável pendente — usar `openclaw skills update`