11 KiB
Guia de Desenvolvimento — 18/10/2025
Este documento consolida o estado atual do ambiente de desenvolvimento, descreve como rodar lint/test/build localmente (e no CI) e registra erros recorrentes com as respectivas soluções.
Resumo rápido
- Node/PNPM: Node 20.9+ (alinhado ao requisito do Next 15) + pnpm 9 (habilite via
corepack enable && corepack prepare pnpm@9 --activate). - Bun (runtime padrão): 1.3+ já instalado no runner e VPS (
bun --version). Após instalar localmente, exportePATH="$HOME/.bun/bin:$PATH"para tornar o binário disponível. Usepnpm dev:bun/pnpm convex:dev:bun/pnpm build:bun/pnpm start:bunpara executar os scripts combun run --bun(scripts Node continuam disponíveis como fallback). - Next.js 15.5.5: Projeto voltou para a versão estável (
next@15.5.5) com Turbopack como bundler padrão e whitelist de domínios garantida pelo middleware. - Lint/Test/Build:
pnpm lint,pnpm test,pnpm build. O script de testes usavitest --run --passWithNoTests, eliminando o modo watch interativo. - Banco DEV: SQLite em
prisma/prisma/db.dev.sqlite. DefinaDATABASE_URL="file:./prisma/db.dev.sqlite"ao chamar CLI do Prisma. - Desktop (Tauri): fonte em
apps/desktop. Usa Radix tabs + componentes shadcn-like, integra com os endpoints/api/machines/*e suporta atualização automática via GitHub Releases. - CI: Workflow
Quality Checksroda lint/test/build para pushes e PRs namain, além do pipeline de deploy existente.
Banco de dados (Prisma)
-
Gere/atualize o schema local:
DATABASE_URL="file:./prisma/db.dev.sqlite" pnpm exec prisma db push DATABASE_URL="file:./prisma/db.dev.sqlite" pnpm prisma:generate DATABASE_URL="file:./prisma/db.dev.sqlite" pnpm auth:seed -
Rode o app Next.js:
pnpm dev:bunAlternativas:
pnpm dev(Node) oupnpm dev:webpackse precisar do fallback oficial. -
Credenciais padrão (seed):
admin@sistema.dev / admin123. -
Herdou dados antigos? Execute
node scripts/remove-legacy-demo-users.mjspara limpar contas demo legadas.
Por quê inline? Evitamos declarar
DATABASE_URLemprisma/.envporque o Prisma lê também o.envda raiz (produção). O override inline garante isolamento do banco DEV.
Next.js 15 (estável)
- Mantemos o projeto em
next@15.5.5, priorizando estabilidade enquanto acompanhamos as novidades do 16. - React 18.2: voltamos para a versão suportada oficialmente pelo Next 15. Evite APIs exclusivas do React 19 (
use(...),useActionState, etc.). - Turbopack segue como bundler padrão, sem flags experimentais adicionais.
- Whitelist de hosts: o release estável 15.5 não aceita
server.allowedHosts(videinvalid-next-config), portanto bloqueamos domínios exclusivamente viamiddleware.ts.
Editor rich text (TipTap) — menções de ticket
- Menções (
ticketMention) agora têm prioridade maior (priority: 1000) e um Link seguro (SafeLinkExtension) foi introduzido para ignorar<a data-ticket-mention="true">. Isso evita que oLinkdo StarterKit capture as âncoras na hidratação, garantindo que as menções continuem como nodes (não como marks) durante a edição. - O mesmo helper
normalizeTicketMentionHtmlé aplicado ao carregar/atualizar conteúdo no editor, dentro dos fluxos de comentários e no Convex. Esse helper reescreve qualquer HTML legado (#123•Assunto) no formato de chip completo (datasets, spans, dot). - Resultado: o chip mantém layout e comportamento ao editar (Backspace/Delete removem o node inteiro, node view continua ativo) sem exigir reload.
- Se precisar adicionar novos comportamentos, importe
SafeLinkExtensione mantenha a ordem[TicketMentionExtension, StarterKit (link:false), SafeLinkExtension, Placeholder]para que o parser continue estável.
Comandos de qualidade
pnpm lint: executa ESLint (flat config) sobre os arquivos do projeto.pnpm test: Vitest em modo não interativo (--run --passWithNoTests). Usepnpm test -- --watchsomente quando quiser rodar em watch localmente. Inclui testes de API (rotas/api/machines/*) e utilitários de SMTP.pnpm build:next build --turbopack.- Scripts com Bun (padrão atual):
pnpm dev:bun,pnpm convex:dev:bun,pnpm build:bun,pnpm start:bun. Eles mantêm opnpmcomo orquestrador, apenas forçando o runtime do Bun viabun run --bun. Ocross-envgaranteNODE_ENVconsistente (development/production) para evitar warnings/falhas no Next. - Fallback Webpack disponível via
pnpm dev:webpack/pnpm build:webpackquando Turbopack não coopera (caso observado em combinações Bun + Next 16). pnpm prisma:generate: necessário antes do build quando o client Prisma muda.
Automação no CI
Arquivo: .github/workflows/quality-checks.yml
Etapas:
- Instala dependências (
pnpm install --frozen-lockfile). pnpm prisma:generate.pnpm lint.pnpm test.pnpm build:bun(Bun 1.3.1 instalado viaoven-sh/setup-bun).
O workflow dispara em todo push/pull_request para main e fornece feedback imediato sem depender do pipeline de deploy.
Testes rápidos via curl (Convites & acessos)
- Rode
pnpm dev:bun(oupnpm devse preferir Node) e autentique-se emhttp://localhost:3000/loginusandoadmin@sistema.dev / admin123. - Copie o valor do cookie
BETTER_AUTH_SESSIONe exporte no shell:export COOKIE="BETTER_AUTH_SESSION=<valor>".
Usuários
# Listar usuários com acesso web
curl -s http://localhost:3000/api/admin/users \
-H "Cookie: $COOKIE" \
-H "Accept: application/json" | jq '.users | map({ id, email, role })' # remova o pipe se não tiver jq
# Criar usuário gestor (ajuste o e-mail se necessário)
NEW_EMAIL="api.teste.$(date +%s)@sistema.dev"
curl -s -X POST http://localhost:3000/api/admin/users \
-H "Cookie: $COOKIE" \
-H "Content-Type: application/json" \
-d "{\"name\":\"Usuário via curl\",\"email\":\"$NEW_EMAIL\",\"role\":\"manager\",\"tenantId\":\"tenant-atlas\"}" \
| tee /tmp/user-created.json
# Remover o usuário recém-criado
USER_ID=$(jq -r '.user.id' /tmp/user-created.json)
curl -i -X DELETE http://localhost:3000/api/admin/users/$USER_ID \
-H "Cookie: $COOKIE"
Os exemplos acima utilizam
jqpara facilitar a leitura. Se não estiver disponível, remova os pipes e leia o JSON bruto.
Convites
# Criar convite válido por 7 dias
INVITE_EMAIL="convite.$(date +%s)@sistema.dev"
curl -s -X POST http://localhost:3000/api/admin/invites \
-H "Cookie: $COOKIE" \
-H "Content-Type: application/json" \
-d "{\"email\":\"$INVITE_EMAIL\",\"name\":\"Convite via curl\",\"role\":\"collaborator\",\"tenantId\":\"tenant-atlas\",\"expiresInDays\":7}" \
| tee /tmp/invite-created.json
# Revogar convite pendente
INVITE_ID=$(jq -r '.invite.id' /tmp/invite-created.json)
curl -i -X PATCH http://localhost:3000/api/admin/invites/$INVITE_ID \
-H "Cookie: $COOKIE" \
-H "Content-Type: application/json" \
-d '{"reason":"Revogado via curl"}'
# Reativar (até 7 dias após a revogação)
curl -i -X PATCH http://localhost:3000/api/admin/invites/$INVITE_ID \
-H "Cookie: $COOKIE" \
-H "Content-Type: application/json" \
-d '{"action":"reactivate"}'
Dica: ao receber
409na criação de convite, há outro convite pendente/aceito para o mesmo e-mail. Revogue ou remova o usuário antes.
Desktop (Tauri)
- Tabs Radix + estilos shadcn:
apps/desktop/src/components/ui/tabs.tsx. - Painel principal:
apps/desktop/src/main.tsx— abas Resumo/Inventário/Diagnóstico/Configurações, envio manual de inventário, seleção de persona (colaborador/gestor) e vínculo com usuário. - Coleta/hardware:
apps/desktop/src-tauri/src/agent.rs. - Variáveis de build:
VITE_APP_URL(URL Web).VITE_API_BASE_URL(API).
Build local
corepack enable && corepack prepare pnpm@9 --activate
pnpm -C apps/desktop install
VITE_APP_URL=http://localhost:3000 \
VITE_API_BASE_URL=http://localhost:3000 \
pnpm -C apps/desktop tauri build
Artefatos: apps/desktop/src-tauri/target/release/bundle/.
Ícone do instalador (NSIS)
-
O Windows espera que
apps/desktop/src-tauri/icons/icon.icocontenha sprites em 16, 24, 32, 48, 64, 128 e 256 px, todos com fundo transparente. Sem esses tamanhos o Explorer gera uma miniatura reduzida com bordas acinzentadas. -
Para atualizar o ícone a partir do
icon-512.png, execute:cd apps/desktop/src-tauri python3 - <<'PY'
from PIL import Image img = Image.open("icons/icon-512.png") img.save("icons/icon.ico", sizes=[(16,16),(24,24),(32,32),(48,48),(64,64),(128,128),(256,256)]) PY
- Depois de regerar `icon.ico`, faça o commit e rode novamente `pnpm -C apps/desktop tauri build` para empacotar o instalador com o ícone correto.
### Atualizações OTA
1. Gere chaves (`pnpm tauri signer generate`).
2. Defina `TAURI_SIGNING_PRIVATE_KEY` (+ password) no ambiente de build.
3. Publique os pacotes e um `latest.json` em release GitHub.
4. O app verifica ao iniciar e pelo botão “Verificar atualizações”.
## Erros recorrentes e soluções
| Sintoma | Causa | Correção |
| --- | --- | --- |
| `ERR_PNPM_OUTDATED_LOCKFILE` no pipeline | Dependências do desktop alteradas sem atualizar `pnpm-lock.yaml` | Rodar `pnpm install` na raiz e commitar o lockfile. |
| Prisma falha com `P2021` / tabelas Better Auth inexistentes | CLI leu `.env` da raiz (produção) | Usar `DATABASE_URL="file:./prisma/db.dev.sqlite"` nos comandos. |
| Vitest trava em modo watch | Script `pnpm test` sem `--run` e CI detecta TTY | Ajustado para `vitest --run --passWithNoTests`. Localmente, use `pnpm test -- --watch` se quiser. |
| Desktop não encontra updater | Falta `latest.json` ou assinatura inválida | Publicar release com `*.sig` e `latest.json` apontando para os pacotes corretos. |
## Cronômetro dos tickets
- A UI e o backend agora compartilham um relógio real alinhado via `serverNow`. Toda resposta de `tickets.workSummary`, listagens de tickets e mutations `startWork/pauseWork` envia `serverNow` (epoch UTC).
- O frontend (`ticket-summary-header` e tabela) calcula um deslocamento (`offset = Date.now() - serverNow`) e projeta `Date.now()` para a linha do tempo do servidor usando `toServerTimestamp`. Isso elimina drift quando o navegador está adiantado/atrasado.
- Durante o `startWork`, se a mutation retornar `status = already_started` sem `startedAt`, a UI usa `getServerNow()` como fallback, e assim que o Convex reenviar a sessão ativa, o reconciliador (`reconcileLocalSessionStart`) substitui o valor local.
- O tempo em execução exibido “ao vivo” torna-se idêntico ao acumulado após pausar, com tolerância de ±1 s por conta do tick do cronômetro. Ao depurar inconsistências, verifique se `serverNow` está chegando (painel de rede) e se o offset em `ticket-timer.utils.ts` está sendo calibrado.
## Referências úteis
- **Deploy (Swarm)**: veja `docs/DEPLOY-RUNBOOK.md`.
- **Plano do agente desktop / heartbeat**: `docs/plano-app-desktop-maquinas.md`.
- **Histórico de incidentes**: `docs/historico-agente-desktop-2025-10-10.md`.
> Última revisão: 18/10/2025. Atualize este guia sempre que o fluxo de DEV ou automações mudarem.
- **Next.js 16 (beta)**: comportamento sujeito a mudanças. Antes de subir para stable, acompanhe o changelog oficial (quebra: `revalidateTag` com segundo argumento, params assíncronos, etc.). Já estamos compatíveis com os breaking changes atuais.