OpenCall

Runbook para IA

Provisionamento via CLI, pra colar numa sessão de Claude Code (ou similar).

Este runbook é pra ser colado numa sessão de IA com acesso a terminal. O objetivo é a IA executar o máximo possível via CLI, parando só nos pontos que exigem uma ação humana (login/2FA, pagamento, propriedade de domínio).

Instrução pra IA que for executar isto

Siga os passos em ordem. Antes de qualquer comando que crie recurso cobrável (instância de VPS, projeto em plano pago) ou seja difícil de reverter, confirme com o humano — não assuma. Depois de cada etapa marcada, mostre o resultado pro humano conferir antes de seguir. Nunca sugira Vercel pra hospedar o app — o motivo está em Deploy do Next.js: o pub/sub de chat/presença é em memória e exige um processo persistente, incompatível com serverless.

Pré-requisitos que só o humano resolve

  • Conta Discord Developer Portal
  • Conta Railway (login via GitHub)
  • Conta Vultr com pagamento configurado — só se for self-host o LiveKit
  • Conta Cloudflare — pro R2
  • Conta LiveKit Cloud — se não for self-host
  • Domínio próprio apontável
  • Repositório do OpenCall clonado localmente

1. Discord Application

Não tem CLI oficial — é a única etapa 100% manual mesmo em modo IA (ver Configurar o Discord). Peça ao humano:

  • DISCORD_CLIENT_ID, DISCORD_CLIENT_SECRET
  • O Discord user ID dele, pra BOOTSTRAP_ADMIN_DISCORD_IDS

2. Instalar as CLIs

npm i -g @railway/cli
railway --version

# Só se for self-host o LiveKit:
brew install vultr/vultr-cli/vultr-cli   # macOS
vultr-cli version

3. Autenticar sem navegador interativo

# Railway: fluxo device-code, mostra link+código pro humano abrir em
# qualquer dispositivo com navegador
railway login --browserless

# Alternativa: token já gerado pelo humano em railway.com/account/tokens
export RAILWAY_API_TOKEN="<token colado pelo humano>"
# Vultr: gerar API key em my.vultr.com/settings/#settingsapi (sem
# device-code flow) — peça ao humano pra colar
export VULTR_API_KEY="<colado pelo humano>"

4. Projeto Railway + Postgres

railway init --name opencall
railway link   # se init não linkar automaticamente
railway add --database postgres

Confirme com o humano se o plano é Hobby ou superior — Free/Trial não sustenta um app rodando 24/7 (necessário pro pub/sub em memória, ver aviso no topo).

5. LiveKit

Caminho Cloud — não tem CLI pra criar o projeto (é web-only). Peça ao humano LIVEKIT_URL, LIVEKIT_API_KEY, LIVEKIT_API_SECRET depois de criar em cloud.livekit.io.

Caminho self-host (ver LiveKit self-host pro detalhe de cada passo):

vultr-cli plans list --type vhf
vultr-cli regions list

vultr-cli instance create \
  --region <region-id> \
  --plan <plan-id-high-frequency> \
  --os 2284 \
  --host opencall-livekit \
  --label "OpenCall LiveKit"

vultr-cli instance list   # pegar o IP

Ação humana obrigatória: apontar um registro DNS tipo A do domínio pro IP da VPS. Confirme propagação antes de seguir:

dig +short SEU-SUBDOMINIO

Depois, instalar o LiveKit via SSH:

ssh root@<ip-da-vps> "curl -sSL https://get.livekit.io | bash -s -- --domain <seu-subdominio>"

Esse instalador é interativo por padrão — se travar esperando input, essa é a etapa mais provável de precisar de um humano completando via SSH manual (junto com o DNS, são os dois pontos de fricção deste runbook). Capturar do output: LIVEKIT_API_KEY, LIVEKIT_API_SECRET, LIVEKIT_URL=wss://<seu-subdominio>.

6. R2 (Cloudflare)

Sem automação via CLI que valha a pena pra um bucket único — peça ao humano pra seguir Armazenamento (R2) e colar: R2_ACCOUNT_ID, R2_ACCESS_KEY_ID, R2_SECRET_ACCESS_KEY, R2_BUCKET, URL pública.

7. Env vars no Railway

railway variables --set "DISCORD_CLIENT_ID=..." \
  --set "DISCORD_CLIENT_SECRET=..." \
  --set "NEXTAUTH_SECRET=$(openssl rand -base64 32)" \
  --set "NEXTAUTH_URL=https://SEU-DOMINIO" \
  --set "BOOTSTRAP_ADMIN_DISCORD_IDS=<id-do-humano>" \
  --set "LIVEKIT_URL=wss://..." \
  --set "LIVEKIT_API_KEY=..." \
  --set "LIVEKIT_API_SECRET=..." \
  --set "R2_ACCOUNT_ID=..." \
  --set "R2_ACCESS_KEY_ID=..." \
  --set "R2_SECRET_ACCESS_KEY=..." \
  --set "R2_BUCKET=..." \
  --set "NEXT_PUBLIC_R2_PUBLIC_BASE_URL=..." \
  --set "NEXT_PUBLIC_APP_URL=https://SEU-DOMINIO"

(DATABASE_URL não precisa ser setada manualmente se o Postgres foi criado no mesmo projeto Railway — referenciar ${{Postgres.DATABASE_URL}} já resolve.)

8. Deploy

railway up
railway domain   # gera/mostra o domínio *.up.railway.app
# ou: railway domain add SEU-DOMINIO (ação humana: apontar CNAME depois)

Pausa pra ação humana: com o domínio definitivo, voltar no Discord Developer Portal e completar o Redirect URI (https://SEU-DOMINIO/api/auth/callback/discord).

9. Criar as tabelas do banco

railway run pnpm prisma db push

(o repo ainda não versiona prisma/migrations/, então db push — não migrate deploy — é o comando que sincroniza o schema; ver nota em Banco de dados)

10. Validação final

  1. Abrir https://SEU-DOMINIO, logar com a conta do BOOTSTRAP_ADMIN_DISCORD_IDS — confirmar acesso a /admin/channels.
  2. Testar uma chamada de voz em /channels.
  3. Mandar uma mensagem com anexo no chat — confirma R2.
  4. Se self-host: seguir infra/vps-metrics/README.md no repo do app pra instalar os coletores de métrica (passo separado, escrito pra execução manual/cron).

Pontos de checkpoint humano (resumo)

  • Criar a Discord Application e colar client id/secret
  • Login inicial em cada provedor (mesmo browserless, alguém aprova no navegador)
  • Confirmar plano pago antes de provisionar (Railway, Vultr)
  • Apontar DNS (A record pra VPS, CNAME pro Railway)
  • Completar o Redirect URI no Discord depois que o domínio final existir

On this page