Conceitos
Dados como arquivos
Por que o Nimbly guarda dados como arquivos simples no Git, o que fica de fora e como continua rápido sem banco de dados.
O Nimbly guarda os dados como arquivos simples no repositório da aplicação. Não há servidor de banco de dados. Um recurso é uma pasta, sua definição é um arquivo JSON, e cada registro é um arquivo JSON próprio. É uma escolha deliberada, e ela define como um projeto Nimbly é construído, compartilhado e operado.
ext/data/projects/
.meta the definition: fields, validation, indexes, permissions
4f1c9a2e7b... one record
9d03b6e1c4... another record
Uma definição, todo o resto acompanha
Um recurso é descrito uma vez, no seu .meta. A partir dessa definição, o Nimbly fornece a visão geral e os formulários do admin, a validação, a API REST e sua descrição OpenAPI, as permissões por operação, o histórico de cada alteração e o contexto que o agente integrado usa. Acrescente um campo ao .meta e tudo isso acompanha. Não há migrações: um campo novo simplesmente fica vazio nos registros antigos até alguém preenchê-lo.
Um id por registro, em todo lugar
Cada registro ganha um id curto e aleatório ao ser criado, como 1ztuvo56o5vze6t0. O id é o nome do arquivo do registro, e nunca muda.
Bancos de dados costumam numerar suas linhas 1, 2, 3. Esses números pertencem a um banco: outro ambiente distribui os mesmos números para registros diferentes, então mover ou juntar dados significa renumerar registros e corrigir todas as referências a eles. No Nimbly esse problema não existe:
- Um registro é o mesmo registro em todo lugar: em desenvolvimento, em staging, em produção, no Git, na API e numa exportação.
- As referências se mantêm. Um campo que aponta para outro registro guarda o id dele, e continua apontando para o mesmo registro aonde quer que os dados vão.
- O conteúdo se move livremente. Registros criados em máquinas ou branches diferentes se juntam sem conflitos, e uma importação em outro site mantém todos os ids.
- Seus próprios ids também funcionam. Um registro pode receber o id que tem em outro sistema, como um número de pedido.
Os visitantes nunca veem esses ids: os endereços públicos usam um slug legível, como /projects/harbour-atlas.
Sem camada de banco de dados
Como os dados são arquivos, uma camada inteira de uma stack web típica simplesmente não existe:
- nenhum servidor de banco de dados para instalar, rodar, proteger, ajustar e fazer backup à parte,
- nenhum ORM ou camada de consultas entre o código e os dados,
- nenhuma migração, e nenhum schema para manter igual entre desenvolvimento, staging e produção,
- nenhuma configuração de conexão nem credenciais de banco,
- nenhum dump para exportar e importar ao compartilhar ou mover um site.
Um site Nimbly é uma pasta: código, conteúdo e dados juntos. Isso mantém a stack pequena, a hospedagem simples e todas as partes da aplicação legíveis.
O conteúdo fica no Git, ao lado do código
Como os registros são arquivos em ext/, o conteúdo é versionado junto com o código que o usa:
- Histórico e reversão. Cada mudança de conteúdo é um commit que você pode inspecionar, comparar e reverter, no mesmo histórico dos templates que o exibem.
- Branches. Um branch de funcionalidade carrega seu próprio conteúdo: um recurso novo com registros de exemplo, uma página reescrita, um menu alterado. Revise e faça merge do conteúdo como de código.
- Diffs pequenos e claros. Um registro é um arquivo, então uma mudança toca só esse registro, e duas pessoas editando registros diferentes nunca entram em conflito.
- Os ambientes ficam alinhados. Desenvolvimento, staging e produção compartilham conteúdo pelo repositório. Quando editores trabalham em produção, o
ext:syncagendado commita as mudanças deles e as envia de volta, para que o próximo deploy e todos os desenvolvedores partam delas. Veja Ambientes.
Clone, e o site está lá
Clonar o repositório da aplicação traz todos os registros, textos de página, configurações, traduções e arquivos de mídia. Rode o setup e o site local mostra o conteúdo real na hora: nenhum banco para instalar, nenhum dump para importar, nenhuma conexão para configurar. O mesmo vale para um agente de programação com IA: ele lê as definições de dados e os registros como arquivos, ao lado do código que os usa.
O que fica fora do Git
Nem tudo o que um site contém pertence a um repositório. O setup escreve um ext/.gitignore que mantém isto em cada ambiente:
| Mantido por ambiente | Por quê |
|---|---|
| Contas de usuário | Senhas e dados pessoais não viajam com o código; cada ambiente tem seu próprio admin |
| Sessões, fila de jobs, estado do agendador | Estado de runtime que muda a cada minuto |
| Histórico de registros | Mantido por 90 dias no ambiente onde a mudança foi feita |
| Caches e imagens redimensionadas | Recriados quando necessário |
.env |
Credenciais e o PEPPER do qual dependem os campos criptografados |
Assim, um repositório guarda o conteúdo e a estrutura do site, e um backup de um site em produção também cobre o que o Git não tem. Veja Backup e recuperação.
Rápido sem banco de dados
Ler um arquivo é rápido, e o Nimbly evita ler o que não precisa:
- Índices. Um campo listado em
indexganha um caminho de busca, para que um slug num endereço encontre seu registro diretamente. - Cache de listas. Para cada campo pelo qual uma página filtra ou ordena, os valores de todos os registros ficam juntos num arquivo de cache, então uma página de 20 entre 50.000 lê 20 registros.
- Cache de consultas. Os resultados das consultas ficam em cache e são invalidados a cada escrita, venha ela do site, da API, do Git ou de uma sincronização.
- Diretórios divididos. Uma pasta com muitíssimos arquivos deixa o sistema de arquivos lento.
"splitdir": trueno.metade um recurso espalha seus registros por dois níveis de subpastas pelo UUID, para que cada pasta continue pequena. Ative-o num recurso que passe de uns 10.000 registros; nada mais muda, nem nos templates, nem nas bibliotecas, nem na API.
Com diretórios divididos e índices, um recurso suporta cerca de 100.000 registros. As escritas num recurso acontecem uma de cada vez, o que mantém os registros consistentes, também com vários contêineres num volume compartilhado.
Projetando recursos com isso em mente
- Um recurso por tipo de coisa. Projetos, pessoas e setores são recursos separados; um campo
selectaponta de um para outro. - Indexe o que você busca. Slugs, endereços de e-mail, ids externos.
- Mantenha os registros focados. Um registro é lido inteiro: coloque dados grandes ou pouco usados num recurso próprio em vez de num campo que só cresce.
- Use os campos do sistema. Todo registro tem
uuid,_created,_modifiede quem os criou; não é preciso criar campos próprios para isso.