MÓDULO 5.1

🌊 Workflow de feature

Specify → Rust → JSON-RPC E2E → UI Tauri/React → testes app → E2E. Seis passos numa ordem deliberada — testes vêm antes da próxima camada.

6
Tópicos
50
Minutos
Avançado
Nível
Workflow
Tipo
1

🧩 Filosofia Unix-style

OpenHuman não é um monolito grande — é um conjunto de domínios pequenos que conversam por fronteiras explícitas. Domain logic vive em src/openhuman/<dominio>/, transporte vive em src/core/, e ninguém invade ninguém.

Os três princípios

  • Módulos pequenos, sharp-responsibility: uma coisa, bem feita, fronteira clara.
  • Tests before the next layer: unit antes de RPC, RPC antes de UI. Untested = incompleto.
  • Docs with code: rustdoc + comentários atualizados no mesmo PR. AGENTS.md quando regras mudam.

✓ Faz

  • Novo domínio em src/openhuman/<dom>/mod.rs + irmãos
  • Controller no registry, schemas em schemas.rs
  • mod.rs só exporta; lógica em ops.rs/store.rs
  • Arquivos ≤500 linhas; quebra quando crescer

✗ Não faz

  • Novo *.rs standalone no root de src/openhuman/
  • Branches por domínio em src/core/cli.rs ou jsonrpc.rs
  • Lógica pesada em src/core/ (é só transporte)
  • Arquitetura paralela porque "fica mais fácil"
Conceito
Domain-driven
Conceito
No parallel arch
Conceito
Controller registry
Conceito
Light mod.rs
2

📐 Os 6 passos do workflow

A sequência não é negociável. Pular um passo (ex: ir direto pra UI) gera retrabalho garantido — porque a UI estará chamando uma RPC que nunca foi validada.

1

Specify contra o codebase atual

Sem nada escrito ainda

Ler domínios existentes, padrões de naming RPC (openhuman.<ns>_<fn>), capability catalog. Nada de inventar.

2

Implementar em Rust

Domínio + schemas + unit tests

Lógica em src/openhuman/<dom>/, schemas registrados, unit tests passando em isolamento antes de continuar.

3

JSON-RPC E2E

Prova de contrato pelo transporte

Estender tests/json_rpc_e2e.rs. Os métodos RPC devem casar exatamente com o que a UI vai chamar.

4

UI no app Tauri

Telas + estado, chamando o core

React + Redux Toolkit + coreRpcClient. Regras ficam no core, UI só orquestra e apresenta.

5

App unit tests (Vitest)

Comportamento de componentes e hooks

Co-localizados com o código, focados em comportamento visível ao usuário, não em internals.

6

App E2E (WDIO)

Fluxo end-to-end no app empacotado

Spec em app/test/e2e/specs/. Asserta efeito visível e estado do mock. Não é testável? Spec está incompleta.

Conceito
Ordem importa
Conceito
Provar isoladamente
Conceito
Contrato RPC primeiro
Conceito
UI por último
3

🦀 Anatomia de um domínio Rust

Cada domínio segue a mesma estrutura. Saber o nome de cada arquivo é metade do trabalho — a outra metade é o conteúdo certo em cada um deles.

src/openhuman/cron/
├── mod.rs          // só exporta — `mod schemas; mod ops; ...`
├── types.rs        // structs/enums do domínio
├── store.rs        // persistência
├── ops.rs          // operações de negócio
├── rpc.rs          // handlers JSON-RPC
├── schemas.rs      // ControllerSchema + registro
└── bus.rs          // EventHandler — <Purpose>Subscriber

💡 Dica do controller migration

Em schemas.rs, exporte:

  • schemas — lista de ControllerSchema
  • all_controller_schemas + all_registered_controllers
  • handle_* fns delegando para rpc.rs

No mod.rs re-exporte como all_<domain>_controller_schemas. Em src/core/all.rs, plug-in. Nunca adicione branch em src/core/dispatch.rs.

📊 Domínios já existentes (referência)

Antes de criar novo domínio, veja se cabe em um existente:

agentmemorychannelscron skillstoolswebhooksintegrations providerscredentialsbillingconfig peoplethreadsnotificationssecurity

+ ~30 outros. Total: ~50 domínios. Reuso > criação.

Arquivo
mod.rs leve
Contrato
RpcOutcome<T>
Registry
all_controllers
Bus
EventHandler
4

🔌 Provando o contrato via JSON-RPC

O contrato RPC é a fronteira mais frágil do projeto: TypeScript de um lado, Rust do outro, serialização no meio. Bug aqui é silencioso até virar runtime error no usuário.

# Suite completa (mock backend up automaticamente)
$ pnpm test:rust

# Um teste específico
$ bash scripts/test-rust-with-mock.sh --test json_rpc_e2e

# Via debug runner — output bounded, log completo em target/debug-logs/
$ pnpm debug rust json_rpc_e2e

⚠️ Erros silenciosos comuns

  • • Campo opcional no schema, mas a UI envia sempre — schema permissivo demais.
  • • Serde rename diferente entre request e response — vira null no cliente.
  • RpcOutcome::Err sem ser tratado na UI — usuário vê tela em branco.
  • • Falta de auth bearer — 401 sem mensagem amigável.
Suite
json_rpc_e2e.rs
Auth
Bearer token
Mock
test-with-mock.sh
Logs
target/debug-logs
5

🖥️ Surfando na UI sem virar peso

A UI não decide — orquestra. Toda regra de negócio fica no core. A UI faz três coisas: chamar RPC, apresentar resultado e capturar input do usuário.

✓ UI saudável

  • Componente pega dado via useQuery/Redux + coreRpcClient
  • Toda string passa por useT() (i18n)
  • invoke('core_rpc_relay', ...) em vez de fetch()
  • Static imports only (no import())

✗ UI doente

  • Regra de negócio em TS (vai duplicar com o core)
  • localStorage ad-hoc em vez de Redux persist
  • String hardcoded em label= ou aria-label=
  • React.lazy(() => import(...)) em produção

🔑 Por que core_rpc_relay?

O fetch() dispararia CORS preflight contra o servidor local. invoke('core_rpc_relay', ...) passa pela ponte IPC do Tauri — sem preflight, com bearer já injetado, e funciona idêntico em dev e produção.

RPC
core_rpc_relay
Estado
Redux Toolkit
i18n
useT()
Imports
Static only
6

📋 Capability catalog & planning

Quando a feature adiciona, remove ou renomeia algo visível ao usuário, atualize o capability catalog no mesmo PR. É o índice central das capacidades do app — sem isso, agentes e documentação ficam desatualizados em silêncio.

📚 Onde mexer

  • src/openhuman/about_app/ — capability catalog
  • AGENTS.md — quando regras/contratos mudam
  • gitbooks/developing/architecture*.md — narrativa estrutural
  • rustdoc dos módulos que ganharam comportamento novo

🎯 Planning rule

Antes de codar, defina os cenários E2E que cobrem:

  • • Happy path
  • • Failure modes (rede, auth, dados inválidos)
  • • Auth gates (usuário sem credencial, sessão expirada)
  • • Regressões conhecidas do domínio

Se não dá pra testar end-to-end, a spec está incompleta ou o cut está grande demais. Quebre o PR.

Catalog
about_app/
Docs
Mesma PR
Planning
E2E upfront
Cut size
Testável

🎓 Resumo do Módulo

Unix-style modules — pequenos, sharp-responsibility, fronteiras explícitas
6 passos, nesta ordem — spec → Rust → RPC → UI → unit → E2E
Domínio = pasta — mod.rs leve, lógica em ops/store/types
Controller registry — nunca branches em cli.rs/jsonrpc.rs
UI orquestra, core decide — sem regra de negócio em TS
Capability catalog — atualize no mesmo PR

Próximo Módulo:

5.2 — Testes em 3 níveis (Vitest, WDIO, cargo + mock)