From 8208a6783d6e2ffb57c1b3f85af7930971ab87f6 Mon Sep 17 00:00:00 2001 From: Pulse Agent Date: Wed, 20 May 2026 19:40:11 -0300 Subject: [PATCH] docs(dev): taskboard + backend API + agent worker + Obsidian vault index --- runbooks/dev-environment.md | 207 ++++++++++++++++++++++++++++++++++++ runbooks/dev-stack.yml | 191 +++++++++++++++++++++++++++++++++ 2 files changed, 398 insertions(+) create mode 100644 runbooks/dev-environment.md create mode 100644 runbooks/dev-stack.yml diff --git a/runbooks/dev-environment.md b/runbooks/dev-environment.md new file mode 100644 index 0000000..cac3eef --- /dev/null +++ b/runbooks/dev-environment.md @@ -0,0 +1,207 @@ +# πŸš€ Ambiente de Desenvolvimento Full-Stack β€” Docker Swarm + +## Arquitetura + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ DEV ORCHESTRATOR β”‚ +β”‚ (gerencia agentes, tasks, logs, hot reload) β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ FRONTEND β”‚ β”‚ BACKEND β”‚ β”‚ WORKERS β”‚ β”‚ +β”‚ β”‚ (Vite+React)β”‚ β”‚ Node+TS) β”‚ β”‚ (Agentes paralelos) β”‚ β”‚ +β”‚ β”‚ HMR: 5173 β”‚ β”‚ HMR: 3001 β”‚ β”‚ Python/Node/Go β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β†˜ β†˜ β†˜ β”‚ +β”‚ └───────────────┴────────── Redis Queue β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”‚ +β”‚ TaskBoard (live) β”‚ +β”‚ LogStream (live) β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +## Stacks + +| Stack | PropΓ³sito | +|-------|-----------| +| `dev` | Ambiente completo (frontend + backend + workers + Redis + taskboard + logs) | +| `dev-frontend` | Apenas Vite HMR (para desenvolvimento isolado) | +| `dev-backend` | Apenas API + workers | + +## Hot Reload + +### Frontend (React + Vite) +```yaml +services: + frontend: + image: node:24-alpine + working_dir: /app + volumes: + - ./frontend:/app:cached # cΓ³digo montado + - /app/node_modules # cache node_modules + command: sh -c "npm install && npm run dev -- --host 0.0.0.0" + networks: [public] + deploy: + replicas: 1 + endpoint_mode: dnsrr +``` + +### Backend (Node + ts-node) +```yaml +services: + backend: + image: node:24-alpine + working_dir: /app + volumes: + - ./backend:/app:cached + - /app/node_modules + command: sh -c "npm install && npx tsx watch src/server.ts" + networks: [public] +``` + +### Python Worker (uvicorn + watcher) +```yaml +services: + worker-py: + image: python:3.12-slim + volumes: + - ./workers/python:/app:cached + - /app/.venv + command: sh -c "pip install -r requirements.txt && watchmedo shell-command --patterns='*.py' --recursive --command='echo CHANGED'" + networks: [public] +``` + +## Logs em Tempo Real + +### OpΓ§Γ£o 1 β€” Loki + Promtail (filebeat alternativa) +```yaml +services: + promtail: + image: grafana/promtail:latest + volumes: + - /var/log:/var/log:ro + - ./promtail-config.yml:/etc/promtail/config.yml + command: -config.file=/etc/promtail/config.yml +``` + +### OpΓ§Γ£o 2 β€” Direto no Dev Orchestrator (stdout aggregator) +```yaml +services: + logstream: + image: node:24-alpine + command: node -e " + const {Redis} = require('ioredis'); + const r = new Redis(process.env.REDIS_URL); + r.subscribe('dev-logs', (err) => { + if(err) return; + r.on('message', (ch, msg) => process.stdout.write(msg)); + }); + " + depends_on: [{service: redis, condition: service_healthy}] +``` + +## Task Queue + Dev Board + +```yaml +# Redis Queue + redis: + image: redis:8-alpine + command: redis-server --appendonly yes --save 5 1 + volumes: + - redis-data:/data + healthcheck: + test: ['CMD', 'redis-cli', 'ping'] + interval: 5s + timeout: 3s + retries: 3 + +# Task Board Web + taskboard: + image: node:24-alpine + working_dir: /app + volumes: + - ./taskboard:/app + command: sh -c "npm install && npm run dev -- --host 0.0.0.0" + ports: + - target: 5174 + published: 3082 + protocol: tcp + mode: host + environment: + - REDIS_URL=redis://redis:6379 + networks: [public] + labels: + - caddy=board.octal.tec.br + - caddy.reverse_proxy={{upstreams 5174}} + +# Worker Agents (paralelos) + worker-a: # Frontend specialist + image: node:24-alpine + command: node /app/workers/agent-a.js + environment: + - REDIS_URL=redis://redis:6379 + - AGENT_ROLE=frontend + - TASK_QUEUE=dev-tasks + depends_on: [{redis, condition: service_healthy}] + + worker-b: # Backend specialist + image: node:24-alpine + command: node /app/workers/agent-b.js + environment: + - REDIS_URL=redis://redis:6379 + - AGENT_ROLE=backend + - TASK_QUEUE=dev-tasks + + worker-c: # DevOps / infra specialist + image: python:3.12-slim + command: python /app/workers/agent-c.py + environment: + - REDIS_URL=redis://redis:6379 + - AGENT_ROLE=devops + - TASK_QUEUE=dev-tasks +``` + +## Task Protocol (Redis) + +```json +// Tarefa enfileirada +{ + "id": "uuid", + "type": "feature|bug|refactor|test", + "priority": "low|medium|high|critical", + "domain": "frontend|backend|devops|fullstack", + "title": "...", + "description": "...", + "files_affected": ["src/..."], + "acceptance_criteria": ["..."], + "created_at": "2026-05-20T19:00:00Z", + "status": "pending|in_progress|done|blocked" +} +``` + +## Volumes + +```yaml +volumes: + redis-data: +``` + +## Deploy + +```bash +docker stack deploy -c runbooks/dev-stack.yml dev +``` + +## Acesso + +| ServiΓ§o | URL | DescriΓ§Γ£o | +|---------|-----|-----------| +| Task Board | `board.octal.tec.br` | Kanban + task queue em tempo real | +| Frontend HMR | `frontend.octal.tec.br` | Vite React com hot reload | +| Backend API | `api.octal.tec.br` | API Node com hot reload (tsx watch) | +| Log Stream | `logs.octal.tec.br` | Logs agregados de todos os workers | + +## πŸ”— Links Úteis +- `board.octal.tec.br` β†’ TaskBoard (kanban + logs) +- `api.octal.tec.br` β†’ API REST (health, tasks, agents) +- `frontend.octal.tec.br` β†’ Frontend HMR +- Vault Obsidian: `/root/Obsidian-Pulse/` β€” `Projetos/pulse-dev.md` diff --git a/runbooks/dev-stack.yml b/runbooks/dev-stack.yml new file mode 100644 index 0000000..9b60c46 --- /dev/null +++ b/runbooks/dev-stack.yml @@ -0,0 +1,191 @@ +version: '3.9' + +networks: + public: + external: true # overlay swarm β€” Attachable=false + +volumes: + redis-data: + dev-frontend-node_modules: + dev-backend-node_modules: + +services: + + # ─── FILA DE TAREFAS + COORDENAÇÃO ─────────────────────────────── + redis: + image: redis:8-alpine + networks: [public] + volumes: + - redis-data:/data + deploy: + replicas: 1 + endpoint_mode: dnsrr + healthcheck: + test: ['CMD', 'redis-cli', 'ping'] + interval: 5s + timeout: 3s + retries: 3 + start_period: 10s + + # ─── TASKBOARD WEB (React standalone β€” sem build, direto no nginx) ── + taskboard: + image: nginx:alpine + networks: [public] + volumes: + - /root/.openclaw/workspace/pulse-dev/taskboard/public:/usr/share/nginx/html:ro + - /root/.openclaw/workspace/pulse-dev/taskboard/public/nginx.conf:/etc/nginx/conf.d/default.conf:ro + deploy: + replicas: 1 + endpoint_mode: dnsrr + labels: + - caddy=board.octal.tec.br + - caddy.reverse_proxy={{upstreams 80}} + depends_on: + redis: + condition: service_healthy + + dev-frontend: + image: node:24-alpine + working_dir: /app + networks: [public] + volumes: + - /root/.openclaw/workspace/pulse-dev/frontend:/app:cached + - dev-frontend-node_modules:/app/node_modules + command: > + sh -c " + if [ ! -d node_modules ]; then + npm install react react-dom vite @vitejs/plugin-react typescript --save-dev 2>/dev/null; + fi && + echo 'FRONTEND hot reload iniciado em :5173' && + npx vite --host 0.0.0.0 --port 5173 + " + deploy: + replicas: 1 + endpoint_mode: dnsrr + labels: + - caddy=frontend.octal.tec.br + - caddy.reverse_proxy={{upstreams 5173}} + healthcheck: + test: ['CMD-SHELL', 'wget -qO- http://localhost:5173 | head -1'] + interval: 15s + timeout: 5s + retries: 3 + + dev-backend: + image: node:24-alpine + working_dir: /app + networks: [public] + volumes: + - /root/.openclaw/workspace/pulse-dev/backend:/app:cached + - dev-backend-node_modules:/app/node_modules + environment: + - REDIS_URL=redis://redis:6379 + - NODE_ENV=development + command: > + sh -c " + if [ ! -d node_modules ]; then + npm install tsx express ioredis cors helmet --save-dev 2>/dev/null; + fi && + echo 'BACKEND hot reload iniciado em :3001' && + npx tsx watch --dir ./src server.ts + " + deploy: + replicas: 1 + endpoint_mode: dnsrr + labels: + - caddy=api.octal.tec.br + - caddy.reverse_proxy={{upstreams 3001}} + depends_on: + redis: + condition: service_healthy + + agent-frontend: + image: node:24-alpine + working_dir: /app + networks: [public] + volumes: + - /root/.openclaw/workspace/pulse-dev/agents/frontend:/app:cached + - dev-frontend-node_modules:/app/node_modules + command: > + sh -c " + if [ ! -f /app/agent.js ]; then echo 'ESPERANDO CODIGO DO AGENTE FRONTEND' && sleep infinity; fi && + if [ ! -d node_modules ]; then npm install ioredis uuid --save 2>/dev/null; fi && + node /app/agent.js + " + environment: + - REDIS_URL=redis://redis:6379 + - AGENT_ID=agent-frontend + - AGENT_ROLE=frontend + - TASK_QUEUE=dev-tasks + - LOG_CHANNEL=dev-logs + deploy: + replicas: 2 + endpoint_mode: dnsrr + depends_on: + redis: + condition: service_healthy + restart_policy: + condition: on-failure + max_attempts: 5 + delay: 5s + + agent-backend: + image: node:24-alpine + working_dir: /app + networks: [public] + volumes: + - /root/.openclaw/workspace/pulse-dev/agents/backend:/app:cached + - dev-backend-node_modules:/app/node_modules + command: > + sh -c " + if [ ! -f /app/agent.js ]; then echo 'ESPERANDO CODIGO DO AGENTE BACKEND' && sleep infinity; fi && + if [ ! -d node_modules ]; then npm install ioredis uuid --save 2>/dev/null; fi && + node /app/agent.js + " + environment: + - REDIS_URL=redis://redis:6379 + - AGENT_ID=agent-backend + - AGENT_ROLE=backend + - TASK_QUEUE=dev-tasks + - LOG_CHANNEL=dev-logs + deploy: + replicas: 2 + endpoint_mode: dnsrr + depends_on: + redis: + condition: service_healthy + restart_policy: + condition: on-failure + max_attempts: 5 + delay: 5s + + agent-devops: + image: node:24-alpine + working_dir: /app + networks: [public] + volumes: + - /root/.openclaw/workspace/pulse-dev/agents/devops:/app:cached + - /usr/local/bin/docker:/usr/local/bin/docker:ro + - /var/run/docker.sock:/var/run/docker.sock:ro + command: > + sh -c " + if [ ! -f /app/agent.js ]; then echo 'ESPERANDO CODIGO DO AGENTE DEVOPS' && sleep infinity; fi && + npm install ioredis uuid 2>/dev/null && + node /app/agent.js + " + environment: + - REDIS_URL=redis://redis:6379 + - AGENT_ID=agent-devops + - AGENT_ROLE=devops + - TASK_QUEUE=dev-tasks + - LOG_CHANNEL=dev-logs + deploy: + replicas: 1 + endpoint_mode: dnsrr + depends_on: + redis: + condition: service_healthy + restart_policy: + condition: on-failure + max_attempts: 5 + delay: 5s