Switch workflows to Bun install/test and update pnpm

This commit is contained in:
Esdras Renan 2025-11-04 23:21:41 -03:00
parent c3237dfb64
commit 775956c160
37 changed files with 2618 additions and 113 deletions

View file

@ -72,13 +72,17 @@ jobs:
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 9
version: 10.20.0
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'
- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: 1.3.1
- name: Verify Bun runtime
run: bun --version
@ -182,17 +186,16 @@ jobs:
uses: actions/cache@v4
with:
path: ${{ env.EFFECTIVE_APP_DIR }}/.next/cache
key: ${{ runner.os }}-nextjs-${{ hashFiles('pnpm-lock.yaml') }}-${{ hashFiles('src/**/*.ts', 'src/**/*.tsx', 'src/**/*.js', 'src/**/*.jsx', 'next.config.ts') }}
key: ${{ runner.os }}-nextjs-${{ hashFiles('pnpm-lock.yaml', 'bun.lock') }}-${{ hashFiles('src/**/*.ts', 'src/**/*.tsx', 'src/**/*.js', 'src/**/*.jsx', 'next.config.ts') }}
restore-keys: |
${{ runner.os }}-nextjs-${{ hashFiles('pnpm-lock.yaml') }}-
${{ runner.os }}-nextjs-${{ hashFiles('pnpm-lock.yaml', 'bun.lock') }}-
- name: Install and build (Next.js)
run: |
cd "$EFFECTIVE_APP_DIR"
corepack enable || true
pnpm --filter web install --no-frozen-lockfile
pnpm prisma:generate
pnpm build:bun
bun install --frozen-lockfile
bun run prisma:generate
bun run build:bun
- name: Publish build to stable APP_DIR directory
run: |
@ -385,7 +388,7 @@ jobs:
-e MACHINE_PROVISIONING_SECRET \
-e MACHINE_TOKEN_TTL_MS \
-e FLEET_SYNC_SECRET \
node:20-bullseye bash -lc "set -euo pipefail; corepack enable; corepack prepare pnpm@9 --activate; mkdir -p \"${PNPM_STORE_DIR:-/tmp/pnpm-store}\"; pnpm config set store-dir \"${PNPM_STORE_DIR:-/tmp/pnpm-store}\"; pnpm install --frozen-lockfile --prod=false; \
node:20-bullseye bash -lc "set -euo pipefail; corepack enable; corepack prepare pnpm@10.20.0 --activate; mkdir -p \"${PNPM_STORE_DIR:-/tmp/pnpm-store}\"; pnpm config set store-dir \"${PNPM_STORE_DIR:-/tmp/pnpm-store}\"; pnpm install --frozen-lockfile --prod=false; \
if [ -n \"$MACHINE_PROVISIONING_SECRET\" ]; then pnpm exec convex env set MACHINE_PROVISIONING_SECRET \"$MACHINE_PROVISIONING_SECRET\" -y; fi; \
if [ -n \"$MACHINE_TOKEN_TTL_MS\" ]; then pnpm exec convex env set MACHINE_TOKEN_TTL_MS \"$MACHINE_TOKEN_TTL_MS\" -y; fi; \
if [ -n \"$FLEET_SYNC_SECRET\" ]; then pnpm exec convex env set FLEET_SYNC_SECRET \"$FLEET_SYNC_SECRET\" -y; fi; \
@ -410,7 +413,7 @@ jobs:
-e CI=true \
-e CONVEX_SELF_HOSTED_URL \
-e CONVEX_SELF_HOSTED_ADMIN_KEY \
node:20-bullseye bash -lc "set -euo pipefail; corepack enable; corepack prepare pnpm@9 --activate; mkdir -p \"${PNPM_STORE_DIR:-/tmp/pnpm-store}\"; pnpm config set store-dir \"${PNPM_STORE_DIR:-/tmp/pnpm-store}\"; pnpm install --frozen-lockfile --prod=false; pnpm exec convex deploy"
node:20-bullseye bash -lc "set -euo pipefail; corepack enable; corepack prepare pnpm@10.20.0 --activate; mkdir -p \"${PNPM_STORE_DIR:-/tmp/pnpm-store}\"; pnpm config set store-dir \"${PNPM_STORE_DIR:-/tmp/pnpm-store}\"; pnpm install --frozen-lockfile --prod=false; pnpm exec convex deploy"
- name: Cleanup old convex build workdirs (keep last 2)
run: |
@ -445,13 +448,12 @@ jobs:
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 9
version: 10.20.0
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'
- name: Install deps (desktop)
run: pnpm install --frozen-lockfile
@ -513,7 +515,7 @@ jobs:
-v /srv/apps/sistema:/app -w /app \
-e CONVEX_SELF_HOSTED_URL -e CONVEX_SELF_HOSTED_ADMIN_KEY="$ADMIN_KEY" \
-e MACHINE_PROVISIONING_SECRET -e MACHINE_TOKEN_TTL_MS -e FLEET_SYNC_SECRET \
node:20-bullseye bash -lc "set -euo pipefail; corepack enable; corepack prepare pnpm@9 --activate; pnpm i --frozen-lockfile --prod=false; \
node:20-bullseye bash -lc "set -euo pipefail; corepack enable; corepack prepare pnpm@10.20.0 --activate; pnpm i --frozen-lockfile --prod=false; \
unset CONVEX_DEPLOYMENT; pnpm exec convex env list; \
if [ -n \"$MACHINE_PROVISIONING_SECRET\" ]; then pnpm exec convex env set MACHINE_PROVISIONING_SECRET \"$MACHINE_PROVISIONING_SECRET\" -y; fi; \
if [ -n \"$MACHINE_TOKEN_TTL_MS\" ]; then pnpm exec convex env set MACHINE_TOKEN_TTL_MS \"$MACHINE_TOKEN_TTL_MS\" -y; fi; \

View file

@ -36,7 +36,7 @@ jobs:
node-version: 20
- name: Enable Corepack
run: corepack enable && corepack prepare pnpm@9 --activate
run: corepack enable && corepack prepare pnpm@10.20.0 --activate
- name: Install Rust (stable)
uses: dtolnay/rust-toolchain@stable

View file

@ -22,16 +22,10 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 9
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: pnpm
- name: Setup Bun
uses: oven-sh/setup-bun@v2
@ -42,25 +36,25 @@ jobs:
run: bun --version
- name: Install dependencies
run: pnpm install --frozen-lockfile
run: bun install --frozen-lockfile
- name: Cache Next.js build cache
uses: actions/cache@v4
with:
path: |
${{ github.workspace }}/.next/cache
key: ${{ runner.os }}-nextjs-${{ hashFiles('pnpm-lock.yaml') }}-${{ hashFiles('**/*.{js,jsx,ts,tsx}') }}
key: ${{ runner.os }}-nextjs-${{ hashFiles('pnpm-lock.yaml', 'bun.lock') }}-${{ hashFiles('**/*.{js,jsx,ts,tsx}') }}
restore-keys: |
${{ runner.os }}-nextjs-${{ hashFiles('pnpm-lock.yaml') }}-
${{ runner.os }}-nextjs-${{ hashFiles('pnpm-lock.yaml', 'bun.lock') }}-
- name: Generate Prisma client
run: pnpm prisma:generate
run: bun run prisma:generate
- name: Lint
run: pnpm lint
run: bun run lint
- name: Test
run: pnpm test
run: bun test
- name: Build
run: pnpm build:bun
run: bun run build:bun

View file

@ -4,16 +4,16 @@ Aplicação **Next.js 16 (App Router)** com **React 19**, **Convex** e **Better
## Requisitos
- Node.js >= 20
- pnpm >= 9 (habilite via `corepack prepare pnpm@9 --activate`)
- (Opcional) Bun >= 1.3 para usar o runtime/test runner do Bun (`bun run --bun ...`). Após instalar via script oficial, adicione `export PATH="$HOME/.bun/bin:$PATH"` ao seu shell (ex.: `.bashrc`) para ter `bun` disponível globalmente.
- CLI do Convex (`pnpm dlx convex dev` instalará automaticamente no primeiro uso)
- Bun >= 1.3 (recomendado 1.3.1). Após instalar via script oficial, adicione `export PATH="$HOME/.bun/bin:$PATH"` ao seu shell (ex.: `.bashrc`) para ter `bun` disponível globalmente.
- Node.js >= 20 (necessário para ferramentas auxiliares como Prisma CLI e Next.js em modo fallback).
- pnpm >= 10 (opcional, usado apenas para fluxos do app desktop/Tauri ou como plano B).
- CLI do Convex (`bunx convex dev` instalará automaticamente no primeiro uso, se ainda não estiver presente).
## Configuração rápida
1. Instale as dependências:
```bash
pnpm install
bun install
```
2. Ajuste o arquivo `.env` (ou crie a partir de `.env.example`) e confirme os valores de:
- `NEXT_PUBLIC_CONVEX_URL` (gerado pelo Convex Dev)
@ -33,14 +33,14 @@ Aplicação **Next.js 16 (App Router)** com **React 19**, **Convex** e **Better
```
6. Em um terminal, execute o backend em tempo real do Convex:
```bash
pnpm convex:dev:bun
bun run convex:dev:bun
```
> Alternativa: `pnpm convex:dev` (runtime Node) caso queira manter o comportamento anterior.
> Alternativa: `bun run convex:dev` (runtime Node) caso queira manter o comportamento anterior.
7. Em outro terminal, suba o frontend Next.js (Turbopack):
```bash
pnpm dev:bun
bun run dev:bun
```
> Fallback: `pnpm dev` (Node) ou `pnpm dev:webpack` caso o Turbopack acione alguma incompatibilidade.
> Fallback: `pnpm dev` (Node) ou `bun run dev:webpack` caso o Turbopack acione alguma incompatibilidade.
8. Com o Convex ativo, acesse `http://localhost:3000/dev/seed` uma vez para popular dados de demonstração (tickets, usuários, comentários) diretamente no banco do Convex.
> Se o CLI perguntar sobre configuração do projeto Convex, escolha criar um novo deployment local (opção padrão) e confirme. As credenciais são armazenadas em `.convex/` automaticamente.
@ -64,16 +64,16 @@ Para fluxos detalhados de desenvolvimento — banco de dados local (SQLite/Prism
## Scripts úteis
- `pnpm dev:bun` — padrão atual para o Next.js com runtime Bun (`pnpm dev` usa Node como fallback).
- `pnpm convex:dev:bun` — runtime Bun para o Convex (`pnpm convex:dev` mantém o fluxo antigo).
- `pnpm build:bun` / `pnpm start:bun` — build e serve com Bun; use `pnpm build`/`pnpm start` se quiser ficar no Node.
- `pnpm dev:webpack` / `pnpm build:webpack` — fallback oficial caso Turbopack apresente problemas.
- `pnpm lint` — ESLint com as regras do projeto.
- `pnpm test` — suíte de testes unitários (Vitest) em modo não interativo.
- `pnpm build` — `next build --turbopack` com otimizações para produção.
- `pnpm auth:seed` — atualiza/cria contas padrão do Better Auth (credenciais em `agents.md`).
- `pnpm prisma migrate deploy` — aplica migrações ao banco SQLite local.
- `pnpm convex:dev` — roda o Convex em modo desenvolvimento, gerando tipos em `convex/_generated`.
- `bun run dev:bun` — padrão atual para o Next.js com runtime Bun (`pnpm dev` usa Node como fallback).
- `bun run convex:dev:bun` — runtime Bun para o Convex (`pnpm convex:dev` mantém o fluxo antigo).
- `bun run build:bun` / `bun run start:bun` — build e serve com Bun; use `pnpm build`/`pnpm start` se quiser ficar no Node.
- `bun run dev:webpack` / `bun run build:webpack` — fallback oficial caso Turbopack apresente problemas.
- `bun run lint` — ESLint com as regras do projeto.
- `bun test` — suíte de testes unitários usando o runner do Bun (o teste de screenshot fica automaticamente ignorado se o matcher não existir).
- `bun run build` — executa `next build --turbopack` usando Node como fallback.
- `bun run auth:seed` — atualiza/cria contas padrão do Better Auth (credenciais em `agents.md`).
- `bunx prisma migrate deploy` — aplica migrações ao banco SQLite local.
- `bun run convex:dev` — roda o Convex em modo desenvolvimento com Node, gerando tipos em `convex/_generated`.
## Transferir dispositivo entre colaboradores
@ -105,9 +105,10 @@ Consulte `PROXIMOS_PASSOS.md` para acompanhar o backlog funcional e o progresso
### Executar com Bun
- `pnpm dev:bun`, `pnpm convex:dev:bun`, `pnpm build:bun` e `pnpm start:bun` já estão configurados; internamente executam `bun run --bun <script>` para usar o runtime do Bun sem abrir mão do `pnpm`. O `cross-env` garante os valores esperados de `NODE_ENV` (`development`/`production`) para evitar warning/bugs no Next.
- Em caso de incompatibilidade do Turbopack (relatada em algumas combinações Bun + Next 16), use `pnpm dev:webpack` ou `pnpm build:webpack` como fallback imediato.
- Os testes continuam sob Vitest (`pnpm test`). Avalie `bun test` somente após validar que os matchers/relatos necessários estão disponíveis.
- `bun install` é o fluxo padrão (o arquivo `bun.lock` deve ser versionado; use `bun install --frozen-lockfile` em CI).
- `bun run dev:bun`, `bun run convex:dev:bun`, `bun run build:bun` e `bun run start:bun` já estão configurados; internamente executam `bun run --bun <script>` para usar o runtime do Bun sem abrir mão dos scripts existentes. O `cross-env` garante os valores esperados de `NODE_ENV` (`development`/`production`).
- Em caso de incompatibilidade do Turbopack (relatada em algumas combinações Bun + Next 16), use `bun run dev:webpack` ou `bun run build:webpack` como fallback imediato.
- `bun test` utiliza o test runner do Bun. O teste de snapshot de screenshot é automaticamente ignorado quando o matcher não está disponível; testes de navegador completos continuam via `bun run test:browser` (Vitest + Playwright).
<!-- ci: smoke test 3 -->

View file

@ -110,7 +110,7 @@ pnpm build
docker run --rm -it -e DATABASE_URL=file:/app/data/db.sqlite \
-v /home/renan/apps/sistema.current:/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 <migration>; pnpm exec prisma migrate deploy'
node:20-bullseye bash -lc 'corepack enable; corepack prepare pnpm@10.20.0 --activate; pnpm i --no-frozen-lockfile; pnpm exec prisma migrate resolve --rolled-back <migration>; pnpm exec prisma migrate deploy'
docker service scale sistema_web=1
```

2386
bun.lock Normal file

File diff suppressed because it is too large Load diff

3
bunfig.toml Normal file
View file

@ -0,0 +1,3 @@
[test]
preload = ["./tests/setup/bun-test-env.ts"]
timeout = 15000

View file

@ -4,10 +4,10 @@ Este documento consolida o estado atual do ambiente de desenvolvimento, descreve
## 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, exporte `PATH="$HOME/.bun/bin:$PATH"` para tornar o binário disponível. Use `pnpm dev:bun` / `pnpm convex:dev:bun` / `pnpm build:bun` / `pnpm start:bun` para executar os scripts com `bun run --bun` (scripts Node continuam disponíveis como fallback).
- **Bun (runtime padrão)**: 1.3+ já instalado no runner e VPS (`bun --version`). Após instalar localmente, exporte `PATH="$HOME/.bun/bin:$PATH"` para tornar o binário disponível. Use `bun install`, `bun run dev:bun`, `bun run convex:dev:bun`, `bun run build:bun` e `bun test` como fluxo principal (scripts Node continuam disponíveis como fallback).
- **Node/pnpm**: Node 20.9+ permanece obrigatório para ferramentas CLI; pnpm 10 está disponível como alternativa apenas para fluxos do desktop/Tauri.
- **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 usa `vitest --run --passWithNoTests`, eliminando o modo watch interativo.
- **Lint/Test/Build**: `bun run lint`, `bun test`, `bun run build:bun`. O test runner do Bun já roda em modo não interativo; utilize `bunx vitest --watch` apenas quando precisar do modo watch manualmente.
- **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.
@ -17,17 +17,18 @@ Este documento consolida o estado atual do ambiente de desenvolvimento, descreve
1. Gere/atualize o schema local:
```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
bun install
DATABASE_URL="file:./prisma/db.dev.sqlite" bunx prisma db push
DATABASE_URL="file:./prisma/db.dev.sqlite" bun run prisma:generate
DATABASE_URL="file:./prisma/db.dev.sqlite" bun run auth:seed
```
2. Rode o app Next.js:
```bash
pnpm dev:bun
bun run dev:bun
```
> Alternativas: `pnpm dev` (Node) ou `pnpm dev:webpack` se precisar do fallback oficial.
> Alternativas: `pnpm dev` (Node) ou `bun run dev:webpack` se precisar do fallback oficial.
3. Credenciais padrão (seed): `admin@sistema.dev / admin123`.
4. Herdou dados antigos? Execute `node scripts/remove-legacy-demo-users.mjs` para limpar contas demo legadas.
@ -50,12 +51,12 @@ Este documento consolida o estado atual do ambiente de desenvolvimento, descreve
## Comandos de qualidade
- `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. 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 o `pnpm` como orquestrador, apenas forçando o runtime do Bun via `bun run --bun`. O `cross-env` garante `NODE_ENV` consistente (`development`/`production`) para evitar warnings/falhas no Next.
- Fallback Webpack disponível via `pnpm dev:webpack` / `pnpm build:webpack` quando 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.
- `bun run lint`: executa ESLint (flat config) sobre os arquivos do projeto.
- `bun test`: roda a suíte de testes utilizando o runner nativo do Bun. Para modo watch, use `bunx vitest --watch` manualmente.
- `bun run build:bun`: `next build --turbopack` usando o runtime Bun. `bun run build` permanece disponível como fallback em Node.
- Scripts com Bun (padrão atual): `bun run dev:bun`, `bun run convex:dev:bun`, `bun run build:bun`, `bun run start:bun`. Eles mantêm os scripts existentes, apenas forçando o runtime do Bun via `bun run --bun`. O `cross-env` garante `NODE_ENV` consistente (`development`/`production`).
- Fallback Webpack disponível via `bun run dev:webpack` / `bun run build:webpack` quando Turbopack não coopera (caso observado em combinações Bun + Next 16).
- `bun run prisma:generate`: necessário antes do build quando o client Prisma muda. Para migrações use `bunx prisma migrate deploy`.
### Automação no CI
@ -63,17 +64,17 @@ 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:bun` (Bun 1.3.1 instalado via `oven-sh/setup-bun`).
1. Instala dependências (`bun install --frozen-lockfile`).
2. `bun run prisma:generate`.
3. `bun run lint`.
4. `bun test`.
5. `bun run build: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)
1. Rode `pnpm dev:bun` (ou `pnpm dev` se preferir Node) e autentique-se em `http://localhost:3000/login` usando `admin@sistema.dev / admin123`.
1. Rode `bun run dev:bun` (ou `pnpm dev` se preferir Node) e autentique-se em `http://localhost:3000/login` usando `admin@sistema.dev / admin123`.
2. Copie o valor do cookie `BETTER_AUTH_SESSION` e exporte no shell: `export COOKIE="BETTER_AUTH_SESSION=<valor>"`.
### Usuários
@ -139,7 +140,7 @@ curl -i -X PATCH http://localhost:3000/api/admin/invites/$INVITE_ID \
### Build local
```bash
corepack enable && corepack prepare pnpm@9 --activate
corepack enable && corepack prepare pnpm@10.20.0 --activate
pnpm -C apps/desktop install
VITE_APP_URL=http://localhost:3000 \
VITE_API_BASE_URL=http://localhost:3000 \

View file

@ -203,7 +203,7 @@ docker run --rm -it \
-w /app \
-e CONVEX_SELF_HOSTED_URL=https://convex.esdrasrenan.com.br \
-e CONVEX_SELF_HOSTED_ADMIN_KEY='COLE_A_CHAVE_AQUI' \
node:20-bullseye bash -lc "corepack enable && corepack prepare pnpm@9 --activate && pnpm install --frozen-lockfile --prod=false && pnpm exec convex deploy"
node:20-bullseye bash -lc "corepack enable && corepack prepare pnpm@10.20.0 --activate && pnpm install --frozen-lockfile --prod=false && pnpm exec convex deploy"
```
Observação
@ -231,7 +231,7 @@ docker run --rm -it \
-v /srv/apps/sistema:/app -w /app \
-e CONVEX_SELF_HOSTED_URL=https://convex.esdrasrenan.com.br \
-e CONVEX_SELF_HOSTED_ADMIN_KEY='COLE_A_CHAVE' \
node:20-bullseye bash -lc "set -euo pipefail; corepack enable && corepack prepare pnpm@9 --activate && pnpm i --frozen-lockfile --prod=false; \
node:20-bullseye bash -lc "set -euo pipefail; corepack enable && corepack prepare pnpm@10.20.0 --activate && pnpm i --frozen-lockfile --prod=false; \
unset CONVEX_DEPLOYMENT; \
pnpm exec convex env set MACHINE_PROVISIONING_SECRET 'seu-hex' -y; \
pnpm exec convex env list"

View file

@ -17,7 +17,7 @@ docker run --rm -it \
-v /srv/apps/sistema:/app -w /app \
-e CONVEX_SELF_HOSTED_URL -e CONVEX_SELF_HOSTED_ADMIN_KEY \
node:20-bullseye bash -lc "set -euo pipefail; \
corepack enable && corepack prepare pnpm@9 --activate && pnpm i --frozen-lockfile --prod=false; \
corepack enable && corepack prepare pnpm@10.20.0 --activate && pnpm i --frozen-lockfile --prod=false; \
unset CONVEX_DEPLOYMENT; \
pnpm exec convex env set MACHINE_PROVISIONING_SECRET '71daa9ef54cb224547e378f8121ca898b614446c142a132f73c2221b4d53d7d6' -y; \
pnpm exec convex env list"
@ -27,7 +27,7 @@ docker run --rm -it \
-v /srv/apps/sistema:/app -w /app \
-e CONVEX_SELF_HOSTED_URL -e CONVEX_SELF_HOSTED_ADMIN_KEY \
node:20-bullseye bash -lc "set -euo pipefail; \
corepack enable && corepack prepare pnpm@9 --activate && pnpm i --frozen-lockfile --prod=false; \
corepack enable && corepack prepare pnpm@10.20.0 --activate && pnpm i --frozen-lockfile --prod=false; \
unset CONVEX_DEPLOYMENT; \
pnpm exec convex env set MACHINE_TOKEN_TTL_MS '2592000000' -y; \
pnpm exec convex env list"
@ -37,7 +37,7 @@ docker run --rm -it \
-v /srv/apps/sistema:/app -w /app \
-e CONVEX_SELF_HOSTED_URL -e CONVEX_SELF_HOSTED_ADMIN_KEY \
node:20-bullseye bash -lc "set -euo pipefail; \
corepack enable && corepack prepare pnpm@9 --activate && pnpm i --frozen-lockfile --prod=false; \
corepack enable && corepack prepare pnpm@10.20.0 --activate && pnpm i --frozen-lockfile --prod=false; \
unset CONVEX_DEPLOYMENT; \
pnpm exec convex env set FLEET_SYNC_SECRET '' -y; \
pnpm exec convex env list"

View file

@ -24,8 +24,8 @@ Resultado: front/back sobem com o novo código sem editar o stack a cada release
- 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"]`
- **Se você optar por usar `/app/scripts/start-web.sh`** (como no workflow atual), ele já garante `pnpm@9` via Corepack/NPM antes de rodar Prisma/Next. Certifique-se de copiar esse arquivo para o build publicado; sem ele, a task cai com `pnpm: command not found`.
- `command: ["bash","-lc","corepack enable && corepack prepare pnpm@10.20.0 --activate && pnpm exec prisma migrate deploy && pnpm start -p 3000"]`
- **Se você optar por usar `/app/scripts/start-web.sh`** (como no workflow atual), ele já garante `pnpm@10.20.0` via Corepack/NPM antes de rodar Prisma/Next. Certifique-se de copiar esse arquivo para o build publicado; sem ele, a task cai com `pnpm: command not found`.
- Env obrigatórias (URLs válidas):
- `DATABASE_URL=file:/app/data/db.sqlite`
- `NEXT_PUBLIC_CONVEX_URL=http://sistema_convex_backend:3210`
@ -43,7 +43,7 @@ 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'
node:20-bullseye bash -lc 'corepack enable; corepack prepare pnpm@10.20.0 --activate; pnpm i --no-frozen-lockfile; pnpm exec prisma migrate status'
```
## Diagnóstico rápido
@ -99,7 +99,7 @@ Causas encontradas:
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"' \
--args 'bash -lc "corepack enable && corepack prepare pnpm@10.20.0 --activate && pnpm exec prisma migrate deploy && pnpm start -p 3000"' \
sistema_web
```
@ -110,7 +110,7 @@ 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'
node:20-bullseye bash -lc 'corepack enable; corepack prepare pnpm@10.20.0 --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
```

View file

@ -4,7 +4,7 @@ Guia rápido para gerar instaladores do app desktop em cada sistema operacional.
## Prérequisitos
- Node.js 20+ e pnpm (Corepack habilitado):
- `corepack enable && corepack prepare pnpm@9 --activate`
- `corepack enable && corepack prepare pnpm@10.20.0 --activate`
- Rust toolchain (stable) instalado.
- Dependências nativas por SO:
- Linux (Debian/Ubuntu):

View file

@ -11,9 +11,9 @@
"lint": "eslint",
"prisma:generate": "prisma generate",
"convex:dev": "convex dev",
"test": "vitest --run --passWithNoTests",
"test:browser": "cross-env VITEST_BROWSER=true vitest --run --browser.headless tests/browser/example.browser.test.ts --passWithNoTests",
"test:all": "cross-env VITEST_BROWSER=true vitest --run --passWithNoTests",
"test": "bun test",
"test:browser": "cross-env VITEST_BROWSER=true bunx vitest --run --browser.headless tests/browser/example.browser.test.ts --passWithNoTests",
"test:all": "cross-env VITEST_BROWSER=true bunx vitest --run --passWithNoTests",
"auth:seed": "node scripts/seed-auth.mjs",
"queues:ensure": "node scripts/ensure-default-queues.mjs",
"desktop:dev": "pnpm --filter appsdesktop tauri dev",
@ -87,6 +87,8 @@
"@tailwindcss/postcss": "^4",
"@tauri-apps/api": "^2.8.0",
"@tauri-apps/cli": "^2.8.4",
"@types/bun": "^1.1.10",
"@types/jsdom": "^21.1.7",
"@types/node": "^20",
"@types/pdfkit": "^0.17.3",
"@types/react": "^18",
@ -109,5 +111,9 @@
"typescript-eslint": "^8.46.2",
"vite-tsconfig-paths": "^5.1.4",
"vitest": "^4.0.1"
}
},
"workspaces": [
".",
"apps/desktop"
]
}

View file

@ -42,7 +42,7 @@ if echo "$CHANGED" | grep -q '^convex/'; then
-v "$APP_DIR":/app \
-w /app \
--env-file .ci.env \
node:20-bullseye bash -lc "corepack enable && corepack prepare pnpm@9 --activate && pnpm install --frozen-lockfile --prod=false && pnpm exec convex deploy"
node:20-bullseye bash -lc "corepack enable && corepack prepare pnpm@10.20.0 --activate && pnpm install --frozen-lockfile --prod=false && pnpm exec convex deploy"
else
echo "[deploy] convex/ changed but .ci.env missing; skip Convex deploy"
fi

View file

@ -34,7 +34,7 @@ ensure_pnpm() {
fi
if command -v corepack >/dev/null 2>&1; then
corepack prepare pnpm@9 --activate >/dev/null 2>&1 || true
corepack prepare pnpm@10.20.0 --activate >/dev/null 2>&1 || true
corepack enable --install-directory "$local_bin" pnpm >/dev/null 2>&1 || true
fi
@ -43,7 +43,7 @@ ensure_pnpm() {
fi
if command -v npm >/dev/null 2>&1; then
npm install --prefix "$pnpm_prefix" pnpm@9 >/dev/null 2>&1 || true
npm install --prefix "$pnpm_prefix" pnpm@10.20.0 >/dev/null 2>&1 || true
if [ -x "${pnpm_prefix}/node_modules/.bin/pnpm" ]; then
ln -sf "${pnpm_prefix}/node_modules/.bin/pnpm" "${local_bin}/pnpm" >/dev/null 2>&1 || true
fi

View file

@ -1,6 +1,19 @@
import { expect, test } from "vitest"
import { expect, test } from "bun:test"
test("CTA button snapshot", async () => {
type ScreenshotMatcher = {
toMatchScreenshot: (name: string) => Promise<unknown> | unknown
}
function isScreenshotMatcher(value: unknown): value is ScreenshotMatcher {
return typeof value === "object" && value !== null && "toMatchScreenshot" in value &&
typeof (value as ScreenshotMatcher).toMatchScreenshot === "function"
}
const matcherProbe = expect({}) as unknown
const hasScreenshotMatcher = isScreenshotMatcher(matcherProbe)
const testFn = hasScreenshotMatcher ? test : test.skip
testFn("CTA button snapshot", async () => {
const html = `
<main
style="
@ -36,5 +49,8 @@ test("CTA button snapshot", async () => {
const ctaButton = document.querySelector("[data-testid='cta']")
expect(ctaButton).toBeTruthy()
await expect(document.body).toMatchScreenshot("cta-button")
const bodyExpectation = expect(document.body) as unknown
if (isScreenshotMatcher(bodyExpectation)) {
await bodyExpectation.toMatchScreenshot("cta-button")
}
})

View file

@ -1,4 +1,4 @@
import { describe, expect, it } from "vitest"
import { describe, expect, it } from "bun:test"
import { buildAssigneeChangeComment } from "../convex/tickets"

View file

@ -1,4 +1,4 @@
import { describe, expect, it } from "vitest"
import { describe, expect, it } from "bun:test"
import { csvEscape, rowsToCsv } from "@/lib/csv"
describe("csvEscape", () => {

View file

@ -1,4 +1,4 @@
import { describe, expect, it } from "vitest"
import { describe, expect, it } from "bun:test"
import { normalizeDeviceRemoteAccess } from "@/components/admin/devices/admin-devices-overview"

View file

@ -1,4 +1,4 @@
import { describe, it, expect, vi } from "vitest"
import { describe, it, expect, vi } from "bun:test"
// Mock tls to simulate an SMTP server over implicit TLS
let lastWrites: string[] = []
@ -13,7 +13,7 @@ vi.mock("tls", () => {
private enqueue(messages: string | string[], type: "data" | "end" = "data") {
const chunks = Array.isArray(messages) ? messages : [messages]
chunks.forEach((chunk, index) => {
const delay = index === 0 ? 0 : 1
const delay = index === 0 ? 0 : 10 // garante tempo para que o próximo `wait(...)` anexe o listener
setTimeout(() => {
if (type === "end") {
void chunk

View file

@ -1,4 +1,4 @@
import { describe, expect, test } from "vitest"
import { describe, expect, test } from "bun:test"
import {
canReactivateInvite,

View file

@ -1,4 +1,4 @@
import { describe, it, expect, vi } from "vitest"
import { describe, it, expect, vi } from "bun:test"
import type { Doc, Id } from "../convex/_generated/dataModel"
import { getByIdHandler } from "../convex/machines"

View file

@ -1,4 +1,4 @@
import { describe, expect, it, vi } from "vitest"
import { describe, expect, it, vi } from "bun:test"
import type { Doc, Id } from "../convex/_generated/dataModel"
import { getTicketsHistoryStatsHandler, listTicketsHistoryHandler } from "../convex/machines"

View file

@ -1,4 +1,4 @@
import { afterAll, beforeAll, describe, expect, it, vi } from "vitest"
import { afterAll, beforeAll, describe, expect, it, vi } from "bun:test"
import { updatePersonaHandler } from "../convex/machines"
import type { Doc, Id } from "../convex/_generated/dataModel"

View file

@ -1,4 +1,4 @@
import { afterAll, beforeAll, describe, expect, it, vi } from "vitest"
import { afterAll, beforeAll, describe, expect, it, vi } from "bun:test"
vi.mock("../convex/rbac", () => ({
requireStaff: vi.fn(),

View file

@ -1,4 +1,4 @@
import { afterAll, beforeAll, describe, expect, it, vi } from "vitest"
import { afterAll, beforeAll, describe, expect, it, vi } from "bun:test"
vi.mock("../convex/rbac", () => ({
requireStaff: vi.fn(),

View file

@ -1,4 +1,4 @@
import { afterAll, beforeAll, describe, expect, it, vi } from "vitest"
import { afterAll, beforeAll, describe, expect, it, vi } from "bun:test"
vi.mock("../convex/rbac", () => ({
requireStaff: vi.fn(),

View file

@ -1,4 +1,4 @@
import { afterAll, beforeAll, describe, expect, it, vi } from "vitest"
import { afterAll, beforeAll, describe, expect, it, vi } from "bun:test"
vi.mock("../convex/rbac", () => ({
requireStaff: vi.fn(),

View file

@ -0,0 +1,96 @@
import "tsconfig-paths/register"
import { vi } from "bun:test"
import { JSDOM } from "jsdom"
// Provide default environment variables expected across the test suite.
process.env.BETTER_AUTH_SECRET ??= "test-secret"
process.env.NEXT_PUBLIC_APP_URL ??= "http://localhost:3000"
process.env.BETTER_AUTH_URL ??= process.env.NEXT_PUBLIC_APP_URL
const OriginalDate = Date
let fixedTimestamp: number | null = null
type MutableVi = typeof vi & {
mocked?: <T>(item: T) => T
setSystemTime?: (value: number | Date) => void
useFakeTimers?: (...args: Array<unknown>) => void
useRealTimers?: (...args: Array<unknown>) => void
}
const viExtended = vi as MutableVi
if (typeof window === "undefined" || typeof document === "undefined") {
const dom = new JSDOM("<!DOCTYPE html><html><body></body></html>", {
url: process.env.NEXT_PUBLIC_APP_URL,
})
const globals = dom.window as unknown as Record<string, unknown>
const globalTarget = globalThis as Record<string, unknown>
for (const key of ["window", "document", "navigator", "HTMLElement", "HTMLAnchorElement", "Node", "Text"]) {
if (!(key in globalTarget)) {
globalTarget[key] = globals[key]
}
}
}
const applyFixedDate = () => {
if (fixedTimestamp === null) {
globalThis.Date = OriginalDate
return
}
const ts = fixedTimestamp
class MockDate extends OriginalDate {
constructor(...args: ConstructorParameters<typeof OriginalDate>) {
if (args.length < 1) {
super(ts)
return
}
super(...args)
}
static now(): number {
return ts
}
}
globalThis.Date = MockDate as unknown as DateConstructor
}
if (!viExtended.mocked) {
viExtended.mocked = <T>(item: T) => item
}
if (!viExtended.setSystemTime) {
viExtended.setSystemTime = (value: number | Date) => {
fixedTimestamp = typeof value === "number" ? value : value.getTime()
applyFixedDate()
}
}
if (!viExtended.useFakeTimers) {
viExtended.useFakeTimers = () => {
// Bun's fake timers are not required for our current tests. This is a noop
// placeholder to keep compatibility with the previous Vitest API.
}
} else {
const originalUseFakeTimers = viExtended.useFakeTimers.bind(vi)
viExtended.useFakeTimers = (...args: Array<unknown>) => {
originalUseFakeTimers(...args)
}
}
if (!viExtended.useRealTimers) {
viExtended.useRealTimers = () => {
fixedTimestamp = null
applyFixedDate()
}
} else {
const originalUseRealTimers = viExtended.useRealTimers.bind(vi)
viExtended.useRealTimers = (...args: Array<unknown>) => {
originalUseRealTimers(...args)
fixedTimestamp = null
applyFixedDate()
}
}
applyFixedDate()

View file

@ -1,4 +1,4 @@
import { describe, expect, it, vi } from "vitest"
import { describe, expect, it, vi } from "bun:test"
import { buildCommentAuthorSummary } from "../convex/tickets"
import type { Doc, Id } from "../convex/_generated/dataModel"

View file

@ -1,4 +1,4 @@
import { describe, expect, it } from "vitest"
import { describe, expect, it } from "bun:test"
import { normalizeCustomFieldInputs } from "../src/lib/ticket-form-helpers"
import type { TicketFormFieldDefinition } from "../src/lib/ticket-form-types"

View file

@ -1,7 +1,7 @@
/**
* @vitest-environment jsdom
*/
import { describe, expect, it } from "vitest"
import { describe, expect, it } from "bun:test"
import { normalizeTicketMentionHtml } from "@/components/ui/rich-text-editor"

View file

@ -1,4 +1,4 @@
import { describe, expect, it } from "vitest"
import { describe, expect, it } from "bun:test"
import { deriveServerOffset, reconcileLocalSessionStart, toServerTimestamp } from "@/components/tickets/ticket-timer.utils"
describe("reconcileLocalSessionStart", () => {

View file

@ -1,4 +1,4 @@
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"
import { afterEach, beforeEach, describe, expect, it, vi } from "bun:test"
import type { Doc, Id } from "../convex/_generated/dataModel"
import { resolveTicketHandler, reopenTicketHandler } from "../convex/tickets"

View file

@ -1,4 +1,4 @@
import { afterEach, describe, expect, it, vi } from "vitest"
import { afterEach, describe, expect, it, vi } from "bun:test"
import type { Doc, Id } from "../convex/_generated/dataModel"
import { submitCsatHandler } from "../convex/tickets"

View file

@ -1,4 +1,4 @@
import { describe, expect, it } from "vitest"
import { describe, expect, it } from "bun:test"
import { dateKeyTZ, isAtHourTZ } from "@/lib/time"
describe("time tz helpers", () => {

View file

@ -1,4 +1,4 @@
import { vi } from "vitest"
import { vi } from "bun:test"
import type { Doc, Id } from "../../convex/_generated/dataModel"