skills/deploy-server/SKILL.md

```
name: deploy-server
description: Use this skill to provision or update a Welley server on a supported cloud (currently DigitalOcean) when the user asks to deploy a new instance or run a server update. Covers single-instance deployments and SSH-based updates, including interactive collection of missing credentials, SSH keys, domain, region, and sizing.
```

# Implantar servidor

## Visão geral

Esta skill cria uma stack Welley de instância única na DigitalOcean e pode executar atualizações por SSH. Ela orienta o agente a reunir os dados que faltam, buscar as especificações de instância disponíveis em uma fonte definida, criar a VM, configurar o host, implantar com `wlycli deployment create` e validar o resultado.

Os nomes dos comandos devem ser iguais aos da CLI:

-   `wlycli deployment create`
-   `wlycli deployment update`
-   `wlycli deployment delete`

## Padrões (DigitalOcean)

-   Região: `nyc3`
-   Imagem: `latest LTS available via API` (resolva com `images?type=distribution`)
-   Nome do droplet: gerado aleatoriamente no formato `wlsly-<adjective>-<surname>` (por exemplo, `wlsly-bright-hopper`). Use o trecho gerador de nomes de `references/digitalocean.md`. Use o mesmo nome para o banco gerenciado, se ele for criado.
-   Plano desejado: Basic / Regular (CPU compartilhada)
-   Tamanho desejado: 2 vCPU / 4 GB de RAM / 80 GB de SSD / 4 TB de transferência (~US$ 24/mês)

## Regra para substituir os padrões

Se o usuário definir qualquer um dos padrões (região, imagem, nome do droplet, projeto, tamanho), o agente deve:

1.  Repetir a alteração exatamente como o usuário informou.
2.  Pedir confirmação antes de continuar.

## Modelo de perguntas interativas

Pergunte só o que estiver faltando. Use exatamente estas perguntas para evitar ambiguidade. Faça as perguntas em rodadas. Rodada 1: no máximo 2 perguntas por vez. A rodada 2 pode apresentar uma opção agrupada de “aceitar todos os padrões”. Se o ambiente aceitar opções, apresente 2 a 3 alternativas por pergunta (A/B/C). Evite respostas livres, a menos que seja necessário.

Perguntas da rodada 1 (identidade e acesso):

1.  “Você tem um token de API da DigitalOcean para usar, ou devo esperar você enviar um?”
2.  “Qual domínio este servidor deve usar (por exemplo, `super-puper.example.com`)? Você controla o DNS dele?”
3.  “Você já tem uma chave pública SSH para usar, ou devo criar e enviar uma?”
4.  “Você quer colocar este droplet em um projeto existente da DigitalOcean? Se sim, informe o nome ou o ID do projeto.”
5.  “Requisito de DNS: você precisa criar registros A/AAAA para `<domain>` e `storage.<domain>` (se não houver CDN). Você consegue fazer isso antes de o certbot rodar?”
6.  “Requisito de DNS para e-mail: o domínio de `--smtp-from` precisa de registros SPF, DMARC e DKIM, senão e-mails de convite e de confirmação para novos destinatários podem ser descartados sem aviso. Eles já estão configurados, ou devo listar os registros que o seu provedor de SMTP exige?”
7.  Se o usuário perguntar onde conseguir um token da DO, envie este link:

```
https://cloud.digitalocean.com/account/api/tokens
```

Perguntas da rodada 2 (tamanho, localização e opções de implantação):

1.  “Você quer a região padrão `nyc3` ou outra região?”
2.  “Você quer o tamanho padrão (2 vCPU / 2 GB) ou outra meta de CPU/RAM?”
3.  “Devo usar o Ubuntu LTS mais recente disponível na API ou uma versão específica do Ubuntu?”
4.  “Qual usuário SSH devemos usar depois do bootstrap (padrão: `wlsly`)? Você pode manter o padrão.”
5.  “Você quer um banco Postgres gerenciado ou prefere usar o contêiner de Postgres incluído?”
6.  Se o Postgres gerenciado for escolhido: “Qual região e qual tamanho devo usar para o banco? Posso usar como padrão `nyc3` e 1 vCPU / 2 GB.”
7.  Se o Postgres gerenciado for escolhido: “Posso criar o banco pelo preço mensal listado pelo provedor?”
8.  “Envie as configurações de SMTP necessárias (host, usuário, senha, remetente). OTEL é opcional: envie só se precisar.”
9.  “O e-mail do administrador é obrigatório para criar. Envie agora (flag: `--email` / `-e`). Se você não enviar, vou pedir duas vezes para confirmar.”

Ofereça uma opção de “aceitar todos os padrões” na rodada 2 para agilizar a coleta de dados.

Se faltar alguma resposta, faça uma pergunta complementar objetiva (no máximo uma ou duas).

## Fluxo de trabalho (DigitalOcean, instância única)

1.  **Reúna os dados necessários (pergunte se faltar algum).**

-   Token de API da DigitalOcean
-   Nome ou ID do projeto (opcional; se não for informado ou não for encontrado, use o projeto padrão)
-   Região
-   Tamanho desejado da instância (por exemplo, 4 vCPU / 16 GB de RAM)
-   Nome do domínio
-   Chave pública SSH (ou confirmação para criar e registrar uma)
-   E-mail do administrador para o primeiro login e a recuperação de senha (obrigatório para criar; `--email` / `-e`). Se faltar, peça duas vezes e confirme que são iguais.
-   Opcional: certificados TLS próprios ou certbot
-   Confirmação de acesso ao DNS (é preciso conseguir criar registros A/AAAA para `<domain>` e para `storage.<domain>`, se for usado)

1.  **Busque os tipos de instância e escolha um tamanho.**

-   Use o trecho de tamanhos de `references/digitalocean.md` para listar e filtrar por CPU/RAM.
-   Confirme com o usuário se houver mais de uma opção compatível.

2b. **Descubra o slug da imagem do Ubuntu.**

-   Chame `GET /v2/images?type=distribution&per_page=200` e filtre pelo Ubuntu.
-   Se o usuário pediu uma versão específica, verifique se o slug dela existe e confirme.
-   Caso contrário, escolha o slug do LTS mais recente da lista e confirme com o usuário antes de criar.

1.  **Crie o droplet.**

-   Use a API da DigitalOcean diretamente (o doctl é opcional).
-   Imagem: prefira a que o usuário indicou; se não houver, escolha o LTS mais recente da lista da API.
-   Anexe o fingerprint da chave SSH ou crie e envie uma chave.
-   Ative o monitoramento.
-   Se o nome/ID do projeto foi informado, mas não foi encontrado, crie o droplet sem projeto (projeto padrão).
-   Observação: a criação do banco gerenciado pode rodar em paralelo com a criação do droplet.

## Orientação de paralelização

O agente deve sobrepor tarefas independentes para reduzir o tempo total:

-   Enquanto reúne os dados do usuário (rodada 2), comece a criar o droplet se o token, a região, o tamanho, a imagem e a chave SSH já estiverem confirmados.
-   Enquanto o droplet está sendo criado, comece a criar o Postgres gerenciado (se foi pedido).
-   Enquanto o droplet está iniciando, continue coletando os dados restantes (SMTP, OTEL, e-mail do administrador).
-   Se faltar algum dado essencial para uma etapa, pause essa etapa e continue com as outras tarefas que podem rodar em paralelo.
-   Se o DNS for gerenciado na DigitalOcean, crie ou atualize os registros A/AAAA assim que o IP do droplet estiver disponível (não espere a etapa completa de implantação).

1.  **DNS e domínio.**

-   Pergunte se o DNS deve ser criado ou atualizado na DigitalOcean ou se ele fica em um DNS externo.
-   Se usar o DNS da DigitalOcean, crie registros A/AAAA apontando para o IP do droplet.

1.  **Configure o host por SSH.**

-   Crie um usuário sem privilégios de root (por exemplo, `wlsly`), dê a ele acesso ao sudo e copie as chaves SSH autorizadas.
-   **Saia do root e entre de novo como o usuário sem privilégios de root** antes de continuar.
-   Instale o Docker e o docker compose.
-   Baixe o binário da CLI do Welley pela AppStore e torne-o executável:
    -   URL base: `https://appstore.allroads.social/v1/social.wellesley.wlycli/latest?develop=stable&platform=<os>/<arch>`
    -   Escolha o valor correto de `platform` conforme o sistema e a arquitetura:
        -   Linux x86\_64: `linux/amd64`
        -   Linux arm64: `linux/arm64`
        -   macOS x86\_64: `darwin/amd64`
        -   macOS arm64: `darwin/arm64`
        -   Windows x86\_64: `windows/amd64`
    -   Exemplo (Linux x86\_64):
        
        ```
        curl -fL 'https://appstore.allroads.social/v1/social.wellesley.wlycli/latest?develop=stable&platform=linux/amd64' -o wlycli
        chmod +x wlycli
        ```
        
    -   Os cabeçalhos de resposta esperados incluem:
        -   `x-artifact-display-name: Welley CLI`
        -   `x-artifact-full-name: social.wellesley.wlycli`
        -   `x-artifact-kind: cli`
        -   `x-artifact-platform: <os>/<arch>`, como `linux/amd64`
        -   `x-artifact-sha256: <sha256>`
        -   `x-artifact-version: <version>`
        -   `x-channel: develop`
    -   Antes de instalar, prefira conferir os cabeçalhos com uma requisição HEAD e verificar se o nome do artefato, o tipo, a plataforma e o canal correspondem ao binário pedido.
-   Verifique o binário da CLI: rode `wlycli -v` e `wlycli deployment --help` para confirmar as informações de build esperadas.

1.  **Implante o Welley.**

-   Rode `wlycli deployment create` com as opções necessárias.
-   Use os padrões de instância única (sem Postgres externo, a menos que o usuário peça).
-   Se o Postgres gerenciado for pedido, crie-o primeiro (banco da DigitalOcean) e depois use o host, a porta, o banco, o usuário e a senha retornados nas flags `--postgres-*`.
-   Se a senha do usuário do banco não for retornada pela API ou pela interface, redefina a autenticação do usuário do banco para obter credenciais novas antes de rodar o `wlycli`.
-   Execuções não interativas devem passar `--email` / `-e`, senão o comando falha.
-   `--base-dir` aponta para o diretório pai; a CLI cria o subdiretório do projeto automaticamente.
-   A CLI se recusa a rodar se o diretório do projeto ou os contêineres já existirem; é preciso limpar tudo antes de tentar de novo.

1.  **Certificados (obrigatório).**

-   Padrão: use o Certbot em modo standalone (não interativo).
-   **O usuário deve apontar os registros A/AAAA do domínio (e de `storage.<domain>`, se for usado) para o IP do droplet antes de o certbot rodar.**
-   A CLI aceita `--public-ip` (substitui o IP detectado) e `--skip-dns-preflight`, caso você precise ignorar a verificação.
-   **Nunca presuma que o DNS está configurado. Pergunte e espere uma confirmação explícita.**
-   **Nunca use `--skip-dns-preflight`, a menos que o usuário peça explicitamente.**
-   Se a CDN não estiver configurada, o certbot deve incluir `storage.<domain>` no pedido do certificado.
-   Use certificados autoassinados só se o usuário pedir explicitamente, e passe `--self-signed-certs` (gera certificados autoassinados em Go).
-   Dê ao usuário as instruções de configuração do DNS e espere a confirmação:
-   “Crie registros A/AAAA para que `<domain>` aponte para o IP do droplet.”
-   “Se `storage.<domain>` for usado, crie também um registro A/AAAA para ele.”
-   “Quando o DNS propagar, me avise e eu continuo. Não consigo ver a propagação, a menos que você peça para eu verificar a resolução.”
-   O agente pode verificar a propagação do DNS por conta própria usando `ping -c 1 <domain>` e comparando o IP com o do droplet. Se forem iguais, siga em frente.

7b. **DNS de e-mail (SPF / DMARC / DKIM).**

-   E-mails enviados de um domínio sem SPF e DMARC costumam ser descartados pelo Gmail e pelo Outlook quando o destinatário é novo, mesmo que o provedor de SMTP informe que foram entregues.
-   `deployment create` mostra um `Warning:` quando o domínio de `--smtp-from` não tem registro SPF, ou não tem registro DMARC em `_dmarc.<domain>` nem em um domínio pai. Isso não bloqueia a implantação. Nunca ignore o aviso: mostre-o ao usuário e passe os registros que ele deve adicionar:
    -   `<mail-domain>` TXT `v=spf1 include:<provider> ~all` (o include exato vem do provedor de SMTP; junte ao registro SPF existente e nunca adicione um segundo)
    -   `_dmarc.<mail-domain>` TXT `v=DMARC1; p=none; rua=mailto:dmarc@<mail-domain>`
    -   DKIM: os registros `<selector>._domainkey.<mail-domain>` que o provedor de SMTP gera quando o domínio é verificado
-   Confira com `dig +short TXT <mail-domain>` e `dig +short TXT _dmarc.<mail-domain>`.
-   A CLI não consegue verificar o DKIM (o seletor depende do provedor). Sempre peça ao usuário que confirme que o DKIM está verificado no provedor de SMTP, mesmo quando o `create` não mostrou nenhum aviso. Com o Amazon SES e provedores parecidos, o SPF é verificado para o domínio de envelope do próprio provedor, então só o DKIM faz o DMARC passar. No SES: em _Verified identities_, abra _`<mail-domain>`_ e veja a seção _DKIM_, que deve indicar _Successful_.

1.  **Valide e informe o resultado.**

-   Confira `docker ps` e os endpoints de saúde dos serviços.
-   Passe os dados finais de conexão e os próximos passos.

## Fluxo de atualização por SSH

Quando o usuário pedir “atualizar o servidor”:

1.  Pergunte o host/IP de destino e o usuário/chave SSH.
2.  Rode `wlycli deployment update --domain <domain> [--force-restart]`.
3.  Verifique o estado dos contêineres e do Nginx.

## Recursos

-   Trechos e exemplos da API da DigitalOcean: `references/digitalocean.md`.

## Segredos e flags

Use estes nomes de flag para os segredos:

-   Host do SMTP: `--smtp-host`
-   Usuário do SMTP: `--smtp-user`
-   Senha do SMTP: `--smtp-password`
-   Remetente do SMTP: `--smtp-from`
-   Endpoint do OTEL: `--otel-endpoint`
-   Cabeçalhos do OTEL: `--otel-headers`

## Comando mínimo de criação

Flags obrigatórias:

-   `--domain`
-   `--email`
-   `--smtp-host`
-   `--smtp-user`
-   `--smtp-password`
-   `--smtp-from`

Exemplo mínimo:

```
wlycli deployment create \
  --domain example.com \
  --email admin@example.com \
  --smtp-host smtp.example.com \
  --smtp-user user \
  --smtp-password pass \
  --smtp-from noreply@example.com
```

## Padrões do Postgres gerenciado (DigitalOcean e CLI)

Ao usar o Postgres gerenciado da DigitalOcean, não dependa dos padrões da CLI. Defina todas as flags `--postgres-*` explicitamente:

-   Padrões típicos da DO:
    -   Porta: `25060`
    -   Banco: `defaultdb`
    -   Usuário: `doadmin`
-   Padrões da CLI (se você omitir as flags):
    -   Porta: `5432`
    -   Banco: `wlsly`
    -   Usuário: `wlsly`

## Notas de uso da CLI

-   Verificação de versão: `wlycli -v` ou `wlycli --version` (flag). Não existe um subcomando `version`.
-   Use `--base-dir` só se quiser um local diferente do padrão (o padrão é `~/.welley`). A CLI cria o diretório se tiver permissão.
-   Execuções SSH não interativas devem incluir `--email` e as outras flags obrigatórias para evitar perguntas.
-   Se o usuário já tiver um binário da CLI no servidor (por exemplo, `~/wcli`), use-o diretamente. Não mude o binário de lugar, a menos que peçam.
-   **Copie os trechos exatamente como estão** em `references/digitalocean.md` para todas as chamadas à API da DO. Não reescreva, não adapte e não improvise o parsing em Python: até pequenas mudanças (por exemplo, de escape ou de aspas) podem quebrar de um shell para outro.
-   **Scripts remotos por SSH:** use sempre `ssh host 'bash -s' << 'EOF'` (heredoc entre aspas). Nunca use `ssh host "..."` com aspas duplas, porque o zsh expande `$(...)` e `[...]` localmente antes de enviar ao host remoto.

## Recuperação de falhas

Se `deployment create` falhar e você precisar tentar de novo:

-   Use `wlycli deployment delete --domain <domain> --yes-please-delete-all-the-data` para limpar.
-   O delete tenta limpar por meio de contêiner os arquivos que pertencem ao root. Se ainda assim falhar, remova o diretório do projeto dentro de `--base-dir` com permissões elevadas e rode de novo.

## Teste prévio da porta 80 (opcional)

Se o certbot falhar, teste se a porta 80 está acessível antes de rodar de novo:

```
docker run --rm -d -p 80:80 --name test-http nginx:alpine
curl -s http://<domain>:80
docker rm -f test-http
```

## Outros documentos

-   [**Welley CLI** docs/index.md](https://welley.com/pt/administrators/docs/cli/)
-   [**Início rápido: implantação mínima do Welley** docs/quick-start.md](https://welley.com/pt/administrators/docs/quick-start/)
-   [**openai.yaml** skills/deploy-server/agents/openai.yaml](https://welley.com/pt/administrators/docs/deploy-server-openai-yaml/)
-   [**Referência da DigitalOcean** skills/deploy-server/references/digitalocean.md](https://welley.com/pt/administrators/docs/deploy-server-digitalocean/)
