domain, flow e step + edges implements. É o que este módulo ensina a gerar com /understand-domain e domain-graph.json.
🏛️ Hierarquia domain → flow → step
Edges de import só repetem o que a IDE já mostra. Knowledge graph estrutural não responde "o que esse código faz" — só "como ele se conecta". A camada de domínio resolve isso anotando 3 níveis hierárquicos sobre o grafo.
🧠 Três níveis
- 1.Business Domain (topo) — cluster: "Order Management", "Logistics", "Warehouse"
- 2.Business Flow (meio) — processo: "Create Order", "Process Refund"
- 3.Business Step (folha) — passo: "Validate input", "Check inventory", "Persist order"
📄 Domain node (exemplo)
{
id: "domain:order-management",
type: "domain",
name: "Order Management",
summary: "Handles the complete order lifecycle...",
tags: ["e-commerce", "core-business"],
complexity: "complex",
domainMeta: {
entities: ["Order", "LineItem", "OrderStatus"],
businessRules: ["Orders require inventory check before confirmation"],
crossDomainInteractions: ["Triggers Logistics on confirmed"]
}
}
📂 domain-graph.json: arquivo separado, schema compartilhado
Approach C do design: arquivos separados (knowledge-graph.json + domain-graph.json) usando o mesmo tipo KnowledgeGraph estendido. Dashboard detecta ambos e oferece um toggle.
✓ Vantagens
- ✓
/understand-domainroda standalone (leve) - ✓Schema compartilhado → search, validation, filtros já funcionam
- ✓Sem risco de poluir o grafo estrutural
- ✓Cada arquivo independentemente válido
✗ Alternativas rejeitadas
- ✗Arquivo único: poluição, dificil iterar
- ✗Schema totalmente novo: quebra search e validação existentes
- ✗Anotar nodes estruturais com domain field: mistura camadas
- ✗Backend separado: complexidade open-source desnecessária
📄 Toggle no dashboard
.understand-anything/
├── knowledge-graph.json ← grafo estrutural (sempre presente)
└── domain-graph.json ← camada de domínio (opcional)
Dashboard detecta ambos:
- Se só estrutural: mostra view padrão
- Se ambos: toggle "Domain ↔ Structural" no canto sup. dir.
- Domain view = default quando disponível
💡 Dica prática
Para projetos legados, comece só com o domain-graph. Você anota a hierarquia de negócio sem rodar o pipeline pesado de estrutural. Vincula implements aos arquivos depois.
📐 Por que substituir dagre por ELK
Com 50+ nós no mesmo rank, o applyDagreLayout TB enfileira tudo numa linha de milhares de pixels. Resultado: nós shrinkam, labels somem, edges viram espaguete. ELK distribui em 2D com algoritmos modernos.
📊 Scope das views afetadas
- Overview (layer clusters): dagre → ELK. Sem novo grouping (layers já agrupam).
- DomainGraphView: dagre → ELK com domain como parent de flow/step.
- Layer-detail: dagre → ELK + folder/community containers + edge aggregation + lazy 2-stage.
- KnowledgeGraphView: permanece em
applyForceLayout— fora do escopo.
📄 Pipeline de layout
existing graph (immutable)
↓
deriveContainers(nodes, edges) // §2 folder + community fallback
↓
buildCompoundGraph() // agrega edges inter-container
↓
runStage1Layout(containers) // ELK só nos containers
↓ [render: containers laid, children unrendered]
↓
runStage2Layout(container) // ELK em filhos sob demanda
↓
React Flow render (parentId)
📦 Containers: folder strategy + community fallback
Sem containers, 100+ nós soltos não têm âncora visual. A layer-detail ganha containers derivados de pasta (default) com fallback para community detection quando a estrutura de pasta é rasa demais.
Folder strategy (default)
Quando estrutura de pasta é informativa
Agrupa nodes pelo primeiro segmento significativo do path. src/auth/* → container "auth". src/api/* → container "api".
Community fallback
Quando todos os arquivos estão na mesma pasta
Roda community detection (Louvain ou similar) nos edges do layer. Forma containers sintéticos com label gerado.
Edge aggregation
Cross-container default, intra-container surface on demand
Por padrão, edges entre containers são agregadas (uma linha grossa em vez de N). Click no container expande os edges individuais.
Single depth (v1)
Sem nesting multi-nível
v1 explicitamente NÃO suporta containers dentro de containers. Mantém o React Flow parentId simples e o layout previsível.
💡 Dica prática
Folder strategy quase sempre ganha — projetos bem organizados já carregam semântica na pasta. Community fallback é seguro como Plan B mas pode gerar labels genéricos ("cluster-1") que confundem.
implements. Para escalar até milhares de nós, o layer-detail troca renderização direta por containers folder/community e lazy two-stage layout (stage 1 = só containers, stage 2 = filhos sob demanda).
🐢 Lazy two-stage layout
Layoutar 1000+ nós de uma vez trava o browser. Two-stage entrega first paint rápido e adia trabalho até o usuário pedir.
⚙️ Estágios
- •Stage 1 — Containers only: ELK roda só nos containers e edges agregadas. Usuário já vê estrutura.
- •Stage 2 — Children on demand: ELK roda nos filhos de UM container quando o usuário clica, dá zoom > 1.0, busca, focus ou tour hit.
- •Size memory: tamanhos de containers calculados em Stage 1 são memorizados para Stage 2 não realocar.
📊 Invariantes preservadas
- 1. Layout pure & memoized: só recomputa quando topologia / persona / diff / focus / nodeTypeFilters mudam
- 2. Visual state é overlay O(n) separado: selection, search highlight, tour highlight, hover NÃO triggam relayout
📄 Cache por container
// useLayerDetailGraph.ts (existente, hook split)
const stage1 = useStage1Layout(containers, aggEdges)
const stage2Cache = useRef(new Map<string, LayoutResult>())
function triggerStage2(containerId) {
if (stage2Cache.current.has(containerId)) return
runELK(container.children).then(result => {
stage2Cache.current.set(containerId, result)
forceUpdate()
})
}
⚠️ GraphIssue: falhas com mensagem, nunca tela em branco
Falhas de layout (ELK timeout, container vazio, edge inválida) são modeladas como GraphIssue — o mesmo tipo já usado pelo schema validator. Renderizam no banner do dashboard com mensagem actionable.
🚨 Anti-pattern: tela branca
Sem GraphIssue, ELK falha e o dashboard mostra nada. Usuário não sabe se o pipeline gerou grafo, se o schema falhou, ou se o layout deu pau. Mensagem clara > silêncio sempre.
✓ FAZER
- ✓try/catch ao redor de cada ELK call
- ✓Mensagem com container affected + sugestão
- ✓Fallback para grafo flat se container falhar
- ✓Banner usa o mesmo componente do schema validator
✗ EVITAR
- ✗console.error e seguir como se nada → tela em branco
- ✗Telemetria remota (Sentry) — não-goal open-source
- ✗Mensagens genéricas tipo "Erro" sem contexto
- ✗Crash do React por uncaught promise rejection
📄 GraphIssue type (compartilhado)
type GraphIssue = {
severity: "warning" | "error"
source: "schema" | "layout" | "ingest"
message: string // human-readable
context?: { containerId?: string; nodeId?: string }
suggestion?: string // actionable next step
}
// Exemplo:
{
severity: "warning",
source: "layout",
message: "Container 'auth' has 0 visible children after filtering",
context: { containerId: "auth" },
suggestion: "Disable node type filter or re-run /understand"
}
💡 Dica prática
Sem telemetria remota é decisão consciente — projeto open-source não envia dados de usuário por padrão. Usuários reportam via GitHub issue com o conteúdo do banner. Banner com suggestion = issue de qualidade.
🎓 Resumo do módulo (e da trilha)
Você concluiu a Trilha 3 — Avançado 🚀
Agora você sabe estender, escalar e visualizar o Understand Anything em produção. Próximo passo: contribuir no repositório no GitHub.