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

461 lines
19 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 dispositivo com Bun instalado (pode ser seu computador local):
```bash
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:
```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 `<URL>` e `<TOKEN>`):
```bash
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:
```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.
- 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:
```powershell
bun install
bun install --cwd apps/desktop
bun run --cwd apps/desktop 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 <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):
```powershell
.\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 → *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 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.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 dispositivo 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 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.