Empacotamento e Implantação
Empacotamento para Implantação
Quando seu app estiver pronto, você precisa empacotá-lo em um arquivo .zip para fazer o upload. O arquivo ZIP deve seguir convenções específicas de estrutura e incluir um arquivo manifest.json obrigatório.
O Arquivo manifest.json (Obrigatório)
Todos os apps devem incluir um arquivo manifest.json no diretório assets/. Este arquivo contém os metadados do seu app:
{
"app": {
"type": "lua",
"name": "my-app",
"title": "My App",
"version": "1.0.0",
"description": "Uma breve descrição do que seu app faz",
"dependencies": [
{
"name": "other-app",
"version": ">=1.0.0"
}
]
},
"contact_fields": [
{
"type": "STRING",
"name": "customer_id",
"display": "ID do Cliente",
"private": false
}
],
"journeys": [
{
"name": "Jornada de Boas-vindas",
"file": "journeys/welcome.md",
"description": "Dá boas-vindas a novos usuários"
}
],
"media_assets": [
{
"asset_path": "images/logo.png",
"filename": "logo.png",
"content_type": "image/png",
"description": "Logotipo da empresa"
}
],
"skills": [
{
"name": "get_weather",
"file": "my-app/skills/get_weather.lua"
}
]
}
Metadados do App (Obrigatório)
Campos obrigatórios:
app.type: O tipo do app (ex:"lua"para apps Lua)app.name: O nome do seu app (deve corresponder ao nome do arquivo Lua principal sem extensão)app.title: O título de exibição para seu app (mostrado na UI da Turn)app.version: String de versão semântica (ex:1.0.0,2.1.3,1.0.0-beta)app.description: Uma breve descrição da funcionalidade do seu app
Campos opcionais:
app.dependencies: Um array de apps que devem estar instalados para que seu app funcione. Cada dependência deve especificar:name: O nome exato do app requeridoversion: Uma restrição de versão (ex:>=1.0.0,~>2.1,1.0.0)
Comportamento de dependências:
- Se
dependenciesnão for especificado ou for um array vazio[], a plataforma assume que seu app não tem dependências e pode ser instalado independentemente - Quando dependências são especificadas, a plataforma valida que todos os apps requeridos estão instalados com versões compatíveis antes de permitir a instalação
- Entradas de dependência inválidas (sem
nameouversion) são silenciosamente ignoradas
Campos de Contato (Opcional)
O array contact_fields define campos personalizados que seu app adicionará aos contatos. Esses campos são criados automaticamente quando o app é instalado usando turn.manifest.install().
"contact_fields": [
{
"type": "STRING",
"name": "customer_id",
"display": "ID do Cliente",
"private": false
},
{
"type": "BOOLEAN",
"name": "is_premium",
"display": "Membro Premium",
"private": false
},
{
"type": "NUMBER",
"name": "loyalty_points",
"display": "Pontos de Fidelidade",
"private": true
}
]
Propriedades do campo:
type(obrigatório): Tipo do campo -"STRING","BOOLEAN","NUMBER", ou"DATE"name(obrigatório): Nome interno do campo (minúsculas, sublinhados permitidos)display(obrigatório): Rótulo legível mostrado na UIprivate(obrigatório):truepara ocultar de usuários não-admin,falsepara mostrar a todos
Notas:
- Campos são criados automaticamente durante a instalação do app
- Campos podem ser inscritos para notificações de mudança usando
turn.app.set_contact_subscriptions() - Use
private: truepara dados sensíveis como registros médicos, informações financeiras ou identificadores pessoais
Jornadas (Opcional)
O array journeys define templates de jornada que seu app fornece. Estes são arquivos markdown no seu diretório assets/ que definem fluxos de conversação.
"journeys": [
{
"name": "Jornada de Boas-vindas",
"file": "journeys/welcome.md",
"description": "Dá boas-vindas a novos usuários e coleta informações básicas"
},
{
"name": "Fluxo de Pagamento",
"file": "journeys/payment.md",
"description": "Processa pagamentos com integração Stripe"
}
]
Propriedades da jornada:
name(obrigatório): Nome de exibição para a jornada na UI da Turnfile(obrigatório): Caminho para o arquivo markdown dentro do diretórioassets/description(obrigatório): Breve descrição do que a jornada faz
Notas:
- Arquivos de jornada são importados automaticamente durante a instalação ao usar
turn.manifest.install() - Jornadas podem chamar de volta para seu app usando a função DSL
app() - Arquivos markdown de jornadas suportam a sintaxe DSL completa de jornadas da Turn.io
Ativos de Mídia (Opcional)
O array media_assets define imagens e outros arquivos de mídia incluídos com seu app. Estes são enviados e disponibilizados para uso em jornadas e mensagens.
"media_assets": [
{
"asset_path": "images/welcome-banner.jpg",
"filename": "welcome-banner.jpg",
"content_type": "image/jpeg",
"description": "Imagem de banner de boas-vindas"
},
{
"asset_path": "images/logo.png",
"filename": "logo.png",
"content_type": "image/png",
"description": "Logotipo da empresa"
},
{
"asset_path": "documents/terms.pdf",
"filename": "termos-de-servico.pdf",
"content_type": "application/pdf",
"description": "Documento de termos de serviço"
}
]
Propriedades do ativo de mídia:
asset_path(obrigatório): Caminho para o arquivo dentro do diretórioassets/do seu appfilename(obrigatório): Nome a usar ao fazer upload (pode ser diferente de asset_path)content_type(obrigatório): Tipo MIME (ex:"image/jpeg","image/png","application/pdf")description(obrigatório): Descrição do propósito do ativo
Tipos de conteúdo suportados:
- Imagens:
image/jpeg,image/png,image/gif,image/webp - Documentos:
application/pdf - Vídeos:
video/mp4,video/3gpp - Áudio:
audio/mpeg,audio/ogg,audio/aac
Notas:
- Arquivos de mídia são enviados para o armazenamento de mídia da Turn durante a instalação
- Arquivos enviados recebem URLs únicas que podem ser usadas em mensagens e jornadas
- Use
turn.assets.read()para acessar o conteúdo binário de ativos para upload
Skills (Opcional)
O array skills define skills de agentes IA que seu app fornece. Apps podem incluir tanto Skills de Código (arquivos Lua) quanto Skills de Conhecimento (arquivos Markdown).
"skills": [
{
"name": "get_weather",
"file": "my-app/skills/get_weather.lua"
},
{
"name": "lookup_order",
"file": "my-app/skills/lookup_order.lua"
},
{
"name": "politica_devolucao",
"file": "my-app/knowledge/politica_devolucao.md"
}
]
Propriedades de skill:
name(obrigatório): O nome da skill usado ao anexar a agentes IAfile(obrigatório): Caminho para o arquivo de skill dentro do pacote do app (.luapara skills de código,.mdpara skills de conhecimento)
Skills de Código (.lua):
- Executam código Lua quando chamadas pelo agente IA
- Devem incluir anotações LDoc definindo parâmetros e tipos de retorno
- Têm acesso à API completa da plataforma
Skills de Conhecimento (.md):
- Retornam conteúdo markdown estático quando chamadas
- Usam frontmatter YAML com campos
nameedescription - Ideais para FAQs, políticas e informações de referência
Notas:
- Skills são referenciadas em agentes IA como
app:nome_do_app:nome_da_skill - Veja Skills de Agentes IA para documentação completa sobre como escrever skills
Sem o arquivo manifest.json, o upload do seu app falhará com um erro :manifest_not_found.
Estrutura do Arquivo ZIP
Seu app deve seguir esta estrutura:
my-app.zip
├── my-app.lua # Arquivo principal (obrigatório, deve corresponder ao nome do app)
├── my-app/ # Opcional: Diretório de módulos
│ ├── utils.lua
│ ├── handlers.lua
│ └── api/
│ └── client.lua
└── assets/ # Obrigatório: Contém manifest e arquivos estáticos
├── manifest.json # OBRIGATÓRIO: Metadados do app
├── liquid/ # Templates Liquid (usados por turn.liquid.render)
│ └── welcome.liquid
├── public/ # Arquivos estáticos servidos via HTTP
│ ├── svg/
│ │ └── icon.svg
│ ├── css/
│ │ └── styles.css
│ └── images/
│ └── logo.png
├── templates/
│ └── welcome.md
└── images/
└── logo.png
Importante: O diretório assets/ agora é obrigatório (não opcional) já que deve conter o arquivo manifest.json.
assets/public/ — Arquivos Estáticos Servidos via HTTP
Arquivos em assets/public/ são servidos diretamente via HTTP em /apps/:uuid/static/*path, sem passar pelo runtime Lua. Use isso para imagens, SVGs, folhas de estilo, fontes e quaisquer outros arquivos que precisam ser carregados por um navegador.
- Em templates Liquid, referencie-os com o filtro
static_url:{{ "svg/icon.svg" | static_url }} - Em código Lua, use
turn.assets.static_url("svg/icon.svg")para gerar a URL
Apenas arquivos dentro de assets/public/ são acessíveis publicamente. Outros diretórios em assets/ (como liquid/, templates/, etc.) não são servidos via HTTP.
Usando o Docker SDK (Recomendado)
Se você usou o Docker SDK para criar o scaffold do seu app, o empacotamento é simples:
make build
# Isso cria my_app-0.0.1.zip (versão do manifest.json)
O comando build automaticamente:
- Inclui seu arquivo
.luaprincipal - Inclui o diretório
assets/commanifest.json - Inclui quaisquer módulos no diretório
lib/ - Exclui arquivos de teste e arquivos de desenvolvimento
Usando o Script Zip-It
O template tradicional inclui um script zip-it.sh que automatiza o empacotamento:
./zip-it.sh
# O script irá remover quaisquer arquivos zip antigos,
# criar um novo arquivo zip com seu código mais recente
Empacotamento Manual
Se você precisar de mais controle sobre o empacotamento:
# App simples (arquivo único)
zip payment-processor-1.0.0.zip payment-processor.lua
# App com módulos
zip -r my-app-1.0.0.zip my-app.lua my-app/
# App com ativos
zip -r my-app-1.0.0.zip my-app.lua my-app/ assets/
# Excluir arquivos de teste
zip -r my-app-1.0.0.zip my-app.lua my-app/ assets/ -x "*/spec/*" "*/turn.lua" "*.rockspec"
# Verificar conteúdo
unzip -l my-app-1.0.0.zip
Notas Importantes
NÃO inclua no seu ZIP:
- Arquivos de teste (diretório
spec/) - Mock da API Turn (
turn.lua) - Arquivos de desenvolvimento (
*.rockspec,.git/, etc.) - Arquivos de documentação (
README.md, a menos que em assets/)
INCLUA:
- Arquivo principal do app (deve corresponder ao nome do app)
- Arquivo
assets/manifest.json(OBRIGATÓRIO) - Todos os módulos Lua necessários
- Pasta de ativos com manifest.json e quaisquer templates/imagens
- Quaisquer arquivos de configuração que seu app precise
Processo de Upload
- Vá para a plataforma Turn.io
- Navegue até Configurações → Apps
- Clique em "Carregar Novo App"
- Selecione seu arquivo ZIP
- A plataforma validará:
- Presença de
assets/manifest.json - Estrutura JSON válida no manifest
- Campos obrigatórios (name, version, description)
- Formato de versionamento semântico
- Presença de
- Após validação bem-sucedida, uma definição de app será criada
Implantação Remota com o SDK
Em vez de construir arquivos ZIP manualmente e enviá-los pela UI, você pode enviar os arquivos do app diretamente para uma instância Turn em execução usando os comandos de implantação remota do SDK. Este é o fluxo de trabalho recomendado para desenvolvimento ativo.
Pré-requisitos
- Seu app foi criado com o Docker SDK (
turn-app new) - O app já está instalado na instância Turn de destino (a instalação inicial é feita pela UI)
- Você possui um token de autenticação da API para a instância de destino
Configurando Targets
Um target é uma referência nomeada para uma instância Turn. Configure targets no diretório do seu app:
# Adicionar um target
make target-add NAME=staging URL=https://sua-instancia.turn.io
# Listar targets configurados
make target-list
# Remover um target
make target-remove NAME=staging
A configuração de targets é armazenada localmente em .turn-targets.json no diretório do seu app (adicione ao .gitignore).
Autenticação
Defina a variável de ambiente TURN_APP_TOKEN com seu token de API antes de executar comandos de push:
export TURN_APP_TOKEN=seu-token-de-api
Você também pode passar inline com cada comando:
TURN_APP_TOKEN=seu-token make push TARGET=staging
Enviando Arquivos
Envie os arquivos do seu app para um target remoto:
# Enviar todos os arquivos
make push TARGET=staging
# Enviar apenas arquivos alterados (mais rápido para atualizações incrementais)
make push TARGET=staging CHANGED=--changed
Quando você faz push, o SDK:
- Lê a versão atual do
assets/manifest.json - Calcula a próxima versão de desenvolvimento (ex:
1.0.0→1.0.1-dev.1→1.0.1-dev.2) - Faz upload dos arquivos para a instância remota
- Atualiza o
assets/manifest.jsonlocal com a nova versão
A instância remota recarrega automaticamente o app com os novos arquivos.
Modo Watch (Push Automático)
Para um ciclo de desenvolvimento ao vivo, use o modo watch para enviar alterações automaticamente conforme você edita arquivos:
make push-watch TARGET=staging
Isso monitora o diretório do seu app por alterações de arquivos e os envia para o target a cada salvamento — similar ao make watch para testes, mas enviando para uma instância remota.
Promovendo para Release
Os pushes de desenvolvimento criam versões de pré-lançamento (ex: 1.0.1-dev.3). Quando estiver pronto para lançar, promova para uma versão estável:
# Promover com incremento de patch (1.0.1-dev.3 → 1.0.1)
make promote TARGET=staging
# Promover com incremento minor (1.0.1-dev.3 → 1.1.0)
make promote TARGET=staging BUMP=--minor
# Promover com incremento major (1.0.1-dev.3 → 2.0.0)
make promote TARGET=staging BUMP=--major
A promoção envia todos os arquivos (não apenas os alterados) para garantir que a versão de release seja um snapshot completo do seu app.
Gerenciamento de Versões
O SDK gerencia versões automaticamente através do seu assets/manifest.json:
- Pushes de desenvolvimento incrementam o número de pré-lançamento dev:
1.0.0→1.0.1-dev.1→1.0.1-dev.2 - Promote remove a tag de pré-lançamento e aplica o incremento:
1.0.1-dev.5→1.0.1(patch),1.1.0(minor), ou2.0.0(major)
Você pode inspecionar todas as versões implantadas em um target:
make versions TARGET=staging
Rollback
Se precisar reverter para uma versão anterior:
make rollback TARGET=staging VERSION=1.0.0
Puxando Jornadas da Produção
Jornadas são frequentemente editadas em produção via a interface do canvas. Para sincronizar essas alterações de volta ao seu repositório local:
make pull TARGET=staging
Isso baixa o arquivo atual do app do servidor e sobrescreve seus arquivos locais em assets/journeys/. Seu diretório git deve estar limpo antes de puxar.
Após puxar, revise as alterações com suas ferramentas preferidas (git diff, seu editor, etc.) e faça commit seletivamente.
Proteção Contra Conflitos de Versão
O servidor rejeita pushes com uma versão mais antiga que a versão ativa atual (HTTP 409). Isso pode acontecer se seu assets/manifest.json local estiver desatualizado — por exemplo, se outro desenvolvedor enviou uma versão mais recente.
Quando isso acontecer:
- Execute
make versions TARGET=stagingpara ver as versões implantadas - Atualize a versão no seu
assets/manifest.jsonlocal para corresponder ou superar a versão remota atual - Tente o push novamente
Fluxo de Trabalho Típico de Desenvolvimento
1. Criar app: turn-app new my_app
2. Desenvolver e testar: make watch (execução automática de testes)
3. Configurar target: make target-add NAME=staging URL=https://...
4. Instalar via UI: Fazer upload do ZIP inicial em Configurações → Apps
5. Enviar para remoto: make push-watch TARGET=staging (ciclo de dev ao vivo)
6. Lançar: make promote TARGET=staging
7. Puxar alterações: make pull TARGET=staging (sincronizar edições de jornadas)
8. Iterar: Continue enviando versões dev, promova quando pronto
Fornecendo Documentação do App na UI
Para garantir uma ótima experiência do usuário, você pode fornecer documentação que aparecerá diretamente na UI da Turn.io. Lide com o evento get_app_info_markdown e retorne uma string Markdown.
Este é o lugar perfeito para explicar o que seu app faz, listar suas funcionalidades e fornecer instruções de configuração ou exemplos de endpoint de API.
elseif event == "get_app_info_markdown" then
return [[
# Meu App Incrível
Este app se integra com o serviço externo `XYZ`.
## Configuração
Para usar este app, forneça sua `XYZ_API_KEY` na configuração abaixo.
## Endpoint de Webhook
Envie requisições `POST` do seu serviço para a seguinte URL:
`/apps/]] .. app.uuid .. [[/webhook`
]]
end