refactor: quality workflow, docs, tests

This commit is contained in:
Esdras Renan 2025-10-16 19:14:46 -03:00
parent a9caf36b01
commit 68ace0a858
27 changed files with 758 additions and 330 deletions

124
docs/DEPLOY-RUNBOOK.md Normal file
View file

@ -0,0 +1,124 @@
# Deploy runbook (Swarm)
Este guia documenta o fluxo de deploy atual e os principais passos de diagnóstico/correção que resolveram o problema do front não atualizar mesmo com o CI verde.
## Visão geral (como você trabalha)
- Você dá push na `main` e aguarda o GitHub Actions concluir.
- O pipeline cria um build imutável no servidor em `/home/renan/apps/sistema.build.<release>`.
- Um symlink estável aponta para o release ativo: `/home/renan/apps/sistema.current`.
- O serviço `sistema_web` monta sempre `/home/renan/apps/sistema.current:/app`. Para atualizar, basta mudar o symlink e forçar a task.
Resultado: front/back sobem com o novo código sem editar o stack a cada release.
## Fluxo de release (mínimo)
1. Gerar build em `/home/renan/apps/sistema.build.<stamp-ou-sha>` (CI faz isso).
2. Atualizar symlink: `ln -sfn /home/renan/apps/sistema.build.<novo> /home/renan/apps/sistema.current`.
3. Rollout do serviço web: `docker service update --force sistema_web`.
4. Opcional: se o `stack.yml` mudou, aplicar: `docker stack deploy --with-registry-auth -c /home/renan/apps/sistema.build.<novo>/stack.yml sistema`.
## Stack estável (essência)
- Mount fixo: `/home/renan/apps/sistema.current:/app` (não interpolar APP_DIR).
- Comando inline (sem script), com migrations na subida:
- `command: ["bash","-lc","corepack enable && corepack prepare pnpm@9 --activate && pnpm exec prisma migrate deploy && pnpm start -p 3000"]`
- Env obrigatórias (URLs válidas):
- `DATABASE_URL=file:/app/data/db.sqlite`
- `NEXT_PUBLIC_CONVEX_URL=http://sistema_convex_backend:3210`
- `NEXT_PUBLIC_APP_URL=https://tickets.esdrasrenan.com.br`
- `BETTER_AUTH_URL=https://tickets.esdrasrenan.com.br`
- Update com `stop-first` (evita `database is locked` em SQLite) + healthcheck.
## Prisma/SQLite do stack
- O volume do stack é namespaced: `sistema_sistema_db` (não `sistema_db`).
- Ao operar Prisma fora do Swarm, use SEMPRE este volume e a mesma `DATABASE_URL`:
```
APP_DIR=/home/renan/apps/sistema.current
docker run --rm -it \
-e DATABASE_URL=file:/app/data/db.sqlite \
-v "$APP_DIR:/app" -v sistema_sistema_db:/app/data -w /app \
node:20-bullseye bash -lc 'corepack enable; corepack prepare pnpm@9 --activate; pnpm i --no-frozen-lockfile; pnpm exec prisma migrate status'
```
## Diagnóstico rápido
- Ver a task atual + erros: `docker service ps --no-trunc sistema_web`
- Logs frescos do serviço: `docker service logs --since=2m -f sistema_web`
- Spec aplicado (Args + Mounts):
```
docker service inspect sistema_web \
--format '{{json .Spec.TaskTemplate.ContainerSpec.Args}} {{json .Spec.TaskTemplate.ContainerSpec.Mounts}}'
```
- Envs do serviço: `docker service inspect sistema_web --format '{{json .Spec.TaskTemplate.ContainerSpec.Env}}'`
## O incidente (front não atualizava) — causa e correções
Sintomas:
- Actions verde, mas UI antiga; logs com rollbacks de `docker service update`.
Causas encontradas:
1) Serviço ainda montava build antigo e comando antigo (spec não mudava).
- Inspect mostrava `Source=/home/renan/apps/sistema.build.<antigo> -> /app` e comando inline antigo.
- Correção: redeploy do stack com mount em `/home/renan/apps/sistema.current` + `docker service update --force sistema_web`.
2) Migration P3009 ("failed migrations") no SQLite do stack.
- Motivo: resolver/aplicar migrations no volume errado (`sistema_db`), enquanto o serviço usa `sistema_sistema_db`.
- Correção determinística:
- `docker service scale sistema_web=0`
- `prisma migrate resolve --rolled-back 20251015223259_add_company_provisioning_code` no volume `sistema_sistema_db` (comando acima em "Prisma/SQLite do stack").
- `pnpm exec prisma migrate deploy`
- `docker service scale sistema_web=1` (ou `update --force`).
3) Rollback por script ausente (`/app/scripts/start-web.sh`).
- Task caía com exit 127 porque o build não continha o script.
- Correção: voltar ao comando inline no stack (sem depender do script) OU garantir o script no build e executável.
4) Falha de env (Invalid URL em `NEXT_PUBLIC_APP_URL`/`BETTER_AUTH_URL`).
- Correção: definir URLs válidas no stack ou via `docker service update --env-add ...`.
## Cheatsheet de correções
- Forçar rollout da task:
- `docker service update --force sistema_web`
- Aplicar build novo (sem tocar stack):
- `ln -sfn /home/renan/apps/sistema.build.<novo> /home/renan/apps/sistema.current`
- `docker service update --force sistema_web`
- Corrigir mount/args no serviço (hotfix):
```
docker service update \
--mount-rm target=/app \
--mount-add type=bind,src=/home/renan/apps/sistema.current,dst=/app \
--args 'bash -lc "corepack enable && corepack prepare pnpm@9 --activate && pnpm exec prisma migrate deploy && pnpm start -p 3000"' \
sistema_web
```
- Resolver P3009 (volume certo) e aplicar migrations:
```
APP_DIR=/home/renan/apps/sistema.current
docker service scale sistema_web=0
docker run --rm -it -e DATABASE_URL=file:/app/data/db.sqlite \
-v "$APP_DIR:/app" -v sistema_sistema_db:/app/data -w /app \
node:20-bullseye bash -lc 'corepack enable; corepack prepare pnpm@9 --activate; pnpm i --no-frozen-lockfile; pnpm exec prisma migrate resolve --rolled-back 20251015223259_add_company_provisioning_code; pnpm exec prisma migrate deploy'
docker service scale sistema_web=1
```
- Criar DB se faltar (P1003):
- `docker run --rm -v sistema_sistema_db:/data busybox sh -lc ': >/data/db.sqlite'`
- Ajustar envs em runtime:
- `docker service update --env-add NEXT_PUBLIC_APP_URL=https://tickets.esdrasrenan.com.br --env-add BETTER_AUTH_URL=https://tickets.esdrasrenan.com.br sistema_web`
## Notas finais
- Como o stack monta `/home/renan/apps/sistema.current`, um novo release exige apenas atualizar o symlink e forçar a task. O `stack.yml` só precisa ser redeployado quando você altera labels/envs/serviços.
- Se a UI parecer não mudar, valide o mount/args via inspect, confira logs da task atual e force hardreload no navegador.

View file

@ -1,79 +1,68 @@
# Guia de DEV — Banco (Prisma), Auth e Desktop (Tauri)
# Guia de Desenvolvimento — 16/10/2025
Este guia descreve o que foi corrigido, por quê e como seguir no DEV, incluindo como gerar o executável do Desktop (Tauri) localmente.
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.
## O que foi feito e por quê
## Resumo rápido
- Ajuste do Prisma no DEV (P2021)
- Problema: o Prisma CLI lia o `.env` da raiz (produção) e o banco local não tinha as tabelas do Better Auth (ex.: `AuthUser`, `AuthSession`).
- Decisão: evitar conflito entre `.env` (raiz) e `prisma/.env` — usamos `DATABASE_URL=...` inline nos comandos do Prisma, apontando para `./prisma/db.dev.sqlite` apenas no DEV.
- Resultado: banco `prisma/prisma/db.dev.sqlite` criado/sincronizado e seed de usuários executado.
- **Node/PNPM**: Node 20 + pnpm 9 (habilite via `corepack enable && corepack prepare pnpm@9 --activate`).
- **Lint/Test/Build**: `pnpm lint`, `pnpm test`, `pnpm build`. O script de testes usa `vitest --run --passWithNoTests`, eliminando o modo watch interativo.
- **Banco DEV**: SQLite em `prisma/prisma/db.dev.sqlite`. Defina `DATABASE_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 Checks` roda lint/test/build para pushes e PRs na `main`, além do pipeline de deploy existente.
- Migração das abas do Desktop para shadcn/Radix
- O Tauri não roda Next.js. Para manter o visual consistente com o web, migramos as abas para um wrapper shadcn-like usando Radix Tabs e Tailwind (`apps/desktop/src/components/ui/tabs.tsx`).
- Incluímos badge de status equivalente ao web e o botão “Enviar inventário agora” (POST `/api/machines/inventory`).
## Banco de dados (Prisma)
- CI (GitHub Actions) e lockfile
- Erro resolvido: `ERR_PNPM_OUTDATED_LOCKFILE` em `apps/desktop`. Atualizamos o `pnpm-lock.yaml` para refletir as novas dependências do Desktop.
- O workflow do desktop usa `--frozen-lockfile`; manter o lockfile em sincronia evita falhas.
1. Gere/atualize o schema local:
## Fluxo de banco (DEV)
```bash
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
```
- Banco de DEV: `file:./prisma/db.dev.sqlite` (arquivo: `prisma/prisma/db.dev.sqlite`).
- Comandos (forçar alvo de DEV no terminal atual):
2. Rode o app Next.js:
```
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
```
```bash
pnpm dev
```
- Rodar app local (Next):
3. Credenciais padrão (seed): `admin@sistema.dev / admin123`.
```
pnpm dev
```
> **Por quê inline?** Evitamos declarar `DATABASE_URL` em `prisma/.env` porque o Prisma lê também o `.env` da raiz (produção). O override inline garante isolamento do banco DEV.
- Login de teste (DEV): `admin@sistema.dev / admin123`
## Comandos de qualidade
- Prisma Studio (DEV):
- `pnpm lint`: executa ESLint (flat config) sobre os arquivos do projeto.
- `pnpm test`: Vitest em modo não interativo (`--run --passWithNoTests`). Use `pnpm test -- --watch` somente quando quiser rodar em watch localmente.
- `pnpm build`: `next build --turbopack`.
- `pnpm prisma:generate`: necessário antes do build quando o client Prisma muda.
```
DATABASE_URL="file:./prisma/db.dev.sqlite" pnpm exec prisma studio
```
### Automação no CI
Observação: evitar `prisma/.env` nesse setup, pois causa conflito com o `.env` da raiz (o Prisma acusa conflitos e falha o comando). Manter o override inline é a forma mais segura de isolar DEV sem tocar produção.
Arquivo: `.github/workflows/quality-checks.yml`
Etapas:
1. Instala dependências (`pnpm install --frozen-lockfile`).
2. `pnpm prisma:generate`.
3. `pnpm lint`.
4. `pnpm test`.
5. `pnpm build`.
O workflow dispara em todo `push`/`pull_request` para `main` e fornece feedback imediato sem depender do pipeline de deploy.
## Desktop (Tauri)
- Onde foram feitas as mudanças principais:
- `apps/desktop/src/components/ui/tabs.tsx` (Tabs Radix + estilos shadcn-like)
- `apps/desktop/src/main.tsx` (layout com abas: Resumo/Inventário/Diagnóstico/Configurações; status badge; botão “Enviar inventário agora”; seleção do perfil de acesso colaborador/gestor e sincronização do usuário vinculado).
- `apps/desktop/src-tauri/src/agent.rs` (coleta e normalização de hardware, discos, GPUs e inventário estendido por SO).
- 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).
- Variáveis de ambiente do Desktop (em tempo de build):
- `VITE_APP_URL` e `VITE_API_BASE_URL` — por padrão, use a URL da aplicação web.
### Build local
### Atualizações automáticas (GitHub)
1. Gere o par de chaves do updater (`pnpm tauri signer generate -- -w ~/.tauri/raven.key`) e configure as variáveis de ambiente `TAURI_SIGNING_PRIVATE_KEY` e `TAURI_SIGNING_PRIVATE_KEY_PASSWORD` antes de rodar `pnpm -C apps/desktop tauri build`.
2. Garanta que `bundle.createUpdaterArtifacts` esteja habilitado (já configurado) para gerar os pacotes `.nsis`/`.AppImage` e os arquivos `.sig`.
3. Publique os artefatos de cada SO em um release do GitHub e atualize o `latest.json` público (ex.: no próprio repositório ou em um gist) com `version`, `notes`, `pub_date` e as entradas por plataforma (`url` e `signature`).
4. O agente já consulta o updater ao iniciar e também possui o botão “Verificar atualizações” na aba Configurações. Ao detectar nova versão o download é feito em segundo plano e o app reinicia automaticamente após o `downloadAndInstall`.
### Build do executável localmente
Você pode gerar o executável local sem precisar da VPS. O que muda é apenas o sistema operacional alvo (Linux/Windows/macOS). O Tauri recomenda compilar em cada SO para obter o bundle nativo desse SO. Em produção, o GitHub Actions já faz isso em matriz.
1) Pré-requisitos gerais
- Node 20 + pnpm 9 (via Corepack)
- Rust (stable) — `rustup` instalado
- Dependências do sistema (Linux):
- `libwebkit2gtk-4.1-dev libayatana-appindicator3-dev librsvg2-dev libxdo-dev libssl-dev build-essential curl wget file`
2) Instalar deps do desktop e buildar
```
```bash
corepack enable && corepack prepare pnpm@9 --activate
pnpm -C apps/desktop install
VITE_APP_URL=http://localhost:3000 \
@ -81,27 +70,28 @@ VITE_API_BASE_URL=http://localhost:3000 \
pnpm -C apps/desktop tauri build
```
3) Saída do build
- Os artefatos ficam em: `apps/desktop/src-tauri/target/release/bundle/`
- No Linux: `.AppImage`/`.deb`/`.rpm` (conforme target)
- No Windows/macOS: executável/instalador específicos do SO (para assinatura, usar chaves/AC, se desejado)
- Para liberar atualizações OTA, publique release no GitHub com artefatos e `latest.json` — o plugin de updater verifica a URL configurada em `tauri.conf.json`.
Artefatos: `apps/desktop/src-tauri/target/release/bundle/`.
### Build na VPS x Local
### Atualizações OTA
- Não há diferença funcional além do SO alvo e de possíveis chaves de assinatura. Use a VPS apenas se quiser gerar pacotes Linux em ambiente isolado. Para Windows/macOS, é preferível buildar nesses SOs ou usar a matriz do GitHub Actions (já configurada).
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”.
## CI/CD — Observações
## Erros recorrentes e soluções
- `desktop-release.yml` (Tauri): instala dependências, faz build por SO e publica artefatos. Mantendo o `pnpm-lock.yaml` atualizado, o passo `--frozen-lockfile` passa.
- `ci-cd-web-desktop.yml`: já usa `pnpm install --no-frozen-lockfile` no web, evitando falhas em pipelines de integração.
- Smoke de provisionamento pode ser desligado definindo `RUN_MACHINE_SMOKE=false` (default); quando quiser exercitar o fluxo complete register/heartbeat, defina `RUN_MACHINE_SMOKE=true`.
| 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. |
## Troubleshooting
## Referências úteis
- Sign-in 500 após `db push`/seed:
- Verifique o terminal do app e confirme a existência da tabela `AuthUser` no Prisma Studio (alvo DEV).
- **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`.
- `ERR_PNPM_OUTDATED_LOCKFILE` no Desktop:
- Atualize `pnpm-lock.yaml` no root após alterar dependências de `apps/desktop/package.json`.
- Alternativa: usar `--no-frozen-lockfile` (não recomendado para releases reproduzíveis).
> Última revisão: 16/10/2025. Atualize este guia sempre que o fluxo de DEV ou automações mudarem.

51
docs/STATUS-2025-10-16.md Normal file
View file

@ -0,0 +1,51 @@
# Status do Projeto — 16/10/2025
Documento de referência sobre o estado atual do sistema (web + desktop), melhorias recentes e pontos de atenção.
## 1. Panorama
- **Web (Next.js 15 + Convex)**: build limpo (`pnpm build`), lint sem avisos e testes estáveis (Vitest em modo não interativo).
- **Desktop (Tauri)**: fluxo de provisionamento e heartbeat operacional; inventário consolidado com coleta multi-plataforma; atualizações OTA suportadas.
- **CI**: workflow `Quality Checks` roda lint/test/build em todo push/PR na `main`; pipeline de deploy (`ci-cd-web-desktop.yml`) permanece responsável por sincronizar com a VPS.
- **Infra**: deploy documentado no runbook (Swarm com symlink `sistema.current`). Migrações Prisma e variáveis críticas mapeadas.
## 2. Melhorias concluídas em 16/10/2025
| Item | Descrição | Impacto |
| --- | --- | --- |
| **Centralização Convex** | Helpers `createConvexClient` e normalização do cookie da máquina (`src/server/convex-client.ts`, `src/server/machines/context.ts`). | Código das rotas `/api/machines/*` ficou mais enxuto e resiliente a erros de configuração. |
| **Auth/Login redirect** | Redirecionamento baseado em role/persona sem uso de `any`, com dependências explícitas (`src/app/login/login-page-client.tsx`). | Evita warnings de hooks e garante rota correta para máquinas/colaboradores. |
| **Ticket header** | Sincronização do responsável com dependências completas (`ticket-summary-header.tsx`). | Removeu warning do lint e previne estados inconsistentes. |
| **Posture / inventário** | Type guards e normalização de métricas SMART/serviços (`convex/machines.ts`). | Reduziu `any`, melhorou detecção de alertas e consistência do metadata. |
| **Docs** | Revisão completa de `docs/DEV.md`, novo `STATUS-2025-10-16.md`, estrutura uniforme e casos de erro registrados. | Documentação enxuta e atualizada, com trilhas claras para DEV/CI/Deploy. |
| **Testes no CI** | Novo workflow `.github/workflows/quality-checks.yml` e script `pnpm test` em modo não-interativo. | Previne “travamentos” e garante checagens de qualidade automáticas. |
## 3. Pontos de atenção (curto prazo)
- **Migrações Prisma em produção**: qualquer mudança requer executar no volume `sistema_sistema_db` (ver `docs/DEPLOY-RUNBOOK.md`). Atenção para evitar regressões P3009.
- **Atualização dos artefatos Tauri**: releases exigem `latest.json` atualizado e assinatura (`*.sig`). Automação via GitHub Actions já preparada, mas depende de manter as chaves seguras.
- **Seeds Better Auth**: se novos perfis/roles forem adicionados, atualizar `scripts/seed-auth.mjs` e o seed do Convex.
- **Variáveis críticas**: `NEXT_PUBLIC_APP_URL`, `BETTER_AUTH_URL`, `MACHINE_PROVISIONING_SECRET` e `NEXT_PUBLIC_CONVEX_URL` devem ser válidas no stack — qualquer alteração de domínio implica revisar `.env` e `stack.yml`.
## 4. Backlog recomendado
1. **Testes end-to-end**: cobrir fluxo de provisionamento (desktop ↔ API) com smoke automatizado (pode rodar condicional no CI).
2. **Autenticação agnóstica**: avaliar suporte para Clerk/Auth0 conforme docs do Convex (custom JWTs).
3. **Observabilidade**: adicionar métricas/alertas para heartbeats em atraso (Convex + dashboards).
4. **Documentação do Desktop Installer**: guias por SO sobre instalação/assinatura e troubleshooting do updater.
## 5. Casos de erro conhecidos
| Cenário | Sintoma | Como resolver |
| --- | --- | --- |
| Token de máquina revogado | POST `/api/machines/sessions` retorna 401 e desktop volta ao onboarding | Reprovisionar pela UI do agente; garantir que `machineToken` foi atualizado. |
| Falha de heartbeat | Logs com `Falha ao registrar heartbeat` + status 500 | Verificar `NEXT_PUBLIC_CONVEX_URL` e conectividade. Roda `pnpm convext:dev` em DEV para confirmar schema. |
| Updater sem atualização | Desktop fica em “Procurando atualização” indefinidamente | Confirmar release publicado com `latest.json` apontando para URLs públicas do bundle e assinaturas válidas. |
## 6. Próximos passos imediatos
- Monitorar execução do novo workflow de qualidade em PRs.
- Garantir que a equipe esteja ciente do procedimento atualizado de deploy (symlink + service update).
- Revisar backlog acima e priorizar smoke tests para o fluxo da máquina.
_Última atualização: 16/10/2025 (UTC-3)._