From e4db48d8b468462eea8897b315d5a8200d959970 Mon Sep 17 00:00:00 2001 From: Esdras Renan Date: Wed, 8 Oct 2025 00:35:24 -0300 Subject: [PATCH] docs: adiciona guia de CI/CD web e desktop --- apps/desktop/docs/guia-ci-cd-web-desktop.md | 471 ++++++++++++++++++++ 1 file changed, 471 insertions(+) create mode 100644 apps/desktop/docs/guia-ci-cd-web-desktop.md diff --git a/apps/desktop/docs/guia-ci-cd-web-desktop.md b/apps/desktop/docs/guia-ci-cd-web-desktop.md new file mode 100644 index 0000000..7b0a8b1 --- /dev/null +++ b/apps/desktop/docs/guia-ci-cd-web-desktop.md @@ -0,0 +1,471 @@ +# Guia completo – CI/CD Web + Desktop + +> Este material detalha, passo a passo, como configurar o pipeline que entrega o front/backend (Next.js + Convex) e os instaladores do aplicativo Tauri, usando apenas uma VPS Linux (Ubuntu) e um computador/VM Windows. Siga na ordem sugerida e marque cada etapa conforme concluir. + +--- + +## 1. Visão geral rápida + +- Objetivo: ao fazer push na branch `main`, a VPS atualiza o site/backend. Ao criar uma tag `vX.Y.Z`, o app desktop é reconstruído, assinado e disponibilizado em `/updates` para auto-update. +- Ferramentas principais: + - GitHub Actions com dois runners self-hosted (Linux e Windows). + - Docker Compose (ou scripts equivalentes) para subir Next.js/Convex na VPS. + - Tauri para build dos instaladores desktop. + - Nginx servindo arquivos estáticos de update. +- Fluxo: + 1. Desenvolvedor envia código para o GitHub. + 2. Job **deploy** roda na própria VPS (runner Linux) e atualiza containers/processos. + 3. Ao criar uma tag `v*.*.*`, job **desktop_release** roda no runner Windows, gera instaladores, assina e envia `latest.json` + binários para a VPS. + +--- + +## 2. Pré-requisitos obrigatórios + +1. Repositório GitHub com o código do projeto (`sistema-de-chamados`). +2. VPS Ubuntu com: + - Acesso SSH com usuário sudo (ex.: `renan`). + - Docker + Docker Compose (ou ambiente que você desejar usar em produção). + - Nginx (ou outro servidor web capaz de servir `/updates` via HTTPS). +3. Computador/VM Windows 10 ou 11 (64 bits) que ficará ligado durante os builds: + - Acesso administrador. + - Espaço livre para builds (mínimo 15 GB). +4. Conta GitHub com permissão Admin no repositório (para registrar runners e secrets). +5. SSH key dedicada para o pipeline acessar a VPS (não reaproveite a sua pessoal). + +--- + +## 3. Preparação do repositório + +1. Na raiz do projeto, confirme os caminhos usados pelo workflow: + - `APP_DIR`: diretório na VPS onde o código (ou docker-compose) ficará. Exemplo: `/srv/apps/sistema`. + - `VPS_UPDATES_DIR`: diretório público servido pelo Nginx. Exemplo: `/var/www/updates`. +2. Garanta que o arquivo `apps/desktop/src-tauri/tauri.conf.json` será atualizado com: + - Chave pública do updater (`updater.pubkey`). + - URL do `latest.json` (por exemplo `https://seu-dominio.com/updates/latest.json`). + - Exemplo de bloco a adicionar mais tarde: + ```json5 + "updater": { + "active": true, + "endpoints": ["https://seu-dominio.com/updates/latest.json"], + "pubkey": "FINGERPRINT_PUBLIC_KEY" + } + ``` +3. Crie (ou mantenha) um arquivo `.github/workflows/ci-cd-web-desktop.yml` para o workflow. O conteúdo será incluído na etapa 9 após todos os preparativos. Como você utiliza Docker Swarm com Portainer, já separe o `stack.yml` (ou compose compatível) que o workflow irá acionar. + +--- + +## 4. Ajustes iniciais na VPS (Ubuntu) + +1. Atualize pacotes: + ```bash + sudo apt update && sudo apt upgrade -y + ``` +2. Instale Docker (o Swarm usa o próprio engine; mantenha o plugin compose se quiser testar localmente): + ```bash + sudo apt install -y docker.io docker-compose-plugin + sudo systemctl enable docker + sudo usermod -aG docker $USER + ``` + > Saia e entre novamente na sessão SSH para aplicar o grupo Docker. +3. Se o Swarm ainda não estiver ativo, inicialize-o no nó manager: + ```bash + docker info | grep Swarm + # se retornar "inactive", rode: + sudo docker swarm init + ``` +4. Verifique o Portainer: + - Acesse o painel na porta configurada (padrão `https://seu-dominio:9443`). + - Confirme que o cluster Swarm está saudável e que o nó aparece como manager. +5. Crie diretórios usados pelo deploy: + ```bash + sudo mkdir -p /srv/apps/sistema + sudo mkdir -p /var/www/updates + sudo chown -R $USER:$USER /srv/apps/sistema + sudo chown -R $USER:$USER /var/www/updates + ``` +6. (Opcional) Clone o repositório atual dentro de `/srv/apps/sistema` se você mantém arquivos como `stack.yml` ali: + ```bash + git clone git@github.com:SEU_USUARIO/sistema-de-chamados.git /srv/apps/sistema + ``` +7. Teste manualmente seu processo de deploy (Docker Swarm/Portainer ou scripts equivalentes) antes de automatizar. Exemplo via CLI: + ```bash + docker stack deploy --with-registry-auth -c stack.yml sistema + docker stack services sistema + ``` + Se preferir Portainer, faça o deploy manual pelo painel para validar. Confirme que o site sobe corretamente e que `/var/www/updates` é servido pelo Nginx (ver etapa 7). + +8. Sobre o Convex: + - **Convex Cloud (recomendado):** apenas garanta que suas variáveis `NEXT_PUBLIC_CONVEX_URL` e `CONVEX_DEPLOYMENT` apontam para o deploy gerenciado. Não é necessário subir container. + - **Convex self-hosted:** inclua um serviço adicional no `stack.yml` (ex.: `convex`) com a imagem oficial (`ghcr.io/get-convex/convex:latest`). Configure volume para o diretório de dados e exponha a porta 3210 internamente. Atualize o Next.js para apontar para `http://convex:3210` dentro da rede do Swarm. + +9. Exemplo de `stack.yml` integrado (baseado no modelo que você já usa no Portainer): + ```yaml + version: "3.8" + + services: + web: + image: ghcr.io/SEU_USUARIO/sistema-web:latest # ajuste para a imagem real + deploy: + mode: replicated + replicas: 2 + placement: + constraints: + - node.role == manager + resources: + limits: + cpus: "1.0" + memory: 1.5G + labels: + - traefik.enable=true + - traefik.http.routers.sistema.rule=Host(`app.seu-dominio.com.br`) + - traefik.http.routers.sistema.entrypoints=websecure + - traefik.http.routers.sistema.tls=true + - traefik.http.routers.sistema.tls.certresolver=le + - traefik.http.services.sistema.loadbalancer.server.port=3000 + env_file: + - ./envs/web.env # variáveis do Next.js + networks: + - traefik_public + - sistema_network + + convex: + image: ghcr.io/get-convex/convex:latest + deploy: + mode: replicated + replicas: 1 + placement: + constraints: + - node.role == manager + command: ["start", "--port", "3210"] + volumes: + - convex_data:/convex/data + networks: + - sistema_network + + networks: + traefik_public: + external: true + sistema_network: + external: false + + volumes: + convex_data: + external: false + ``` + - Adapte nomes das imagens (`web`, `convex`) e os labels do Traefik conforme seu ambiente. + - Caso use Portainer, faça upload desse arquivo na interface e execute o deploy da stack. + +--- + +## 5. Gerar chaves do updater Tauri + +1. Em qualquer máquina com Node/pnpm (pode ser seu computador local): + ```bash + pnpm install + pnpm --filter appsdesktop tauri signer generate + ``` +2. O comando gera: + - Chave privada (`tauri.private.key`). + - Chave pública (`tauri.public.key`). +3. Guarde os arquivos em local seguro. Você usará o conteúdo da chave privada nos secrets `TAURI_PRIVATE_KEY` e `TAURI_KEY_PASSWORD`. A chave pública vai no `tauri.conf.json`. +4. Copie a chave pública para o arquivo `apps/desktop/src-tauri/tauri.conf.json` no bloco `"updater"` (conforme indicado na etapa 3). + +--- + +## 6. Configurar Nginx para servir as atualizações + +1. Certifique-se de ter um domínio apontando para a VPS e um certificado TLS válido (Let's Encrypt é suficiente). +2. Crie (ou edite) o arquivo `/etc/nginx/sites-available/sistema-updates.conf` com algo semelhante: + ```nginx + server { + listen 80; + listen 443 ssl; + server_name seu-dominio.com; + + # Configuração SSL (ajuste conforme seu certificado) + ssl_certificate /etc/letsencrypt/live/seu-dominio.com/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/seu-dominio.com/privkey.pem; + + location /updates/ { + alias /var/www/updates/; + autoindex off; + add_header Cache-Control "no-cache"; + } + } + ``` +3. Crie o link simbólico e teste: + ```bash + sudo ln -s /etc/nginx/sites-available/sistema-updates.conf /etc/nginx/sites-enabled/ + sudo nginx -t + sudo systemctl reload nginx + ``` +4. Verifique pelo navegador: `https://seu-dominio.com/updates/` deve listar vazio (ou mostrar erro 403 se o autoindex estiver desativado, o que é aceitável). Apenas confirme que não retorna 404. + +--- + +## 7. Registrar runner self-hosted na VPS (Linux) + +1. No GitHub, acesse o repositório → *Settings* → *Actions* → *Runners* → *New self-hosted runner*. +2. Escolha Linux x64 e anote a URL e o token fornecidos. +3. Na VPS, prepare um usuário dedicado (opcional, mas recomendado): + ```bash + sudo adduser --disabled-password --gecos "" actions + sudo usermod -aG docker actions + sudo su - actions + ``` +4. Baixe e instale o runner (substitua `` e ``): + ```bash + mkdir actions-runner && cd actions-runner + curl -o actions-runner.tar.gz -L + tar xzf actions-runner.tar.gz + ./config.sh --url https://github.com/SEU_USUARIO/sistema-de-chamados \ + --token \ + --labels "self-hosted,linux,vps" + ``` +5. Instale como serviço: + ```bash + sudo ./svc.sh install + sudo ./svc.sh start + ``` +6. Volte ao GitHub e confirme que o runner aparece como `online`. +7. Teste executando um workflow simples (pode ser o pipeline de deploy após concluir todas as etapas). Lembre-se: o runner precisa ter permissão de escrita para `/srv/apps/sistema` e `/var/www/updates`. + +--- + +## 8. Registrar runner self-hosted no Windows + +1. Baixe e instale os pré-requisitos: + - Git para Windows. + - Node.js 20 (instalação inclui npm). + - Habilite o Corepack: abra o PowerShell como administrador e rode: + ```powershell + corepack enable + corepack prepare pnpm@latest --activate + ``` + - Rust toolchain: https://rustup.rs (instale padrão). + - Visual Studio Build Tools (C++ build tools) ou `Desktop development with C++`. + - WebView2 Runtime (https://developer.microsoft.com/microsoft-edge/webview2/). +2. Opcional: instale as dependências do Tauri rodando uma vez: + ```powershell + pnpm install + pnpm --filter appsdesktop tauri info + ``` +3. No GitHub → *Settings* → *Actions* → *Runners* → *New self-hosted runner* → escolha Windows x64 e copie URL/token. +4. Em `C:\actions-runner` (recomendado): + ```powershell + mkdir C:\actions-runner + cd C:\actions-runner + Invoke-WebRequest -Uri -OutFile actions-runner.zip + Expand-Archive -Path actions-runner.zip -DestinationPath . + .\config.cmd --url https://github.com/SEU_USUARIO/sistema-de-chamados ` + --token ` + --labels "self-hosted,windows,desktop" + ``` +5. Instale como serviço (PowerShell administrador): + ```powershell + .\svc install + .\svc start + ``` +6. Confirme no GitHub que o runner aparece como `online`. +7. Mantenha a máquina ligada e conectada durante o período em que o workflow precisa rodar: + - Para releases desktop, o runner só precisa estar ligado enquanto o job `desktop_release` estiver em execução (crie a tag e aguarde o workflow terminar). + - Após a conclusão, você pode desligar o computador até a próxima release. +8. Observação importante: o runner Windows pode ser sua máquina pessoal. Garanta apenas que: + - Você confia no código que será executado (o runner processa os jobs do repositório). + - O serviço do runner esteja ativo enquanto o workflow rodar (caso desligue o PC, as releases ficam na fila). + - Há espaço em disco suficiente e nenhuma política corporativa bloqueando a instalação dos pré-requisitos. + +--- + +## 9. Configurar secrets e variables no GitHub + +1. Acesse o repositório → *Settings* → *Secrets and variables* → *Actions*. +2. Adicione os secrets: + - `VPS_HOST` → domínio ou IP da VPS. + - `VPS_USER` → usuário com acesso SSH (ex.: `renan`). + - `VPS_SSH_KEY` → conteúdo **completo** da chave privada gerada apenas para o pipeline (ver abaixo). + - `TAURI_PRIVATE_KEY` → conteúdo do arquivo `tauri.private.key`. + - `TAURI_KEY_PASSWORD` → senha informada ao gerar a chave (se deixou em branco, repita em branco aqui). +3. Gerar chave SSH exclusiva para o pipeline (se ainda não fez): + ```bash + ssh-keygen -t ed25519 -C "github-actions@seu-dominio" -f ~/.ssh/github-actions + ``` + - Suba o conteúdo de `~/.ssh/github-actions` (privada) para o secret `VPS_SSH_KEY`. + - Adicione a chave pública `~/.ssh/github-actions.pub` em `~/.ssh/authorized_keys` do usuário na VPS. +4. Adicione **Environment variables** (opcional) para evitar editar o YAML: + - `APP_DIR` → `/srv/apps/sistema` + - `VPS_UPDATES_DIR` → `/var/www/updates` + (Se preferir, mantenha-as definidas direto no workflow.) + +--- + +## 10. Criar o workflow GitHub Actions + +1. No repositório, crie o arquivo `.github/workflows/ci-cd-web-desktop.yml` com o conteúdo: + ```yaml + name: CI/CD - Web + Desktop + + on: + push: + branches: [ main ] + tags: + - "v*.*.*" + + permissions: + contents: write + + env: + VPS_UPDATES_DIR: /var/www/updates + APP_DIR: /srv/apps/sistema + + jobs: + deploy: + name: Deploy Web/Backend (VPS) + runs-on: [self-hosted, linux, vps] + if: startsWith(github.ref, 'refs/heads/main') + steps: + - uses: actions/checkout@v4 + + - name: Setup pnpm & Node + uses: pnpm/action-setup@v4 + with: + version: 9 + - uses: actions/setup-node@v4 + with: + node-version: 20 + cache: pnpm + + - name: Deploy stack (Docker Swarm) + working-directory: ${{ env.APP_DIR }} + run: | + # git pull origin main || true + # Atualize o arquivo stack.yml ou compose compatível antes do deploy. + docker stack deploy --with-registry-auth -c stack.yml sistema + docker stack services sistema + + desktop_release: + name: Release Desktop (Tauri) + runs-on: [self-hosted, windows, desktop] + if: startsWith(github.ref, 'refs/tags/v') + steps: + - uses: actions/checkout@v4 + + - name: Setup pnpm & Node + uses: pnpm/action-setup@v4 + with: + version: 9 + - uses: actions/setup-node@v4 + with: + node-version: 20 + cache: pnpm + + - name: Setup Rust toolchain + uses: dtolnay/rust-toolchain@stable + + - name: Install deps + run: pnpm install --frozen-lockfile + + - name: Build + Sign + Release (tauri-action) + uses: tauri-apps/tauri-action@v0 + env: + TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }} + TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }} + with: + tagName: ${{ github.ref_name }} + releaseName: "Desktop ${{ github.ref_name }}" + releaseDraft: false + prerelease: false + updaterJsonKeepName: true + + - name: Upload latest.json + bundles para VPS + uses: appleboy/scp-action@v0.1.7 + with: + host: ${{ secrets.VPS_HOST }} + username: ${{ secrets.VPS_USER }} + key: ${{ secrets.VPS_SSH_KEY }} + source: | + **/bundle/**/latest.json + **/bundle/**/* + target: ${{ env.VPS_UPDATES_DIR }} + overwrite: true + ``` +2. Ajuste o bloco de deploy conforme seu processo (por exemplo, use `pnpm build && pm2 restart` se não usar Docker ou substitua por chamada à API do Portainer caso faça o deploy por lá). +3. Faça commit desse arquivo e suba para o GitHub (`git add .github/workflows/ci-cd-web-desktop.yml`, `git commit`, `git push`). + +--- + +## 11. Testar o pipeline + +1. **Teste do runner Linux:** + - Faça uma alteração simples na branch `main`. + - `git push origin main`. + - No GitHub, verifique o workflow → job `deploy`. + - Confirme via SSH na VPS (ex.: `docker stack services sistema`) ou pelo Portainer que os serviços foram atualizados. +2. **Teste do runner Windows:** + - Atualize `apps/desktop/src-tauri/tauri.conf.json` com a chave pública e URL do updater. + - Faça commit e `git push`. + - Crie a tag: `git tag v1.0.0` → `git push origin v1.0.0`. + - Verifique no GitHub → job `desktop_release`. + - Após concluir, confira em `/var/www/updates` se existem `latest.json` e os instaladores gerados. +3. Instale o app desktop (Windows, macOS ou Linux conforme artefatos) e abra-o: + - O aplicativo deve carregar a interface web apontando para sua URL. + - Ao publicar nova tag (ex.: `v1.0.1`), o app deve oferecer update automático. + +--- + +## 12. Rotina diária de uso + +1. Desenvolvimento comum: + - Trabalhe em branch própria. + - Abra PR para `main`. + - Ao fazer merge na `main`, o job `deploy` roda e publica a nova versão da stack no Swarm (visível no Portainer). +2. Nova versão desktop: + - Ajuste o app, aumente o campo `version` no `tauri.conf.json`. + - `git commit` e `git push`. + - Crie tag `vX.Y.Z` e envie (`git tag v1.2.0`, `git push origin v1.2.0`). + - Aguarde a finalização do job `desktop_release`. + - Usuários recebem o update automático na próxima abertura. +3. Renovação de certificado: + - Garanta que o certificado TLS usado pelo Nginx é renovado (p. ex. `certbot renew`). +4. Manter runners: + - VPS: monitore serviço `actions.runner.*`. Reinicie se necessário (`sudo ./svc.sh restart`). + - Windows: mantenha máquina ligada e atualizada. Se o serviço parar, abra `services.msc` → `GitHub Actions Runner` → Start. + +--- + +## 13. Boas práticas e segurança + +- Proteja a chave privada do updater; trate como segredo de produção. +- Use usuário dedicado na VPS para o runner e restrinja permissões apenas aos diretórios necessários. +- Faça backup periódico de `/var/www/updates` (para poder servir instaladores antigos se necessário). +- Nunca faça commit do arquivo `.env` nem das chaves privadas. +- Atualize Docker, Node e Rust periodicamente. + +--- + +## 14. Solução de problemas comuns + +| Sintoma | Possível causa | Como corrigir | +| --- | --- | --- | +| Job `deploy` falha com “permission denied” | Runner não tem acesso ao diretório do app | Ajuste permissões (`sudo chown -R actions:actions /srv/apps/sistema`). | +| Job `desktop_release` falha na etapa `tauri-action` | Toolchain incompleto no Windows | Reinstale Rust, WebView2 e componentes C++ do Visual Studio. | +| Artefatos não chegam à VPS | Caminho incorreto ou chave SSH inválida | Verifique `VPS_HOST`, `VPS_USER`, `VPS_SSH_KEY` e se a pasta `/var/www/updates` existe. | +| App não encontra update | URL ou chave pública divergente no `tauri.conf.json` | Confirme que `endpoints` bate com o domínio HTTPS e que `pubkey` é exatamente a chave pública gerada. | +| Runner aparece offline no GitHub | Serviço parado ou máquina desligada | VPS: `sudo ./svc.sh status`; Windows: abra `Services` e reinicie o `GitHub Actions Runner`. | + +--- + +## 15. Checklist final de implantação + +1. [ ] VPS atualizada, Docker/Nginx funcionando. +2. [ ] Diretórios `/srv/apps/sistema` e `/var/www/updates` criados com permissões corretas. +3. [ ] Nginx servindo `https://seu-dominio.com/updates/`. +4. [ ] Runner Linux registrado com labels `self-hosted,linux,vps`. +5. [ ] Runner Windows registrado com labels `self-hosted,windows,desktop`. +6. [ ] Chaves do updater Tauri geradas e chave pública no `tauri.conf.json`. +7. [ ] Secrets e variables configurados no GitHub (`VPS_*`, `TAURI_*`). +8. [ ] Workflow `.github/workflows/ci-cd-web-desktop.yml` criado e commitado. +9. [ ] Deploy automático testado com push em `main`. +10. [ ] Release desktop testada com tag `v1.0.0`. + +Com todos os itens marcados, o pipeline estará pronto para ser usado sempre que você fizer novas entregas.