Sistema de arquivos
Buildprint materializa uma ramificação do Bubble como uma árvore de pequenos arquivos que você edita como código. Quando você executa buildprint apply, a CLI lê esses arquivos, recompõe-os em um JSON de app do Bubble e envia o trabalho para o Bubble.
Esta página é a referência para essa árvore de arquivos projetada: o que cada diretório contém, como os arquivos são formatados, como funcionam os IDs de entidade e o que você não deve alterar. Para o modelo de git-ref e worktree por trás de um workspace (snapshots, refs publicadas, sync e apply), veja a página Workspaces.
Por que uma árvore de arquivos, e não JSON bruto
Um app do Bubble é um grande objeto JSON. Editá-lo diretamente gera diffs inutilizáveis, conflitos impossíveis de mesclar e nenhum lugar natural para um agente usar grep e editar. Buildprint projeta esse JSON em um arquivo por entidade relevante, de modo que:
Os diffs permanecem pequenos e localizados na entidade que você alterou.
O merge padrão em três vias do git funciona durante
sync, porque os arquivos são pequenos e a serialização é determinística.Você edita com as ferramentas que já usa (
read,grep,edit) em vez de fazer cirurgia com JSON path.
A projeção é uma representação normalizada e editável, não um despejo fiel aos bytes. Campos voláteis e derivados do Bubble são removidos na entrada e reconstituídos na saída.
Layout dentro de uma ramificação
Cada ramificação do Bubble é um worktree do git em <app-root>/<branch>/. Dentro dele, a árvore se parece com isto:
<branch>/
app.json # top-level app scalars only
settings/
client-safe.json # Bubble settings minus keys lifted elsewhere
api-connector/<plugin-id>/
plugin.json
calls/<call-id>.json
translations/
index.json # app-text ids -> label or true
<language>.json # full locale object for one language
data_types/<type-id>/
type.json # fields inline
option_sets/<id>/
option-set.json # values inline, ordered by sort_factor
styles/
<Type>/<style-id>.json # grouped by element type
tokens.json # color tokens
defaults.json # default styles + default icon set
fonts.json # font tokens + fonts
pages/<page-id>/
page.json # page props + root children: [...]
elements/<map-key>/
element.json # props, type, style, states
<child-map-key>/element.json
workflows/<wf-id>/
workflow.json # trigger + meta + action ordering
actions/<step>.json # one file per editor step
element-definitions/<id>/ # reusables, same shape as pages
mobile-views/<id>/ # mobile screens, same shape as pages
global-elements/<id>/ # shared surfaces, same shape as pages
api/
<folder-id>/
config.json # { "name": "Folder name" }
<wf-id>/
workflow.json
actions/<step>.json
<wf-id>/ # backend workflow with no folder
workflow.json
actions/<step>.json
pages/<page-id>/workflows/<folder-id>/
config.json
<wf-id>/
workflow.json
actions/<step>.json
issues/<source-id>/<index>.json # read-only Bubble issue checker outputapp.json
Somente escalares do app no nível superior. Tudo o que tem identidade própria (uma página, um tipo de dado, um workflow) é colocado no próprio diretório, para que este arquivo permaneça pequeno.
pages/, element-definitions/, mobile-views/, global-elements/
As quatro raízes de canvas de elementos. Cada raiz recebe um diretório nomeado pelo seu id, contendo um arquivo raiz (page.json, ou reusable.json para definições de elementos) além de uma árvore elements/ e uma árvore workflows/.
As pastas de elementos espelham a contenção: se o elemento B é filho do elemento A, a pasta de B fica dentro da pasta de A. O nome da pasta é a chave de mapa do elemento no objeto elements que o contém, o que não é o mesmo que o campo interno id do elemento. Veja “Element IDs and references” abaixo.
Workflows de nível de página e de nível reutilizável ficam em workflows/<wf-id>/, com o trigger e os metadados em workflow.json e um arquivo por ação em actions/. Os arquivos de ação são nomeados pelo número de etapa do editor começando em 1 (1.json, 2.json, ...); eles são recompostos de volta para as chaves brutas de ação baseadas em zero do Bubble.
api/
Backends (workflows do lado do servidor), agrupados em pastas. Um workflow que pertence a uma pasta do Bubble fica em <folder-id>/<wf-id>/, com o nome exibido da pasta em um config.json irmão. Um workflow sem pasta fica diretamente em api/<wf-id>/. As pastas de backend de escopo de página aparecem em api/pages/<page-id>/workflows/.
data_types/, option_sets/
Um diretório por tipo de dado ou conjunto de opções, cada um com um único arquivo. Os campos de tipo de dado são incorporados em type.json. Os valores do conjunto de opções são incorporados em option-set.json, ordenados por sort_factor.
styles/
Estilos nomeados agrupados pelo tipo de elemento do Bubble ao qual se aplicam: styles/<Type>/<style-id>.json. O valor type não é repetido no corpo do arquivo; o nome do diretório é a fonte da verdade para isso. Estilos sem tipo ficam em um diretório sentinela bp_no_type/. Três arquivos irmãos guardam tokens de design que foram extraídos do corpo do estilo: tokens.json (cores), defaults.json (estilos padrão e conjunto de ícones) e fonts.json (fontes).
settings/
client-safe.json contém as configurações do app Bubble, menos as partes que foram levadas para suas próprias árvores. api-connector/ contém um diretório por plugin do API Connector, com suas chamadas divididas em arquivos separados. translations/ contém index.json (os ids de texto do app, cada um mapeado para um rótulo ou para o marcador true do Bubble) mais um <language>.json por localidade.
issues/
Uma projeção somente leitura da saída do verificador de issues do próprio Bubble, gravada durante o sync para que você possa inspecionar os problemas sinalizados pelo Bubble. Este diretório é ignorado ao fazer assemble; o Bubble recompõe essas entradas por conta própria, então editar aqui não produz efeito.
Campos deslocados: edite o layout, não o corpo
Vários campos do Bubble são representados pela estrutura de diretórios, e não por um valor em um arquivo. Eles são removidos no sync e reconstituídos a partir da árvore no apply. Para alterar um deles, mova ou renomeie o layout, não uma chave JSON:
Tipo de estilo: o diretório
styles/<Type>/em que um arquivo de estilo fica.Pertencimento de workflow a pasta e nome da pasta: o diretório
api/<folder-id>/e seuconfig.json.Ids de texto de tradução e texto por localidade:
settings/translations/index.jsone<language>.json.
O corpo do arquivo nunca repete um campo deslocado.
Ordem dos elementos filhos: children: []
O arquivo de cada elemento contém um array children listando as chaves de mapa dos filhos diretos na ordem de exibição:
{
"type": "Group",
"children": ["aBcDe", "fGhIj"]
}buildprint check impõe que o conjunto de subpastas de um elemento seja exatamente igual ao conjunto de chaves de mapa em seu array children. O array é o manifesto canônico local da ordem de exibição. Para reordenar filhos, reordene o array. Não edite manualmente properties.order nem properties.zindex para reordenar: esses são campos reais do Bubble para ordem de renderização, e o Buildprint nunca os sintetiza quando o JSON de origem já não os incluía.
Element IDs and references
O nome da pasta de um elemento é sua chave de mapa no objeto elements pai. Seu id interno vive dentro de element.json e normalmente é uma string diferente (a chave de pasta bTKHu pode conter um elemento cujo id é bTKHJ).
Essa distinção importa quando você segue referências. As referências cruzadas do Bubble, como destinos element_id de workflow, ações ShowElement / HideElement / DisplayGroupData e expressões GetElement, apontam para o id interno, não para a chave da pasta. Não resolva uma referência fazendo grep por um segmento de pasta. Use buildprint context <element-path-or-id-or-map-key> para uma busca ciente de referências e buildprint tree para ver a contenção e a visibilidade efetiva.
O Bubble gera e possui esses ids. As novas entidades que você criar pela CLI receberão ids atribuídos para você; você não os cria manualmente.
Formato canônico de JSON
Um único formatador é o único escritor desses arquivos, e cada arquivo é determinístico: o mesmo app sempre produz os mesmos bytes. É essa determinismo que torna sync passível de merge. As regras:
UTF-8, finais de linha LF, uma nova linha final, indentação de 2 espaços.
Sem espaços em branco no fim da linha, sem retornos de carro, sem tabulações.
As chaves dos objetos são ordenadas alfabeticamente, seguindo a forma como o Bubble as lê.
Mapas com chaves inteiras (workflow
actions, elementstates,TextExpression.entries) preservam sua ordem numérica em vez de serem classificados, e lacunas esparsas são mantidas literalmente.
Escreva suas edições e deixe a CLI reformatar na próxima ida e volta; não brigue com o formatador tentando ajustar manualmente o espaçamento ou a ordem das chaves.
campos _bp_
O layout de elementos carrega um auxiliar _bp_layout. O prefixo _bp_ é reservado para Buildprint; não crie você mesmo chaves _bp_*.
O que não editar
.buildprint/
na raiz do app. Isso contémapp.json` (id do app e referência do token) e o repositório git bare compartilhado dos snapshots do Bubble. É gerenciado pelo Buildprint e excluído dos seus commits via o arquivo de exclusão local do git. Nunca edite nem comite isso.issues/dentro da ramificação. Verificador de issues somente leitura; ignorado no apply.
Validando e aplicando
A árvore de arquivos não é validada enquanto você digita. Execute buildprint check para hidratar o escopo alterado e executar as regras de referência e estrutura, depois buildprint apply para compilar suas edições no Bubble e aplicá-las.