
Guardar dados e arquivos do app sem migration nem credencial de nuvem
Nesta página · 9 seções
Para guardar dados num app, muitos caminhos exigem desenhar tabelas, escrever a migration e subir o schema antes de gravar o primeiro registro. Para arquivos, costuma-se criar um bucket, gerar credenciais de nuvem e configurar permissões. O Storage existe para encurtar esse começo. Você grava um documento, o esquema nasce dele, e os arquivos vão para um armazenamento que já está ligado à sua instância.
Coleções: o primeiro insert desenha o esquema
O Storage é schema-less. Uma coleção é uma tabela criada na hora: o primeiro documento define as colunas e o tipo de cada uma. Os inserts seguintes gravam no mesmo formato. Se o id já existe, o registro é atualizado (upsert).
import Storage from '@ciromaciel/storage-sdk'
const storage = new Storage('https://storage.manager.myinfrastructure.click', 'stk_sua_chave')
await storage.collection('memories').insert({
id: 'msg_123',
content: 'Usuário prefere modo escuro',
tags: ['ui', 'preferencia']
})
Essa liberdade tem um limite que vale conhecer: o tipo de uma coluna fica fixo pelo primeiro valor que chegou. Se a primeira vez veio um número, mandar texto nessa coluna depois pode ser recusado ou gravado de forma inconsistente, e o SDK não altera o tipo depois. Para carga em lote, insertBulk grava vários documentos de forma atômica internamente, e deleteBulk remove por lista de ids.
Ler funciona com filtros simples: $eq, $gt, $gte, $lt, $lte, $neq e $like, combinados sempre com AND (não há OR). Para paginar, use selectPage, que aceita offset e devolve items e a informação de página; o select devolve só o array de linhas e ignora page/offset.
Arquivos: upload com progresso e cancelamento
Para imagens, PDFs e logs longos, use o módulo de blobs. O upload devolve uma tarefa que você pode acompanhar e cancelar:
const tarefa = storage.blob.upload(arquivo, (p) => {
console.log(`${p.percent}% enviado`)
})
const url = await tarefa.execute()
// tarefa.abort() cancela o envio
O arquivo fica no armazenamento de objetos da instância. Você não recebe chave de bucket e não escreve regra de acesso à nuvem: a chave stk_ já é a credencial do conjunto.
Consultas SQL: leitura, sem escrita
Para agregações e junções simples, storage.sql aceita um SELECT com parâmetros:
const linhas = await storage.sql(
'SELECT categoria, count(*) AS total FROM itens WHERE preco > ? GROUP BY categoria',
[100]
)
Só leitura. INSERT, UPDATE, DELETE e qualquer DDL são recusados. Escrita passa pelas funções do SDK, que validam o que entra.
Duas portas, duas credenciais
O Storage aceita dois tipos de acesso, e a diferença é quem está do outro lado: código de backend com chave de API, ou agente de IA via MCP.
Para o código do seu backend, use a chave de API stk_. Ela sai do painel, aparece mascarada e tem o botão de copiar; é mostrada inteira uma única vez, quando a instância nasce (ou na rotação). Trate como segredo: não a coloque no navegador em produção. Ela dá acesso total à instância dela e a nenhuma outra; não existe chave REST com escopo restrito (os escopos valem só no MCP).
Para um agente de IA, o caminho é o servidor MCP, em https://storage.manager.myinfrastructure.click/mcp/<tenantId>. Aqui não existe chave. O cliente abre o navegador, você entra na sua conta e aprova os escopos, por OAuth 2.1. O tenantId não é segredo: ele aparece na aba MCP do painel e identifica a instância.
Pelo MCP, o agente tem 13 ferramentas: sete de leitura (listar coleções, descrever coleção, consultar coleção, buscar por vetor, SQL, estatísticas e listar arquivos) e seis de escrita (inserir documento, inserir vários, apagar documento, enviar arquivo, gravar arquivo e apagar arquivo). Não existem ferramentas para apagar a instância, apagar uma coleção inteira ou rotacionar a chave. Um agente que lê uma instrução maliciosa não encontra um gatilho para isso.
Quando não usar
O Storage não substitui um banco com transações entre coleções, nem um sistema com JOIN no filtro do select: para cruzar coleções, a via é o SQL, que é só de leitura. Não há assinatura de eventos em tempo real nem webhook de mudança: quem precisa saber que algo mudou consulta. Também não há JOIN entre coleções pelo select; para cruzar, use o SQL, que é só de leitura. Esquema declarado com migrations também não existe. Se o seu app depende disso, o Storage não é a peça certa.
Perguntas frequentes
Preciso criar a tabela antes de gravar?
Não. A coleção nasce no primeiro insert, com as colunas daquele documento. Depois disso, o tipo de cada coluna fica fixo.
Posso guardar embeddings para busca por similaridade?
Sim. Salve o vetor como um array de números num campo e consulte com vectorIndex, vector e vectorTopK no select.
O agente pode apagar dados sem eu perceber?
Ele pode apagar documentos e arquivos individuais, pelas ferramentas de escrita. Não pode apagar a instância, uma coleção inteira nem rotacionar a chave. O que ele fez fica registrado no painel.
Para continuar lendo
Login sem senha com código no e-mail: como funciona e quando usar
Como um agente de IA faz login no seu app: OAuth 2.1 e o passo humano
Dados do próprio app, e nada além
Quando o app guarda o que o usuário produz (notas, preferências, histórico, arquivos enviados), o Storage cuida do armazenamento sem que você administre uma nuvem para isso. Os dados ficam isolados por instância, e você decide o que o agente pode alterar. Conhecer o Storage
Fontes
Quem escreveu
Continue lendo
Como um agente de IA faz login no seu app: OAuth 2.1 e o passo humanoAssunto parecido · · 5 min
Como cobrar assinatura no seu app sem escrever webhookMais recente · · 4 min
E-mail transacional pelo seu domínio: verificação, eventos e supressãoMais recente · · 6 min
Função serverless com agendamento: código sob demanda com um endpointMais recente · · 6 min
Onde hospedar uma SPA em React ou Vite sem quebrar as rotasMais recente · · 5 min
Liberar e bloquear partes do app pelo plano do usuárioMais recente · · 4 min