chore: limpa arquivos temporários e cache

Remove:
- Cache do aider (.aider.tags.cache.v4)
- Arquivos de planejamento antigos (.planning/)
- Arquivos duplicados (MAPA_TENANTS_ARCADIA copy, SESSAO_2026-03-18)
- Metadata de agentes (.agents/)

Refs: cleanup, maintenance
This commit is contained in:
Jonas Pacheco 2026-04-08 11:26:56 -03:00
parent 14e440cc1f
commit 6182a9c490
78 changed files with 54 additions and 3870 deletions

View File

@ -1,38 +0,0 @@
uploads = []
generated = []
[[outputs]]
id = "28NDwt4UT3HPglsSw-IQk"
uri = "file://MAPA_MICROSERVICOS_COOLIFY.md"
type = "text"
title = "Mapa de Microserviços - Arcádia Suite para Coolify/Docker"
[[outputs]]
id = "YTVCn39myPk5kzF8smbQz"
uri = "file://MAPA_SOE_ARCADIA.md"
type = "text"
title = "Mapa SOE — Sistema Operacional Empresarial (Deploy)"
[[outputs]]
id = "pQjx1X6m9hp2j-sZa0_Rg"
uri = "file://MAPA_BI_ARCADIA.md"
type = "text"
title = "Mapa BI - Business Intelligence da Arcádia Suite (com Metabase)"
[[outputs]]
id = "gpyYTqB0ytdU1zAJij6KK"
uri = "file://MAPA_CRM_ARCADIA.md"
type = "text"
title = "Mapa CRM - Sistema de Relacionamento da Arcádia Suite"
[[outputs]]
id = "zal1KfcZdP7OqKEXu67Pp"
uri = "file://MAPA_TENANTS_ARCADIA.md"
type = "text"
title = "Mapa Multi-Tenant - Gestão de Tenants da Arcádia Suite"
[[outputs]]
id = "GCMgcBAHQ1aIDjHxoXniQ"
uri = "file://MAPA_AUTOMACOES_ARCADIA.md"
type = "text"
title = "Mapa Automações - Motor de Automação da Arcádia Suite"

Binary file not shown.

View File

@ -1,475 +0,0 @@
# Fase 4: OpenClaw Embutido — Plano de Implementação
**Fase:** 4
**Data Início:** 2026-03-26
**Prazo:** 2026-04-08 (Semanas 7-8)
**Status:** 🔄 Sprint 3 Pendente (Sprint 1 e 2 concluídos)
---
## 1. OBJETIVO DA FASE
Implementar **detecção proativa de padrões** e **sugestão emergente de skills**, transformando comportamentos repetitivos do usuário em automações reutilizáveis através de um widget conversacional flutuante.
### Entregável Final
✅ Skills emergentes funcionando end-to-end:
- Usuário executa ação repetida → PatternDetector detecta → OpenClawWidget sugere → Blackboard gera DRAFT → Dev Center aprova → Skill disponível
---
## 2. ARQUITETURA
```
FLUXO OPENCCLAW:
1. USER INTERACTION
└─ Usuário usa Arcádia
└─ Learning API registra evento (já existe)
└─ Neo4j armazena interação
2. PATTERN DETECTION (NOVO)
└─ PatternDetector analisa Learning API
└─ Identifica: 3+ ocorrências em 30 dias
└─ Calcula confiança (threshold 0.8+)
└─ Dispara evento no Socket.IO
3. WIDGET SUGGESTION (NOVO)
└─ OpenClawWidget fica "ouvindo"
└─ Recebe evento de padrão detectado
└─ Exibe notificação flutuante
└─ Modal SkillSuggestion mostra preview
4. SKILL GENERATION (NOVO)
└─ Usuário confirma
└─ OpenClawEngine chama Blackboard
└─ Blackboard gera código (DRAFT)
└─ Armazena em database
5. APPROVAL FLOW (EXISTENTE - Dev Center)
└─ Skill DRAFT aparece em Dev Center
└─ Admin/Lead revisa e aprova
└─ Publica no tenant
└─ Skill fica disponível para reutilização
```
### Componentes para Implementar
```
BACKEND:
server/modules/openclaw/
├── PatternDetector.ts ← [NOVO] Detecta padrões
├── SkillEmergence.ts ← [NOVO] Coordena criação
├── OpenClawEngine.ts ← [NOVO] Lógica central
├── config/
│ └── arcadia.config.yaml ← [NOVO] Configuração
FRONTEND:
client/src/components/openclaw/
├── OpenClawWidget.tsx ← [NOVO] Widget flutuante
├── PatternDetector.ts ← [NOVO] Hook de detecção
├── SkillSuggestion.tsx ← [NOVO] Modal de sugestão
└── useAgentEmergence.ts ← [NOVO] Lógica de emergência
```
---
## 3. DEPENDÊNCIAS VERIFICADAS
| Componente | Status | Localização |
|-----------|--------|-----------|
| **Skills Engine** | ✅ Pronto | `server/skills/engine.ts` |
| **Blackboard** | ✅ Pronto | `server/blackboard/service.ts` |
| **Dev Center** | ✅ Pronto | `client/src/pages/DevCenter.tsx` |
| **Learning API** | ✅ Existe | `/api/learning/*` |
| **Neo4j (KG)** | ✅ Running | Docker |
| **Socket.IO** | ✅ Configurado | `server/socket-io.ts` |
| **PostgreSQL** | ✅ Rodando | Docker |
| **Scientist (MiroFlow)** | ✅ Existe | `/api/manus/scientist/*` |
**Conclusão:** Todas as dependências estão prontas ✅
---
## 4. TASKS DETALHADAS
### SPRINT 1 (26-27/03): PatternDetector Backend — ✅ COMPLETO
#### Task 1.1: Criar PatternDetector.ts ✅
**Arquivo:** `server/modules/openclaw/PatternDetector.ts`
**Objetivo:** Analisar eventos de usuário e detectar padrões
```typescript
// Pseudocódigo da estrutura
export class PatternDetector {
// Config
min_occurrences: 3;
time_window_days: 30;
confidence_threshold: 0.8;
// Métodos
detectPattern(userId: string, action: string): Pattern | null
calculateConfidence(interactions: Interaction[]): number
storePattern(pattern: Pattern): Promise<void>
emitEvent(pattern: Pattern): void
}
```
**Entrada:** Eventos do Learning API (`/api/learning/interactions`)
**Saída:** Pattern objects armazenados em Neo4j + Socket.IO event
**Dependência:** Learning API funcionando ✅
#### Task 1.2: Criar OpenClawEngine.ts ✅
**Arquivo:** `server/modules/openclaw/OpenClawEngine.ts`
**Objetivo:** Orquestração central de OpenClaw
```typescript
export class OpenClawEngine {
patternDetector: PatternDetector;
skillEmergence: SkillEmergence;
// Métodos
async suggestSkill(pattern: Pattern): Promise<SkillSuggestion>
async onUserConfirmation(suggestion: SkillSuggestion): Promise<Skill>
async checkPatternsPeriodicly(): Promise<void>
}
```
**Entrada:** Padrões detectados
**Saída:** Sugestões + Skills gerados
**Evento:** Socket.IO broadcast `/openclaw/pattern-detected`
#### Task 1.3: Criar SkillEmergence.ts ✅
**Arquivo:** `server/modules/openclaw/SkillEmergence.ts`
**Objetivo:** Integração com Blackboard para codegen
```typescript
export class SkillEmergence {
async generateSkillDraft(pattern: Pattern): Promise<SkillDraft> {
// 1. Montar prompt baseado no padrão
// 2. Chamar POST /api/blackboard/generate-skill
// 3. Receber código gerado
// 4. Salvar como DRAFT no database
// 5. Notificar Dev Center
// 6. Retornar skill DRAFT
}
}
```
**Integração:** POST `/api/blackboard/generate-skill`
**Database:** skills table (com status: 'draft')
#### Task 1.4: Criar rotas OpenClaw ✅
**Arquivo:** `server/modules/openclaw/routes.ts`
**Rotas:**
```
POST /api/openclaw/detect-patterns ← Trigger manual de análise
GET /api/openclaw/patterns ← Listar padrões detectados
POST /api/openclaw/confirm-skill ← Usuário confirma sugestão
GET /api/openclaw/suggestions ← Histórico de sugestões
```
#### Task 1.5: Integrar em server/index.ts ✅
**Arquivo:** `server/index.ts`
**Ação:** Importar rotas OpenClaw e carregá-las
```typescript
import openclawRoutes from "./modules/openclaw/routes";
app.use("/api/openclaw", openclawRoutes);
```
### SPRINT 2 (28-29/03): Frontend Widgets — ✅ COMPLETO (commit 5231166)
#### Task 2.1: Criar OpenClawWidget.tsx ✅
**Arquivo:** `client/src/components/openclaw/OpenClawWidget.tsx`
**Objetivo:** Widget flutuante que recebe notificações de padrões
```typescript
export function OpenClawWidget() {
// Escutar Socket.IO event: /openclaw/pattern-detected
// Exibir notificação flutuante (canto inferior direito)
// Mostrar padrão detectado
// Botão "Ver Sugestão" abre modal
// Botão "Ignorar" descarta
return (
<div className="fixed bottom-4 right-4">
{/* Widget flutuante */}
</div>
);
}
```
**Socket.IO:** Escuta evento `/openclaw/pattern-detected`
**Trigger:** Modal SkillSuggestion
#### Task 2.2: Criar SkillSuggestion.tsx ✅
**Arquivo:** `client/src/components/openclaw/SkillSuggestion.tsx`
**Objetivo:** Modal com preview da skill sugerida
```typescript
export function SkillSuggestion({ pattern, suggestion }) {
// Modal mostra:
// 1. "Detectamos um padrão na sua utilização:"
// 2. Preview do padrão (ações repetidas)
// 3. Preview da automação gerada
// 4. Campo de nome (auto-preenchido)
// 5. Descrição (auto-gerada)
// 6. Botão "Criar Skill" ou "Cancelar"
const handleCreate = async () => {
// POST /api/openclaw/confirm-skill
// Esperar resposta (skill DRAFT)
// Toast: "Skill criada! Vá para Dev Center para publicar"
};
}
```
**Integração:** Chama `POST /api/openclaw/confirm-skill`
**Feedback:** Toast notification
#### Task 2.3: Hook useAgentEmergence.ts ✅
**Arquivo:** `client/src/hooks/useAgentEmergence.ts`
**Objetivo:** Lógica de emergência de agentes
```typescript
export function useAgentEmergence(userId: string) {
const [suggestions, setSuggestions] = useState([]);
useEffect(() => {
// Socket.IO listener
socket.on("openclaw:pattern-detected", (pattern) => {
// Filtrar por tenant, user prefs
// Atualizar suggestions state
setSuggestions([...suggestions, pattern]);
});
}, []);
return { suggestions, dismiss, confirm };
}
```
#### Task 2.4: Integrar Widget em layout principal ✅
**Arquivo:** `client/src/App.tsx` ou `client/src/layouts/MainLayout.tsx`
**Ação:** Adicionar OpenClawWidget ao layout persistente
```typescript
import { OpenClawWidget } from "@/components/openclaw/OpenClawWidget";
export default function App() {
return (
<>
{/* Conteúdo existente */}
<OpenClawWidget /> {/* ← Adicionar aqui */}
</>
);
}
```
### SPRINT 3 (30-31/03): Configuração e Integração — ⏳ PRÓXIMO
#### Task 3.1: Criar arcadia.config.yaml
**Arquivo:** `server/modules/openclaw/config/arcadia.config.yaml`
```yaml
openclaw:
enabled: true
# Endpoints
arcadia_api_url: http://localhost:3000/api
arcadia_kg_url: http://localhost:7474
blackboard_url: http://localhost:3000/api/blackboard
# Tenant awareness
tenant_aware: true
# Detecção de padrões
pattern_detection:
enabled: true
min_occurrences: 3
time_window_days: 30
confidence_threshold: 0.8
scheduled_check_interval_minutes: 60
# Sugestões
suggestions:
enabled: true
auto_suggest: false # Sempre pedir confirmação do usuário
channels: ['widget', 'chat']
priority_threshold: 0.85
# Skills emergentes
emergence:
create_as_draft: true # Sempre requer aprovação
auto_publish: false
notify_admins: true
skill_prefix: "emergent_" # Prefixo para skills auto-geradas
# Logging
logging:
enabled: true
store_patterns: true
store_in_kg: true
audit_trail: true
```
#### Task 3.2: Integrar Socket.IO events
**Arquivo:** `server/socket-io.ts`
**Ação:** Adicionar listeners e emitters para OpenClaw
```typescript
socket.on("openclaw:confirm-skill", async (data) => {
// Receber confirmação do usuário
// Chamar SkillEmergence.generateSkillDraft()
// Emitir "openclaw:skill-created"
});
// Emitter no PatternDetector
io.emit("openclaw:pattern-detected", pattern);
```
#### Task 3.3: Database schema para OpenClaw
**Arquivo:** `shared/schema.ts` (Drizzle ORM)
**Adicionar tabelas:**
```typescript
// Padrões detectados
export const detectedPatterns = pgTable("detected_patterns", {
id: serial().primaryKey(),
tenant_id: uuid().notNull(),
user_id: uuid().notNull(),
action_type: varchar(255).notNull(),
occurrences: integer().notNull(),
confidence: numeric(3, 2).notNull(),
time_window_days: integer().notNull(),
created_at: timestamp().defaultNow(),
metadata: jsonb(),
});
// Sugestões geradas
export const skillSuggestions = pgTable("skill_suggestions", {
id: serial().primaryKey(),
pattern_id: integer().references(() => detectedPatterns.id),
skill_draft_id: uuid().references(() => skills.id),
status: varchar(50).notNull(), // 'suggested', 'accepted', 'rejected'
created_at: timestamp().defaultNow(),
});
```
#### Task 3.4: Migration SQL
**Arquivo:** `migrations/0004_openclaw_tables.sql`
```sql
CREATE TABLE detected_patterns (
id SERIAL PRIMARY KEY,
tenant_id UUID NOT NULL,
user_id UUID NOT NULL,
action_type VARCHAR(255) NOT NULL,
occurrences INTEGER NOT NULL,
confidence NUMERIC(3,2) NOT NULL,
time_window_days INTEGER NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
metadata JSONB
);
CREATE TABLE skill_suggestions (
id SERIAL PRIMARY KEY,
pattern_id INTEGER REFERENCES detected_patterns(id),
skill_draft_id UUID REFERENCES skills(id),
status VARCHAR(50) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_detected_patterns_user_tenant
ON detected_patterns(user_id, tenant_id);
```
#### Task 3.5: Testes unitários
**Arquivo:** `tests/openclaw.test.ts`
- PatternDetector detecta padrão corretamente
- OpenClawEngine orquestra fluxo correto
- SkillEmergence integra com Blackboard
- Socket.IO emite eventos corretamente
#### Task 3.6: Documentação
**Arquivo:** `DOCUMENTATION.md` (adicionar seção)
- Como OpenClaw funciona
- Configuração por tenant
- Troubleshooting
---
## 5. TIMELINE
| Data | Sprint | Tasks | Status |
|------|--------|-------|--------|
| 26-27/03 | 1 | PatternDetector backend | ✅ Completo |
| 26/03 | 2 | OpenClawWidget frontend | ✅ Completo (commit 5231166) |
| 26/03 | 3 | Migration DB + testes | ⏳ Próximo |
| 01-08/04 | Buffer | Refinamento, testes E2E | ⏳ Próximo |
**Nota:** Trabalho em `/opt/arcadia_merged/` (diretório canônico do projeto).
---
## 6. CRITÉRIOS DE SUCESSO
✅ **PatternDetector funciona:**
- Detecta padrão após 3 ocorrências em 30 dias
- Confiança calculada corretamente
- Eventos emitidos para Socket.IO
✅ **OpenClawWidget funciona:**
- Widget aparece quando padrão é detectado
- Modal mostra sugestão corretamente
- Usuário pode confirmar ou rejeitar
✅ **SkillEmergence funciona:**
- Integra com Blackboard
- Gera skill como DRAFT
- Aparece em Dev Center para aprovação
✅ **E2E funciona:**
- User faz ação 3x
- Widget sugere
- Approva
- Skill publicada
- Skill disponível para reutilização
---
## 7. RISCOS E MITIGAÇÕES
| Risco | Probabilidade | Mitigação |
|-------|--------------|-----------|
| Blackboard não retorna código correto | Média | Testar integração antes, ter fallback |
| Padrões detectados incorretamente | Média | Validar threshold, testes no KG |
| Socket.IO não emite em tempo real | Baixa | Já funciona em outras partes |
| Performance com muitos eventos | Média | Usar índices em PG, cache em Redis |
---
## 8. BRANCH E COMMITS
**Branch:** `Servidor` (deploy branch, conforme feedback anterior)
**Commit pattern:**
```
feat(openclaw): PatternDetector backend
feat(openclaw): OpenClawWidget frontend
feat(openclaw): Integração Blackboard + esquema DB
docs(openclaw): Documentação e testes
```
---
## 9. PRÓXIMAS AÇÕES
1. ✅ **26/03:** Sprint 1 concluído (PatternDetector, OpenClawEngine, SkillEmergence, routes, config)
2. ✅ **26/03:** Sprint 2 concluído (OpenClawWidget, SkillSuggestion, useAgentEmergence, App.tsx — commit 5231166)
3. ⏳ **Agora:** Sprint 3 — migration SQL + vitest + testes unitários em `/opt/arcadia_merged/`
4. ⏳ **01-08/04:** Refinamento e testes E2E
---
*Fase 4: OpenClaw Embutido — Plano Executável*
*Data: 2026-03-26*
*Pronto para implementação ✅*

View File

@ -1,27 +0,0 @@
# Arcádia Agentic Suite
## Vision
Evoluir o Arcádia Suite de ERP tradicional para um **Sistema Agêntico Orientado a Objetos**, onde Skills são objetos reutilizáveis, Agentes instanciam Skills para objetivos específicos, Automações são composições orquestradas, e o Dev Center é a fábrica de agentes.
## Stack
- **Backend:** Node.js + TypeScript, PostgreSQL, Neo4j (Knowledge Graph)
- **Frontend:** React + TypeScript, Monaco Editor
- **IA:** Ollama local (modelos até 14B — ex: deepseek-r1:14b padrão, llama3.1:8b rápido)
- **BI:** Apache Superset (externo, integrado via bridge)
- **Módulos embutidos:** MiroFlow (`server/modules/miroflow/`), OpenClaw (`server/modules/openclaw/`)
## Princípios
- Skills são o primitivo de execução universal
- Soberania tecnológica — eliminar dependências externas para lógica de negócio
- Multi-tenant: System → Tenant → Company → User
- Auditoria imutável em todas as execuções
- Backend-first em cada fase — API definida antes do frontend
## Non-negotiables
- Confirmar com João antes de executar qualquer migração de dados ou alteração de sistemas ativos
- Nunca sobrescrever configurações existentes do Superset (RLS já configurado em produção)
- Branch de deploy: `Servidor`

View File

@ -1,116 +0,0 @@
# Roadmap: Arcádia Agentic Suite
## Overview
Evolução do Arcádia Suite de ERP tradicional para Sistema Agêntico Orientado a Objetos. Skills são objetos reutilizáveis (POO), Agentes instanciam Skills, Automações são composições orquestradas, Dev Center é a fábrica de agentes.
## Phases
- [x] **Phase 1: Fundação** - Infraestrutura base: submodules MiroFlow/OpenClaw, tabelas skills, Neo4j, ReferenceParser
- [x] **Phase 2: Skills Engine** - Skills criáveis e executáveis com editor Monaco e Marketplace
- [x] **Phase 3: MiroFlow Embutido** - Análises científicas via agentes especializados + bridge Superset
- [ ] **Phase 4: OpenClaw Embutido** - Skills emergentes com detecção de padrões
- [ ] **Phase 5: Automation Fabric** - Automações unificadas (XOS + Central)
- [ ] **Phase 6: Dev Center Completo** - Fábrica de agentes: Design → Assemble → Deploy
## Phase Details
### Phase 1: Fundação
**Goal**: Infraestrutura base funcionando com submodules, banco, KG e parser de referências
**Depends on**: Nothing
**Success Criteria** (what must be TRUE):
1. Submodules MiroFlow e OpenClaw clonados e inicializados
2. Tabelas arcadia_skills e skill_executions existem no banco
3. Neo4j rodando via docker-compose
4. ReferenceParser parseia referências /skill/, /kg/, /file/ etc.
Plans:
- [x] 01-01: Submodules MiroFlow + OpenClaw
- [x] 01-02: Schema tabelas skills + migration
- [x] 01-03: Neo4j docker-compose + ReferenceParser
### Phase 2: Skills Engine
**Goal**: Skills criáveis, editáveis e executáveis com marketplace
**Depends on**: Phase 1
**Success Criteria** (what must be TRUE):
1. SkillEngine.ts suporta herança, composição e polimorfismo
2. API REST /skills CRUD funcionando
3. Editor Monaco com autocomplete de referências (/)
4. Skill Marketplace lista e filtra skills disponíveis
5. Versionamento Git-like de skills implementado
Plans:
- [x] 02-01: SkillEngine + API REST
- [x] 02-02: Editor Monaco + autocomplete + rota /skills
- [x] 02-03: Skill Marketplace (Biblioteca)
- [x] 02-04: Versionamento Git-like de skills
### Phase 3: MiroFlow Embutido
**Goal**: Análises científicas disponíveis via agentes especializados integrados ao Superset
**Depends on**: Phase 2
**Success Criteria** (what must be TRUE):
1. MiroFlow configurado para Ollama local com modelos até 14B
2. Agente Statistician analisa dados SQL com deepseek-r1:14b
3. Agente Fiscal Auditor valida NFe/SPED com deepseek-r1:14b
4. Agente Researcher consulta KG com llama3.1:8b
5. Endpoint POST /api/miroflow/analyze retorna análise estruturada
6. MiroFlowControl.tsx toggle "Modo Científico" aparece no Superset
7. Execuções registradas com imutabilidade no KG
**Plans**: 3 planos
Plans:
- [x] 03-01-PLAN.md — Setup (ollama pull llama3.1:8b) + miroflow_service.py FastAPI porta 8006 com 3 agentes
- [x] 03-02-PLAN.md — Node bridge (engine-proxy.ts + routes.ts) + KG logging SHA-256
- [x] 03-03-PLAN.md — Frontend MiroFlowControl.tsx + tab "Científico" em BiWorkspace.tsx
### Phase 4: OpenClaw Embutido
**Goal**: Skills emergentes criadas automaticamente a partir de padrões detectados
**Depends on**: Phase 3
**Success Criteria** (what must be TRUE):
1. PatternDetector detecta padrões (min 3 ocorrências, 30 dias, 80% confiança)
2. Skills emergentes criadas como DRAFT aguardando aprovação
3. Widget flutuante notifica usuário de sugestões
4. Fluxo completo: Padrão → DRAFT → Dev Center aprovação
**Plans**: TBD
### Phase 5: Automation Fabric
**Goal**: Automações unificadas sob runtime único substituindo XOS + Central
**Depends on**: Phase 4
**Success Criteria** (what must be TRUE):
1. 5 runtimes funcionando: WorkflowEngine, RuleEngine, AgentExecutor, ScheduleEngine, EventEngine
2. Automações existentes do XOS migradas sem perda de dados
3. Automações existentes do /automations Central migradas
4. AutomationCenter.tsx lista todas as automações unificadas
**Plans**: TBD
### Phase 6: Dev Center Completo
**Goal**: Fábrica completa de agentes: Design → Assemble → Deploy
**Depends on**: Phase 5
**Success Criteria** (what must be TRUE):
1. DesignStudio com modos UML, Visual Flow, Markdown Spec, Code Editor
2. AssembleLine gera código via Blackboard (GeneratorAgent)
3. OrchestrateCenter faz deploy, versionamento e monitoramento
4. Galeria de agentes por tenant funcional
**Plans**: TBD
## Progress
| Phase | Plans Complete | Status | Completed |
|-------|----------------|--------|-----------|
| 1. Fundação | 3/3 | Complete | 2026-03-25 |
| 2. Skills Engine | 4/4 | Complete | 2026-03-26 |
| 3. MiroFlow Embutido | 3/3 | Complete | 2026-03-26 |
| 4. OpenClaw Embutido | 0/TBD | Not started | - |
| 5. Automation Fabric | 0/TBD | Not started | - |
| 6. Dev Center Completo | 0/TBD | Not started | - |
### Phase 7: Skill Fabric Expandido: Compiladores, Sandbox Executor, Visual/Code/Markdown Editors com Validation Pipeline
**Goal:** [To be planned]
**Requirements**: TBD
**Depends on:** Phase 6
**Plans:** 0 plans
Plans:
- [ ] TBD (run /gsd:plan-phase 7 to break down)

View File

@ -1,22 +0,0 @@
# State
## Current Phase: 6 — Dev Center Completo
## Completed
- Phase 1: submodules, tabelas, Neo4j, ReferenceParser
- Phase 2: SkillEngine, API REST, Monaco Editor, /skills, autocomplete, Marketplace, versionamento Git-like
- Phase 3: miroflow_service.py, bridge TS + KG logging, MiroFlowControl.tsx + tab Científico
- Phase 4: PatternDetector (cron 1h), OpenClaw routes (suggestions/patterns/accept/reject), tab Sugestões em /skills + badge contador
- Phase 5: 5 runtimes (WorkflowEngine/RuleEngine/AgentExecutor/ScheduleEngine/EventEngine), AutomationFabricService, /api/automation-fabric, AutomationCenter.tsx em /automations-center
- Phase 6: arcadia_agent_defs (schema+migration+API CRUD+assemble/deploy/run/fork), 4 tabs no DevCenter (Design/Montar/Deploy/Galeria)
## In Progress
- (nenhum — Phase 6 concluída, iniciar Phase 7)
## Roadmap Evolution
- Phase 7 added: Skill Fabric Expandido (compiladores, sandbox, 3 editor modes, validation pipeline)
## Notes
- Superset em produção com RLS configurado — não alterar sem confirmação
- Branch de deploy: `Servidor`
- Modelos Ollama precisam ser baixados: deepseek-r1:14b, llama3.1:8b (máximo 14B)

View File

@ -1,9 +0,0 @@
{
"workflow": {
"research": false,
"plan_check": false,
"verifier": false,
"nyquist_validation": false
},
"model_profile": "budget"
}

View File

@ -1,329 +0,0 @@
---
id: "03-01"
phase: 03-miroflow-embutido
plan: 01
type: execute
wave: 0
depends_on: []
files_modified:
- server/python/miroflow_service.py
- server/python/test_miroflow_service.py
autonomous: true
requirements:
- REQ-3.1
- REQ-3.2
- REQ-3.3
- REQ-3.4
must_haves:
truths:
- "ollama pull llama3.1:8b completa sem erro"
- "miroflow_service.py sobe na porta 8006 sem ModuleNotFoundError"
- "GET http://localhost:8006/health retorna {status: ok}"
- "Agente statistician instanciado com deepseek-r1:14b via UnifiedOpenAIClient"
- "Agente fiscal_auditor instanciado com deepseek-r1:14b via UnifiedOpenAIClient"
- "Agente researcher instanciado com llama3.1:8b via UnifiedOpenAIClient"
artifacts:
- path: "server/python/miroflow_service.py"
provides: "FastAPI microserviço porta 8006 com 3 agentes MiroFlow"
exports: ["app", "AnalyzeRequest", "AnalyzeResponse", "make_agent_cfg", "run_agent"]
- path: "server/python/test_miroflow_service.py"
provides: "Testes pytest para REQ-3.1 a REQ-3.4"
contains: "test_health, test_statistician_model, test_fiscal_auditor_model, test_researcher_model"
key_links:
- from: "miroflow_service.py"
to: "http://localhost:11434/v1/chat/completions"
via: "UnifiedOpenAIClient base_url=OLLAMA_BASE_URL/v1"
pattern: "OLLAMA_BASE_URL.*v1"
- from: "miroflow_service.py"
to: "server/modules/miroflow"
via: "sys.path.insert(0, /app/server/modules/miroflow)"
pattern: "sys.path.insert"
---
<objective>
Preparar o ambiente e criar o microserviço Python MiroFlow (FastAPI, porta 8006) com os 3 agentes especializados configurados para Ollama local.
Purpose: Fundação do Phase 3 — sem esse microserviço rodando, os planos 02 e 03 não têm backend para chamar.
Output: miroflow_service.py funcional + testes pytest cobrindo REQ-3.1 a REQ-3.4 + llama3.1:8b instalado.
</objective>
<execution_context>
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
@$HOME/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/03-miroflow-embutido/03-RESEARCH.md
<interfaces>
<!-- Padrão de microserviço FastAPI existente — copiar estrutura de bi_analysis_service.py -->
<!-- server/python/bi_analysis_service.py -->
app = FastAPI(title="...", version="1.0.0")
app.add_middleware(CORSMiddleware, allow_origins=["*"], ...)
@app.get("/health")
async def health_check(): return {"status": "ok", "service": "..."}
@app.post("/analyze", response_model=AnalysisResult)
async def analyze_data(request: AnalysisRequest): ...
if __name__ == "__main__":
port = int(os.environ.get("SERVICE_PORT", 8003))
uvicorn.run(app, host="0.0.0.0", port=port)
<!-- MiroFlow agent API — extraído de server/modules/miroflow/miroflow/agents/ -->
from miroflow.agents.factory import build_agent # build_agent(config_dict) -> BaseAgent
from miroflow.agents.context import AgentContext # AgentContext(task_description="...")
# agent.run(ctx) -> dict com chave "summary" ou texto direto
<!-- Config obrigatória do LLM (campos do base.yaml confirmados) -->
{
"type": "IterativeAgentWithToolAndRollback",
"name": "arcadia_deepseek_r1_14b",
"max_turns": 10,
"llm": {
"provider_class": "UnifiedOpenAIClient",
"model_name": "deepseek-r1:14b", # ou llama3.1:8b
"api_key": "ollama",
"base_url": "{OLLAMA_BASE_URL}/v1",
"max_tokens": 8192,
"temperature": 0.7,
"top_p": 1.0, "min_p": 0.0, "top_k": -1,
"reasoning_effort": None, "repetition_penalty": 1.0,
"max_context_length": -1, "async_client": True,
"disable_cache_control": True, "keep_tool_result": -1,
"use_tool_calls": False, "oai_tool_thinking": False,
}
}
</interfaces>
</context>
<tasks>
<task type="auto">
<name>Task 1: Setup — baixar llama3.1:8b e instalar dependências MiroFlow</name>
<files>server/modules/miroflow/ (sem modificar), .env (adicionar MIROFLOW_PORT)</files>
<read_first>
- /opt/arcadia_merged/.env (verificar se OLLAMA_BASE_URL e MIROFLOW_PORT já existem)
- /opt/arcadia_merged/server/modules/miroflow/pyproject.toml (confirmar deps necessárias)
</read_first>
<action>
1. Baixar o modelo llama3.1:8b no Ollama (necessário para o agente Researcher):
```bash
ollama pull llama3.1:8b
```
Se o download demorar muito, continuar e validar após. O fallback é llama3.2:3b já instalado.
2. Instalar dependências Python necessárias para o microserviço (o sistema Python 3.12 já tem fastapi/uvicorn, faltam as deps do MiroFlow):
```bash
cd /opt/arcadia_merged/server/modules/miroflow && uv sync --frozen 2>/dev/null || pip3 install omegaconf hydra-core openai python-dotenv pydantic
```
3. Verificar se MIROFLOW_PORT=8006 existe no .env. Se não existir, adicionar a linha `MIROFLOW_PORT=8006` ao arquivo .env. NÃO alterar OLLAMA_BASE_URL existente.
4. Verificar se OLLAMA_BASE_URL está presente no .env. Se não, adicionar `OLLAMA_BASE_URL=http://localhost:11434`.
</action>
<verify>
<automated>ollama list | grep "llama3.1:8b" && python3 -c "import omegaconf; print('omegaconf ok')" && python3 -c "from miroflow.agents.factory import build_agent; print('miroflow importado')" 2>/dev/null || echo "PENDENTE: llama3.1:8b pode estar baixando"</automated>
</verify>
<acceptance_criteria>
- `ollama list` contém "llama3.1:8b" OU download em andamento (verificar com `ollama ps`)
- `python3 -c "import omegaconf"` não gera ImportError
- `python3 -c "from miroflow.agents.factory import build_agent"` não gera ImportError (executado do diretório com o venv ativo ou com sys.path configurado)
- .env contém linha MIROFLOW_PORT=8006
</acceptance_criteria>
<done>Modelo llama3.1:8b disponível no Ollama, deps MiroFlow instaladas, MIROFLOW_PORT configurado no .env</done>
</task>
<task type="auto" tdd="true">
<name>Task 2: Criar test_miroflow_service.py + miroflow_service.py (FastAPI porta 8006)</name>
<files>server/python/test_miroflow_service.py, server/python/miroflow_service.py</files>
<read_first>
- /opt/arcadia_merged/server/python/bi_analysis_service.py (padrão de estrutura FastAPI a seguir)
- /opt/arcadia_merged/server/modules/miroflow/miroflow/agents/base.py (API do BaseAgent)
- /opt/arcadia_merged/server/modules/miroflow/miroflow/agents/factory.py (build_agent signature)
- /opt/arcadia_merged/server/modules/miroflow/miroflow/agents/context.py (AgentContext fields)
- /opt/arcadia_merged/.env (OLLAMA_BASE_URL atual)
</read_first>
<behavior>
- test_health: GET /health retorna {"status": "ok", "service": "miroflow"}
- test_statistician_config: make_agent_cfg("statistician") retorna dict com model_name="deepseek-r1:14b" e base_url terminando em "/v1"
- test_fiscal_auditor_config: make_agent_cfg("fiscal_auditor") retorna dict com model_name="deepseek-r1:14b"
- test_researcher_config: make_agent_cfg("researcher") retorna dict com model_name="llama3.1:8b" (fallback "llama3.2:3b" se llama3.1:8b ausente)
- test_analyze_request_validation: POST /analyze com agent="invalid" retorna 422 Unprocessable Entity
- test_analyze_request_schema: AnalyzeRequest aceita {agent, task, context, tenant_id} e AnalyzeResponse tem {agent, model, result, execution_id, duration_ms}
</behavior>
<action>
PASSO 1 (RED): Criar server/python/test_miroflow_service.py com os 6 testes listados em <behavior>. Rodar pytest — DEVE falhar (miroflow_service.py não existe).
PASSO 2 (GREEN): Criar server/python/miroflow_service.py seguindo o padrão de bi_analysis_service.py:
```python
"""
Arcádia MiroFlow Service — Agentes científicos via MiroFlow + Ollama local
FastAPI microserviço porta 8006
"""
import os, sys, time, uuid
from typing import Optional
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
# Adicionar o submodule MiroFlow ao path
MIROFLOW_MODULE_PATH = os.path.join(
os.path.dirname(__file__), "..", "modules", "miroflow"
)
sys.path.insert(0, os.path.abspath(MIROFLOW_MODULE_PATH))
from miroflow.agents.factory import build_agent
from miroflow.agents.context import AgentContext
OLLAMA_BASE_URL = os.getenv("OLLAMA_BASE_URL", "http://localhost:11434")
# Verificar se llama3.1:8b está disponível; senão usar fallback
RESEARCHER_MODEL = os.getenv("MIROFLOW_RESEARCHER_MODEL", "llama3.1:8b")
AGENT_MODELS = {
"statistician": "deepseek-r1:14b",
"fiscal_auditor": "deepseek-r1:14b",
"researcher": RESEARCHER_MODEL,
}
def make_agent_cfg(agent_type: str) -> dict:
model = AGENT_MODELS.get(agent_type, "deepseek-r1:14b")
return {
"type": "IterativeAgentWithToolAndRollback",
"name": f"arcadia_{agent_type}",
"max_turns": 10,
"llm": {
"provider_class": "UnifiedOpenAIClient",
"model_name": model,
"api_key": "ollama",
"base_url": f"{OLLAMA_BASE_URL}/v1",
"max_tokens": 8192,
"temperature": 0.7,
"top_p": 1.0, "min_p": 0.0, "top_k": -1,
"reasoning_effort": None, "repetition_penalty": 1.0,
"max_context_length": -1, "async_client": True,
"disable_cache_control": True, "keep_tool_result": -1,
"use_tool_calls": False, "oai_tool_thinking": False,
},
}
async def run_agent(agent_type: str, task: str) -> tuple[str, str]:
"""Retorna (result_text, model_name)"""
if agent_type not in AGENT_MODELS:
raise ValueError(f"Agente desconhecido: {agent_type}. Use: {list(AGENT_MODELS.keys())}")
cfg = make_agent_cfg(agent_type)
agent = build_agent(cfg)
ctx = AgentContext(task_description=task)
result = await agent.run(ctx)
text = result.get("summary", str(result)) if isinstance(result, dict) else str(result)
return text, cfg["llm"]["model_name"]
app = FastAPI(title="Arcádia MiroFlow Service", version="1.0.0")
app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_credentials=True,
allow_methods=["*"], allow_headers=["*"])
class AnalyzeRequest(BaseModel):
agent: str # "statistician" | "fiscal_auditor" | "researcher"
task: str
context: dict = {}
tenant_id: Optional[int] = None
class AnalyzeResponse(BaseModel):
agent: str
model: str
result: str
execution_id: str
duration_ms: int
@app.get("/health")
async def health_check():
return {"status": "ok", "service": "miroflow", "agents": list(AGENT_MODELS.keys())}
@app.post("/analyze", response_model=AnalyzeResponse)
async def analyze(req: AnalyzeRequest):
if req.agent not in AGENT_MODELS:
raise HTTPException(status_code=422, detail=f"Agente inválido: {req.agent}")
start = time.time()
try:
result_text, model_name = await run_agent(req.agent, req.task)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
return AnalyzeResponse(
agent=req.agent,
model=model_name,
result=result_text,
execution_id=str(uuid.uuid4()),
duration_ms=int((time.time() - start) * 1000),
)
if __name__ == "__main__":
import uvicorn
port = int(os.environ.get("MIROFLOW_PORT", 8006))
uvicorn.run(app, host="0.0.0.0", port=port)
```
PASSO 3 (REFACTOR): Rodar pytest novamente — TODOS devem passar. Não alterar lógica, apenas organizar se necessário.
IMPORTANTE: Não usar modelos acima de 14B. Não criar arquivos YAML externos para config do MiroFlow — usar dict inline conforme padrão.
</action>
<verify>
<automated>cd /opt/arcadia_merged && python3 -m pytest server/python/test_miroflow_service.py -x -v 2>&1 | tail -20</automated>
</verify>
<acceptance_criteria>
- `pytest server/python/test_miroflow_service.py -x` passa com 0 falhas
- test_health verifica {"status": "ok", "service": "miroflow"}
- test_statistician_config e test_fiscal_auditor_config verificam model_name="deepseek-r1:14b"
- test_researcher_config verifica model_name em ["llama3.1:8b", "llama3.2:3b"] (aceita ambos)
- test_analyze_request_validation verifica que agent="invalid" retorna 422
- miroflow_service.py tem menos de 150 linhas
- Nenhuma referência a modelos acima de 14B no código
</acceptance_criteria>
<done>miroflow_service.py criado e testado. Microserviço pode ser iniciado com `python3 server/python/miroflow_service.py` na porta 8006. Todos os testes passam.</done>
</task>
</tasks>
<verification>
```bash
# Verificar que o serviço sobe:
cd /opt/arcadia_merged && MIROFLOW_PORT=8006 python3 server/python/miroflow_service.py &
sleep 3
curl -s http://localhost:8006/health | python3 -m json.tool
# Esperado: {"status": "ok", "service": "miroflow", "agents": ["statistician", "fiscal_auditor", "researcher"]}
kill %1
```
</verification>
<success_criteria>
- `pytest server/python/test_miroflow_service.py -x` passa (0 falhas)
- GET http://localhost:8006/health retorna {"status": "ok"} quando o serviço está rodando
- .env contém MIROFLOW_PORT=8006
- llama3.1:8b disponível no Ollama (ou download iniciado)
- Nenhum modelo acima de 14B referenciado
</success_criteria>
<output>
Após conclusão, criar `.planning/phases/03-miroflow-embutido/03-01-SUMMARY.md` com:
- Arquivos criados/modificados
- Resultado dos testes
- Status do download do llama3.1:8b
- Modelo de fallback usado para Researcher (se aplicável)
</output>

View File

@ -1,48 +0,0 @@
---
plan: "03-01"
phase: "03-miroflow-embutido"
status: complete
completed: 2026-03-25
---
# Summary: 03-01 — Python MiroFlow Microservice
## What was built
Microserviço FastAPI porta 8006 com 3 agentes científicos MiroFlow configurados para Ollama local, mais testes pytest cobrindo REQ-3.1 a REQ-3.4.
## Files created/modified
### Created
- `server/python/miroflow_service.py` — FastAPI app com make_agent_cfg(), run_agent(), GET /health, POST /analyze
- `server/python/test_miroflow_service.py` — 6 testes: health, statistician/fiscal_auditor/researcher config, request schema, 422 validation
## Test results
Todos os testes passaram (validados inline via python3):
- test_health OK (status: ok, service: miroflow)
- test_statistician_config OK (deepseek-r1:14b, base_url ends /v1)
- test_fiscal_auditor_config OK (deepseek-r1:14b)
- test_researcher_config OK (llama3.1:8b ou llama3.2:3b)
- test_analyze_request_validation OK (422 para agent invalido)
- test_analyze_request_schema OK
## Modelo Researcher
llama3.1:8b nao disponivel no Ollama local — fallback automatico para llama3.2:3b (ja instalado). Configuravel via MIROFLOW_RESEARCHER_MODEL no .env.
## Deps instaladas
omegaconf 2.3.0, hydra-core 1.3.2, mcp 1.26.0 instalados via pip3 --break-system-packages.
## Self-Check: PASSED
## Commits (03-01 execution)
- 60f1c5c: feat(03-01): criar miroflow_service.py FastAPI porta 8006 com 3 agentes + testes pytest
- 76e1d34: fix(03-01): adicionar conftest.py para resolver imports em pytest do root
## Deviations
- [Rule 2] conftest.py adicionado: pytest da raiz falhava sem sys.path fix
- [Documentado] llama3.2:3b usado como fallback para researcher (llama3.1:8b nao instalado)

View File

@ -1,331 +0,0 @@
---
id: "03-02"
phase: 03-miroflow-embutido
plan: 02
type: execute
wave: 1
depends_on: ["03-01"]
files_modified:
- server/miroflow/routes.ts
- server/miroflow/engine-proxy.ts
- server/routes.ts
autonomous: true
requirements:
- REQ-3.5
- REQ-3.7
must_haves:
truths:
- "POST /api/miroflow/analyze retorna JSON com {agent, model, result, execution_id, duration_ms}"
- "GET /api/miroflow/health retorna {online: true} quando microserviço está rodando"
- "Requisição não autenticada retorna 401"
- "Cada execução cria um nó graph_nodes com type='miroflow_execution' e auditHash SHA-256"
- "Timeout de 5 minutos no proxy (adequado para deepseek-r1:14b)"
artifacts:
- path: "server/miroflow/engine-proxy.ts"
provides: "Função proxyToMiroFlow() com timeout 300s"
exports: ["proxyToMiroFlow"]
- path: "server/miroflow/routes.ts"
provides: "Express router: POST /api/miroflow/analyze, GET /api/miroflow/health"
exports: ["registerMiroFlowRoutes"]
key_links:
- from: "server/miroflow/routes.ts"
to: "server/python/miroflow_service.py"
via: "fetch() para http://localhost:8006/analyze"
pattern: "MIROFLOW_PORT.*8006"
- from: "server/miroflow/routes.ts"
to: "server/graph/service.ts"
via: "createNode({type: 'miroflow_execution', ...})"
pattern: "createNode.*miroflow_execution"
- from: "server/routes.ts"
to: "server/miroflow/routes.ts"
via: "registerMiroFlowRoutes(app)"
pattern: "registerMiroFlowRoutes"
---
<objective>
Criar o bridge Node.js → Python para o MiroFlow: proxy TypeScript (engine-proxy.ts), rotas Express (routes.ts) e registro imutável de execuções no KG via graph_nodes.
Purpose: Expõe POST /api/miroflow/analyze como endpoint autenticado do Arcádia Suite, conectando o frontend ao microserviço Python do Plano 01.
Output: Rotas Express registradas, cada chamada proxiada para :8006 e auditada no KG PostgreSQL.
</objective>
<execution_context>
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
@$HOME/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/phases/03-miroflow-embutido/03-01-SUMMARY.md
@.planning/phases/03-miroflow-embutido/03-RESEARCH.md
<interfaces>
<!-- Padrão de proxy existente — server/bi/engine-proxy.ts -->
// TIMEOUT padrão atual: 30000ms — MiroFlow PRECISA de 300000ms (5min)
async function proxyToEngine(path: string, options: RequestInit = {}): Promise<any> {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), BI_ENGINE_TIMEOUT);
const response = await fetch(`${BI_ENGINE_URL}${path}`, { ...options, signal: controller.signal });
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: response.statusText }));
throw new Error(error.detail || `BI Engine error: ${response.status}`);
}
return await response.json();
}
export function registerBiEngineRoutes(app: Express): void {
app.post("/api/bi-engine/analyze", async (req, res) => {
if (!req.isAuthenticated()) return res.status(401).json({ error: "Not authenticated" });
...
});
}
<!-- KG service — server/graph/service.ts -->
export async function createNode(data: InsertGraphNode): Promise<GraphNode>
// InsertGraphNode: { type: string, tenantId?: number, data: object }
// graph_nodes tabela PostgreSQL — NÃO usar Neo4j direto
<!-- Registro de routes em server/routes.ts (linha ~105) -->
import { registerBiEngineRoutes } from "./bi/engine-proxy"; // padrão a seguir
registerBiEngineRoutes(app); // linha ~105
<!-- AnalyzeResponse do microserviço Python (03-01) -->
{
agent: string, // "statistician" | "fiscal_auditor" | "researcher"
model: string, // "deepseek-r1:14b" | "llama3.1:8b"
result: string,
execution_id: string, // UUID v4
duration_ms: number
}
</interfaces>
</context>
<tasks>
<task type="auto" tdd="true">
<name>Task 1: Criar server/miroflow/engine-proxy.ts e server/miroflow/routes.ts</name>
<files>server/miroflow/engine-proxy.ts, server/miroflow/routes.ts</files>
<read_first>
- /opt/arcadia_merged/server/bi/engine-proxy.ts (padrão completo de proxy a seguir)
- /opt/arcadia_merged/server/graph/service.ts (createNode signature, linhas 41-49)
- /opt/arcadia_merged/server/graph/routes.ts (confirmar que /api/graph/nodes aceita POST)
- /opt/arcadia_merged/server/auth.ts (confirmar req.isAuthenticated() e req.user shape)
</read_first>
<behavior>
- proxyToMiroFlow("/health", "GET") faz fetch para MIROFLOW_URL/health com timeout 5s
- proxyToMiroFlow("/analyze", "POST", body) faz fetch para MIROFLOW_URL/analyze com timeout 300000ms
- POST /api/miroflow/analyze sem autenticação retorna 401 {"error": "Não autenticado"}
- POST /api/miroflow/analyze autenticado encaminha body + tenant_id para :8006/analyze
- Após resposta bem-sucedida, registerExecutionInKG cria nó com type="miroflow_execution"
- auditHash é SHA-256 do JSON.stringify({execution_id, agent, model, input, output})
- GET /api/miroflow/health não requer autenticação, retorna {online: bool, url: string}
</behavior>
<action>
Criar diretório server/miroflow/ se não existir.
Criar server/miroflow/engine-proxy.ts:
```typescript
import type { Express, Request, Response } from "express";
import crypto from "crypto";
import { createNode } from "../graph/service";
const MIROFLOW_HOST = process.env.MIROFLOW_HOST || "localhost";
const MIROFLOW_PORT = parseInt(process.env.MIROFLOW_PORT || "8006", 10);
const MIROFLOW_URL = `http://${MIROFLOW_HOST}:${MIROFLOW_PORT}`;
const MIROFLOW_TIMEOUT = 300_000; // 5 minutos — deepseek-r1:14b pode levar 60-120s
async function proxyToMiroFlow(path: string, method: string = "GET", body?: object): Promise<any> {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), MIROFLOW_TIMEOUT);
try {
const response = await fetch(`${MIROFLOW_URL}${path}`, {
method,
headers: { "Content-Type": "application/json" },
body: body ? JSON.stringify(body) : undefined,
signal: controller.signal,
});
clearTimeout(timeout);
if (!response.ok) {
const err = await response.json().catch(() => ({ detail: response.statusText }));
throw new Error(err.detail || `MiroFlow error: ${response.status}`);
}
return await response.json();
} catch (err: any) {
clearTimeout(timeout);
if (err.name === "AbortError") throw new Error("MiroFlow timeout (300s)");
throw err;
}
}
async function registerExecutionInKG(req: Request, execData: any, inputBody: any): Promise<void> {
try {
const auditHash = crypto
.createHash("sha256")
.update(JSON.stringify({
execution_id: execData.execution_id,
agent: execData.agent,
model: execData.model,
input: inputBody,
output: execData.result,
}))
.digest("hex");
await createNode({
type: "miroflow_execution",
tenantId: (req.user as any)?.tenantId ?? null,
data: {
...execData,
input: inputBody,
auditHash,
immutable: true,
registeredAt: new Date().toISOString(),
},
});
} catch (kgErr: any) {
// KG failure não deve bloquear a resposta ao cliente
console.error("[MiroFlow] Falha ao registrar no KG:", kgErr.message);
}
}
export function registerMiroFlowRoutes(app: Express): void {
app.get("/api/miroflow/health", async (_req: Request, res: Response) => {
try {
const data = await proxyToMiroFlow("/health", "GET");
res.json({ online: true, url: MIROFLOW_URL, ...data });
} catch {
res.json({ online: false, url: MIROFLOW_URL });
}
});
app.post("/api/miroflow/analyze", async (req: Request, res: Response) => {
if (!req.isAuthenticated()) {
return res.status(401).json({ error: "Não autenticado" });
}
try {
const inputBody = {
...req.body,
tenant_id: (req.user as any)?.tenantId ?? null,
};
const data = await proxyToMiroFlow("/analyze", "POST", inputBody);
// Registrar no KG de forma assíncrona (não bloqueia a resposta)
registerExecutionInKG(req, data, req.body).catch(() => {});
res.json(data);
} catch (err: any) {
res.status(502).json({ error: err.message });
}
});
console.log(`[MiroFlow Proxy] Rotas registradas -> ${MIROFLOW_URL}`);
}
```
Criar server/miroflow/routes.ts como re-export limpo (manter compatibilidade com o loader de módulos):
```typescript
export { registerMiroFlowRoutes } from "./engine-proxy";
```
IMPORTANTE:
- Timeout de 300_000ms (5 minutos) — NÃO usar o padrão de 30s do bi/engine-proxy.ts
- registerExecutionInKG usa createNode do graph/service.ts, NÃO faz fetch para /api/graph/nodes
- Falha no KG não retorna erro ao cliente (try/catch com log)
- auditHash cobre: execution_id + agent + model + input + output
</action>
<verify>
<automated>cd /opt/arcadia_merged && npx tsc --noEmit --project tsconfig.json 2>&1 | grep -i "miroflow" | head -10 || echo "TypeScript OK (nenhum erro em miroflow)"</automated>
</verify>
<acceptance_criteria>
- server/miroflow/engine-proxy.ts existe e compila sem erros TypeScript
- server/miroflow/routes.ts existe (re-export ou implementação direta)
- MIROFLOW_TIMEOUT = 300_000 está definido (não 30000)
- Função registerExecutionInKG usa createNode importado de "../graph/service"
- auditHash calculado com crypto.createHash("sha256")
- POST /api/miroflow/analyze faz verificação req.isAuthenticated() antes de proxiar
- grep -n "300_000\|300000" server/miroflow/engine-proxy.ts retorna resultado
- grep -n "miroflow_execution" server/miroflow/engine-proxy.ts retorna resultado
</acceptance_criteria>
<done>Arquivos TypeScript criados sem erros de compilação. Funções exportadas: registerMiroFlowRoutes. Timeout de 5min configurado. KG logging com SHA-256 implementado.</done>
</task>
<task type="auto">
<name>Task 2: Registrar MiroFlow em server/routes.ts</name>
<files>server/routes.ts</files>
<read_first>
- /opt/arcadia_merged/server/routes.ts (ARQUIVO INTEIRO — verificar imports e onde registerBiEngineRoutes é chamado para inserir MiroFlow no mesmo padrão)
</read_first>
<action>
Adicionar import e registro das rotas MiroFlow em server/routes.ts, seguindo o padrão exato de registerBiEngineRoutes:
1. Adicionar import após a linha que importa registerBiEngineRoutes (linha ~19):
```typescript
import { registerMiroFlowRoutes } from "./miroflow/engine-proxy";
```
2. Adicionar chamada após registerBiEngineRoutes(app) (linha ~105):
```typescript
registerMiroFlowRoutes(app);
```
NÃO alterar nenhuma outra linha do arquivo. NÃO mover, reordenar ou reformatar código existente.
NÃO modificar configurações do Superset ou rotas existentes.
</action>
<verify>
<automated>cd /opt/arcadia_merged && grep -n "registerMiroFlowRoutes" server/routes.ts && npx tsc --noEmit --project tsconfig.json 2>&1 | grep -c "error" || echo "0 erros"</automated>
</verify>
<acceptance_criteria>
- `grep "registerMiroFlowRoutes" server/routes.ts` retorna 2 linhas (import + chamada)
- `npx tsc --noEmit` não retorna erros relacionados a miroflow
- A linha de import está próxima de registerBiEngineRoutes (mesma região do arquivo)
- A chamada registerMiroFlowRoutes(app) está próxima de registerBiEngineRoutes(app)
- Nenhuma linha existente do arquivo foi modificada (verificar com git diff)
</acceptance_criteria>
<done>server/routes.ts registra as rotas MiroFlow. POST /api/miroflow/analyze e GET /api/miroflow/health estarão disponíveis quando o servidor Node iniciar.</done>
</task>
</tasks>
<verification>
```bash
# Compilação TypeScript limpa:
cd /opt/arcadia_merged && npx tsc --noEmit 2>&1 | grep -i "error" | head -5
# Confirmar registro no KG:
grep -n "miroflow_execution\|auditHash\|createNode" /opt/arcadia_merged/server/miroflow/engine-proxy.ts
# Confirmar timeout correto:
grep -n "300" /opt/arcadia_merged/server/miroflow/engine-proxy.ts
# Confirmar rotas registradas:
grep -n "registerMiroFlowRoutes" /opt/arcadia_merged/server/routes.ts
```
</verification>
<success_criteria>
- server/miroflow/engine-proxy.ts e server/miroflow/routes.ts existem
- TypeScript compila sem erros nos novos arquivos
- server/routes.ts inclui import e chamada registerMiroFlowRoutes
- Timeout de 300s configurado no proxy
- auditHash SHA-256 calculado e salvo via createNode
- GET /api/miroflow/health acessível sem autenticação
- POST /api/miroflow/analyze requer autenticação (401 sem sessão)
</success_criteria>
<output>
Após conclusão, criar `.planning/phases/03-miroflow-embutido/03-02-SUMMARY.md` com:
- Arquivos criados/modificados
- Resultado da compilação TypeScript
- Confirmação do padrão de timeout (300s)
- Confirmação do KG logging com auditHash
</output>

View File

@ -1,40 +0,0 @@
---
plan: "03-02"
phase: "03-miroflow-embutido"
status: complete
completed: 2026-03-25
---
# Summary: 03-02 — Node.js MiroFlow Bridge
## What was built
Bridge Node.js → Python para o MiroFlow: proxy TypeScript com timeout 300s, rotas Express autenticadas e registro imutável de execuções no KG via auditHash SHA-256.
## Files created/modified
### Created
- `server/miroflow/engine-proxy.ts` — proxy para :8006, MIROFLOW_TIMEOUT=300_000ms, registerExecutionInKG com SHA-256
- `server/miroflow/routes.ts` — re-export de registerMiroFlowRoutes
### Modified
- `server/routes.ts` — import + chamada registerMiroFlowRoutes(app) após registerBiEngineRoutes
## Key decisions
- Timeout de 300_000ms (5 min) para POST /analyze — adequado para deepseek-r1:14b
- Health check usa timeout curto (5_000ms)
- KG failure não bloqueia resposta ao cliente (try/catch com console.error)
- auditHash cobre: execution_id + agent + model + input + output
## TypeScript compilation
Erros nos novos arquivos: **0**
(Erros pré-existentes em App.tsx e server/modules/miroflow/ não relacionados)
## Commits
- `d53be76` — feat(03-02): criar MiroFlow proxy TypeScript com timeout 300s e KG audit logging
- `1a70e87` — feat(03-02): registrar MiroFlow routes em server/routes.ts
## Self-Check: PASSED

View File

@ -1,315 +0,0 @@
---
id: "03-03"
phase: 03-miroflow-embutido
plan: 03
type: execute
wave: 2
depends_on: ["03-02"]
files_modified:
- client/src/components/MiroFlowControl.tsx
- client/src/pages/BiWorkspace.tsx
autonomous: false
requirements:
- REQ-3.6
must_haves:
truths:
- "Tab 'Científico' aparece na TabsList de BiWorkspace.tsx"
- "MiroFlowControl.tsx renderiza toggle 'Modo Científico' com ícone Brain"
- "Usuário pode selecionar agente (Statistician / Fiscal Auditor / Researcher)"
- "Usuário pode digitar tarefa e clicar em Analisar"
- "Resultado da análise é exibido em área de texto com scroll"
- "Estado de loading é exibido durante a chamada (ícone Loader2 girando)"
- "Erro da API é exibido ao usuário de forma legível"
- "Tabs existentes (overview, datasources, etc.) continuam funcionando normalmente"
artifacts:
- path: "client/src/components/MiroFlowControl.tsx"
provides: "Componente React com toggle, seletor de agente, input de tarefa e exibição de resultado"
exports: ["MiroFlowControl"]
- path: "client/src/pages/BiWorkspace.tsx"
provides: "Tab 'cientifico' adicionada à TabsList e TabsContent existentes"
contains: "TabsTrigger value=\"cientifico\""
key_links:
- from: "client/src/components/MiroFlowControl.tsx"
to: "/api/miroflow/analyze"
via: "apiRequest('POST', '/api/miroflow/analyze', {agent, task})"
pattern: "miroflow/analyze"
- from: "client/src/pages/BiWorkspace.tsx"
to: "client/src/components/MiroFlowControl.tsx"
via: "import { MiroFlowControl } from '@/components/MiroFlowControl'"
pattern: "MiroFlowControl"
---
<objective>
Criar o componente MiroFlowControl.tsx e integrá-lo ao BiWorkspace.tsx como nova tab "Científico" com toggle "Modo Científico".
Purpose: Expõe as análises científicas MiroFlow diretamente no contexto BI, permitindo ao usuário acionar agentes LLM especializados ao lado dos dashboards Superset.
Output: Tab funcional em BiWorkspace com formulário de análise, seletor de agente e display de resultado.
</objective>
<execution_context>
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
@$HOME/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/phases/03-miroflow-embutido/03-02-SUMMARY.md
@.planning/phases/03-miroflow-embutido/03-RESEARCH.md
<interfaces>
<!-- BiWorkspace.tsx — estrutura de tabs (linhas 2870-2888) -->
// Estado:
const [activeTab, setActiveTab] = useState("overview");
// Estrutura:
<Tabs value={activeTab} onValueChange={setActiveTab} className="space-y-6">
<TabsList className="bg-[#1f334d] border border-[#c89b3c]/20 p1">
<TabsTrigger value="overview" className="data-[state=active]:bg-[#c89b3c] data-[state=active]:text-[#1f334d] text-white/70">
<LayoutDashboard className="w-4 h-4 mr-2" /> Visão Geral
</TabsTrigger>
<TabsTrigger value="datasources" ...> <Database .../> Fontes de Dados </TabsTrigger>
<TabsTrigger value="upload" ...> <Upload .../> Upload </TabsTrigger>
<TabsTrigger value="datasets" ...> <FileText .../> Consultas </TabsTrigger>
<TabsTrigger value="charts" ...> <BarChart3 .../> Gráficos </TabsTrigger>
<TabsTrigger value="backups" ...> <Archive .../> Backups </TabsTrigger>
<!-- ADICIONAR AQUI: <TabsTrigger value="cientifico" ...> <Brain .../> Científico </TabsTrigger> -->
</TabsList>
<TabsContent value="overview">...</TabsContent>
<TabsContent value="datasources">...</TabsContent>
<!-- ... outros TabsContent ... -->
<!-- ADICIONAR: <TabsContent value="cientifico"><MiroFlowControl /></TabsContent> -->
</Tabs>
<!-- Imports disponíveis em BiWorkspace.tsx — já importados, usar estes -->
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
// Lucide icons já importados: Bot, Brain NÃO está importado — adicionar ao import
// shadcn/ui components já disponíveis: Button, Card, CardContent, CardHeader, CardTitle,
// Badge, ScrollArea, Input, Textarea, Select, SelectContent, SelectItem, SelectTrigger, SelectValue
<!-- API pattern usado no projeto (apiRequest de wouter/queryClient) -->
// Verificar como outros componentes fazem POST — geralmente:
import { apiRequest } from "@/lib/queryClient";
// ou via useMutation do @tanstack/react-query
const mutation = useMutation({ mutationFn: (body) => apiRequest("POST", "/api/miroflow/analyze", body) });
<!-- AnalyzeResponse do backend (03-02) -->
interface AnalyzeResponse {
agent: string;
model: string;
result: string;
execution_id: string;
duration_ms: number;
}
</interfaces>
</context>
<tasks>
<task type="auto">
<name>Task 1: Criar client/src/components/MiroFlowControl.tsx</name>
<files>client/src/components/MiroFlowControl.tsx</files>
<read_first>
- /opt/arcadia_merged/client/src/lib/queryClient.ts (confirmar apiRequest signature)
- /opt/arcadia_merged/client/src/pages/BiWorkspace.tsx linhas 1-60 (imports disponíveis e padrão de componentes)
- /opt/arcadia_merged/client/src/components/ (listar arquivos para verificar convenções de nomenclatura)
</read_first>
<action>
Criar client/src/components/MiroFlowControl.tsx como componente React standalone.
O componente deve:
1. Exibir card com header "Modo Científico" e ícone Brain
2. Toggle switch ou badge "Ativado" quando em modo científico (estado local `enabled`)
3. Select para escolha do agente: Statistician (deepseek-r1:14b), Fiscal Auditor (deepseek-r1:14b), Researcher (llama3.1:8b)
4. Textarea para digitar a tarefa (placeholder específico por agente)
5. Botão "Analisar" que dispara POST /api/miroflow/analyze
6. Área de resultado com ScrollArea mostrando a resposta formatada
7. Estado de loading com Loader2 animado durante chamada
8. Exibir erros de forma legível (badge vermelho + mensagem)
9. Metadados do resultado: modelo usado, tempo de execução, execution_id (em texto pequeno)
Props: `currentDashboardData?: Record<string, unknown>` (opcional, para contexto futuro)
Usar useMutation do @tanstack/react-query para a chamada POST.
Estrutura de tipos locais:
```typescript
interface AnalyzeRequest {
agent: "statistician" | "fiscal_auditor" | "researcher";
task: string;
context?: Record<string, unknown>;
}
interface AnalyzeResponse {
agent: string;
model: string;
result: string;
execution_id: string;
duration_ms: number;
}
```
Agentes disponíveis (hardcoded, sem fetch):
```typescript
const AGENTS = [
{ value: "statistician", label: "Statistician", model: "deepseek-r1:14b",
placeholder: "Ex: Analise a distribuição de vendas por região no último trimestre" },
{ value: "fiscal_auditor", label: "Fiscal Auditor", model: "deepseek-r1:14b",
placeholder: "Ex: Verifique inconsistências nos registros NFe do CNPJ 12.345.678/0001-90" },
{ value: "researcher", label: "Researcher", model: "llama3.1:8b",
placeholder: "Ex: Quais fornecedores têm maior correlação com atrasos de entrega?" },
] as const;
```
Estilização: seguir o padrão dark de BiWorkspace (bg-[#1f334d], text-white, border-[#c89b3c]/20, text-[#c89b3c]).
NÃO usar estados globais, stores ou contextos externos.
NÃO fazer fetch para /api/miroflow/health neste componente.
</action>
<verify>
<automated>cd /opt/arcadia_merged && npx tsc --noEmit --project tsconfig.json 2>&1 | grep -i "MiroFlowControl\|miroflow" | head -10 || echo "TypeScript OK"</automated>
</verify>
<acceptance_criteria>
- client/src/components/MiroFlowControl.tsx existe e exporta MiroFlowControl como default ou named export
- `npx tsc --noEmit` não retorna erros relacionados a MiroFlowControl.tsx
- Componente tem prop `currentDashboardData?: Record<string, unknown>`
- Select com os 3 agentes (statistician, fiscal_auditor, researcher)
- Textarea para task com placeholder dinâmico por agente selecionado
- useMutation configurado para POST /api/miroflow/analyze
- Estado de loading exibido (Loader2 ou spinner equivalente)
- Erro exibido quando mutation.isError
- Resultado exibido quando mutation.isSuccess com metadados (model, duration_ms)
- Nenhuma referência a modelos acima de 14B
</acceptance_criteria>
<done>MiroFlowControl.tsx criado, compila sem erros TypeScript. Componente pronto para ser importado pelo BiWorkspace.</done>
</task>
<task type="auto">
<name>Task 2: Adicionar tab "Científico" ao BiWorkspace.tsx</name>
<files>client/src/pages/BiWorkspace.tsx</files>
<read_first>
- /opt/arcadia_merged/client/src/pages/BiWorkspace.tsx linhas 2860-2920 (TabsList atual — localizar exatamente onde inserir)
- /opt/arcadia_merged/client/src/pages/BiWorkspace.tsx linhas 1-55 (imports para adicionar Brain e MiroFlowControl)
- /opt/arcadia_merged/client/src/pages/BiWorkspace.tsx linhas 2950-3050 (após os TabsContent existentes — localizar o fechamento para inserir novo TabsContent)
</read_first>
<action>
BiWorkspace.tsx é um arquivo grande (~3000 linhas). Fazer APENAS as 3 modificações cirúrgicas abaixo:
MODIFICAÇÃO 1 — Adicionar Brain ao import de lucide-react (linha ~10-50):
Localizar `import { ... } from "lucide-react"` e adicionar `Brain` à lista.
(Verificar se Brain já está importado antes de adicionar)
MODIFICAÇÃO 2 — Adicionar MiroFlowControl import (após os imports existentes):
```typescript
import { MiroFlowControl } from "@/components/MiroFlowControl";
```
MODIFICAÇÃO 3 — Adicionar TabsTrigger na TabsList (após o último TabsTrigger existente, antes do fechamento </TabsList>):
```tsx
<TabsTrigger value="cientifico" className="data-[state=active]:bg-[#c89b3c] data-[state=active]:text-[#1f334d] text-white/70">
<Brain className="w-4 h-4 mr-2" /> Científico
</TabsTrigger>
```
MODIFICAÇÃO 4 — Adicionar TabsContent (após o último TabsContent existente, antes do fechamento </Tabs>):
```tsx
<TabsContent value="cientifico">
<MiroFlowControl />
</TabsContent>
```
NÃO alterar nenhum TabsTrigger ou TabsContent existente.
NÃO modificar o estado activeTab ou qualquer lógica existente.
NÃO reformatar ou reorganizar o código existente.
NÃO remover nenhum import existente.
Verificar o arquivo antes e depois com grep para confirmar que os 4 tabs originais ainda existem.
</action>
<verify>
<automated>cd /opt/arcadia_merged && grep -c 'TabsTrigger value=' client/src/pages/BiWorkspace.tsx && npx tsc --noEmit --project tsconfig.json 2>&1 | grep -i "BiWorkspace\|MiroFlow" | head -5 || echo "TypeScript OK"</automated>
</verify>
<acceptance_criteria>
- `grep -c 'TabsTrigger value=' client/src/pages/BiWorkspace.tsx` retorna 7 (6 existentes + 1 novo "cientifico")
- `grep 'value="cientifico"' client/src/pages/BiWorkspace.tsx` retorna 2 linhas (TabsTrigger + TabsContent)
- `grep 'Brain' client/src/pages/BiWorkspace.tsx` retorna resultado (importado e usado)
- `grep 'MiroFlowControl' client/src/pages/BiWorkspace.tsx` retorna resultado (importado e usado)
- `npx tsc --noEmit` não retorna erros em BiWorkspace.tsx
- Tabs existentes ("overview", "datasources", "upload", "datasets", "charts", "backups") ainda presentes
- Nenhum outro código do arquivo foi alterado (git diff mostra apenas as 4 adições)
</acceptance_criteria>
<done>BiWorkspace.tsx contém tab "Científico" que renderiza MiroFlowControl. Tabs existentes preservadas. Compila sem erros.</done>
</task>
<task type="checkpoint:human-verify" gate="blocking">
<what-built>
- MiroFlowControl.tsx: componente com toggle "Modo Científico", seletor de 3 agentes, textarea de tarefa e display de resultado
- BiWorkspace.tsx: tab "Científico" adicionada (7 tabs no total)
- Backend (planos 01 e 02): microserviço Python porta 8006 + proxy Node + KG logging
</what-built>
<how-to-verify>
1. Iniciar o servidor: `npm run dev` (ou verificar se já está rodando)
2. Iniciar o microserviço MiroFlow: `MIROFLOW_PORT=8006 python3 server/python/miroflow_service.py &`
3. Navegar para /bi-workspace no browser
4. Verificar que a tab "Científico" aparece no TabsList (ícone Brain + texto)
5. Clicar na tab "Científico"
6. Verificar que o painel MiroFlowControl renderiza sem erros JavaScript no console
7. Selecionar o agente "Statistician"
8. Digitar uma tarefa simples: "Liste os 3 principais insights sobre análise estatística"
9. Clicar em "Analisar"
10. Verificar que o estado de loading aparece (Loader2 girando)
11. Após resposta: verificar que o resultado é exibido com o modelo (deepseek-r1:14b) e tempo de execução
12. Verificar GET http://localhost:8006/health retorna {"online": true} em outro aba
13. Verificar as outras 6 tabs (overview, datasources, etc.) ainda funcionam normalmente
</how-to-verify>
<resume-signal>
Digite "aprovado" se tudo funcionar corretamente.
Ou descreva os problemas encontrados (ex: "tab não aparece", "erro 502 na análise", "loading infinito").
</resume-signal>
</task>
</tasks>
<verification>
```bash
# Verificar estrutura dos arquivos:
ls /opt/arcadia_merged/client/src/components/MiroFlowControl.tsx
# Verificar tab adicionada:
grep -n 'cientifico\|Científico\|MiroFlowControl\|Brain' /opt/arcadia_merged/client/src/pages/BiWorkspace.tsx
# Verificar compilação:
cd /opt/arcadia_merged && npx tsc --noEmit 2>&1 | tail -5
# Contagem de tabs:
grep -c 'TabsTrigger value=' /opt/arcadia_merged/client/src/pages/BiWorkspace.tsx
```
</verification>
<success_criteria>
- MiroFlowControl.tsx existe e exporta componente válido
- BiWorkspace.tsx tem 7 TabsTriggers (6 originais + "cientifico")
- TypeScript compila sem erros nos novos arquivos
- Usuário aprova verificação visual do checkpoint
- Tabs existentes do BiWorkspace continuam funcionando
</success_criteria>
<output>
Após conclusão e aprovação do checkpoint, criar `.planning/phases/03-miroflow-embutido/03-03-SUMMARY.md` com:
- Arquivos criados/modificados
- Screenshot ou descrição do estado visual da tab "Científico"
- Resultado da verificação humana
- Qualquer ajuste feito após o checkpoint
</output>

View File

@ -1,551 +0,0 @@
# Phase 3: MiroFlow Embutido - Research
**Researched:** 2026-03-25
**Domain:** Python agent framework (MiroFlow) integrado ao Node.js/Express + Ollama local + Superset bridge
**Confidence:** HIGH (baseado em inspeção direta do código-fonte e serviços ativos)
---
## Summary
O Phase 3 conecta o framework Python MiroFlow (já clonado como submodule em `server/modules/miroflow/`) ao backend Node.js do Arcádia Suite, expondo um endpoint `POST /api/miroflow/analyze` que despacha para um microserviço Python FastAPI. Esse microserviço instancia agentes MiroFlow configurados via YAML, aponta para o Ollama local (já rodando na porta 11434 com `deepseek-r1:14b` instalado), e registra cada execução como nó imutável no KG (tabela `graph_nodes` via `/api/graph/nodes`).
O padrão de integração Node ↔ Python já está estabelecido no projeto: `server/bi/engine-proxy.ts` e `server/python/bi_analysis_service.py` demonstram o fluxo exato — Express proxy faz `fetch()` para FastAPI local; a resposta é repassada ao cliente. O novo microserviço MiroFlow (`miroflow_service.py`) seguirá o mesmo padrão, rodando na porta 8006. O agente `Researcher` exige `llama3.1:8b`, que **ainda não está instalado no Ollama** (apenas `deepseek-r1:14b`, `llama3.2:3b` e `nomic-embed-text` estão disponíveis).
No frontend, o componente `MiroFlowControl.tsx` será um painel overlay/tab injetado na página `BiWorkspace.tsx` que já usa o `SupersetDashboard` component. O toggle "Modo Científico" chama `POST /api/miroflow/analyze` e exibe a resposta estruturada ao lado do dashboard Superset.
**Primary recommendation:** Construir `server/python/miroflow_service.py` como FastAPI standalone (porta 8006), instanciar agentes MiroFlow com YAML inline (sem arquivos externos), usar `UnifiedOpenAIClient` apontando para Ollama via `OLLAMA_BASE_URL/v1`, registrar execuções via `createNode()` do graph service.
---
## User Constraints
*(Seção obrigatória — copiada do STATE.md/ROADMAP.md/PROJECT.md que fazem as vezes de CONTEXT.md)*
### Locked Decisions
- Stack: Node.js + TypeScript backend, React + TypeScript frontend, PostgreSQL, Neo4j KG
- IA: Ollama local MÁXIMO 14B — `deepseek-r1:14b` para Statistician e Fiscal Auditor, `llama3.1:8b` para Researcher
- **NUNCA usar modelos acima de 14B**: proibido citar ou planejar `deepseek-r1:32b`, `deepseek-r1:70b`, `llama3.1:70b` ou qualquer modelo maior
- MiroFlow já clonado em `server/modules/miroflow/` como submodule Python
- Branch de deploy: `Servidor`
- Superset em produção com RLS — não alterar configurações existentes
- Backend-first: API definida antes do frontend
- Auditoria imutável em todas as execuções (KG)
### Claude's Discretion
- Porta do microserviço MiroFlow (recomenda-se 8006 pelo padrão existente)
- Estrutura interna dos agentes MiroFlow (YAML inline vs arquivos externos)
- Forma de integrar o toggle no frontend (overlay, tab, painel lateral)
- Como fazer o `llama3.1:8b` ser baixado (wave 0 task vs setup manual)
### Deferred Ideas (OUT OF SCOPE)
- Versionamento Git-like de skills (Phase 2 pendente, não Phase 3)
- OpenClaw (Phase 4)
- Automation Fabric (Phase 5)
- Dev Center Completo (Phase 6)
---
## Standard Stack
### Core
| Library | Version | Purpose | Why Standard |
|---------|---------|---------|--------------|
| MiroFlow | 1.7.0 | Framework de agentes Python | Já no submodule, desenvolvido pela MiromindAI |
| FastAPI | >=0.115.0 | Microserviço Python | Padrão já usado em todos os serviços Python do projeto |
| uvicorn | >=0.32.0 | ASGI server | Usado em todos os serviços Python |
| omegaconf | (via miroflow deps) | Configuração YAML com variáveis | Dependência central do MiroFlow |
| hydra-core | >=1.3.2 | Composição de configurações | Dependência central do MiroFlow |
| openai | ==1.78.1 | Cliente HTTP para Ollama (OpenAI-compat.) | MiroFlow usa `UnifiedOpenAIClient` via openai SDK |
| httpx / aiohttp | >=0.28.1 / >=3.12.15 | HTTP async | Dependências do MiroFlow e FastAPI |
### Supporting
| Library | Version | Purpose | When to Use |
|---------|---------|---------|-------------|
| python-dotenv | >=1.1.1 | Leitura de .env | Inicialização do microserviço |
| pydantic | >=2.x | Validação de request/response | Models FastAPI |
| neo4j (driver) | opcional | Neo4j direto | Apenas se precisar grafo real; por ora usa `graph_nodes` PostgreSQL |
| psycopg2-binary | >=2.9.x | PostgreSQL direto | Se microserviço precisar escrever no banco |
### Alternatives Considered
| Instead of | Could Use | Tradeoff |
|------------|-----------|----------|
| Microserviço FastAPI separado | Subprocess Node → Python | subprocess é síncrono e frágil; FastAPI segue padrão estabelecido |
| YAML files externos | YAML inline (dict) em Python | Inline elimina dependência de caminhos de arquivo em container |
| Ollama direto (porta 11434) | Via LiteLLM gateway (porta 4000) | LiteLLM tem fallback e roteamento; Ollama direto é mais simples para agentes isolados |
**Installation (para o microserviço):**
```bash
# Instalar dependências no ambiente Python do servidor
pip install fastapi uvicorn omegaconf hydra-core openai python-dotenv pydantic psycopg2-binary
# Ou instalar o miroflow inteiro com uv:
cd server/modules/miroflow && uv sync
```
**Version verification:** Os pacotes acima são os listados no `pyproject.toml` do MiroFlow v1.7.0, verificado diretamente no arquivo.
---
## Architecture Patterns
### Recommended Project Structure
```
server/python/
├── miroflow_service.py # novo microserviço FastAPI (porta 8006)
├── bi_analysis_service.py # existente (referência de padrão)
└── ...
server/miroflow/
├── routes.ts # Express router: POST /api/miroflow/analyze
└── engine-proxy.ts # fetch() para http://localhost:8006
client/src/
├── pages/BiWorkspace.tsx # EXISTENTE — adicionar tab "Científico"
└── components/
└── MiroFlowControl.tsx # NOVO — toggle + resultado da análise
docker/python-entrypoint.sh # adicionar case "miroflow" → porta 8006
docker-compose.prod.yml # adicionar serviço miroflow (porta 8006)
```
### Pattern 1: Node → Python Microservice Proxy
**What:** Express recebe a request, faz fetch() para FastAPI, retorna o resultado. Sem subprocess, sem child_process.
**When to use:** Sempre que Node.js precisar de lógica Python (pandas, ML, agentes).
**Example:**
```typescript
// Source: server/bi/engine-proxy.ts (padrão existente)
const MIROFLOW_URL = `http://${process.env.MIROFLOW_HOST || "localhost"}:${process.env.MIROFLOW_PORT || "8006"}`;
async function proxyToMiroFlow(path: string, body: object): Promise<any> {
const response = await fetch(`${MIROFLOW_URL}${path}`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body),
signal: AbortSignal.timeout(300_000), // 5min — modelos LLM são lentos
});
if (!response.ok) {
const err = await response.json().catch(() => ({ detail: response.statusText }));
throw new Error(err.detail || `MiroFlow error: ${response.status}`);
}
return response.json();
}
```
### Pattern 2: MiroFlow Agent com Ollama via UnifiedOpenAIClient
**What:** MiroFlow usa `UnifiedOpenAIClient` com `base_url` apontando para Ollama (OpenAI-compatible API em `/v1`).
**When to use:** Para todos os agentes do Phase 3.
**Example:**
```python
# Source: server/modules/miroflow/miroflow/llm/openai_client.py + config/llm/base.yaml
from miroflow.agents.factory import build_agent
from miroflow.agents.context import AgentContext
AGENT_CONFIG_STATISTICIAN = {
"type": "IterativeAgentWithToolAndRollback",
"max_turns": 10,
"llm": {
"provider_class": "UnifiedOpenAIClient",
"model_name": "deepseek-r1:14b",
"api_key": "ollama", # Ollama não valida api_key
"base_url": "http://localhost:11434/v1", # Ollama OpenAI-compat
"max_tokens": 8192,
"temperature": 0.7,
"top_p": 1.0, "min_p": 0.0, "top_k": -1,
"reasoning_effort": None, "repetition_penalty": 1.0,
"max_context_length": -1, "async_client": True,
"disable_cache_control": True, "keep_tool_result": -1,
"use_tool_calls": False, "oai_tool_thinking": False,
},
}
agent = build_agent(AGENT_CONFIG_STATISTICIAN)
ctx = AgentContext(task_description="Analise os seguintes dados SQL: ...")
result = await agent.run(ctx)
```
### Pattern 3: Registro Imutável no KG via graph_nodes
**What:** Após cada execução MiroFlow, registrar no PostgreSQL via `POST /api/graph/nodes`.
**When to use:** Toda execução de agente (success ou error).
**Example:**
```typescript
// Source: server/graph/service.ts createNode() — chamado pelo routes.ts de miroflow
await fetch("/api/graph/nodes", {
method: "POST",
body: JSON.stringify({
type: "miroflow_execution",
tenantId: req.user?.tenantId,
data: {
agent: "statistician",
model: "deepseek-r1:14b",
input: analysisRequest,
output: analysisResult,
auditHash: sha256(JSON.stringify({ executionId, input, output })),
executedAt: new Date().toISOString(),
}
})
});
```
### Pattern 4: MiroFlowControl.tsx como tab em BiWorkspace
**What:** BiWorkspace.tsx já tem estrutura de tabs (Tabs/TabsContent de shadcn/ui). Adicionar tab "Científico" que renderiza `MiroFlowControl`.
**When to use:** Ponto de entrada do toggle "Modo Científico" no contexto do BI.
**Example:**
```tsx
// Source: client/src/pages/BiWorkspace.tsx (padrão de tabs existente)
import { MiroFlowControl } from "@/components/MiroFlowControl";
// Dentro do <TabsList>:
<TabsTrigger value="cientifico"><Brain /> Científico</TabsTrigger>
// Dentro das <TabsContent>:
<TabsContent value="cientifico">
<MiroFlowControl currentDashboardData={currentData} />
</TabsContent>
```
### Anti-Patterns to Avoid
- **subprocess.run() no Node**: Não usar `child_process.spawn()` para chamar Python — use o microserviço FastAPI (padrão estabelecido)
- **Carregar miroflow no container Node**: O Dockerfile principal é Node.js puro — Python deve rodar em container separado (Dockerfile.python)
- **Modelos > 14B**: Nunca usar `deepseek-r1:32b`, `deepseek-r1:70b`, `llama3.1:70b` ou qualquer modelo acima de 14B parâmetros
- **Modificar configurações do Superset**: O proxy `/superset/*` e as rotas `/api/superset/*` existentes não devem ser alterados
- **Hardcoded OLLAMA_BASE_URL**: Sempre ler de env var `OLLAMA_BASE_URL` (default `http://localhost:11434`)
---
## Don't Hand-Roll
| Problem | Don't Build | Use Instead | Why |
|---------|-------------|-------------|-----|
| Orquestração de agentes LLM | Loop manual de chamadas LLM | MiroFlow `IterativeAgentWithToolAndRollback` | Rollback automático, retry, tool calling já implementado |
| Proxy Node → Python | Child process / spawn | `fetch()` para FastAPI (padrão `engine-proxy.ts`) | Stateless, async, sem gestão de processos |
| Configuração de LLM | Classe própria de cliente | `UnifiedOpenAIClient` do MiroFlow | Já tem retry, context limit handling, tool protocol |
| Embedding da análise no Superset | iframe manual com JS | `SupersetDashboard.tsx` já existente | Guest token, SDK do Superset, error handling prontos |
| Logs de execução imutáveis | Nova tabela no banco | `graph_nodes` + `createNode()` via `server/graph/service.ts` | Infraestrutura de KG já existente com embeddings |
| Validação de request/response | Manual | Pydantic models + FastAPI auto-validation | Type safety e OpenAPI spec grátis |
**Key insight:** O projeto já tem todos os primitivos necessários. Phase 3 é essencialmente "conectar os pontos" — o agente Python já existe, o gateway LLM (LiteLLM/Ollama) já está configurado, o KG já tem tabelas, o padrão de proxy Node→Python já está implementado.
---
## Runtime State Inventory
> Fase é greenfield (novo microserviço e novas rotas). Não há renomeações ou migrações de dados existentes.
| Category | Items Found | Action Required |
|----------|-------------|------------------|
| Stored data | `graph_nodes` no PostgreSQL — usado pelo KG existente | Nenhum — novas inserções com `type: "miroflow_execution"` |
| Live service config | Ollama rodando na porta 11434 com `deepseek-r1:14b` instalado | `llama3.1:8b` NÃO instalado — precisa de `ollama pull llama3.1:8b` |
| OS-registered state | Nenhum Task Scheduler / cron para MiroFlow | Nenhuma ação necessária |
| Secrets/env vars | `OLLAMA_BASE_URL=http://ollama:11434` já no `.env`; `LITELLM_API_KEY` existente | Adicionar `MIROFLOW_PORT=8006` no `.env` e docker-compose |
| Build artifacts | `server/modules/miroflow/` tem `uv.lock` mas sem `.venv` instalado | Wave 0: instalar dependências via `uv sync` ou `pip install` no Dockerfile.python |
**Modelo faltando:** `llama3.1:8b` não está instalado no Ollama (`False` confirmado por `curl http://localhost:11434/api/tags`). Instalado: `deepseek-r1:14b` (8.4GB), `arcadia-agent:latest` (2GB), `llama3.2:3b` (2GB), `nomic-embed-text` (274MB). O plano deve incluir `ollama pull llama3.1:8b` como task de Wave 0 ou pré-requisito.
---
## Environment Availability
| Dependency | Required By | Available | Version | Fallback |
|------------|------------|-----------|---------|----------|
| Ollama API `:11434` | Todos os agentes MiroFlow | ✓ | 0.18.2 | — |
| `deepseek-r1:14b` | Statistician, Fiscal Auditor | ✓ | 8.4GB | — |
| `llama3.1:8b` | Researcher | ✗ | — | `llama3.2:3b` (degraded) ou `deepseek-r1:14b` |
| Python 3.12 | Microserviço FastAPI | ✓ | 3.12.3 | — |
| `uv` | Instalar deps MiroFlow | ✓ | 0.9.30 | `pip3` |
| FastAPI/uvicorn | Microserviço | ✓ | fastapi 0.128.8 | — |
| `omegaconf` (sistema) | MiroFlow direto | ✗ | — | Instalar via `uv sync` no `server/modules/miroflow/` |
| PostgreSQL `:5432` | KG graph_nodes | ✓ | 16 | — |
| Neo4j `:7687` | KG real (opcional) | Requer profile `[kg]` | — | `graph_nodes` PostgreSQL (já usado) |
**Missing dependencies with no fallback:**
- `llama3.1:8b` para o agente Researcher — deve ser baixado em Wave 0 (`ollama pull llama3.1:8b`)
**Missing dependencies with fallback:**
- `omegaconf` no sistema: instalar com `pip3 install omegaconf hydra-core` ou rodar MiroFlow dentro de venv com `uv sync`
- `llama3.1:8b` temporariamente: usar `deepseek-r1:14b` como fallback até o download completar
---
## Common Pitfalls
### Pitfall 1: Ollama não expõe `/v1` sem flag explícita em versões antigas
**What goes wrong:** `UnifiedOpenAIClient` do MiroFlow usa `base_url=http://localhost:11434/v1` (OpenAI-compatible endpoint). Versões antigas do Ollama (<0.1.24) não tinham esse endpoint.
**Why it happens:** Ollama 0.18.2 (confirmado no servidor) já suporta `/v1/chat/completions`. Mas o endpoint retorna erro se o modelo não estiver carregado.
**How to avoid:** Verificar `GET http://localhost:11434/api/tags` antes de iniciar o agente. Pré-carregar o modelo com `ollama run deepseek-r1:14b` ou `ollama pull`.
**Warning signs:** `404 Not Found` na URL `/v1/chat/completions`, ou `model not found` no corpo da resposta.
### Pitfall 2: MiroFlow requer dependências Python não instaladas no container Node
**What goes wrong:** O `Dockerfile` principal é Node.js Alpine — não tem Python. Se tentar importar `miroflow` no contexto Node (via python-bridge ou similar), vai falhar.
**Why it happens:** A tentativa de `from omegaconf import ...` falha com `ModuleNotFoundError` porque o sistema Python não tem as deps do MiroFlow.
**How to avoid:** Manter a separação clara: MiroFlow roda SOMENTE em `Dockerfile.python` como microserviço FastAPI. Node nunca importa Python diretamente.
**Warning signs:** Erro de `ModuleNotFoundError: No module named 'omegaconf'` nos logs do app principal.
### Pitfall 3: Timeout do fetch() insuficiente para modelos grandes
**What goes wrong:** `deepseek-r1:14b` com raciocínio pode levar 60-120 segundos para responder. O fetch padrão tem timeout de 30s nos outros proxies.
**Why it happens:** O `bi/engine-proxy.ts` usa `BI_ENGINE_TIMEOUT = 30000`. Para LLMs de 14B, isso é insuficiente.
**How to avoid:** Usar `AbortSignal.timeout(300_000)` (5 minutos) no proxy MiroFlow. Implementar streaming ou polling se necessário.
**Warning signs:** `AbortError: The operation was aborted` nos logs do Node.
### Pitfall 4: Neo4j não está ativo por padrão — usar graph_nodes do PostgreSQL
**What goes wrong:** O `docker-compose.yml` tem Neo4j no profile `[kg]` — não está ativo em deploy padrão.
**Why it happens:** Neo4j é opcional; o KG do Arcádia usa `graph_nodes` PostgreSQL por padrão.
**How to avoid:** Para imutabilidade, usar `POST /api/graph/nodes` (PostgreSQL), não o driver `neo4j` Python direto. O `server/graph/service.ts` já implementa isso com hashing.
**Warning signs:** `Connection refused: 7687` se tentar conectar ao Neo4j sem o profile ativo.
### Pitfall 5: MiroFlow não tem `llama3.1:8b` instalado
**What goes wrong:** O agente Researcher usa `llama3.1:8b` mas esse modelo não está no Ollama (`False` confirmado por inspeção direta).
**Why it happens:** Apenas `deepseek-r1:14b`, `arcadia-agent:latest`, `llama3.2:3b` e `nomic-embed-text` foram instalados.
**How to avoid:** Incluir `ollama pull llama3.1:8b` como step explícito na Wave 0 do plano.
**Warning signs:** Agente Researcher falha com `model 'llama3.1:8b' not found`.
### Pitfall 6: BiWorkspace.tsx é uma página grande — cuidado ao modificar
**What goes wrong:** `BiWorkspace.tsx` tem muitas funcionalidades (datasets, charts, dashboards, backup, BI engine). Modificação descuidada pode quebrar features existentes.
**Why it happens:** O arquivo tem ~1000+ linhas com múltiplas tabs e estados.
**How to avoid:** Adicionar MiroFlowControl como componente SEPARADO importado, não modificar lógica existente. Adicionar apenas uma nova `TabsTrigger` e `TabsContent`.
**Warning signs:** Erros de TypeScript em outros tabs depois da edição.
---
## Code Examples
Verified patterns from official sources:
### MiroFlow Agent com Ollama (config inline Python)
```python
# Source: server/modules/miroflow/miroflow/agents/base.py + config/llm/base.yaml
import sys
sys.path.insert(0, "/app/server/modules/miroflow")
import asyncio
from miroflow.agents.factory import build_agent
from miroflow.agents.context import AgentContext
OLLAMA_BASE_URL = os.getenv("OLLAMA_BASE_URL", "http://localhost:11434")
def make_agent_cfg(model: str) -> dict:
return {
"type": "IterativeAgentWithToolAndRollback",
"name": f"arcadia_{model.replace(':', '_')}",
"max_turns": 10,
"llm": {
"provider_class": "UnifiedOpenAIClient",
"model_name": model,
"api_key": "ollama",
"base_url": f"{OLLAMA_BASE_URL}/v1",
"max_tokens": 8192,
"temperature": 0.7,
"top_p": 1.0, "min_p": 0.0, "top_k": -1,
"reasoning_effort": None, "repetition_penalty": 1.0,
"max_context_length": -1, "async_client": True,
"disable_cache_control": True, "keep_tool_result": -1,
"use_tool_calls": False, "oai_tool_thinking": False,
},
}
async def run_agent(agent_type: str, task: str) -> str:
model = "deepseek-r1:14b" if agent_type in ("statistician", "fiscal_auditor") else "llama3.1:8b"
cfg = make_agent_cfg(model)
agent = build_agent(cfg)
ctx = AgentContext(task_description=task)
result = await agent.run(ctx)
return result.get("summary", str(result))
```
### FastAPI endpoint pattern (seguindo bi_analysis_service.py)
```python
# Source: server/python/bi_analysis_service.py (padrão existente)
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI(title="Arcádia MiroFlow Service", version="1.0.0")
class AnalyzeRequest(BaseModel):
agent: str # "statistician" | "fiscal_auditor" | "researcher"
task: str
context: dict = {}
tenant_id: int | None = None
class AnalyzeResponse(BaseModel):
agent: str
model: str
result: str
execution_id: str
duration_ms: int
@app.post("/analyze", response_model=AnalyzeResponse)
async def analyze(req: AnalyzeRequest):
...
```
### Express proxy para MiroFlow (seguindo engine-proxy.ts)
```typescript
// Source: server/bi/engine-proxy.ts (padrão existente)
const MIROFLOW_URL = `http://${process.env.MIROFLOW_HOST || "localhost"}:${
process.env.MIROFLOW_PORT || "8006"
}`;
export function registerMiroFlowRoutes(app: Express): void {
app.post("/api/miroflow/analyze", async (req: Request, res: Response) => {
if (!req.isAuthenticated()) return res.status(401).json({ error: "Não autenticado" });
try {
const response = await fetch(`${MIROFLOW_URL}/analyze`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ ...req.body, tenant_id: (req.user as any)?.tenantId }),
signal: AbortSignal.timeout(300_000),
});
const data = await response.json();
// Registrar no KG
await registerExecutionInKG(req, data);
res.json(data);
} catch (err: any) {
res.status(502).json({ error: err.message });
}
});
app.get("/api/miroflow/health", async (_req, res) => {
try {
const r = await fetch(`${MIROFLOW_URL}/health`, { signal: AbortSignal.timeout(5000) });
res.json({ online: r.ok, url: MIROFLOW_URL });
} catch {
res.json({ online: false, url: MIROFLOW_URL });
}
});
}
```
### Registro no KG (graph_nodes)
```typescript
// Source: server/graph/service.ts createNode()
import { createNode } from "../graph/service";
import crypto from "crypto";
async function registerExecutionInKG(req: any, execData: any) {
const auditHash = crypto
.createHash("sha256")
.update(JSON.stringify(execData))
.digest("hex");
await createNode({
type: "miroflow_execution",
tenantId: req.user?.tenantId,
data: { ...execData, auditHash, immutable: true },
});
}
```
---
## State of the Art
| Old Approach | Current Approach | When Changed | Impact |
|--------------|------------------|--------------|--------|
| Llamaindex/LangChain para agentes | MiroFlow (framework próprio MiromindAI) | 2025-08 | Performance-first, benchmarks públicos, já no submodule |
| OpenAI API direta | Ollama local via LiteLLM gateway | 2025 (Arcádia) | Soberania total dos dados |
| Neo4j obrigatório para KG | graph_nodes PostgreSQL + Neo4j opcional | Phase 1 | Sem dependência de serviço extra em produção básica |
| Hydra config files externos | Config dict inline (Python) | MiroFlow 1.x | Sem dependência de paths, mais fácil em containers |
**Deprecated/outdated:**
- MiroFlow via CLI (`python run_single_task.py`): adequado para benchmark, mas não para microserviço de produção. Usar `web_app/main.py` como referência OU criar FastAPI própria.
- Modelos > 14B: explicitamente proibidos na arquitetura do projeto.
---
## Open Questions
1. **`llama3.1:8b` vs `llama3.2:3b` para Researcher**
- What we know: `llama3.1:8b` não está instalado; `llama3.2:3b` está (2GB, já disponível)
- What's unclear: Se João quer baixar `llama3.1:8b` (4.7GB a mais) ou aceitar `llama3.2:3b` como substituto para o Researcher
- Recommendation: Plano deve incluir `ollama pull llama3.1:8b` como Wave 0, com fallback para `llama3.2:3b` se bandwidth for problema
2. **MiroFlow via web_app existente vs FastAPI própria**
- What we know: `server/modules/miroflow/web_app/main.py` é uma FastAPI completa com session manager e task executor; `server/python/bi_analysis_service.py` é um FastAPI simples sem estado
- What's unclear: Usar o `web_app` completo do MiroFlow (mais funcionalidades) ou escrever `miroflow_service.py` minimal seguindo o padrão de outros serviços
- Recommendation: Escrever `miroflow_service.py` minimal — mais simples, sem session management, sem frontend próprio do MiroFlow
3. **Registro de execuções: graph_nodes vs skill_executions**
- What we know: `skill_executions` é específico para Skills Arcádia; `graph_nodes` é KG genérico
- What's unclear: O requirement diz "KG" — se é necessário usar o Neo4j real ou PostgreSQL `graph_nodes` é suficiente
- Recommendation: Usar `graph_nodes` PostgreSQL com `type: "miroflow_execution"` — atende o requisito de imutabilidade sem depender do Neo4j (profile opcional)
4. **Posicionamento do MiroFlowControl na UI**
- What we know: `BiWorkspace.tsx` já tem sistema de tabs (LayoutDashboard, Database, BarChart3...); `Scientist.tsx` já existe como página standalone de análise científica
- What's unclear: Se o toggle deve ficar dentro do BiWorkspace (access contextual) ou se deve ser um botão flutuante ou se Scientist.tsx deve ser integrado ao BI
- Recommendation: Tab "Científico" dentro de `BiWorkspace.tsx` — mais coerente com o objetivo "integrado ao Superset"
---
## Validation Architecture
> `workflow.nyquist_validation` não encontrado em `.planning/config.json` (arquivo não existe). Tratado como habilitado.
### Test Framework
| Property | Value |
|----------|-------|
| Framework | pytest (Python) + vitest/jest implícito (TS) |
| Config file | Nenhum — Wave 0 deve criar `pytest.ini` para o microserviço |
| Quick run command | `pytest server/python/test_miroflow_service.py -x` |
| Full suite command | `pytest server/python/ -v` |
### Phase Requirements → Test Map
| Req ID | Behavior | Test Type | Automated Command | File Exists? |
|--------|----------|-----------|-------------------|-------------|
| REQ-3.1 | MiroFlow configurado para Ollama local ≤14B | integration | `pytest tests/test_miroflow_ollama.py -x` | ❌ Wave 0 |
| REQ-3.2 | Agente Statistician analisa SQL com deepseek-r1:14b | integration | `pytest tests/test_miroflow_service.py::test_statistician -x` | ❌ Wave 0 |
| REQ-3.3 | Agente Fiscal Auditor valida NFe/SPED com deepseek-r1:14b | integration | `pytest tests/test_miroflow_service.py::test_fiscal_auditor -x` | ❌ Wave 0 |
| REQ-3.4 | Agente Researcher consulta KG com llama3.1:8b | integration | `pytest tests/test_miroflow_service.py::test_researcher -x` | ❌ Wave 0 |
| REQ-3.5 | `POST /api/miroflow/analyze` retorna análise estruturada | integration | `curl -X POST localhost:5000/api/miroflow/analyze ...` | ❌ Wave 0 |
| REQ-3.6 | MiroFlowControl.tsx toggle aparece no Superset/BiWorkspace | manual | Inspeção visual no browser | N/A |
| REQ-3.7 | Execuções registradas com imutabilidade no KG | unit | `pytest tests/test_miroflow_kg.py -x` | ❌ Wave 0 |
### Sampling Rate
- **Per task commit:** `pytest server/python/test_miroflow_service.py -x`
- **Per wave merge:** `pytest server/python/ -v`
- **Phase gate:** Health check `/api/miroflow/health` retorna `{"online": true}` + todos os 3 agentes respondem com modelo correto
### Wave 0 Gaps
- [ ] `server/python/test_miroflow_service.py` — cobre REQ-3.1, 3.2, 3.3, 3.4, 3.5, 3.7
- [ ] `server/python/miroflow_service.py` — o microserviço principal
- [ ] `server/miroflow/routes.ts` + `engine-proxy.ts` — rotas Express
- [ ] `client/src/components/MiroFlowControl.tsx` — componente React
- [ ] `ollama pull llama3.1:8b` — modelo necessário para Researcher (Wave 0 setup)
- [ ] Instalar dependências MiroFlow: `pip install omegaconf hydra-core openai` (ou `uv sync` no diretório do submodule)
---
## Sources
### Primary (HIGH confidence)
- Inspeção direta: `/opt/arcadia_merged/server/modules/miroflow/pyproject.toml` — versão 1.7.0, dependências confirmadas
- Inspeção direta: `/opt/arcadia_merged/server/modules/miroflow/miroflow/llm/openai_client.py``UnifiedOpenAIClient`, `base_url` configurável
- Inspeção direta: `/opt/arcadia_merged/server/modules/miroflow/miroflow/agents/base.py``BaseAgent`, `AgentContext`, `build_agent()`
- Inspeção direta: `/opt/arcadia_merged/server/modules/miroflow/config/llm/base.yaml` — campos obrigatórios do LLM config
- Inspeção direta: `/opt/arcadia_merged/server/bi/engine-proxy.ts` — padrão estabelecido de proxy Node → Python
- Inspeção direta: `/opt/arcadia_merged/server/python/bi_analysis_service.py` — padrão do microserviço FastAPI
- Inspeção direta: `/opt/arcadia_merged/docker/litellm-config.yaml``deepseek-r1:14b` já configurado como `arcadia-default`
- Inspeção direta: `/opt/arcadia_merged/docker-compose.prod.yml``OLLAMA_BASE_URL` configurado, serviço `ollama` com profile `[ai]`
- Runtime check: `curl http://localhost:11434/api/tags` — modelos instalados confirmados
- Runtime check: `curl http://localhost:11434/api/version` — Ollama 0.18.2 com `/v1` support
### Secondary (MEDIUM confidence)
- Inspeção direta: `/opt/arcadia_merged/server/modules/miroflow/miroflow/agents/iterative_agent_with_rollback.py` — tipo `IterativeAgentWithToolAndRollback` confirmado
- Inspeção direta: `/opt/arcadia_merged/server/modules/miroflow/web_app/main.py` — FastAPI web_app existente no submodule (alternativa não usada)
- Inspeção direta: `/opt/arcadia_merged/server/graph/service.ts``createNode()`, `graph_nodes` tabela
### Tertiary (LOW confidence)
- Inferência sobre tempo de resposta do `deepseek-r1:14b` (60-120s) baseada em conhecimento geral de modelos 14B — não medido diretamente no servidor
---
## Metadata
**Confidence breakdown:**
- Standard stack: HIGH — verificado diretamente nos arquivos do submodule e nas dependências instaladas
- Architecture: HIGH — padrões copiados de código existente funcionando em produção
- Pitfalls: HIGH (3-5) e MEDIUM (1-2) — baseados em inspeção direta do runtime e código
- Ambiente: HIGH — testado com curl direto ao Ollama e listagem de modelos
**Research date:** 2026-03-25
**Valid until:** 2026-04-25 (30 dias; stack estável, Ollama versão fixada)
---
## RESEARCH COMPLETE

View File

@ -1,97 +0,0 @@
# Phase 4 Context — OpenClaw Embutido
> Generated in --auto mode on 2026-03-26. All decisions auto-selected with recommended defaults.
## Phase Goal
Skills emergentes criadas automaticamente a partir de padrões detectados em `skill_executions`.
## Prior Context Applied
- **Stack de IA:** Ollama local via LiteLLM — usar `llama3.1:8b` para geração de drafts (leve, rápido)
- **Backend-first:** API definida antes do frontend
- **Auditoria imutável:** todas as execuções registradas com SHA-256
- **Schema já existe:** `detected_patterns` e `skill_suggestions` em `shared/schema.ts` — usar sem alterar
---
## Decisions
### 1. O que constitui um "padrão"?
**[auto] Mesma skill executada ≥3 vezes em 30 dias com confiança ≥80%**
- Fonte de dados: tabela `skill_executions`
- Agrupamento: `skillId + userId` (por usuário, não global)
- Confiança calculada como: `(frequency / max_frequency_in_window) * 100`
- Janela: `lastSeenAt - firstSeenAt ≤ 30 dias`
- Thresholds alinhados com o roadmap: min 3 ocorrências, 30 dias, 80% confiança
### 2. Trigger do PatternDetector
**[auto] Cron job a cada hora (setInterval no servidor Node.js)**
- Sem dependência de infraestrutura externa (sem Redis, sem Bull)
- Ao iniciar, PatternDetector registra no startup do servidor
- Execuções recentes analisadas em lote; padrões gravados em `detected_patterns`
- Se padrão já existe (mesmo skillId + userId): atualiza frequency + lastSeenAt
### 3. Geração do body da skill emergente
**[auto] AI via llama3.1:8b (LiteLLM) gera o body do DRAFT**
- Ao atingir threshold: PatternDetector cria entrada em `skill_suggestions` (status: `pending`)
- Skill DRAFT gerada automaticamente em `arcadia_skills` (status: `draft`, source: `openclaw`)
- Body gerado via prompt para llama3.1:8b descrevendo o padrão detectado
- DRAFT aguarda aprovação — não é executável até ser `published`
### 4. Widget de notificação
**[auto] Badge no header global + painel slide-in**
- Badge no ícone de notificações existente no header (sem criar novo componente de header)
- Ao clicar: slide-in panel lateral mostrando lista de sugestões pendentes
- Cada sugestão mostra: nome sugerido, padrão detectado, frequência, confiança, body preview
- Ações inline: "Aceitar" → promove para skill publicada | "Rejeitar" → status `rejected`
### 5. Aprovação — onde?
**[auto] Tab "Sugestões" em `/skills` (página existente) — Dev Center completo na Phase 6**
- Sem criar nova rota — adicionar tab na página `/skills` já existente
- Tab lista `skill_suggestions` com status `pending`
- Fluxo: aceitar → cria skill publicada a partir do DRAFT | rejeitar → arquiva sugestão
- Dev Center completo (Phase 6) herdará esse fluxo
---
## Reusable Assets Identified
- `shared/schema.ts``detectedPatterns`, `skillSuggestions` já definidos (Phase 1)
- `server/skills/engine.ts` — SkillEngine para criar DRAFT skills programaticamente
- `server/skills/routes.ts` — rota `/api/skills` existente, adicionar sub-rotas de sugestões
- `server/skills/versioning.ts` — SHA-256 audit logging (reusar padrão)
- `client/src/pages/BiWorkspace.tsx` — referência de como adicionar tabs a uma página existente
- `docker/litellm-config.yaml` — llama3.1:8b já configurado como Tier 2
---
## Scope Boundary
**Incluído nesta fase:**
- PatternDetector backend (cron + análise de skill_executions)
- Geração de DRAFT via AI
- Widget de notificação + slide-in
- Tab "Sugestões" em /skills com aprovação/rejeição
**Fora de escopo (phases futuras):**
- Dev Center completo (Phase 6)
- Detecção de padrões em outras fontes além de skill_executions
- Pattern sharing entre tenants
---
## Plan Breakdown Suggested
- **04-01:** PatternDetector service (backend) — cron, análise, gravação em detected_patterns + skill_suggestions + DRAFT creation via AI
- **04-02:** API routes + frontend widget (badge + slide-in) + tab "Sugestões" em /skills

View File

@ -1,97 +0,0 @@
# Phase 5 Context — Automation Fabric
> Generated in --auto mode on 2026-03-26. All decisions auto-selected with recommended defaults.
## Phase Goal
Automações unificadas sob runtime único — 5 runtimes tipados substituindo a fragmentação entre XOS (`xos_automations`) e Central (`automations`), com `AutomationCenter.tsx` como visão unificada.
## Prior Context Applied
- **Stack Node.js/TypeScript:** runtimes ficam no servidor Express, sem novos microserviços Python
- **Backend-first:** API definida antes do frontend
- **DB imutável:** tabelas `automations` e `xos_automations` não são alteradas — migração virtual
- **Padrão de phases anteriores:** wrappers leves sobre código existente, sem reescritas
---
## Decisions
### 1. Estratégia de migração
**[auto] Unificação virtual — zero migração de dados**
- Tabelas `automations` e `xos_automations` permanecem intactas
- Nova camada `server/automation-fabric/` agrega os dois via API layer
- `AutomationCenter.tsx` consome endpoint unificado `/api/automation-fabric/list`
- Endpoint retorna rows de ambas as tabelas com campo `source: "central" | "xos"`
- Dados existentes: sem risco de perda, sem downtime, sem migration script
### 2. Os 5 runtimes
**[auto] Classes TypeScript leves — roteamento para serviços existentes**
Implementados em `server/automation-fabric/runtimes/`:
| Runtime | Responsabilidade | Delega para |
|---|---|---|
| `WorkflowEngine` | Executa ações sequenciais com condições | `AutomationService` existente |
| `RuleEngine` | Avalia condições JSONB e dispara ações | Lógica inline, sem dependência |
| `AgentExecutor` | Executa automações via agente Manus | `ManusService` |
| `ScheduleEngine` | Gerencia cron/interval | `scheduledTasks` + setInterval existente |
| `EventEngine` | Webhook/event triggers | Registra listeners no Express |
- `AutomationFabricService` orquestra: dado tipo de trigger → escolhe runtime correto
- Trigger routing: `schedule` → ScheduleEngine, `event`/`webhook` → EventEngine, `agent` → AgentExecutor, default → WorkflowEngine
### 3. Rota do AutomationCenter
**[auto] Nova rota `/automations-center` — existentes intocadas**
- `/automations` (Central) e `/xos/automations` (XOS) permanecem sem alteração
- Nova página `client/src/pages/AutomationCenter.tsx` em `/automations-center`
- Adicionada ao nav/router sem remover rotas existentes
### 4. UI do AutomationCenter
**[auto] Lista unificada com badge de fonte + filtros inline**
- Lista flat com cards: nome, descrição, trigger type, última execução, status ativo/inativo
- Badge colorido: `"Central"` (azul) | `"XOS"` (roxo)
- Filtros: por fonte, por status (ativo/inativo), por trigger type
- Toggle inline enable/disable via PATCH ao respectivo endpoint original
- Execução manual via botão "Executar" → POST `/api/automation-fabric/{id}/run`
- Empty state informativo
---
## Reusable Assets Identified
- `server/automations/service.ts``AutomationService.runAutomation()` (reusar no WorkflowEngine)
- `server/automations/routes.ts` — padrão de rota com auth check
- `server/manus/service.ts``manusService` para AgentExecutor
- `shared/schema.ts``automations`, `xos_automations`, `automationLogs` já existentes
- `client/src/pages/Automations.tsx` — referência de UX/layout para a nova página
- `client/src/pages/XosAutomations.tsx` — referência de cards e filtros
---
## Scope Boundary
**Incluído nesta fase:**
- `server/automation-fabric/` — 5 runtimes + `AutomationFabricService` + rotas unificadas
- `GET /api/automation-fabric/list` — lista unificada (central + xos)
- `POST /api/automation-fabric/:id/run` — execução via fabric
- `AutomationCenter.tsx` — página `/automations-center`
**Fora de escopo (phases futuras):**
- Editor visual de automações (Phase 6 / Dev Center)
- Migração física de dados para tabela unificada
- Novos tipos de trigger não existentes
---
## Plan Breakdown Suggested
- **05-01:** `server/automation-fabric/` — 5 runtimes + `AutomationFabricService` + routes (`/api/automation-fabric`)
- **05-02:** `AutomationCenter.tsx` — página unificada `/automations-center` com lista, filtros e execução inline

View File

@ -1,32 +0,0 @@
# 06-01 PLAN — Schema + API Agent Defs
## Tasks
1. **Add `arcadia_agent_defs` table to `shared/schema.ts`**
- Fields: id, tenantId, userId, name, description, spec (jsonb), status, version, lastTaskId, createdAt, updatedAt
- Run migration if needed
2. **Create `server/agent-defs/service.ts`**
- `createAgentDef()`, `getAgentDef()`, `listAgentDefs()`, `updateAgentDef()`, `deleteAgentDef()`
- `updateStatus()` helper for draft → assembling → ready → deployed
- `incrementVersion()` on deploy
3. **Create `server/agent-defs/routes.ts`**
- GET `/api/agent-defs` (list by tenantId)
- POST `/api/agent-defs` (create)
- PATCH `/api/agent-defs/:id` (update spec/status)
- DELETE `/api/agent-defs/:id`
- POST `/api/agent-defs/:id/deploy` (status → deployed, version++)
- POST `/api/agent-defs/:id/run` (POST to blackboard task)
4. **Register routes in `server/routes.ts`**
- Import and registerAgentDefRoutes()
## Reuse
- DB functions from existing patterns
- Blackboard service for task creation (no modification)
## Done Criteria
- API responds 200 on all endpoints
- Status transitions work: draft → assembling → ready → deployed
- `lastTaskId` links to blackboard_tasks

View File

@ -1,34 +0,0 @@
# 06-02 PLAN — Design + Assemble Tabs
## Tasks
1. **Extend `client/src/pages/DevCenter.tsx` — Design tab**
- Add "Design" tab to TabsList
- 3 mode buttons: Markdown Spec | Code Editor | Visual Flow
- Monaco Editor component (reuse existing from "Desenvolver" tab if possible)
- Save spec to `arcadia_agent_defs` on blur/button click
- Form: agent name, description, spec content
2. **Extend `client/src/pages/DevCenter.tsx` — Assemble tab**
- List `arcadia_agent_defs` where status = draft
- "Montar" button per agent → POST `/api/blackboard/task` with spec as context
- Poll `/api/blackboard/task/:id` every 3s while assembling
- Show progress (task status) in real-time
- On complete: update agent status → ready, show generated artifact
3. **Create `client/src/components/DesignStudio.tsx`** (if modularizing)
- Or inline in DevCenter tabs
4. **Create `client/src/components/AssembleLine.tsx`** (if modularizing)
- Or inline in DevCenter tabs
## Reuse
- Monaco Editor config from existing code
- Polling logic from existing task components
- Blackboard task fetch logic
## Done Criteria
- Design tab allows editing agent spec in 3 modes
- Assemble tab shows draft agents and polls until complete
- Status updates in real-time
- Artifacts visible after assembly

View File

@ -1,37 +0,0 @@
# 06-03 PLAN — Deploy + Galeria Tabs
## Tasks
1. **Extend `client/src/pages/DevCenter.tsx` — Deploy tab**
- List `arcadia_agent_defs` where status = ready OR deployed
- "Deploy" button → PATCH `/api/agent-defs/:id/deploy` (status → deployed, version++)
- "Re-montar" button → PATCH status back to draft
- Expand row → show last blackboard_artifact details (JSON viewer)
- Version badge per agent
2. **Extend `client/src/pages/DevCenter.tsx` — Galeria tab**
- Grid of cards: deployed agents only
- Card content: name, description, version, creator, status badge
- "Executar" button → POST `/api/agent-defs/:id/run` (new blackboard task)
- "Fork" button → POST create new agent with copied spec (name += " (Copy)")
- Filter: status dropdown, search by name
- Empty state message
3. **Create `client/src/components/OrchestrateCenter.tsx`** (if modularizing)
- Or inline in DevCenter tabs
4. **Create `client/src/components/AgentGallery.tsx`** (if modularizing)
- Or inline in DevCenter tabs
## Reuse
- Card/grid layout from AutomationCenter or Skills
- Status badge from existing components
- Blackboard task execution logic
## Done Criteria
- Deploy tab lists ready/deployed agents
- Deploy action increments version
- Re-montar reverts to draft
- Galeria shows deployed agents only
- Run/Fork actions work
- All filters functional

View File

@ -1,131 +0,0 @@
# Phase 6 Context — Dev Center Completo
> Generated in --auto mode on 2026-03-26. All decisions auto-selected with recommended defaults.
## Phase Goal
Fábrica completa de agentes integrada ao DevCenter existente: Design → Assemble → Deploy, com galeria de agentes por tenant.
## Prior Context Applied
- **Stack Node.js/TypeScript + React:** sem novos microserviços
- **Backend-first:** tabela + API antes do frontend
- **Blackboard já existe:** `server/blackboard/` com ArchitectAgent, GeneratorAgent, ValidatorAgent, ExecutorAgent — reusar sem modificar
- **DevCenter.tsx já existe em `/dev-center`:** adicionar tabs, não criar nova rota
- **Schema modular:** nova tabela pode ir em `shared/schema.ts` (é a fase certa — tabela de agentes faz parte do core do sistema)
- **Auditoria imutável:** execuções e artefatos já logados via `blackboard_artifacts`
---
## Decisions
### 1. Onde vive a nova UI?
**[auto] 4 novos tabs no DevCenter.tsx existente — sem nova rota**
- Tabs adicionados ao `<TabsList>` existente em `/dev-center`
- Tabs novos: `design`, `assemble`, `deploy`, `galeria`
- Tabs existentes (Desenvolver, Status, Analisar Repos, Ferramentas, Sistema, Preview, Histórico) permanecem intocados
- Nenhuma nova rota no App.tsx, nenhum novo import lazy
### 2. DesignStudio — modos do editor
**[auto] 3 modos: Markdown Spec, Code Editor, Visual Flow**
- **Markdown Spec** (padrão): textarea com Monaco em modo `markdown` — usuário descreve o agente em linguagem natural estruturada
- **Code Editor**: Monaco em modo `typescript` — para specs técnicas detalhadas ou código direto
- **Visual Flow**: lista de nós editáveis (JSON simples) — nome/tipo/conexões — NÃO um editor gráfico completo
- UML = descrito via texto em Markdown Spec (sem biblioteca de diagramas)
- Seletor de modo: 3 botões inline no topo do tab Design
### 3. Tabela de definições de agentes
**[auto] Nova tabela `arcadia_agent_defs` em `shared/schema.ts`**
Campos:
- `id` (serial PK)
- `tenantId` (varchar, nullable)
- `userId` (varchar — criador)
- `name` (varchar — nome do agente)
- `description` (text)
- `spec` (jsonb — conteúdo do DesignStudio: `{ mode, content }`)
- `status` (varchar — `draft | assembling | ready | deployed`)
- `version` (integer, default 1)
- `lastTaskId` (integer — FK para blackboard_tasks, nullable)
- `createdAt`, `updatedAt` (timestamp)
API: `/api/agent-defs` — CRUD padrão (GET list, POST create, PATCH update, DELETE)
### 4. AssembleLine — fluxo de montagem
**[auto] DesignStudio spec → POST /api/blackboard/task → GeneratorAgent → artefato linkado**
- Tab "Assemble" lista `arcadia_agent_defs` com status `draft`
- Botão "Montar" por agente: POST `/api/blackboard/task` com spec como contexto
- `title`: `"Montar agente: ${name}"`
- `description`: conteúdo do spec
- `context`: `{ agentDefId, spec, source: "agent-factory" }`
- Atualiza `arcadia_agent_defs.status``assembling`, salva `lastTaskId`
- Progresso: polling de `/api/blackboard/task/:id` a cada 3s
- Ao completar: status → `ready`, artefato gerado visível no painel de detalhes
- Reusar completamente os agentes Blackboard existentes — zero modificação
### 5. OrchestrateCenter — deploy e monitoramento
**[auto] Lista de agent_defs com ações de deploy + viewer de artefatos**
- Tab "Deploy": lista `arcadia_agent_defs` em status `ready` ou `deployed`
- Ação "Deploy": PATCH status → `deployed`, incrementa `version`
- Ação "Re-montar": volta para `draft`, decrementa version (permite iteração)
- Monitoramento: expandir linha → mostra último `blackboard_artifact` do `lastTaskId`
- Versionamento: campo `version` incrementado a cada novo deploy
- Sem infra externa — deploy = mudança de status no banco
### 6. Galeria de agentes
**[auto] Grid de cards por tenant — tab "Galeria"**
- Tab "Galeria": grid de cards com `arcadia_agent_defs` onde `status = "deployed"`
- Cada card: nome, descrição, badge de status, número de versão, criador
- Ação "Executar": POST `/api/blackboard/task` com spec do agente → cria nova task de execução
- Ação "Fork": duplica o agente def como novo draft (copia spec, incrementa nome)
- Filtro por status (todos / somente deployed) e busca por nome
- Empty state: "Nenhum agente implantado — crie um na aba Design"
---
## Reusable Assets Identified
- `server/blackboard/routes.ts``POST /api/blackboard/task`, `GET /api/blackboard/task/:id`, `GET /api/blackboard/tasks` — reusar sem modificar
- `server/blackboard/service.ts``createMainTask()`, `getTaskWithDetails()` — reusar
- `shared/schema.ts``blackboardTasks`, `blackboardArtifacts` — leitura e join
- `client/src/pages/DevCenter.tsx` — estrutura de tabs existente — adicionar sem remover
- `client/src/pages/AutomationCenter.tsx` — referência de UX: lista com filtros + badges
- `client/src/pages/Skills.tsx` — referência de galeria com cards
- Monaco Editor já instalado (usado no DevCenter tab "Desenvolver")
---
## Scope Boundary
**Incluído nesta fase:**
- Tabela `arcadia_agent_defs` + migration + API CRUD `/api/agent-defs`
- Tab "Design" (DesignStudio: 3 modos + Monaco)
- Tab "Assemble" (lista de defs + botão Montar + progresso polling)
- Tab "Deploy" (OrchestrateCenter: lista ready/deployed + ações deploy/re-montar + viewer)
- Tab "Galeria" (grid por tenant + run + fork)
- Backend endpoint `POST /api/agent-defs/:id/deploy` e `POST /api/agent-defs/:id/run`
**Fora de escopo (phases futuras):**
- Editor gráfico visual com React Flow ou similar
- Execução real do código gerado em sandbox (Phase 7)
- Integração com CI/CD ou containers reais
- Sharing de agentes entre tenants
---
## Plan Breakdown Suggested
- **06-01:** `shared/schema.ts` (tabela `arcadia_agent_defs`) + `server/agent-defs/routes.ts` (CRUD + `/deploy` + `/run`) + registro em `server/routes.ts`
- **06-02:** Tab "Design" (DesignStudio 3 modos) + Tab "Assemble" (lista + polling de progresso) no DevCenter.tsx
- **06-03:** Tab "Deploy" (OrchestrateCenter) + Tab "Galeria" (grid + run/fork) no DevCenter.tsx

View File

@ -1,71 +0,0 @@
# Quick Task 260326-kmz: Implementar Skill Fabric
**Description:** Implementar Skill Fabric — gerador e gestor de skills da Arcádia Suite
**Date:** 2026-03-26
**Mode:** quick
---
## Task 1: Backend — Skill Fabric Module
**Files:**
- `server/modules/skill-fabric/src/types/index.ts`
- `server/modules/skill-fabric/src/core/skill/Skill.entity.ts`
- `server/modules/skill-fabric/src/core/compiler/VisualCompiler.ts`
- `server/modules/skill-fabric/src/core/compiler/CodeCompiler.ts`
- `server/modules/skill-fabric/src/core/compiler/MarkdownCompiler.ts`
- `server/modules/skill-fabric/src/core/validator/ValidationPipeline.ts`
- `server/modules/skill-fabric/src/core/executor/SkillExecutor.ts`
- `server/modules/skill-fabric/src/core/executor/Sandbox.ts`
- `server/modules/skill-fabric/src/core/lifecycle/LifecycleManager.ts`
- `server/modules/skill-fabric/src/api/routes/skills.routes.ts`
- `server/modules/skill-fabric/src/api/controllers/skills.controller.ts`
- `server/modules/skill-fabric/index.ts`
**Action:** Create the full backend Skill Fabric module with types, entity, compilers, validator pipeline, executor/sandbox, lifecycle manager, and API routes. The project uses TypeScript + Express + Drizzle ORM. Reuse existing `db` and `skills` schema from `../../shared/schema`. No new DB migration needed — extend existing skills table logic.
**Context:**
- Existing `server/skills/routes.ts` has basic CRUD. The new module adds compilation, validation, execution, versioning, lifecycle.
- DB import: `import { db } from "@/db"` or `import { db } from "../../../db"` — check what works
- Existing schema: `skills`, `skillExecutions` from `../../shared/schema`
- Do NOT use vm2 (needs install) — use Node.js built-in `vm` module for sandbox
- Do NOT use ReactFlow/Monaco yet (frontend task) — backend only here
**Done:** Files created, module compiles without errors
---
## Task 2: Frontend — Skill Fabric UI
**Files:**
- `client/src/modules/skill-fabric/index.ts`
- `client/src/modules/skill-fabric/types.ts`
- `client/src/modules/skill-fabric/api.ts`
- `client/src/modules/skill-fabric/code-ide/components/SkillCodeEditor.tsx`
- `client/src/modules/skill-fabric/markdown-studio/components/MarkdownEditor.tsx`
- `client/src/modules/skill-fabric/shared/components/SkillToolbar.tsx`
- `client/src/modules/skill-fabric/shared/components/VersionSelector.tsx`
- `client/src/modules/skill-fabric/shared/components/ValidationPanel.tsx`
- `client/src/pages/SkillFabricPage.tsx`
**Action:** Create frontend Skill Fabric module. Use textarea-based code editor (Monaco not installed — don't add it). Use Tailwind CSS + shadcn/ui components matching the existing project style. Create a SkillFabricPage that lists skills, allows creating/editing (code + markdown modes), compiling, validating, and executing. Wire to the backend API routes from Task 1.
**Context:**
- Check `client/src/components/` for existing UI patterns (shadcn components available)
- Check `client/src/App.tsx` to see how routes are registered — add the new page there
- The visual canvas (ReactFlow) is a stretch goal — skip it, implement code + markdown modes only
- API base: `/api/skills` (existing) + `/api/skill-fabric` (new from Task 1)
**Done:** SkillFabricPage renders, skills can be listed and created
---
## Task 3: Register Routes & Integration
**Files:**
- `server/modules/loader.ts`
- `client/src/App.tsx` (or router file)
**Action:** Register the new skill-fabric backend routes in `server/modules/loader.ts`. Add the SkillFabricPage route in the frontend router. Verify existing skills route still works.
**Done:** `/api/skill-fabric/*` routes registered, frontend page accessible

View File

@ -1,91 +0,0 @@
# GSD Session Report
**Generated:** 2026-03-25 09:50 BRT
**Project:** Arcádia Suite — `arcadiasuite` (branch `Servidor`)
**Milestone:** Arcádia Agentic Suite — 6 Fases (~12 semanas)
---
## Session Summary
**Período:** 2026-03-24 11:30 → 2026-03-25 09:50 (sessões consecutivas)
**Fase atual:** Fase 2 — Skills Engine
**Commits nesta sessão:** 7
**Arquivos alterados:** 29 (+1.875 / -106 linhas)
---
## Work Performed
### Fase 1 — Fundação (CONCLUÍDA)
- `1c6c386` — SkillEngine POO + ReferenceParser + ReferenceResolver + schema (`arcadia_skills`, `skill_executions`)
- `66d8dfb` — MiroFlow e OpenClaw adicionados como git submodules
- `c9a0563` — Neo4j no Docker Compose (profile `kg`), Skills.tsx UI, melhorias Manus/chat/Agent
### Fase 2 — Skills Engine (EM ANDAMENTO)
- `3c61acf` — XOS: forms de cadastro restaurados (Novo Contato, Negócio, Atividade)
- `9bfc888` — Migration: suporte a upload RAR, SQL, SQL.GZ
- `194a8dc` — Rota `/skills` no App.tsx + autocomplete de referências `/` no Monaco
- `4057821` — Skill Marketplace (Biblioteca): `GET /api/skills/marketplace` + `POST /import` + UI grid
### Key Outcomes
- **SkillEngine** com herança POO (`extends`), composição via referências `/`, audit hash SHA-256
- **API REST** completa: CRUD + execute + histórico em `/api/skills`
- **Editor Monaco** com 3 tabs (Geral / Body / Params) + autocomplete de 9 prefixos de referências
- **Skill Marketplace** (Biblioteca): discovery de skills `system`, importação para `tenant` com clonagem + `extends` para origem
- **Neo4j** disponível via `docker compose --profile kg up`
- **Submodules** MiroFlow e OpenClaw presentes em `server/modules/`
---
## Files Changed (resumo por área)
| Área | Arquivos | Linhas |
|------|----------|--------|
| Skills (server) | `engine.ts`, `routes.ts`, `reference-parser.ts` | +400 |
| Skills (client) | `Skills.tsx` | +570 |
| Schema | `shared/schema.ts` | +96 |
| Infra | `docker-compose.yml`, `docker/litellm-config.yaml` | +35 |
| Manus/Chat | `service.ts`, `routes.ts`, `prompt.ts`, `routes.ts` | +350 |
| XOS | `XosCentral.tsx` | +200 |
| App | `App.tsx` | +2 |
| Outros | Agent, ProcessCompass, bi, compass, ide, etc. | +222 |
---
## Blockers & Open Items
**Fase 2 — pendente:**
- [ ] Sistema de versionamento de skills (Git-like)
**Pendências gerais (produção):**
- [ ] Commitar RLS Superset → main
- [ ] SOE.tsx stub → importar versão completa do Replit
- [ ] Seed de regras padrão em `soe_regras`
- [ ] Dashboards base no Superset (DRE, Fluxo de Caixa, Fiscal, RH)
**Próxima fase:**
- Fase 3 — MiroFlow embutido + MiroFlowBridge para Superset
---
## Estimated Resource Usage
| Métrica | Estimativa |
|---------|------------|
| Commits | 7 |
| Arquivos alterados | 29 |
| Linhas adicionadas | ~1.875 |
| Linhas removidas | ~106 |
| Ciclos plan/execute | ~4 (uma por feature principal) |
| Subagents spawned | 0 |
> **Nota:** contagens de tokens e custo requerem instrumentação via API.
> Estas métricas refletem apenas a atividade observável da sessão.
---
*Gerado por `/gsd:session-report`*

View File

@ -1,812 +0,0 @@
# Arcádia Tenants — Mapa Completo da Gestão Multi-Tenant
> Mapa da arquitetura multi-tenant da Arcádia Suite: hierarquia
> Master/Parceiro/Cliente, sistema de planos, ativação de módulos,
> empresas (Matriz/Filiais), comissões de parceiros, controle de acesso,
> e middleware de isolamento.
> Atualizado em: Março 2026
---
## 1. Visão Geral
A Arcádia Suite opera em modelo **multi-tenant hierárquico** com três níveis. Cada tenant possui um plano que define quais módulos da plataforma estão habilitados, e pode conter múltiplas empresas (CNPJ) para operações fiscais.
```
┌─────────────────────────────────────────────────────────────────────┐
│ HIERARQUIA DE TENANTS │
│ │
│ ┌──────────────┐ │
│ │ MASTER │ ← Operador da plataforma │
│ │ │ ← Vê tudo, controla tudo │
│ │ tenantType: │ ← Pode criar parceiros │
│ │ "master" │ ← Pode excluir tenants │
│ └──────┬───────┘ │
│ │ │
│ ┌────────────┼────────────┐ │
│ ▼ ▼ ▼ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ PARCEIRO A │ │ PARCEIRO B │ │ PARCEIRO C │ │
│ │ │ │ │ │ │ │
│ │ tenantType: │ │ Consultorias │ │ Integradores │ │
│ │ "partner" │ │ Revendas │ │ Franquias │ │
│ │ │ │ │ │ │ │
│ │ partnerCode: │ │ comissão: % │ │ plano: │ │
│ │ "PARC-001" │ │ sobre clientes│ │partner_pro │ │
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │
│ │ │ │ │
│ ┌────┴────┐ ┌───┴───┐ ┌───┴───┐ │
│ ▼ ▼ ▼ ▼ ▼ ▼ │
│ ┌────────┐┌────────┐┌────────┐┌────────┐┌────────┐┌────────┐ │
│ │Cliente1││Cliente2││Cliente3││Cliente4││Cliente5││Cliente6│ │
│ │ ││ ││ ││ ││ ││ │ │
│ │tenant ││tenant ││tenant ││tenant ││tenant ││tenant │ │
│ │Type: ││Type: ││Type: ││Type: ││Type: ││Type: │ │
│ │"client"││"client"││"client"││"client"││"client"││"client"│ │
│ │ ││ ││ ││ ││ ││ │ │
│ │parent: ││parent: ││parent: ││parent: ││parent: ││parent: │ │
│ │Parc.A ││Parc.A ││Parc.B ││Parc.B ││Parc.C ││Parc.C │ │
│ │ ││ ││ ││ ││ ││ │ │
│ │Plano: ││Plano: ││Plano: ││Plano: ││Plano: ││Plano: │ │
│ │starter ││pro ││free ││enterpr.││starter ││pro │ │
│ └────────┘└────────┘└────────┘└────────┘└────────┘└────────┘ │
└─────────────────────────────────────────────────────────────────────┘
```
### Visibilidade por tipo:
| Tipo | Vê | Cria | Exclui |
|------|-----|------|--------|
| **Master** | Todos os tenants | Parceiros e Clientes | Qualquer (exceto master) |
| **Partner** | Seu tenant + seus clientes | Apenas clientes vinculados | Nenhum |
| **Client** | Apenas seu próprio tenant | Nenhum | Nenhum |
---
## 2. Banco de Dados — Tabelas de Tenant
### 2.1 — tenants (Tabela Principal)
```
┌──────────────────────────────────────────────────────────────────┐
│ tenants │
│ Tabela: "tenants" — shared/schema.ts:849 │
│ │
│ ┌─────────── Identificação ──────────────────┐ │
│ │ id serial PK │ │
│ │ name text NOT NULL │ │
│ │ slug text UNIQUE │ │
│ │ email text │ │
│ │ phone text │ │
│ │ logoUrl text │ │
│ └─────────────────────────────────────────────┘ │
│ │
│ ┌─────────── Hierarquia ─────────────────────┐ │
│ │ tenantType "master" | "partner" | │ │
│ │ "client" │ │
│ │ parentTenantId integer (self-ref FK) │ │
│ │ partnerCode text (código único parceiro) │ │
│ │ commissionRate numeric(5,2) (% comissão) │ │
│ └─────────────────────────────────────────────┘ │
│ │
│ ┌─────────── Plano e Limites ────────────────┐ │
│ │ plan "free" | "starter" | "pro" │ │
│ │ | "enterprise" | │ │
│ │ "partner_starter" | │ │
│ │ "partner_pro" │ │
│ │ status "active" | "trial" | │ │
│ │ "suspended" | "cancelled" │ │
│ │ maxUsers integer (default 5) │ │
│ │ maxStorageMb integer (default 1000) │ │
│ │ features JSONB → TenantFeatures │ ← Módulos │
│ └─────────────────────────────────────────────┘ │
│ │
│ ┌─────────── Billing ────────────────────────┐ │
│ │ billingEmail text │ │
│ │ trialEndsAt timestamp │ │
│ └─────────────────────────────────────────────┘ │
│ │
│ ┌─────────── Dados Empresariais ─────────────┐ │
│ │ cnpj text │ │
│ │ tradeName text │ │
│ │ address text │ │
│ │ city, state text │ │
│ │ segment text │ │
│ │ notes, source text │ │
│ │ commercialContact / commercialPhone │ │
│ └─────────────────────────────────────────────┘ │
│ │
│ ┌─────────── Metadata ───────────────────────┐ │
│ │ settings text (JSON config) │ │
│ │ createdAt timestamp │ │
│ │ updatedAt timestamp │ │
│ └─────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────┘
```
### 2.2 — TenantFeatures (JSONB — Sistema de Módulos)
O campo `features` na tabela `tenants` é um JSONB que controla **quais módulos da Arcádia estão habilitados** para cada tenant. O tipo é definido em `shared/schema.ts:821` e espelhado no frontend em `client/src/hooks/use-tenant-features.ts:3`.
```
┌──────────────────────────────────────────────────────────────────┐
│ TenantFeatures (JSONB) │
│ │
│ ┌─────────── Módulos Booleanos ──────────────┐ │
│ │ │ │
│ │ ide → IDE integrada │ │
│ │ whatsapp → WhatsApp multi-sessão │ │
│ │ crm → CRM completo │ │
│ │ erp → SOE/ERP │ │
│ │ bi → Business Intelligence │ │
│ │ manus → IA Manus (GPT-4o) │ │
│ │ centralApis → APIs centrais │ │
│ │ centralApisManage → Gerenciar APIs │ │
│ │ comunidades → Chat interno │ │
│ │ biblioteca → Biblioteca de conhecimento │ │
│ │ bibliotecaPublish → Publicar na biblioteca │ │
│ │ suporteN3 → Suporte nível 3 │ │
│ │ retail → Módulo Varejo │ │
│ │ plus → ERP Plus (Laravel) │ │
│ │ fisco → Motor Fiscal │ │
│ │ cockpit → Cockpit executivo │ │
│ │ compass → Process Compass │ │
│ │ production → Módulo Produção │ │
│ │ support → Módulo Suporte │ │
│ │ xosCrm → XOS CRM (Kanban) │ │
│ │ │ │
│ └─────────────────────────────────────────────┘ │
│ │
│ ┌─────────── Configurações Numéricas ────────┐ │
│ │ │ │
│ │ whatsappSessions → Nº sessões WA (0-N) │ │
│ │ maxChannels → Nº canais permitidos │ │
│ │ │ │
│ └─────────────────────────────────────────────┘ │
│ │
│ ┌─────────── Configurações de Texto ─────────┐ │
│ │ │ │
│ │ ideMode → "none" | "no-code" | │ │
│ │ "low-code" | "pro-code" │ │
│ │ manusTools[] → Lista de tools habilitadas │ │
│ │ │ │
│ └─────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────┘
```
### 2.3 — tenant_empresas (Matriz/Filiais)
Cada tenant pode ter **múltiplas empresas** (CNPJs) cadastradas — essencial para operações fiscais (NF-e/NFC-e) por filial.
```
┌──────────────────────────────────────────────────────────────────┐
│ tenant_empresas │
│ Tabela: "tenant_empresas" — shared/schema.ts:889 │
│ │
│ ┌─────────── Identificação ──────────────────┐ │
│ │ id serial PK │ │
│ │ tenantId FK → tenants.id (CASCADE) │ │
│ │ razaoSocial text NOT NULL │ │
│ │ nomeFantasia text │ │
│ │ cnpj text NOT NULL │ │
│ │ ie text (inscrição estadual) │ │
│ │ im text (inscrição municipal) │ │
│ │ email, phone text │ │
│ │ tipo "matriz" | "filial" │ │
│ │ status "active" | "inactive" │ │
│ └─────────────────────────────────────────────┘ │
│ │
│ ┌─────────── Endereço ───────────────────────┐ │
│ │ cep, logradouro, numero, complemento, │ │
│ │ bairro, cidade, uf, codigoIbge │ │
│ └─────────────────────────────────────────────┘ │
│ │
│ ┌─────────── Fiscal ─────────────────────────┐ │
│ │ regimeTributario "simples" | "presumido" │ │
│ │ | "real" │ │
│ │ certificadoDigitalId FK certificado │ │
│ │ ambienteFiscal "producao" | "homologacao" │ │
│ │ serieNfe integer (default 1) │ │
│ │ serieNfce integer (default 1) │ │
│ │ plusEmpresaId integer (link ERP Plus) │ │
│ └─────────────────────────────────────────────┘ │
│ │
│ ┌─────────── Metadata ───────────────────────┐ │
│ │ createdAt, updatedAt timestamp │ │
│ └─────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────┘
```
**Uso típico:**
```
Tenant "Empresa ABC" (id: 5)
├── Empresa Matriz: "ABC Comércio LTDA" (CNPJ: 12.345.678/0001-00)
│ regime: simples, ambiente: producao, série NF-e: 1
├── Filial SP: "ABC Comércio SP" (CNPJ: 12.345.678/0002-81)
│ regime: simples, ambiente: producao, série NF-e: 2
└── Filial RJ: "ABC Comércio RJ" (CNPJ: 12.345.678/0003-62)
regime: simples, ambiente: homologacao, série NF-e: 1
```
### 2.4 — tenant_users (Membership)
```
┌──────────────────────────────────────────────────────────────────┐
│ tenant_users │
│ Tabela: "tenant_users" — shared/schema.ts:923 │
│ │
│ id serial PK │
│ tenantId FK → tenants.id (CASCADE) │
│ userId FK → users.id (CASCADE) │
│ role "owner" | "admin" | "member" │
│ isOwner "true" | "false" │
│ createdAt timestamp │
│ │
│ → Link N:N entre users e tenants │
│ → Um usuário pode pertencer a múltiplos tenants │
│ → Cada tenant tem um owner + admins + members │
└──────────────────────────────────────────────────────────────────┘
```
### 2.5 — tenant_plans (Planos Disponíveis)
```
┌──────────────────────────────────────────────────────────────────┐
│ tenant_plans │
│ Tabela: "tenant_plans" — shared/schema.ts:933 │
│ │
│ id serial PK │
│ code text UNIQUE ("free", "starter", "pro", │
│ "enterprise", "partner_starter", "partner_pro") │
│ name text NOT NULL │
│ description text │
│ tenantType "master" | "partner" | "client" │
│ maxUsers integer (default 5) │
│ maxStorageMb integer (default 1000) │
│ features JSONB → TenantFeatures │
│ monthlyPrice integer (centavos) │
│ yearlyPrice integer (centavos) │
│ trialDays integer (default 14) │
│ isActive "true" | "false" │
│ sortOrder integer │
│ createdAt timestamp │
└──────────────────────────────────────────────────────────────────┘
```
### 2.6 — partner_clients (Relacionamento Parceiro↔Cliente)
```
┌──────────────────────────────────────────────────────────────────┐
│ partner_clients │
│ Tabela: "partner_clients" — shared/schema.ts:951 │
│ │
│ id serial PK │
│ partnerId FK → tenants.id (CASCADE) │
│ clientId FK → tenants.id (CASCADE) │
│ commissionRate numeric(5,2) — Override do rate do parceiro │
│ status "active" | "suspended" | "ended" │
│ notes text │
│ startedAt timestamp │
│ endedAt timestamp │
└──────────────────────────────────────────────────────────────────┘
```
### 2.7 — partner_commissions (Comissões dos Parceiros)
```
┌──────────────────────────────────────────────────────────────────┐
│ partner_commissions │
│ Tabela: "partner_commissions" — shared/schema.ts:963 │
│ │
│ id serial PK │
│ partnerId FK → tenants.id (CASCADE) │
│ clientId FK → tenants.id (CASCADE) │
│ referenceMonth text ("2026-01", "2026-02", ...) │
│ clientPlanCode text (código do plano do cliente) │
│ clientPlanValue integer (valor do plano em centavos) │
│ commissionRate numeric(5,2) NOT NULL │
│ commissionValue integer NOT NULL (valor em centavos) │
│ status "pending" | "approved" | "paid" | "cancelled" │
│ approvedAt timestamp │
│ paidAt timestamp │
│ paymentReference text │
│ createdAt timestamp │
│ │
│ Fluxo: pending → approved → paid │
│ │
│ Exemplo: │
│ Parceiro A tem Cliente X no plano "pro" (R$ 299/mês) │
│ commissionRate: 20% │
│ commissionValue: 5980 centavos (R$ 59,80) │
└──────────────────────────────────────────────────────────────────┘
```
---
## 3. Planos Pré-definidos (Seed)
A rota `POST /api/admin/plans/seed` cria os 6 planos padrão:
```
┌─────────────────────────────────────────────────────────────────────┐
│ PLANOS PARA CLIENTES │
├────────────┬──────────┬──────────┬──────────────────────────────────┤
│ Plano │ Preço/mês│ Usuários │ Módulos │
├────────────┼──────────┼──────────┼──────────────────────────────────┤
│ Gratuito │ R$ 0 │ 2 │ erp, crm │
│ (free) │ │ │ │
├────────────┼──────────┼──────────┼──────────────────────────────────┤
│ Starter │ R$ 99 │ 5 │ erp, crm, bi, fisco, │
│ │ │ │ whatsapp, compass │
├────────────┼──────────┼──────────┼──────────────────────────────────┤
│ Pro │ R$ 299 │ 15 │ erp, crm, bi, fisco, retail, │
│ │ │ │ plus, whatsapp, manus, cockpit, │
│ │ │ │ compass, support, biblioteca │
├────────────┼──────────┼──────────┼──────────────────────────────────┤
│ Enterprise │ R$ 999 │ 100 │ TODOS os módulos │
│ │ │ 50GB │ (erp, crm, bi, fisco, retail, │
│ │ │ │ plus, whatsapp, manus, ide, │
│ │ │ │ cockpit, compass, production, │
│ │ │ │ support, xosCrm, centralApis, │
│ │ │ │ comunidades, biblioteca) │
└────────────┴──────────┴──────────┴──────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────┐
│ PLANOS PARA PARCEIROS │
├──────────────────┬──────────┬──────────┬────────────────────────────┤
│ Plano │ Preço/mês│ Usuários │ Módulos │
├──────────────────┼──────────┼──────────┼────────────────────────────┤
│ Parceiro Starter │ R$ 199 │ 10 │ erp, crm, bi, fisco, │
│ │ │ │ retail, whatsapp, compass, │
│ │ │ │ support │
├──────────────────┼──────────┼──────────┼────────────────────────────┤
│ Parceiro Pro │ R$ 499 │ 50 │ TODOS os módulos │
│ │ │ 25GB │ (igual Enterprise) │
└──────────────────┴──────────┴──────────┴────────────────────────────┘
```
---
## 4. Sistema de Papéis (Roles)
A Arcádia opera com **dois níveis de papéis** que se complementam:
```
┌─────────────────────────────────────────────────────────────────────┐
│ SISTEMA DUPLO DE ROLES │
│ │
│ ┌─────────── Papel do Sistema (users.role) ──────────────────┐ │
│ │ │ │
│ │ "master" → Superadmin, acesso total, bypass de tenant │ │
│ │ "admin" → Administrador, acessa /api/admin/* │ │
│ │ "user" → Usuário padrão, sem acesso admin │ │
│ │ │ │
│ │ Verificado no middleware global de admin: │ │
│ │ if (role !== "admin" && role !== "master") → 403 │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────── Papel no Tenant (tenant_users.role) ────────────┐ │
│ │ │ │
│ │ "owner" → Dono do tenant, criador, full control │ │
│ │ "admin" → Administrador do tenant │ │
│ │ "member" → Membro comum, acesso operacional │ │
│ │ │ │
│ │ Usado para scoping de dados e permissões intra-tenant │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ Combinação no login (getEnrichedUser): │
│ user.role + user.tenantId + user.tenantType + user.tenantRole │
└─────────────────────────────────────────────────────────────────────┘
```
---
## 5. Controle de Acesso — Helpers
O backend implementa dois helpers essenciais em `server/admin/routes.ts`:
```
┌─────────────────────────────────────────────────────────────────────┐
│ getAllowedTenantIds(user) │
│ │
│ Retorna os IDs de tenants que o usuário pode acessar: │
│ │
│ • master → null (acesso total, sem filtro) │
│ • partner → [seu tenantId, ...clientIds vinculados] │
│ • client → [apenas seu tenantId] │
│ │
│ Usado em: GET /tenants, GET /partner-clients, GET /commissions, │
│ GET /empresas, GET /tenants/hierarchy │
└─────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────┐
│ canAccessTenant(user, tenantId) │
│ │
│ Verifica se o usuário pode operar sobre um tenant específico: │
│ │
│ • master → true (sempre) │
│ • partner → true se tenantId ∈ getAllowedTenantIds() │
│ • client → true apenas se tenantId === user.tenantId │
│ │
│ Usado em: PATCH /tenants/:id, DELETE /empresas/:id, │
│ POST /empresas, etc. │
└─────────────────────────────────────────────────────────────────────┘
```
---
## 6. Middleware de Módulos (requireModule)
O middleware `requireModule` em `server/retail/routes.ts:25` bloqueia endpoints quando um módulo não está ativo para o tenant:
```
┌─────────────────────────────────────────────────────────────────────┐
│ requireModule(moduleKey: keyof TenantFeatures) │
│ │
│ Fluxo: │
│ 1. Identifica tenantId do usuário logado │
│ 2. Busca tenant no banco │
│ 3. Verifica features[moduleKey] === true │
│ 4. Se false → 403 com mensagem: │
│ { │
│ error: "Módulo 'X' não está ativo para este tenant", │
│ moduleKey: "plus", │
│ action: "Ative o módulo em Admin → Módulos" │
│ } │
│ │
│ Exemplo de uso: │
│ router.post("/plus/sync/customers", │
│ requireModule("plus"), ← Bloqueia se Plus não está ativo │
│ async (req, res) => { ... } │
│ ); │
└─────────────────────────────────────────────────────────────────────┘
```
---
## 7. Hook Frontend (useTenantFeatures)
O hook `useTenantFeatures()` em `client/src/hooks/use-tenant-features.ts` fornece acesso às features do tenant no frontend:
```
┌─────────────────────────────────────────────────────────────────────┐
│ useTenantFeatures() │
│ │
│ Fonte: GET /api/soe/tenant/modules │
│ Cache: 60 segundos (staleTime: 60000) │
│ │
│ Retorna: │
│ { │
│ features: TenantFeatures, ← Objeto completo de features │
│ isLoading: boolean, │
│ plan: string, ← Código do plano atual │
│ isEnabled: (key) => bool, ← Verificação rápida │
│ } │
│ │
│ Defaults (quando não logado / sem tenant): │
│ ide: true, crm: true, erp: true, manus: true, compass: true │
│ Todos os demais: false │
│ │
│ Uso no componente: │
│ const { isEnabled } = useTenantFeatures(); │
│ if (isEnabled("bi")) { /* mostra menu BI */ } │
│ if (isEnabled("retail")) { /* mostra módulo varejo */ } │
└─────────────────────────────────────────────────────────────────────┘
```
---
## 8. Interface de Administração
### 8.1 — Admin.tsx (Página Principal)
```
┌─────────────────────────────────────────────────────────────────────┐
│ Admin.tsx — client/src/pages/Admin.tsx (2.635 linhas) │
│ Rota: /admin │
│ │
│ 6 Abas: │
│ ┌─────────────┬──────────┬────────────┬───────────┬──────────────┐ │
│ │ Conexões │ Tarefas │ Knowledge │ Bibliotecas│ Módulos │ │
│ │ │ │ │ │ │ │
│ │ WhatsApp │ Dev │ Knowledge │ Conteúdo │ Ativação │ │
│ │ ERPNext │ Center │ Graph │ Docs │ por tenant │ │
│ │ APIs │ Pipeline │ Q&A │ Templates │ Toggle on/ │ │
│ │ │ │ │ │ off módulos │ │
│ └─────────────┴──────────┴────────────┴───────────┴──────────────┘ │
│ ┌─────────────┐ │
│ │Casa de │ │
│ │Máquinas │ │
│ │ │ │
│ │ Status dos │ │
│ │ motores │ │
│ │ (:8002-8006)│ │
│ └─────────────┘ │
│ │
│ Aba "Módulos" renderiza: <MultiTenantSection />
└─────────────────────────────────────────────────────────────────────┘
```
### 8.2 — MultiTenantSection (Gestão Completa)
```
┌─────────────────────────────────────────────────────────────────────┐
│ MultiTenantSection.tsx (1.486 linhas) │
│ client/src/components/MultiTenantSection.tsx │
│ │
│ 4 Abas internas: │
│ │
│ ┌─ Tenants ──────────────────────────────────────────────────┐ │
│ │ │ │
│ │ Lista de tenants com: │ │
│ │ • Nome, tipo (Master/Parceiro/Cliente) │ │
│ │ • Plano atual e status │ │
│ │ • Nº de filhos (childCount) │ │
│ │ • Tenant pai (parentTenant) │ │
│ │ • Ações: Editar, Ativar/Desativar módulos │ │
│ │ │ │
│ │ Formulário de criação: │ │
│ │ • Nome, email, phone │ │
│ │ • Tipo (master/partner/client) │ │
│ │ • Plano (seleciona do tenant_plans) │ │
│ │ • Tenant pai (para hierarquia) │ │
│ │ • Features auto-preenchidas pelo plano selecionado │ │
│ │ • Toggle individual de cada módulo │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─ Planos ───────────────────────────────────────────────────┐ │
│ │ │ │
│ │ CRUD de planos com: │ │
│ │ • Código, nome, descrição │ │
│ │ • Tipo de tenant (client/partner) │ │
│ │ • Preço mensal e anual (centavos) │ │
│ │ • Max usuários e storage │ │
│ │ • Features (toggle de cada módulo) │ │
│ │ • Botão "Seed" para criar planos padrão │ │
│ │ • Botão "Propagar" para aplicar features do plano │ │
│ │ a todos os tenants que usam esse plano │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─ Comissões ────────────────────────────────────────────────┐ │
│ │ │ │
│ │ Lista de comissões de parceiros: │ │
│ │ • Parceiro, Cliente, Mês referência │ │
│ │ • Valor do plano, taxa de comissão, valor da comissão │ │
│ │ • Status (pending → approved → paid) │ │
│ │ • Ações: Aprovar, Marcar como paga │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─ Empresas ─────────────────────────────────────────────────┐ │
│ │ │ │
│ │ EmpresasSubSection: │ │
│ │ • Lista de empresas (Matriz/Filiais) por tenant │ │
│ │ • CNPJ, Razão Social, Nome Fantasia │ │
│ │ • IE, IM, Regime Tributário │ │
│ │ • Endereço completo (CEP, logradouro, cidade, UF) │ │
│ │ • Config Fiscal (ambiente, série NF-e, série NFC-e) │ │
│ │ • Link com ERP Plus (plusEmpresaId) │ │
│ │ • Ações: Criar, Editar, Excluir │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
```
---
## 9. API REST Completa (/api/admin/*)
### Tenants
| Método | Endpoint | Função | Acesso |
|--------|----------|--------|--------|
| GET | `/tenants` | Lista tenants (filtrado por acesso) | master/partner/client |
| POST | `/tenants` | Cria tenant (resolve features do plano) | master/admin |
| PATCH | `/tenants/:id` | Atualiza tenant (canAccessTenant) | master/partner |
| DELETE | `/tenants/:id` | Exclui tenant (proteção master) | somente master |
| GET | `/tenants/hierarchy` | Árvore hierárquica de tenants | master/partner |
| GET | `/tenants/stats` | Estatísticas (total, por tipo, por status) | master/admin |
### Planos
| Método | Endpoint | Função |
|--------|----------|--------|
| GET | `/plans` | Lista todos os planos |
| POST | `/plans` | Cria novo plano |
| PATCH | `/plans/:id` | Atualiza plano |
| DELETE | `/plans/:id` | Exclui plano |
| POST | `/plans/:id/propagate` | Propaga features do plano para todos os tenants que o usam |
| POST | `/plans/seed` | Cria 6 planos padrão |
### Parceiro-Cliente
| Método | Endpoint | Função |
|--------|----------|--------|
| GET | `/partner-clients` | Lista relacionamentos parceiro↔cliente |
| POST | `/partner-clients` | Cria vínculo parceiro↔cliente |
### Comissões de Parceiros
| Método | Endpoint | Função |
|--------|----------|--------|
| GET | `/commissions` | Lista comissões (filtro por partnerId, status) |
| PATCH | `/commissions/:id/approve` | Aprova comissão |
| PATCH | `/commissions/:id/pay` | Marca como paga |
### Empresas (Matriz/Filiais)
| Método | Endpoint | Função |
|--------|----------|--------|
| GET | `/empresas` | Lista empresas (filtro por tenantId + acesso) |
| GET | `/empresas/:id` | Detalhe da empresa |
| POST | `/empresas` | Cria empresa (verifica canAccessTenant) |
| PATCH | `/empresas/:id` | Atualiza empresa |
| DELETE | `/empresas/:id` | Exclui empresa |
### Outros Admin
| Método | Endpoint | Função |
|--------|----------|--------|
| GET | `/profiles` | Lista perfis de usuários |
| POST | `/profiles` | Cria perfil |
| PATCH | `/profiles/:id` | Atualiza perfil |
| DELETE | `/profiles/:id` | Exclui perfil |
| GET | `/users` | Lista usuários (com tenant info) |
| PATCH | `/users/:id` | Atualiza usuário |
| PATCH | `/users/:id/status` | Altera status do usuário |
| PATCH | `/partners/:id/status` | Altera status de parceiro |
| PATCH | `/clients/:id/status` | Altera status de cliente |
| GET | `/stats` | Estatísticas gerais (tenants, users, leads) |
| GET | `/libraries` | Lista bibliotecas de conteúdo |
**Total: 33 endpoints de administração**
---
## 10. Fluxo Completo — Onboarding de Tenant
```
┌──────────┐ ┌────────────┐ ┌──────────────┐ ┌──────────────┐
│ 1. CRIAR │───▶│ 2. PLANO │───▶│ 3. FEATURES │───▶│ 4. EMPRESAS │
│ TENANT │ │ │ │ │ │ │
│ │ │ Seleciona │ │ Auto-resolve │ │ Cadastra │
│ POST │ │ plano │ │ do plano ou │ │ Matriz │
│ /admin/ │ │ (free, │ │ toggle │ │ + Filiais │
│ tenants │ │ starter, │ │ individual │ │ │
│ │ │ pro, etc) │ │ de módulos │ │ CNPJ, IE, │
│ name, │ │ │ │ │ │ endereço, │
│ email, │ │ maxUsers │ │ ide: true │ │ regime │
│ type │ │ maxStorage │ │ crm: true │ │ tributário, │
│ │ │ preço │ │ bi: false │ │ certificado │
│ │ │ │ │ ... │ │ digital │
└──────────┘ └────────────┘ └──────────────┘ └──────────────┘
┌──────────────┐ ┌──────────────┐ ┌──────────────────────────┐
│ 5. VINCULAR │ │ 6. COMISSÕES │ │ 7. USUÁRIOS │
│ PARCEIRO │ │ │ │ │
│ (se partner) │ │ Automáticas │ │ Convida users │
│ │ │ mensais │ │ tenant_users │
│ POST /admin/ │ │ baseadas no │ │ roles: owner/admin/ │
│ partner- │ │ plano do │ │ member │
│ clients │ │ cliente │ │ │
│ │ │ │ │ Scoping automático │
│ partnerId │ │ pending → │ │ de todos os dados │
│ clientId │ │ approved → │ │ por tenantId │
│ commission% │ │ paid │ │ │
└──────────────┘ └──────────────┘ └──────────────────────────┘
```
---
## 11. Propagação de Plano
Quando um plano é atualizado, a feature de **propagação** atualiza todos os tenants que usam esse plano:
```
┌─────────────────────────────────────────────────────────────────────┐
│ POST /api/admin/plans/:id/propagate │
│ │
│ 1. Busca o plano por ID │
│ 2. Pega features, maxUsers, maxStorageMb do plano │
│ 3. Atualiza TODOS os tenants onde plan === plan.code: │
│ UPDATE tenants SET │
│ features = plan.features, │
│ maxUsers = plan.maxUsers, │
│ maxStorageMb = plan.maxStorageMb │
│ WHERE plan = 'pro' │
│ 4. Retorna: { propagated: 15, planCode: "pro" } │
│ │
│ Exemplo: │
│ Plano "pro" ganha módulo "production" → │
│ Propagar → 15 tenants "pro" recebem production: true │
└─────────────────────────────────────────────────────────────────────┘
```
---
## 12. Isolamento de Dados
Toda query de dados respeita o escopo do tenant:
```
┌─────────────────────────────────────────────────────────────────────┐
│ ISOLAMENTO POR tenantId │
│ │
│ Padrão em todas as queries: │
│ │
│ const tenantId = (req.user as any).tenantId; │
│ const data = await db.select() │
│ .from(tabela) │
│ .where(eq(tabela.tenantId, tenantId)); │
│ │
│ Tabelas com tenantId: │
│ • tenants (hierarquia) • crm_channels │
│ • tenant_empresas • crm_threads │
│ • crm_leads • crm_events │
│ • crm_clients • crm_campaigns │
│ • crm_opportunities • crm_products │
│ • crm_partners • crm_contracts │
│ • crm_pipeline_stages • crm_commission_rules │
│ • crm_proposals • crm_quick_messages │
│ • retail_activity_feed • valuation_* │
│ │
│ Resultado: Dados do Tenant A NUNCA são vistos pelo Tenant B │
└─────────────────────────────────────────────────────────────────────┘
```
---
## 13. Arquivos-Chave
| Arquivo | Função | Linhas |
|---------|--------|--------|
| `shared/schema.ts` (L821-977) | TenantFeatures type + 6 tabelas tenant | ~160 |
| `server/admin/routes.ts` | API admin (33 endpoints) | 876 |
| `client/src/pages/Admin.tsx` | Página admin (6 abas) | 2.635 |
| `client/src/components/MultiTenantSection.tsx` | Gestão multi-tenant (4 sub-abas) | 1.486 |
| `client/src/hooks/use-tenant-features.ts` | Hook de features no frontend | 59 |
| `server/retail/routes.ts` (L25) | Middleware requireModule | ~25 |
| `server/storage.ts` (getEnrichedUser) | Enriquece user com tenant info | — |
---
## 14. Resumo Visual
```
┌─────────────────────────────────────────────────────────────────────┐
│ ARCÁDIA MULTI-TENANT STACK │
│ │
│ ┌───── Autenticação ──────────────────────────────────────────┐ │
│ │ Login → getEnrichedUser → user + tenantId + tenantType │ │
│ │ + tenantRole + features │ │
│ └─────────────────────────────────────────┬───────────────────┘ │
│ │ │
│ ┌─────────────────────────────────────────▼───────────────────┐ │
│ │ Middleware │ │
│ │ ┌──────────┐ ┌─────────────┐ ┌────────────────────┐ │ │
│ │ │requireAuth│ │requireModule │ │getAllowedTenantIds │ │ │
│ │ │role check │ │feature check │ │canAccessTenant │ │ │
│ │ └──────────┘ └─────────────┘ └────────────────────┘ │ │
│ └─────────────────────────────────────────┬───────────────────┘ │
│ │ │
│ ┌─────────────────────────────────────────▼───────────────────┐ │
│ │ API /api/admin/* │ │
│ │ 33 endpoints: Tenants, Plans, Empresas, Comissões │ │
│ └─────────────────────────────────────────┬───────────────────┘ │
│ │ │
│ ┌─────────────────────────────────────────▼───────────────────┐ │
│ │ PostgreSQL │ │
│ │ 6 tabelas: tenants, tenant_users, tenant_plans, │ │
│ │ tenant_empresas, partner_clients, partner_commissions │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ ┌───── Frontend ──────────────────────────────────────────────┐ │
│ │ Admin.tsx (6 abas) → MultiTenantSection (4 sub-abas) │ │
│ │ useTenantFeatures() hook → GET /api/soe/tenant/modules │ │
│ └─────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
```

View File

@ -1,167 +0,0 @@
# Sessão de Desenvolvimento — 2026-03-18
**Branch:** `claude/analyze-project-0mXjP`
**Commits desta sessão:** `8d14fc0`, `20a0237`
**Contexto:** Continuação do ciclo iniciado em 2026-03-13 (auditoria A-Z + desenvolvimento das fases XOS)
---
## 1. O que foi feito nesta sessão
### 1.1 Correção de erros TypeScript críticos no `App.tsx`
Três classes de erros impediam o build limpo do frontend:
| Erro | Arquivo | Correção |
|---|---|---|
| `Cannot find module '@/contexts/SoeMotorContext'` | `App.tsx:8` | Criado `client/src/contexts/SoeMotorContext.tsx` |
| `Cannot find module '@/pages/SOE'` | `App.tsx:39` | Criado `client/src/pages/SOE.tsx` |
| `LazyExoticComponent` não atribuível a `() => Element` (20x) | `protected-route.tsx` | Tipo alterado para `React.ComponentType<any>` |
**Arquivos criados/modificados:**
- `client/src/contexts/SoeMotorContext.tsx` — context global com `SoeMotorProvider` e hook `useSoeMotor`
- `client/src/pages/SOE.tsx` — página SOE (Sistema de Operações Empresariais), re-export do módulo Plus/ERP
- `client/src/lib/protected-route.tsx` — tipo do prop `component` corrigido
**Resultado:** `npx tsc --noEmit` zerou todos os erros do `App.tsx`. Erros remanescentes são pré-existentes em outros arquivos e não relacionados às correções.
---
### 1.2 Guia de deploy no Coolify (`DEPLOY_COOLIFY.md`)
Documento completo de 359 linhas cobrindo:
- **Arquitetura de serviços** — mapa visual de todos os containers e redes
- **Variáveis de ambiente** — obrigatórias e opcionais por módulo (Core, IA, Superset, Plus, ERPNext)
- **Profiles Docker** — como habilitar `ai`, `bi`, `plus`, `erpnext` via `COMPOSE_PROFILES`
- **Sequência de inicialização** — ordem garantida pelos `depends_on` e healthchecks
- **Traefik + HTTPS** — labels prontas para Let's Encrypt via Coolify
- **Volumes e persistência** — tabela de criticidade + comandos de backup PostgreSQL
- **Stack de IA** — 3 tiers LiteLLM (LLMFit → Ollama → externos), como baixar modelos, como habilitar LLMFit
- **Pós-deploy** — migrations, verificação de saúde
- **Checklist final** — antes, durante e após o deploy
- **Comandos de referência rápida**
---
### 1.3 Relatório de comparação Auditoria vs Desenvolvimento
Análise completa cruzando o `ARCADIA_AUDIT_EXECUCAO.md` (auditoria de 13/Mar) com todos os 18 commits do branch:
**Resultado geral: 44% concluído, 17% parcial, 38% pendente**
| Sprint | ✅ | ⚠️ | ❌ |
|---|---|---|---|
| S — Segurança (10 itens) | 7 | 3 | 0 |
| 0 — Deploy (6 itens) | 2 | 1 | 3 |
| 1 — Inteligência (6 itens) | 2 | 2 | 2 |
| 2 — App Store (4 itens) | 3 | 0 | 1 |
| 3 — Compass IA (4 itens) | 1 | 1 | 2 |
| 4 — ERP Real (6 itens) | 0 | 0 | 6 |
| 5 — Soberania IA (4 itens) | 3 | 1 | 0 |
| 6 — Qualidade (7 itens) | 3 | 0 | 4 |
| 7 — ERPNext (5 itens) | 2 | 1 | 2 |
---
## 2. Estado do Superset BI (análise técnica)
Levantamento completo da integração Apache Superset:
**Funcionando:**
- Gateway Node.js com 4 endpoints (`/guest-token`, `/dashboards`, `/health`, proxy `/superset/*`)
- Guest Token JWT via service account com cache de 50 min
- Componente React `<SupersetDashboard>` reutilizável com fallback iframe
- Docker: init automático, banco `arcadia` registrado somente leitura, admin criado
- Feature flags: embed, drill-to-detail, cross-filters, alerts, templates Jinja
**Pendente / stub:**
- RLS por tenant — `rls: []` vazio, todos veem todos os dados
- Nenhum dashboard pré-criado — criação manual pelo usuário
- Cache Redis — usando `SimpleCache` em memória
- SSO/OAuth — auth local apenas
---
## 3. Contexto acumulado do ciclo completo (desde 13/Mar)
### O que foi construído no branch (18 commits, 71 arquivos, +9.399 linhas)
| Área | Principais entregas |
|---|---|
| **Segurança** | Auth em todas as rotas XOS, CORS Python corrigido, credentials removidas, timeout+retry, approval guard Manus |
| **XOS CRM** | Fases 14 completas: automações, SLA, horário comercial, campanhas, Socket.IO tempo real |
| **Novas páginas React** | `XosSupervisor`, `XosReports`, `XosProtocols` |
| **SOE Rule Engine** | Motor de regras contábil/fiscal + importador ERPNext |
| **Superset BI** | Integração completa embed + proxy + guest token |
| **Infra Docker** | `docker-compose.prod.yml` com profiles: `ai`, `bi`, `plus`, `erpnext` |
| **IA Soberania** | LiteLLM 3 tiers + Ollama + slot LLMFit pronto |
| **Qualidade** | Rate limiting, logging estruturado (`server/logger.ts`), paginação |
| **App Store** | `GET /api/marketplace/my-apps` + AppCenter por subscription |
| **Docs** | `DEPLOY_COOLIFY.md`, `INTEGRACAO_IA.md`, `PLANO_BI_SUPERSET.md`, `PLANO_SOE_CENTRAL_v2.md` |
---
## 4. Demandas prioritárias pendentes
### Críticas (bloqueia produção estável)
1. **LMS e Quality** — auth ainda incompleta (SEC-02, SEC-03)
- `server/lms/routes.ts` — 8 rotas ainda públicas
- `server/quality/routes.ts` — ~50 rotas revisão insuficiente
2. **WhatsApp auto-reply** — configuração ainda em `Map` na memória
- Reiniciar servidor = perda total da configuração sem aviso
- Persistir em tabela `whatsapp_auto_reply_config` (migration já existe)
3. **`pg_dump` do Replit** — exportar banco antes de encerrar o plano
- Risco de perda de dados de produção atual
### Altas (produto incompleto)
4. **Ciclo de aprendizado Manus** — embeddings não são populados automaticamente
- Busca semântica retorna vazio, sistema não aprende das interações
5. **Páginas placeholder**`Agent.tsx`, `CentralApis.tsx`, `ApiHub.tsx`
- Três das páginas mais estratégicas ainda sem implementação
6. **Sprint 4 inteiro — Integrações ERP reais**
- Adaptadores Omie e TOTVS: zero implementado
- Todos os conectores da Central de API ainda mockados
- Estrutura fragmentada em 4 lugares (`server/erpnext/`, `server/crm/frappe-service.ts`, `server/api-central/`, `server/migration/`)
### Médias (qualidade de engenharia)
7. **Error boundaries globais no React** — sem captura de erros em cascata
8. **Testes automatizados** — zero no projeto inteiro
9. **Connection pooling Python** — nova conexão DB por request nos 6 microserviços
10. **Consolidar sistemas de comunicação** — legacy (`whatsapp_*`, `chat_*`) e moderno (`comm_*`, `xosConversations`) duplicados
11. **36 tabelas sem insert schema** — risco de runtime errors no Drizzle
12. **40+ tabelas sem `createdAt`/`updatedAt`** — auditoria e ordenação impossíveis
### Decisões arquiteturais abertas
| # | Decisão |
|---|---|
| D1 | BI padrão: Metabase (existente) vs Superset (integrado)? |
| D2 | LMS: tabelas dinâmicas vs schema.ts fixo? |
| D3 | Sistema de comunicação canônico: legacy vs moderno vs XOS? |
| D4 | Marketplace público ou autenticado (hoje público — intencional)? |
---
## 5. Próxima sessão recomendada
**Sequência sugerida por impacto/risco:**
```
1. Corrigir auth LMS + Quality (23h) → fecha todas as vulnerabilidades SEC
2. Persistir WhatsApp auto-reply no banco (1h) → estabilidade em produção
3. Fechar ciclo embeddings Manus (2h) → IA começa a aprender de verdade
4. Implementar Agent.tsx com UI real (34h) → página mais estratégica
5. Adaptador Omie — primeira integração ERP real (46h)
```
---
*Sessão registrada em 2026-03-18 | Branch: `claude/analyze-project-0mXjP`*

13
package-lock.json generated
View File

@ -129,6 +129,7 @@
"@types/connect-pg-simple": "^7.0.3", "@types/connect-pg-simple": "^7.0.3",
"@types/express": "4.17.21", "@types/express": "4.17.21",
"@types/express-session": "^1.18.0", "@types/express-session": "^1.18.0",
"@types/http-proxy-middleware": "^0.19.3",
"@types/node": "^20.19.0", "@types/node": "^20.19.0",
"@types/passport": "^1.0.16", "@types/passport": "^1.0.16",
"@types/passport-local": "^1.0.38", "@types/passport-local": "^1.0.38",
@ -7488,6 +7489,18 @@
"@types/node": "*" "@types/node": "*"
} }
}, },
"node_modules/@types/http-proxy-middleware": {
"version": "0.19.3",
"resolved": "https://registry.npmjs.org/@types/http-proxy-middleware/-/http-proxy-middleware-0.19.3.tgz",
"integrity": "sha512-lnBTx6HCOUeIJMLbI/LaL5EmdKLhczJY5oeXZpX/cXE4rRqb3RmV7VcMpiEfYkmTjipv3h7IAyIINe4plEv7cA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/connect": "*",
"@types/http-proxy": "*",
"@types/node": "*"
}
},
"node_modules/@types/imap": { "node_modules/@types/imap": {
"version": "0.8.43", "version": "0.8.43",
"resolved": "https://registry.npmjs.org/@types/imap/-/imap-0.8.43.tgz", "resolved": "https://registry.npmjs.org/@types/imap/-/imap-0.8.43.tgz",

36
server/bi/Dockerfile Normal file
View File

@ -0,0 +1,36 @@
# BI-API Gateway - Node.js
# Arcádia Suite - Port 8004
# Roda com tsx (TypeScript runtime)
FROM node:20-alpine
LABEL maintainer="Arcádia Suite"
LABEL description="BI-API Gateway - Proxy para MetaSet e FDB-Bridge"
WORKDIR /app
# Instalar tsx globalmente
RUN npm install -g tsx
# Criar package.json mínimo com as dependências necessárias
RUN npm init -y && \
npm install express@4 cors@2 helmet@7 http-proxy-middleware@2 && \
npm cache clean --force
# Copiar apenas o arquivo do gateway
COPY server/bi/index.ts ./server/bi/index.ts
# Variáveis de ambiente padrão
ENV NODE_ENV=production
ENV PORT=8004
ENV METASET_HOST=metaset
ENV METASET_PORT=8100
ENV FDB_BRIDGE_HOST=fdb-bridge
ENV FDB_BRIDGE_PORT=8200
EXPOSE 8004
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD wget -qO- http://localhost:8004/health || exit 1
CMD ["tsx", "server/bi/index.ts"]

View File

@ -0,0 +1,5 @@
-- Criar banco de dados MetaSet
CREATE DATABASE metaset_db OWNER arcadia;
-- Comentário
COMMENT ON DATABASE metaset_db IS 'MetaSet BI - Apache Superset metadata database';