sistema-de-chamados/apps/desktop/docs/guia-ci-cd-web-desktop.md
2025-11-05 20:49:19 -03:00

19 KiB
Raw Blame History

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:
      "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:

    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):

    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:

    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:

    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:

    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:

    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):

    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 dispositivo com Bun instalado (pode ser seu computador local):
    bun install
    bun install --cwd apps/desktop
    bun run --cwd apps/desktop 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:
    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:
    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 → SettingsActionsRunnersNew 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):
    sudo adduser --disabled-password --gecos "" actions
    sudo usermod -aG docker actions
    sudo su - actions
    
  4. Baixe e instale o runner (substitua <URL> e <TOKEN>):
    mkdir actions-runner && cd actions-runner
    curl -o actions-runner.tar.gz -L <URL>
    tar xzf actions-runner.tar.gz
    ./config.sh --url https://github.com/SEU_USUARIO/sistema-de-chamados \
      --token <TOKEN> \
      --labels "self-hosted,linux,vps"
    
  5. Instale como serviço:
    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.
    • Bun 1.3+: instale via instalador oficial (iwr https://bun.sh/install.ps1 | invoke-expression) e garanta que bun esteja no PATH.
    • Node.js 20 (opcional, caso precise rodar scripts em Node durante o build).
    • 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:
    bun install
    bun install --cwd apps/desktop
    bun run --cwd apps/desktop tauri info
    
  3. No GitHub → SettingsActionsRunnersNew self-hosted runner → escolha Windows x64 e copie URL/token.
  4. Em C:\actions-runner (recomendado):
    mkdir C:\actions-runner
    cd C:\actions-runner
    Invoke-WebRequest -Uri <URL> -OutFile actions-runner.zip
    Expand-Archive -Path actions-runner.zip -DestinationPath .
    .\config.cmd --url https://github.com/SEU_USUARIO/sistema-de-chamados `
      --token <TOKEN> `
      --labels "self-hosted,windows,desktop"
    
  5. Instale como serviço (PowerShell administrador):
    .\svc install
    .\svc start
    
  6. Confirme no GitHub que o runner aparece como online.
  7. Mantenha a dispositivo 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 dispositivo 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 → SettingsSecrets and variablesActions.
  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):
    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:
    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 Bun
            uses: oven-sh/setup-bun@v1
            with:
              bun-version: 1.3.1
    
         - 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 Bun
            uses: oven-sh/setup-bun@v1
            with:
              bun-version: 1.3.1
    
          - name: Setup Rust toolchain
            uses: dtolnay/rust-toolchain@stable
    
          - name: Install deps
            run: bun 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 bun run 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.0git 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 dispositivo ligada e atualizada. Se o serviço parar, abra services.mscGitHub 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 dispositivo 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.