Caderno De Estudos

← início

Caderno de estudos — SAP BTP na prática

Mantido durante nossa sessão de aprendizado. Cada aula tem: conceito, comando e lição.

Aula 1 — Subir ferramentas para a nuvem da SAP

Como funciona a "conta" do SAP BTP

ConceitoO que éOnde vimos
Global accountA conta-mãe (contrato), agrupa tudo0494f001trial (trial)
Subaccount"Ambiente/projeto" dentro da global accounttrial (ID b3161ad1-...)
EntitlementO direito de usar um serviço (o que você pode)btp list accounts/entitlement
Service offering / planServiço que se instancia e faz bind num apphana, xsuaa, document-translation
SubscriptionAtivação de uma aplicação SaaS (ganha URL)build-code (SAP Build Code)
Target"Onde" os comandos do btp atuambtp target --subaccount ...

Anatomia de um comando do btp CLI

btp <ação> <grupo>/<objeto> --parâmetros

Exemplos:

btp list  accounts/entitlement        # listar direitos

btp list accounts/subscription # listar aplicações assinadas

btp subscribe accounts/subaccount --to-app build-code --plan free

btp target --subaccount &lt;ID&gt; # definir onde os comandos atuam

Regra de ouro: na dúvida, btp help, btp help <ação>, btp help <ação> <objeto>.

Ferramentas instaladas nesta máquina

FerramentaPapel
btpAdministração da conta (subscrições, serviços, entitlements)
cf (+ plugin multiapps)Deploy de aplicações no Cloud Foundry
Node.js / npmRuntime para CAP
cds (@sap/cds-dk)Framework CAP: modelo, serviço, build
mbtEmpacotar tudo num arquivo .mtar
gitControle de versão

O ciclo de desenvolvimento (o caminho do código)

cds watch        → develop local (http://localhost:4004)

mbt build → empacota (mta_archives/*.mtar)

cf deploy *.mtar → envia e sobe no Cloud Foundry

cf logs &lt;app&gt; → ver logs de execução

Aula bônus: inspecionar JSON sem adivinhar

btp --format json list accounts/subscription > subs.json

jq &#x27;type&#x27; subs.json # object? array?

jq &#x27;keys&#x27; subs.json # [&quot;applications&quot;]

jq &#x27;.applications[] | select(.appName==&quot;build-code&quot;) | {state, subscriptionUrl}&#x27; subs.json

Lição que aprendemos na prática: usei .status, mas o campo real era .state.

Resultado: null 15 vezes. Nunca confie num nome de campo sem inspecionar.

Aula 2 — IA no BTP: onde cada coisa mora

ServiçoO que fazDisponível no trial?
SAP AI CoreMotor para rodar modelos de IA❌ (precisa Free Tier / GenAI Hub Trial / conta corporativa)
Generative AI HubLLMs da SAP (GPT, Gemini, Claude...) via AI Core❌ (mesma situação)
Joule for developersCopiloto de programação dentro do SAP Build Code✅ (assinamos o build-code free)
Joule SkillsCriar skills para a Joule dos usuários finais❌ (Joule Studio é pago)
Document Information ExtractionIA de extração de dados de documentos✅
Document TranslationTradução de documentos✅

Nosso exemplo prático: ~/projects/ai-lab

App CAP + UI5 com adaptador de IA que escolhe o provedor automaticamente:

  1. 1. SAP AI Core (quando existir binding aicore ou AICORE_SERVICE_KEY)
  2. 2. LLM externo compatível com OpenAI (quando houver LLM_API_KEY)
  3. 3. mock (fallback — funciona sempre, para desenvolvimento)

Arquivos-chave:

db/schema.cds           modelo de dados (Interactions)

srv/ai-service.cds contrato do serviço OData

srv/ai-service.js lógica (handler da action ask)

srv/lib/ai-provider.js adaptador de provedores de IA

app/ui/ interface UI5

mta.yaml receita de deploy (srv + approuter + xsuaa)

Comandos úteis do dia a dia (no projeto)

cd ~/projects/ai-lab

npx cds watch # rodar local

curl &#x27;http://localhost:4004/api/ai/provider()&#x27;

mbt build &amp;&amp; cf deploy mta_archives/ai-lab_1.0.0.mtar -f

Aula 4 — Autenticação × Autorização (o famoso "Access denied")

EtapaPerguntaFerramenta
Autenticação"Você é quem diz ser?"Login (SAP ID) → gera um token JWT
Autorização"Você tem permissão para isso?"Roles contidas no token

Regras aprendidas:

  1. 1. Assinar uma aplicação não dá permissão a ninguém — é preciso atribuir role collections.
  2. 2. O token JWT fica "congelado" no navegador por horas: depois de mudar roles, faça login de novo (ou use janela anônima).

Comandos usados nesta aula

btp help security                                            # descobrir objetos de segurança

btp list security/role-collection --subaccount &lt;ID&gt; # listar conjuntos de permissões

btp help assign security/role-collection # conferir a sintaxe

btp assign security/role-collection &quot;Build Code - Lobby Admin&quot; \

--to-user [email protected] --subaccount &lt;ID&gt;

Roles do SAP Build Code (encontradas na prática)

Role collectionPara que serve
Build Code - Lobby AdminAcessar o lobby como administrador
Build Code - Lobby DeveloperAcessar o lobby como desenvolvedor

Aula 5 — Identity Providers (IDP) e Boosters

O caso do "Access Denied" no SAP Build Lobby

Sintoma: assinatura OK + roles atribuídas, mas o lobby responde:

Access Denied — You need permission to access this page. Request access from your administrator.

Causa (encontrada na comunidade SAP): em contas trial, o SAP Build usa um

Custom Identity Provider (IDP) — um "diretório de logins" próprio do serviço.

Se você entra com o IDP padrão (sap.default, ou seja, o SAP ID), a aplicação

não te reconhece, mesmo com as role collections atribuídas.

Conceito: Identity Provider (IDP)

TermoO que é
IDPQuem guarda os logins e prova "quem você é"
Default IDP (sap.default)O SAP ID (accounts.sap.com)
Custom IDPIDP próprio do tenant/serviço (criado pelo trial para o SAP Build)
TrustA configuração de confiança entre o subaccount e o IDP

Conceito: Booster

Um assistente guiado do Cockpit que executa a configuração de ponta a ponta:

Ação: rodar o booster "Get Started with SAP Build Code"

(Global Account → menu lateral → Boosters).

Lições de investigação (aplicadas nesta aula)

  1. 1. A mensagem de erro é pista, não obstáculo: ela mandou olhar a "Configuração inicial".
  2. 2. Documentação oficial (help.sap.com / learning.sap.com) antes de tentar adivinhar.
  3. 3. Comunidade SAP é uma fonte de verdade validada (solução aceita com selo de especialista).
  4. 4. Saída truncada engana: head -30 cortou roles e me levou a atribuir as erradas.

Aula 6 — Sessões expiram (e explicam sintomas estranhos)

login → TOKEN de acesso (curto) + TOKEN de renovação (refresh)

→ quando ambos vencem, é preciso logar de novo

Vimos na prática: btp get accounts/global-account falhou com "Your login has expired"

depois de ~4h. Solução: relogar (btp login --sso). Sessões velhas no navegador também

causam erros de autorização ("Access denied", "no global account").

Aula 7 — Identificadores: use a fonte autoritativa

ObjetoID correto (CLI)IDs "errados" que apareceram
Global account9b6aad2f-4bf4-47fb-869f-5546df9e28fd698a0962-... (veio do JSON de assinatura)
Subaccountb3161ad1-354c-405e-a039-c47d410d83b8—

Lição: o mesmo objeto pode aparecer com IDs diferentes em contextos diferentes

(comercial × técnico). Sempre confirme com btp get accounts/global-account.

Como saber se o problema é conta ou sessão

btp get accounts/global-account     # a conta existe? qual o ID?

btp list security/user --global-account &lt;subdomain&gt; # quem são os membros?

Se o CLI vê tudo (conta + usuário), mas o navegador não → suspeite da sessão do navegador,

não da conta. Teste rápido: janela anônima.

Aula 8 — Contas trial têm portal de entrada próprio

Sintoma: o cockpit padrão (cockpit.btp.cloud.sap) responde

"Não foi possível encontrar nenhuma conta global associado ao seu usuário" —

mesmo sendo membro da conta, como o CLI comprova.

Causa: contas trial são acessadas por um portal de entrada específico:

https://account.hanatrial.ondemand.com/   →  "Go To Your Trial Account"

De lá o cockpit abre no contexto correto (região + IDP do trial).

Entrar pelo cockpit "normal" é o que produz o erro.

Setup correto do SAP Build Code (tutorial oficial)

  1. 1. Entrar pelo portal do trial (account.hanatrial.ondemand.com)
  2. 2. (Opcional, conforme tutorial) desassinar o SAP Business Application Studio
  3. 3. Cockpit → Boosters → "Get Started with SAP Build Code" → Start
  4. 4. O booster:

- valida autorizações, provedor e região

- atribui as roles necessárias ao usuário no IDP padrão

- cria/verifica as assinaturas

  1. 5. Se você também usar um IDP customizado (ex.: por causa do SAP Build Apps),

pode ser preciso adicionar também as roles Build Code Administrator / Build Code Developer

Nota oficial: a versão trial do SAP Build Code só está disponível na região US10.

Aula 9 — Cockpits são REGIONAIS (a causa do "nenhuma conta global")

URLResultado real
https://account.hanatrial.ondemand.com/ (doc antiga)❌ 403 — portal desativado
https://cockpit.btp.cloud.sap/cockpit/?region=trial✅ 302 → amer.cockpit.btp.cloud.sap/cockpit/?region=trial
https://amer.cockpit.btp.cloud.sap/cockpit/?region=trial✅ 200 — cockpit correto para trial US10
https://cockpit.btp.cloud.sap/ (sem parâmetro)❌ não encontra contas trial

Conclusão: o cockpit é um app por região, e contas trial US10 vivem no cockpit

amer. Sem o ?region=trial, a mensagem é "nenhuma conta global associada ao seu usuário"

— mesmo com a conta existindo e o CLI a enxergando perfeitamente.

Como diagnosticar de verdade (em vez de adivinhar)

curl -sS -o /dev/null -w '%{http_code} -> %{redirect_url}\n' -I "<URL>"

getent hosts &lt;host&gt; # ver DNS / para onde resolve

Esses dois comandos provaram: portal antigo morto (403) e redirecionamento regional (302).

Aula 10 — O portal do TRIAL e os "Feature Sets" do cockpit

Descoberta: existe um portal específico de trial

https://account.hanatrial.ondemand.com/cockpit

→ 302 → https://account.hanatrial.ondemand.com/trial/#/home/trial ← portal do trial

O tutorial do Build Code dizia exatamente isso: *"Access your global account and click

Go To Your Trial Account"*. Era este o endereço.

Lição de diagnóstico: curl sem User-Agent leva 403

curl -I https://account.hanatrial.ondemand.com/                     # 403 (parece morto)

curl -A &quot;Mozilla/5.0 ... Chrome/140&quot; https://account.hanatrial... # 302 (vivo!)

Muitos sites bloqueiam curl puro (WAF). **Sempre repita o teste com -A (User-Agent)

e com GET** antes de concluir que algo não existe.

Conceito: Feature Sets do cockpit

Existem duas versões do cockpit SAP BTP:

Feature SetContextoObservação
Aconta antigas/Neo e trials antigosURL account.*/cockpit
Bcontas modernascockpit.btp.cloud.sap (regional: amer/emea/apac)

As próprias mensagens internas do cockpit dizem:

*"To see those accounts, you need to go to a version of the SAP BTP cockpit that supports

feature set A"* — ou seja, o cockpit "normal" não lista contas que vivem no outro feature set.

Isso explica o erro recorrente "nenhuma conta global associada ao seu usuário".

Aula 11 — SAP Build Code: assinatura, booster e roles

# Assinar o Build Code (plano free)

btp subscribe accounts/subaccount --subaccount &lt;ID&gt; --to-app build-code --plan free

Ver o que foi criado

btp list security/role-collection --subaccount &lt;ID&gt; | grep -i &#x27;build code&#x27;

O "Access denied" no Lobby não era falta de role: era o setup incompleto.

O booster "Get Started with SAP Build Code" (Aceleradores, no cockpit do trial)

executa em sequência:

  1. 1. Atribuir quotas de serviço
  2. 2. Assinar aplicativos SaaS
  3. 3. Criar instâncias de serviço
  4. 4. Criar role collection (ex.: Build Code Administrator, Build Code Developer)
  5. 5. Atribuir role collection ao usuário
Lição: dependendo do estado da conta, rodar o booster duas vezes faz diferença —
a primeira rodada pode pular etapas que a segunda executa.

Aula 12 — BAS × Build Code (planos concorrentes)

ProdutoPapel
SAP Business Application Studio (BAS)IDE da SAP (sem Joule)
SAP Build CodeBAS + Joule + ferramentas (plano build-code)

Mensagem da Joule: "upgrade to the build-code plan" → o dev space precisa ser provido

pelo plano do Build Code. O tutorial oficial manda desassinar o BAS antes de rodar o booster.

Estado ao final desta sessão

ItemSituação
Cobrança de assinaturabuild-code (free) + sapappstudiotrial (trial) assinados
RolesBuild Code Administrator/Developer criadas e atribuídas ✅
Lobbyabre normalmente ✅
Projeto ai-joule-labcriado no lobby ✅
Dev space (ws-* no CF)❌ não provisionado → editor/Joule ainda não abre
Navegador operado porxdotool (cliques/teclado) + ffmpeg (screenshots)

Truques de automação usados (úteis para qualquer troubleshooting)

xdotool windowactivate <ID> && xdotool mousemove X Y click 1   # operar a tela

ffmpeg -f x11grab -video_size 1920x1020 -i :0.0+0,0 -frames:v 1 tela.png

curl -A &quot;Mozilla/5.0 ...&quot; https://site # sites bloqueiam curl sem User-Agent

Aula 13 — Dev space "Interrompido" e automação em segundo plano

O problema do "Interrompido"

Ao desinscrever o BAS, o dev space antigo (Full_Stack, criado sob o plano BAS) ficou

"Interrompido" — e o projeto apontava para ele. Solução: ao criar um projeto novo,

escolher Área do desenvolvedor: Novo (criar um dev space limpo no plano build-code).

Resultado: ws-0msl7 criado ✅ e a IDE abriu com o projeto ai-joule-lab2.

Técnica: operar o navegador em SEGUNDO PLANO (sem roubar foco)

  1. 1. Subir um Chrome separado com CDP (protocolo de depuração):
  2.    google-chrome --headless=new --remote-debugging-port=9222 \
    

--user-data-dir=/tmp/opencode/cdp-profile \

--disable-background-timer-throttling --disable-renderer-backgrounding

  1. 2. Copiar os cookies do perfil real (Default/Cookies + Local State) para o novo perfil

→ a sessão já vem logada, sem precisar de senha!

  1. 3. Controlar via WebSocket + CDP (Node puro, sem dependências):

- Page.navigate, Page.captureScreenshot

- Input.dispatchMouseEvent, Input.dispatchKeyEvent, Input.insertText

- Runtime.evaluate (rodar JS na página)

Bônus: código SSO do Cloud Foundry automatizado

O código temporário do cf login --sso pode ser lido da própria página de passcode:

// navegar para https://login.cf.us10-001.hana.ondemand.com/passcode

// clicar na conta e ler: document.body.innerText

cf login -a https://api.cf.us10-001.hana.ondemand.com --sso-passcode &lt;CODIGO&gt;

Limite encontrado

O workbench do BAS/Build Code roda dentro de iframes que **não aceitam eventos

sintéticos (CDP). Para usar a Joule**, o último passo (abrir o painel dela) deve ser

feito no navegador normal:

Ctrl+Shift+P  →  Joule: Focus on Joule View

Aula 14 — Joule funcionando! 🎉

Estado final da trilha:

ItemStatus
SAP Build Code assinado (free)✅
Roles (Build Code Administrator/Developer)✅
Dev space novo (Build Code plan)✅ ws-0msl7
Projeto no Storyboard✅ ai-joule-lab2
Joule aberta na IDE✅ ("Hi! I'm Joule, your digital assistant")

Comandos que a Joule oferece no trial:

Primeiro prompt sugerido (para colar na Joule)

Create a CAP data model for a purchase order application with entities

PurchaseOrder and PurchaseOrderItem, and expose both in a service

Limite técnico importante (documentado para o futuro)

O workbench do SAP Build Code/BAS (VS Code web dentro de iframes):

(testado com Emulation.setFocusEmulationEnabled e sem override de viewport)

→ Para usar a Joule, o último passo é sempre humano: digitar/colar no painel.

A automação cobre todo o resto (lobby, criação de projeto, dev space, login SSO).

Técnicas que ficaram no repertório

TécnicaPara que serve
Chrome headless + CDP + cookies copiadosOperar sites logados em segundo plano
curl -A "<UA de navegador>"Testar sites que bloqueiam curl
`btp --format json ... \jq`Automatizar o btp CLI
Ler o código SSO da página de passcodecf login --sso-passcode sem intervenção

Pendências / próximos passos

Aula 15 — Copiar texto do OpenCode (TUI) sem travar

Sintoma: ao arrastar o mouse para selecionar um texto no OpenCode, a tela parece

travada e só volta dando Ctrl+C (que fecha o app!).

Causa: o OpenCode (TUI) usa captura de mouse (mouse: true por padrão). Os

eventos de arrastar vão para o app em vez de selecionar no terminal. E Ctrl+C é o

atalho de sair (app.exit).

Soluções:

SoluçãoComo
Shift + arrastarSeleção nativa do terminal (fura a captura) + Ctrl+Shift+C para copiar
Desligar a captura (aplicado)~/.config/opencode/cli.json → {"mouse": false}
Cópia automática ao selecionar"terminal": {"copy": "select"}
Copiar mensagem pelo próprio app<leader>y (padrão: Ctrl+X depois Y)
Alternativa infalívelCopiar do arquivo exportado em chats/ (aberto no VS Code)

Config final aplicada nesta máquina (a que funciona bem):

```json title="~/.config/opencode/cli.json"

{

"$schema": "https://opencode.ai/v2/cli.json",

"mouse": true,

"terminal": { "copy": "select" }

}


&gt; Por que mouse: true (e não false)? O OpenCode roda em tela cheia

&gt; (&quot;alternate screen&quot;) — sem a captura de mouse, a rolagem para de funcionar e não

&gt; há scrollback do terminal para usar. Então o melhor equilíbrio é:

&gt; manter o mouse ligado (rolagem/scroll normal) e copiar de outro jeito:

Como copiarPassos
Copiar mensagem (recomendado)Ctrl+X e depois Y (messages.copy) — sem mouse!
Copiar várias mensagens / sessãoCtrl+X e depois X (session.export) → abre num editor
Seleção com mouseSegure Shift enquanto arrasta (fura a captura do app) → copia ao soltar
Alternativa infalívelArquivo exportado em chats/ aberto no VS Code

Rolagem com teclado (sempre funciona): PageUp/PageDown, Ctrl+Alt+U/Ctrl+Alt+D

(meia página), Ctrl+G (início), Ctrl+Alt+G (fim), Ctrl+X + G (linha do tempo).

Aula 16 — 🎉 O fluxo completo: Storyboard → Joule → UI Fiori

Resultado da sessão: a Joule gerou um app SAP Fiori Elements (List Report + Object Page)

a partir do Storyboard! 🏆

O fluxo canônico (decorar!)

  1. 1) Modelo de dados → db/schema.cds (namespace + entity)
  2. 2) Serviço → srv/service.cds (service + projeção)
  3. 3) Storyboard → atualiza sozinho ao salvar os CDS
  4. 4) Joule → Ctrl+Shift+P → "Joule: Focus on Joule View"
  5. 5) Comando → /fiori-gen-cap-ui <descrição do que gerar>
  6. 
    

Detalhes que fazem diferença

DetalheExplicação
O comando precisa de descrição/fiori-gen-cap-ui sozinho → &quot;Type a prompt to get started&quot;. Ex.: /fiori-gen-cap-ui Generate a SAP Fiori Elements list report for PurchaseOrders
O Storyboard lê os arquivosSalvar db/schema.cds + srv/service.cds já atualiza o desenho
Terminal da IDE é o caniveteCtrl+Shift+P → Terminal: Create New Terminal → cria/verifica arquivos
Page MapDepois de gerar, a Joule abre o Page Map (List Report → Object Page) para edição visual
Arquivos geradosapp/&lt;appname&gt;/webapp/... (i18n, manifest, journeys de teste)

Criar arquivos CDS pelo terminal (exemplo usado)

bash

cat > ~/projects/ai-joule-lab2/db/schema.cds << 'CDSEOF'

namespace ai.joule.lab;

entity PurchaseOrder {

key ID : UUID;

orderNumber : String(20);

supplier : String(100);

amount : Decimal(15, 2);

status : String(20);

orderDate : Date;

}

CDSEOF

cat > ~/projects/ai-joule-lab2/srv/service.cds << 'CDSEOF'

using { ai.joule.lab as db } from '../db/schema';

service PurchaseService {

entity PurchaseOrders as projection on db.PurchaseOrder;

}

CDSEOF


Automação da IDE (lições práticas)

  • xdotool funciona na IDE do SAP — desde que:

1. usar as coordenadas da tela (a barra do Chrome ocupa ~104 px no topo);

2. minimizar o OpenCode/VS Code antes (senão o foco vai para eles!);

3. windowactivate --sync + windowraise na janela do Chrome.

  • OpenCode: Ctrl+S suspende a saída (XON/XOFF) e Ctrl+Q retoma — se &quot;congelar&quot;, tente isso.

Aula 17 — Rodando o app gerado pela Joule (no dev space)

bash

cd ~/projects/<projeto>

npm install

npm run watch-<appname> # ex.: watch-purchaseorders (script já vem do Build Code)

```

DetalheExplicação
Rodar em backgroundsetsid npm run watch-... < /dev/null > /tmp/cds.log 2>&1 & — sem setsid/< /dev/null o processo morre com EBADF: read quando o comando do terminal termina
URL do appO dev space publica a porta sozinho: port4004-workspaces-<dspace>.us10.trial.applicationstudio.cloud.sap/<app>/index.html
List Report com buscaA tabela só carrega ao clicar em "Iniciar" (Go)
Dados de exemplodb/data/<namespace>-<Entity>.csv (ex.: ai.joule.lab-PurchaseOrder.csv) — carregados ao reiniciar o cds watch
Conferir o servidortail -f /tmp/cds.log → mostra Server v10.x launched, requests OData etc.

Acesso "mais inteligente" ao dev space (o que existe × o que não)

trabalhar localmente (CLI/API/Coolify) é o caminho pragmático

Dica de automação (xdotool na IDE)