Mapa da trilha
Conteúdo detalhado
🌊 Workflow de feature
Do specify ao E2E, em 6 passos. A ordem importa: testes antes da próxima camada.
Unidades pequenas, com responsabilidade afiada, compostas por fronteiras explícitas. Domínio em src/openhuman/<dominio>/, transporte em src/core/.
Código grande sem fronteiras vira lama. O OpenHuman é grande justamente porque cada domínio sabe seu lugar e não vaza.
Domínio dedicado, no parallel architectures, mod.rs leve, controllers no registry — nunca branches em cli.rs/jsonrpc.rs.
Antes de escrever uma linha, ancore a feature em padrões existentes: domínios atuais, registry, naming openhuman.<ns>_<fn>.
Arquitetura paralela é a doença mais cara de curar. Se já existe um padrão, use-o.
Capability catalog (src/openhuman/about_app/), naming RPC, controller-only exposure, sem novos arquivos no root de src/openhuman/.
Lógica de domínio em src/openhuman/<dominio>/, schemas + handlers no registry, unit tests até funcionar em isolamento.
Provar a lógica em Rust antes da UI evita debug cruzado: se quebra, você sabe que é a UI, não o core.
ops.rs, store.rs, types.rs, schemas.rs, rpc.rs; RpcOutcome<T> contract; mod.rs apenas exporta.
Estenda tests/json_rpc_e2e.rs para que os métodos RPC casem exatamente com o que a UI vai chamar.
Erros de contrato são silenciosos. Provar pelo transporte garante que serialização, auth e shape do payload batem.
scripts/test-rust-with-mock.sh, mock API server, bearer token em OPENHUMAN_CORE_TOKEN, request/response shape.
Telas e estado no React usando core_rpc_relay / coreRpcClient. Regras ficam no core.
UI orquestra e apresenta — não decide. Lógica duplicada em TS é dívida garantida.
Sempre invoke('core_rpc_relay', ...) (evita CORS preflight), i18n via useT(), no dynamic imports em prod.
Antes de codar, defina os cenários E2E que cobrem happy path, falhas, auth e regressões. Não testável = spec incompleta.
Escopo definido por testes é escopo que cabe num PR. Sem isso, features incham até o infinito.
Vitest co-localizado, WDIO em app/test/e2e/specs/, atualizar about_app/ no mesmo PR.
🧪 Testes em 3 níveis
Vitest co-localizado, WDIO dual-platform, cargo com mock. Coverage gate ≥80% em linhas alteradas.
Pirâmide do projeto: unit (Vitest + cargo) rápido e barato, RPC (JSON-RPC E2E) prova o contrato, E2E (WDIO) prova o fluxo completo.
Cada nível pega uma classe diferente de bug. Confiar só em E2E é lento; só em unit é cego.
Comportamento sobre implementação, mocks determinísticos, sem rede real, sem flake de tempo.
Testes *.test.ts / *.test.tsx ao lado do código em app/src/**. Config em app/test/vitest.config.ts.
Teste perto do código é teste que existe. Pastas separadas viram cemitério.
pnpm test, pnpm test:coverage, helpers em app/src/test/, debug runner pnpm debug unit.
Mesmo mock backend usado por unit, RPC E2E e WDIO. Core em scripts/mock-api-core.mjs, server em scripts/mock-api-server.mjs.
Um mock só evita drift de comportamento entre níveis. Resultados determinísticos via POST /__admin/reset.
/__admin/health, /__admin/reset, /__admin/behavior, /__admin/requests; rodar manual com pnpm mock:api.
E2E roda contra o app empacotado. Linux usa tauri-driver (WebDriver :4444). macOS usa Appium Mac2 (XCUITest :4723) no .app.
CI roda no Linux. Dev local em Mac roda nativo. Ambos os caminhos têm que funcionar antes do PR.
Specs em app/test/e2e/specs/, helpers element-helpers.ts (clickNativeButton, waitForWebView), nunca raw XCUIElementType*.
pnpm test:rust sobe o mock backend e roda cargo test. Para um teste só: bash scripts/test-rust-with-mock.sh --test json_rpc_e2e.
Provar o contrato RPC sem depender de backend real evita flake e acelera o ciclo.
Suite tests/json_rpc_e2e.rs, debug runner pnpm debug rust, logs em target/debug-logs/.
PRs devem ter ≥80% de cobertura nas linhas alteradas. Workflow .github/workflows/coverage.yml usa diff-cover sobre Vitest + cargo-llvm-cov.
Cobertura global engana — o que importa é cobrir o que você acabou de mudar. Sem isso, código novo entra sem rede.
Teste happy path + edge cases, não só o caminho feliz; merged LCOV (app + core + Tauri shell).
🌿 Git, PRs e CI
Fork model, branch off upstream/main, push em origin, PR contra tinyhumansai:main. Hooks, templates e i18n parity.
Layout obrigatório: origin aponta pro seu fork (push aqui), upstream aponta pra tinyhumansai/openhuman (fetch-only).
Push direto no upstream polui branches e fura code review. Trate upstream como leitura.
git remote rename origin upstream, git remote add origin git@github.com:<seu>/openhuman.git, git fetch upstream.
Antes de qualquer mudança: git fetch upstream && git checkout -b <branch> upstream/main. Trabalho fica na feature branch.
Main limpa só avança via merge. Misturar trabalho local em main quebra o rebase e força resets dolorosos.
Branch atômica por feature, nomes descritivos, rebase sobre upstream/main quando necessário.
Push pra origin, abrir PR contra tinyhumansai/openhuman:main com --head <seu-user>:<branch>.
Origem do PR sendo o fork mantém upstream limpo. --head resolve ambiguidade quando há mesma branch em vários remotes.
Issue templates em .github/ISSUE_TEMPLATE/, PR template em .github/PULL_REQUEST_TEMPLATE.md, seguir verbatim.
Husky roda pnpm rust:check antes de cada push. --no-verify só para falhas pré-existentes não relacionadas ao seu PR.
Pegar erro de compile localmente é segundos; pegar no CI é minutos e desperdício de tempo de reviewer.
Prettier, ESLint, tsc --noEmit, cargo fmt, cargo check — todos parte do ciclo local.
Toda string de UI passa por useT(). Chave nova vai em en.ts e no chunk correspondente en-N.ts + mesma posição em todos os 12 locales.
CI roda pnpm i18n:check. Faltando chave em qualquer locale = PR não merge. Use inglês como placeholder.
Locales: ar, bn, de, es, fr, hi, id, it, ko, pt, ru, zh-CN. Hard-coded em JSX/label=/aria-label= não passa.
Gates de merge: coverage ≥80% em linhas alteradas, pnpm i18n:check, ESLint/Prettier, tsc --noEmit, cargo check, suite de testes.
Saber o que CI checa = não ter PR vermelho por surpresa. Rode local antes de pushar.
Workflows em .github/workflows/, debug runners para logs locais, rebase quando upstream avança.