Como dominar a suíte de comandos do Modeler CLI, decifrar os erros de compilação, aplicar convenções de nomenclatura universais e gerenciar arquivos de tradução de locale.

No ecossistema de desenvolvimento tradicional da Salesforce, desenvolvedores estão habituados com mensagens de erro claras e amigáveis emitidas pelo compilador do Apex ou pelo linter do Lightning Web Components (LWC). Mensagens como “Variable does not exist” ou “Missing return statement” indicam exatamente a linha e a coluna onde o problema reside.

No entanto, ao ingressar no desenvolvimento mobile offline para o Salesforce Consumer Goods Cloud (CGC) Modeler, o paradigma muda drasticamente.

O Modeler opera através de um compilador de múltiplos estágios acionado via linha de comando (sf mdl build). Esse compilador valida centenas de contratos XML contra schemas XSD rígidos, inspeciona assinaturas de cabeçalho JSDoc em scripts JavaScript (.bl.js), cruza dependências entre processos e telas e checa a integridade das tabelas do banco de dados relacional local (appl/data/app.db3).

Quando uma regra sintática ou convenção estrutural é violada, o compilador frequentemente emite códigos numéricos herméticos (como 0311263000000001 ou 00000016) ou, pior ainda, o build passa com sucesso, mas a aplicação quebra em tempo de execução com telas brancas ou avisos de componentes ausentes.

Neste guia técnico, vamos mapear a suíte completa de comandos do Modeler CLI, estabelecer as convenções de nomenclatura inegociáveis, construir uma matriz de troubleshooting para diagnóstico rápido de falhas e estruturar o ciclo de internacionalização (i18n) em arquivos de locale.


1. A Suíte de Comandos do Modeler CLI e o Fluxo de Trabalho

A compilação e teste de artefatos no Modeler é gerenciada pelo plugin do Salesforce CLI (@ind-rcg/modeler-sfdx-cli-plugin). Os comandos possuem duas variações de sintaxe: o formato longo (sf modeler workspace <comando>) e o atalho canônico curto (sf mdl <comando>).

Comandos Essenciais do Terminal:

Comando CurtoComando CompletoPropósito Operacional
sf mdl buildsf modeler workspace buildCompila todos os contratos XML, arquivos .bl.js e gera os pacotes executáveis de runtime.
sf mdl cleansf modeler workspace cleanupRemove todos os artefatos compilados na pasta de saída, prevenindo builds corrompidos.
sf mdl validatesf modeler workspace validateExecuta a validação estrita dos contratos contra os schemas XSD sem gerar artefatos físicos.
sf mdl simulatesf modeler workspace server startInicializa o servidor local de desenvolvimento e abre o simulador da aplicação móvel no navegador.
sf mdl packagesf modeler workspace packageEmpacota a aplicação compilada em um arquivo compactado pronto para implantação no ambiente Salesforce.
sf mdl addsf modeler workspace addExecuta o assistente de scaffolding interativo para criar novos módulos, BOs, LOs, UIs e processos.

O Problema do “Stale Build” (Compilação Viciada)

Um dos problemas mais traiçoeiros enfrentados por desenvolvedores é alterar um arquivo de interface ou regra de negócio, rodar o sf mdl build e perceber que o simulador continua executando o código antigo. Isso acontece quando artefatos gerados anteriormente na pasta temporária não são sobrescritos.

A regra de ouro ao diagnosticar comportamentos inesperados é executar a limpeza completa antes da compilação:

# Limpeza forçada e recompilação limpa
sf mdl clean && sf mdl build

2. Naming Conventions: As Regras Inegociáveis de Nomenclatura

O compilador do Modeler baseia seu motor de descoberta e vinculação de dependências em convenções de nomenclatura estritas. Desviar desses padrões quebra o mapeamento entre camadas.

A Regra de Ouro: Chaves Primárias São Sempre pKey

No Modeler, qualquer campo que represente a chave primária de um registro **DEVE chamar-se rigorosamente pKey**. Nunca utilize nomes como idIdkey ou pk.

Essa convenção aplica-se simultaneamente a três camadas:

  1. Na propriedade com id="true" do BusinessObject: <SimpleProperty id="true" name="pKey" type="DomPKey" storable="false" dataSourceProperty="pKey" />
  2. Na propriedade com id="true" do ListItem: <SimpleProperty id="true" name="pKey" type="DomPKey" dataSourceProperty="pKey" />
  3. No mapeamento do DataSource correspondente: <Attribute name="pKey" table="Visit" column="Id" />

Padrões Canônicos de Nome de Arquivo e Prefixos:

Tipo de ArtefatoConvenção de ArquivoExemplo Real
DataSource de BODsBo{Nome}_sf.datasource.xmlDsBoVisit_sf.datasource.xml
DataSource de LODsLo{Nome}_sf.datasource.xmlDsLoOpenOrders_sf.datasource.xml
DataSource de LookupDsLu{Nome}_sf.datasource.xmlDsLuCustomer_sf.datasource.xml
BusinessObjectBo{Nome}.businessobject.xmlBoVisit.businessobject.xml
ListObjectLo{Nome}.listobject.xmlLoOpenOrders.listobject.xml
ListItemLi{Nome}.listitem.xmlLiOpenOrders.listitem.xml
ProcessFlow{Modulo}_{Tela}Process.processflow.xmlCall_DetailProcess.processflow.xml
UserInterface{Modulo}_{Tela}UI.userinterface.xmlCall_DetailUI.userinterface.xml
Business Logic{NomeDoObjeto}.{Metodo}.bl.jsBoVisit.AfterLoadAsync.bl.js

Namespace com Dois Pontos Duplos (::) em Process e UI

Enquanto BusinessObjects e ListObjects utilizam identificadores simples (ex: name="BoVisit"), os contratos de **ProcessFlow e UserInterface exigem obrigatoriamente o formato de namespace corporativo Namespace::Nome**:

<!-- No ProcessFlow -->
<Process name="Call::VisitDetailProcess" defaultAction="ShowView" schemaVersion="0.0.0.5">

<!-- Na UserInterface -->
<UIDescription name="Call::VisitDetailUI" schemaVersion="0.0.0.5">

A Pegadinha da Estrutura de Pastas: ListObjects Ficam em BO/

Uma confusão comum é tentar criar uma pasta chamada LO/ dentro do módulo. No Modeler, **tanto BusinessObjects quanto ListObjects, ListItems e LookupObjects residem dentro da pasta src/{Modulo}/BO/**:

src/Call/
  ├── BO/
  │   ├── BoVisit/
  │   │   ├── BoVisit.businessobject.xml
  │   │   └── Mv2/
  │   └── LoOpenOrders/
  │       ├── LoOpenOrders.listobject.xml
  │       ├── LiOpenOrders.listitem.xml
  │       └── Mv2/
  ├── DS/
  │   ├── DsBoVisit_sf.datasource.xml
  │   └── DsLoOpenOrders_sf.datasource.xml
  └── PR/
      └── Call_VisitDetail/
          ├── Call_VisitDetailProcess.processflow.xml
          └── Call_VisitDetailUI.userinterface.xml

3. Matriz Completa de Troubleshooting: Erros de Build

Quando o comando sf mdl build falha, a mensagem do terminal indica a categoria da violação estrutural. Consulte a matriz abaixo para identificar e corrigir a falha instantaneamente:

1. Falhas em Business Logic e JSDoc (.bl.js)

Código / Mensagem de ErroCausa RaizSolução Técnica
03112630 (Start tag missing)O marcador de início de código customizado está ausente, incorreto ou tem indentação diferente de 4 espaços.Verifique se as 3 linhas do marcador Add your customizing javaScript code below. estão idênticas ao template canônico com 4 espaços de recuo.
03112631 (End tag missing)O marcador final de código customizado foi alterado ou apagado.Restaure o bloco de 3 linhas Add your customizing javaScript code above..
Cannot read properties of undefined (reading 'name')Bloco JSDoc ausente ou tags obrigatórias faltando antes da função.Adicione o cabeçalho JSDoc com @function@this@kind@async e @namespace CUSTOM.
method not foundO nome declarado na tag @function não coincide com o nome físico do arquivo ou com a tag <Method> no XML.Sincronize rigorosamente o nome do método no XML, no arquivo .bl.js e na tag @function.

2. Falhas Estruturais na UserInterface (.userinterface.xml)

Mensagem de ErroCausa RaizSolução Técnica
Element 'DataGrid': This element is not expectedO controle DataGrid foi declarado isolado dentro de uma área comum.Envolva o DataGrid obrigatoriamente dentro de um container <FastDataEntryGrid> acompanhado de uma <DataInputArea>.
Element 'Label': This element is not expectedTentativa de usar uma tag <Label> solta como elemento de tela.Tags de texto não são controles de primeiro nível. Declare o texto via <Resource target="Label" type="Label" ... /> dentro do bloco <Bindings>.
Element 'ImageButton': This element is not expected (Erro 00000001)O botão com imagem foi inserido dentro de um GroupElement ou SingleElementArea.Mova o ImageButton para ser filho direto de uma <Area areaPattern="GroupedElementsArea"> ou use ButtonGridArea.
Missing required event or binding (Erro 00000016 / 00000018)CardContainer foi declarado sem os bindings de controle obrigatórios.Adicione simultaneamente o binding target="IsReadyToLoad" e o evento <LoadContainerData event="..." />.

3. Falhas no ProcessFlow (.processflow.xml)

Mensagem de ErroCausa RaizSolução Técnica
Element 'TransitionTo': This element is not expectedUma tag <TransitionTo> foi colocada dentro de uma ação presente em <EntryActions>.Remova a tag. Ações de entrada executam de forma puramente linear e transicionam automaticamente para o defaultAction.
Element 'Return': This element is not expectedA tag <Return> foi utilizada em uma ação que não gera retorno ou foi posicionada fora de ordem.Verifique se o actionType suporta retorno e respeite a ordem interna dos nós da ação.
Attribute 'object' is not allowedUso de sintaxe legada do Modeler em ações de carga.Substitua o atributo object="BoVisit" por type="BoVisit".

4. Falhas Silenciosas em Runtime (Quando o Build Passa, Mas o App Quebra)

Alguns dos bugs mais complexos não são capturados durante a compilação, manifestando-se apenas quando o simulador é inicializado:

1. SQLITE_ERROR: no such column: X

  • Causa: O DataSource mapeou um campo do Salesforce que não existe no banco de dados local do dispositivo.
  • Diagnóstico no Terminal: Inspecione as colunas físicas da tabela no SQLite:
sqlite3 appl/data/app.db3 "PRAGMA table_info(Visit);"
  • Solução: Se o campo não aparecer na listagem, adicione-o ao Field Set de mobilidade na organização Salesforce (Mobility_relevant) e realize uma nova sincronização móvel.

2. Database is not defined

  • Causa: Em um DataSource scripteado (external="true"), o desenvolvedor tentou executar consultas SQL diretamente dentro da tag <Load> (ex: Database.loadRecordsAsync(...) ou db.exec(...)).
  • Solução: O bloco <Load> é um construtor de queries, não um executor. Ele deve obrigatoriamente RETORNAR a string SQL formatada através de return Utils.replaceMacrosParam(sql, params);.

3. “We couldn’t render this component” em Cockpit Cards

  • Causa: A variável de contexto DisplayedSubcomponentName está retornando null ou um valor que não coincide exatamente com o atributo name do <CockpitList>.
  • Solução: Sincronize a string do <CockpitList name="OpenOrders"> com o literal passado na ação do ProcessFlow: <Input name="type" value="OpenOrders" type="Literal" />.

5. Arquitetura de Internacionalização (i18n): Rótulos de Locale

O Modeler suporta múltiplos idiomas de forma nativa através de arquivos XML organizados na pasta src/Locale/{lang}.locale.xml (como en.locale.xml e pt.locale.xml).

A estrutura do arquivo segue uma hierarquia estrita:

<?xml version="1.0" encoding="UTF-8"?>
<Locale language="pt" languageCode="pt">
  <Translations>
    <!-- SEÇÃO 1: READ-ONLY (Rótulos do Framework: Yes, No, Cancel, Save, OK) -->
    <Framework>
      <Label id="Yes" text="Sim" translationStatus="7" />
      <Label id="No" text="Não" translationStatus="7" />
      <Label id="Save" text="Salvar" translationStatus="7" />
    </Framework>

    <!-- SEÇÃO 2: READ-ONLY (Termos Globais Core: Customer, Product, Visit) -->
    <Global>
      <Label id="Customer" text="Cliente" translationStatus="7" />
    </Global>

    <!-- SEÇÃO 3: EDITÁVEL (Rótulos Customizados das Telas) -->
    <UserInterfaceContracts>
      <!-- Um container <UserInterface> para cada arquivo UI existente -->
      <UserInterface id="Call_DetailUI">
        <Label id="CustomerNotesLabelId" text="Observações Gerais do Cliente" translationStatus="7" />
        <Label id="BtnConfirmRescheduleId" text="Confirmar Reagendamento" translationStatus="7" />
      </UserInterface>
    </UserInterfaceContracts>
  </Translations>
</Locale>

Regras Críticas de Internacionalização:

  1. As Seções Framework e Global São Intocáveis: Nunca adicione ou edite rótulos nessas seções. Elas pertencem ao núcleo da Salesforce e são sobrescritas integralmente durante upgrades do pacote.
  2. Rótulos Customizados Pertencem a <UserInterfaceContracts>: Toda tradução de telas do seu projeto deve ser inserida dentro de um nó <UserInterface id="...">, cujo atributo id deve coincidir exatamente com o nome da tela (ex: Call_DetailUI).
  3. Identificadores de Rótulo Idênticos: O atributo id do <Label> deve ser exatamente o mesmo em todos os arquivos de idioma (en.locale.xmlpt.locale.xmles.locale.xml). Apenas o atributo text varia.
  4. Ciclo de Vida do translationStatus:
  • 1 (Novo): Rótulo criado, aguardando tradução formal.
  • 6 (Revisão Necessária): O texto original em inglês foi modificado e as demais línguas precisam ser ajustadas.
  • 7 (Traduzido e Verificado): Tradução aprovada para produção.

Conclusão

Compreender o comportamento do compilador do Modeler CLI, respeitar as convenções estritas de nomenclatura e aplicar padrões sistemáticos de troubleshooting são os divisores de águas entre projetos móveis caóticos e implementações de alta confiabilidade no Salesforce Consumer Goods Cloud. Ao antecipar falhas de XSD, validar esquemas de banco local preventivamente e manter a disciplina na gestão de rótulos internacionalizados, arquitetos e desenvolvedores garantem pipelines de entrega contínua estáveis e livres de regressões para a operação em campo.

Sua equipe já passou horas tentando decifrar um erro numérico no sf mdl build? Compartilhe suas experiências e dúvidas nos comentários abaixo ou marque seus colegas de engenharia na discussão no LinkedIn.

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *