01Visão geral do projeto
keepix.cloud é um host de mídia para produtos que precisam servir arquivos de outras pessoas: fotos de catálogo em uma vitrine, imagens de avaliações em um marketplace, vídeo de walkthrough em um aplicativo. Você envia o original em uma solicitação assinada, e a resposta já traz os endereços finalizados — um conjunto nomeado de variantes WebP para uma imagem, uma escada HLS para um vídeo. Os arquivos são servidos do próprio subdomínio do cliente, então o leitor vê sua marca e nunca nos vê.
A premissa é que a mídia não é um recurso que você constrói uma vez por projeto. Todo produto que permite que as pessoas enviem algo acaba escrevendo a mesma coisa novamente: redimensionamento, conversão de formato, um esquema de nomenclatura, uma política de cache, remoção de metadados, um caminho para deletar-tudo-sobre-esta-pessoa. Escrito uma quinta vez, é escrito mal uma quinta vez — e as partes que dão errado (uma tag GPS vazada, um SVG que acabou sendo um script) falham silenciosamente, sem um erro e sem uma linha de log.
Então construímos o serviço em torno de uma ideia: o endereço é declarado pelo serviço e armazenado pelo cliente, nunca computado do lado do cliente. Essa única decisão remove a maneira mais comum como as integrações de mídia falham — uma página que renderiza perfeitamente com um buraco onde a foto do produto deveria estar.
Nós projetamos e construímos todo o produto: o pipeline de entrada, o modelo de variantes, a escada de vídeo, o modelo multi-inquilino com seus próprios domínios e chaves de assinatura, a cobrança medida, o painel, o contrato da API pública e a documentação. Abaixo está qual problema ele resolve, como é montado e quais decisões de engenharia faríamos da mesma forma novamente.
02Contexto e o problema
Armazenar uma imagem enviada é fácil. Manter um caminho de mídia que permaneça correto por anos, sob carga, em vários produtos e arquivos de outras pessoas, não é. Quando analisamos a tarefa, as armadilhas apareceram rapidamente.
- Larguras arbitrárias são uma armadilha.Uma URL como
?w=473parece flexível e, na verdade, é dois problemas ao mesmo tempo: um cache que nunca esquenta, porque cada página pede um número ligeiramente diferente, e uma maneira gratuita para qualquer um ocupar o processador pedindo mil larguras em sequência. - Um endereço computado quebra silenciosamente.A regra "id → shard → path", embutida no código do cliente, sobrevive exatamente até a primeira mudança de layout do outro lado. Então a página ainda é renderizada e o produto simplesmente tem um buraco onde sua foto estava — sem erro, nada no log.
- Metadados são um vazamento que ninguém percebe.As coordenadas GPS da casa de alguém, presentes no EXIF de uma foto de avaliação, não geram erro, não quebram a página e não alcançam monitoramento. É apenas um vazamento quando alguém olha.
- SVG não é uma imagem.É uma marcação executável. Aceito como uma imagem e servido do próprio domínio do cliente, um script dentro dele é executado em nome desse domínio.
- A exclusão precisa ser comprovável.Um pedido de exclusão do GDPR respondido marcando linhas como deletadas enquanto os bytes permanecem no disco é uma exclusão que não aconteceu.
- Vídeo é um conjunto, não um arquivo.Um upload precisa se tornar uma escada reproduzível, um quadro de pôster e uma alternativa — e nada disso pode acontecer dentro da solicitação que aceitou o arquivo.
- A cobrança precisa ser honesta em números pequenos.Um gigabyte pode custar menos de um centavo; arredondar para centavos inteiros consome toda a fatura medida e torna a fatura uma ficção.
Havia um requisito a mais, e ele moldou todo o design: o serviço não deve sair para a internet de forma alguma. Um host de mídia que busca uma imagem de um endereço de terceiros em nome do cliente sabe quem pediu o quê e entrega esse conhecimento a qualquer CDN que usou. keepix não conhece nenhum endereço de terceiros, e isso é uma propriedade do código, não uma promessa na página de preços.
03Objetivos do projeto
A tarefa se transformou em uma lista de metas que mantivemos em cada etapa:
- Um pedido recebido, endereços finalizados. O cliente envia o original e imediatamente recebe de volta os endereços para armazenar — sem segunda chamada, sem esperar que um trabalho termine para imagens.
- Um conjunto nomeado e finito de variantes. Três larguras para imagens e quatro formas para vídeo, declaradas por tipo de arquivo, para que o cache esteja aquecido e o processador não esteja à disposição.
- O domínio próprio do cliente. Arquivos servidos de
img.theirdomain, com o serviço invisível na barra de endereços. - Um cache que pode ser mantido para sempre. O endereço carrega um hash do conteúdo, então substituir um arquivo muda seu endereço e atinge o leitor de imediato.
- Segurança embutida no caminho. Tipo determinado pela análise, uma verificação de vírus que recusa em vez de deixar passar, re-encodificação em cada imagem, metadados removidos, SVG recusado em ambas as extremidades.
- Apagamento comprovável. Um pedido pelo próprio cliente
owner_ref, e uma resposta que nomeia quantos objetos e arquivos foram. - Multi-inquilino com isolamento real.Domínios próprios, tipos e variantes próprios, tetos próprios, duas chaves de assinatura para que a rotação não cause tempo de inatividade.
- Cobrança medida que você pode verificar.Armazenamento como uma média em vez de um pico, tráfego como os bytes realmente entregues, operações contadas uma a uma — detalhadas por dia no painel.
- Uma API que admite o que fez.Cada resposta diz o que foi feito e o que foi pulado, e há um endpoint de reconciliação seca para verificar uma migração em lotes.
04O que fizemos
keepix se divide em algumas partes claras, cada uma com uma função:
- Recepção. Um endpoint assinado aceita o original com seu tipo, sua chave e a lista de variantes desejadas. As imagens retornam prontas na mesma resposta; o vídeo entra em uma fila e a resposta informa isso.
- O pipeline de processamento. Detecção de tipo, verificação de vírus, re-encodificação, remoção de metadados, construção de variantes — em uma ordem fixa que não pode ser pulada por solicitação.
- Entrega. Um host separado sem sessões, sem JavaScript e sem
Set-Cookie, servindo arquivos diretamente do disco com um cache imutável de um ano. - A API do inquilino. Assinada com HMAC-SHA256, com endpoints para resolver endereços, reconciliar em lotes, exportar um inventário, deletar um objeto e apagar tudo que pertence a uma pessoa.
- O painel.Pastas, arrastar e soltar, pesquisa por título, descrição e tags — e uso detalhado por dia. Funciona totalmente sem JavaScript; o script adiciona conveniência, não a capacidade de trabalhar.
- Faturamento.Pacotes mais excesso medido, mantido em centésimos de centavo, com a entrada parando em vez de gastar dinheiro silenciosamente no plano gratuito.
- O estoque.Uma camada de mercado onde os inquilinos podem comprar e vender seu próprio trabalho, compartilhando o mesmo armazenamento e caminho de entrega.
Tudo abaixo é uma análise mais detalhada das decisões dentro dessas peças — aquelas que seriam caras para mudar mais tarde.
05Arquitetura da solução
O serviço é três espaços com pontos de entrada fisicamente separados, e essa separação é a espinha dorsal de todo o design:
- Entrega pública — sem API alguma. O servidor web procura o arquivo no disco e o serve. Não encontrado significa 404, não "gerar no momento". Não há código executável nesse caminho, que é o motivo pelo qual o host de entrega pode carregar
default-src 'none'; sandboxe levar isso a sério. - A API privada do inquilino. Cada solicitação assinada; a assinatura cobre o método, o caminho com sua string de consulta, o timestamp e um hash do corpo. Assinar o caminho sem a consulta deixaria
tipoechavenão assinado — intercambiável, e ninguém notaria. - A API de administração para o painel de controle, em seu próprio ponto de entrada com suas próprias credenciais.
As respostas são sempre JSON e sempre em inglês, com uma redação por código de recusa — assim, a mesma falha é registrada da mesma forma no log de cada cliente, independentemente do idioma que seu produto fala.
Dentro, o armazenamento se divide em uma árvore fria que mantém os originais, que nunca são servidos externamente, e a árvore servida de variantes. Manter o original é o que torna uma nova variante possível um ano depois sem pedir ao cliente para enviar nada novamente — e é também por isso que "não servimos o arquivo que você enviou" pode ser uma regra absoluta em vez de uma geralmente.
06A vida de um arquivo
Um arquivo passa por uma sequência fixa, e a ordem é o ponto:
- O tipo é determinado pela análise — a partir do conteúdo, não da extensão e não do que o cliente diz que é. A extensão do arquivo de saída é atribuída pelo serviço.
- A verificação de vírus é executada, e ela pode recusar. Se o scanner estiver inacessível, a entrada responde
503em vez de deixar o arquivo passar. Passar um arquivo silenciosamente enquanto a verificação está inativa é uma mentira sobre o trabalho realizado, e é o tipo de mentira que só aparece muito depois. - A imagem é re-encodificada. Nenhum byte do arquivo que chegou é servido de volta.
- Os metadados não sobrevivem à re-encodificação. EXIF e GPS estão ausentes por causa de como o caminho é construído, não porque quem fez o upload se lembrou de removê-los.
- As variantes são construídas e seus endereços são retornados na mesma resposta.
SVG não é aceito nem servido — nunca, na entrada ou na saída. A verificação é executada duas vezes, no tipo de conteúdo declarado e nos primeiros bytes do arquivo, porque para SVG um sniffer de tipo frequentemente dirá apenas "texto". O que é servido é WebP, JPEG, PNG, MP4, uma lista de reprodução HLS e seus segmentos; tudo o mais é um 415.
A entrada é idempotente: o mesmo sha256 sob a mesma chave não refaz o trabalho e retorna os mesmos endereços. As tentativas após uma conexão quebrada são, portanto, gratuitas, o que é importante quando o arquivo tem dois gigabytes e a rede é um telefone.
07Variantes nomeadas, não larguras arbitrárias
As imagens têm três larguras nomeadas — miniatura 400, cartão 1000, completo 1400, todos WebP com qualidade 82 — e você solicita uma variante pelo nome. O conjunto é finito e declarado por tipo de arquivo. Esta é a decisão em que todo o serviço se baseia, e ela remove uma classe de problemas em vez de um bug.
Duas regras governam quando uma variante pode legitimamente não aparecer, e ambas existem para evitar mentir ao leitor:
- Nada é esticado. Se o original é mais estreito do que a largura da variante, a variante permanece no tamanho do original e a resposta diz isso honestamente — os
wehcampos carregam os números reais. Uma cópia ampliada parece ser culpa do serviço, e realmente seria. - Cópias idênticas não são armazenadas duas vezes.Se duas larguras produzirem o mesmo arquivo, o segundo endereço não é criado. Dois arquivos idênticos em bytes em dois endereços são dois downloads da mesma coisa no telefone de alguém.
O que significa que a resposta deve ser lida, não assumida: você pode pedir duas variantes e receber uma, com um pulada bloco explicando o porquê. Tornamos isso uma resposta normal e esperada, em vez de um caso extremo, porque uma integração escrita contra a forma otimista quebra na primeira imagem pequena que um usuário faz upload.
Adicionar uma nova variante mais tarde não requer reenvio de nada: ela é construída a partir do original na árvore fria. Essa é a razão pela qual o original é mantido.
08Vídeo: uma escada HLS, um pôster e uma prévia
Um upload de vídeo se torna um conjunto, porque é isso que um jogador realmente precisa: um escada HLS de até três passos de qualidade (640, 1280 e 1920 px), um pôster retirado a 10% da duração, um preview silencioso dos primeiros segundos para hover e autoplay no feed, e um MP4 como uma alternativa para clientes mais antigos.
Um passo mais largo do que o original não é feito, pela mesma razão que uma imagem esticada não é: uma cópia ampliada parece um erro do serviço. O pôster é retirado a um décimo da duração em vez de no primeiro quadro, porque o primeiro quadro de um vídeo real é muito frequentemente preto.
O processamento de vídeo não acontece dentro da solicitação que aceitou o arquivo — ele vai para uma fila, e a resposta diz isso. A resposta de recebimento é honesta sobre quais partes estão prontas agora e quais estão pendentes, para que um cliente possa armazenar o que tem e perguntar novamente mais tarde, em vez de bloquear a tela de upload de um usuário durante uma transcodificação.
09Seu próprio domínio e um cache para sempre
Os arquivos são servidos do próprio subdomínio do inquilino — img.theirdomain — que o inquilino aponta para o serviço com um registro A. O leitor vê sua marca e seu endereço, e não vê o keepix de forma alguma. No plano gratuito, o domínio é compartilhado; ambos os caminhos funcionam da mesma maneira.
Um inquilino pode conectar quantos domínios quiser, mas exatamente um canônico um, e essa restrição é deliberada: com dois domínios canônicos, um arquivo recebe dois endereços, o que significa dois caches e os mesmos bytes baixados duas vezes no telefone do mesmo leitor.
Os cabeçalhos de entrega são os mesmos para todos os inquilinos e não mudam: um ano inteiro imutável cache, nosniff, default-src 'none'; sandbox, uma política CORS permissiva para leitura, e não um único Set-Cookie. O cache eterno é seguro precisamente porque o endereço carrega um hash do conteúdo: mude os bytes e o endereço muda com eles, então uma imagem substituída chega ao leitor imediatamente em vez de esperar um TTL.
E é exatamente por isso que o endereço não pode ser computado do lado do cliente. Ele é retornado pelo serviço, armazenado ao lado do registro ao qual pertence, e solicitado novamente através de resolver se for perdido.
10Recepção: tipo, verificação de vírus, metadados
Tudo no serviço é um arquivo que alguma pessoa enviou — uma foto em uma avaliação, um vídeo de walkthrough. As regras de entrada são escritas para o bem deles, em vez de por uma questão de forma, e cada um deles existe porque a alternativa falha silenciosamente.
Determinar o tipo por análise em vez de por extensão não é pedantismo: a extensão é a única coisa que um uploader controla completamente.Recusar quando o scanner está fora do ar custa disponibilidade e compra a garantia de que "escaneado" significa escaneado.Recodificar cada imagem significa que um arquivo elaborado nunca chega a um leitor em sua forma original.Removendo metadados durante essa re-encode significa que não pode ser esquecido.
Do lado da entrega, as garantias são estruturais em vez de procedimentais. O host de entrega não tem sessões, nenhum JavaScript e nenhum código executável no caminho; o conteúdo é enviado com uma política de segurança de conteúdo que impediria um navegador de executar qualquer coisa, mesmo que algo perigoso tivesse entrado. Duas camadas independentes, porque as falhas interessantes são aquelas em que a primeira camada foi mal configurada e ninguém percebeu.
O log de entrega, com os endereços dos leitores, vive 24 horas. Nada no serviço precisa disso por mais tempo, o que torna mantê-lo por mais tempo uma simples acumulação de rastros de outras pessoas.
11Apagando tudo sobre uma pessoa
Cada objeto carrega um owner_ref — como o inquilino chama o proprietário daquele arquivo. Para imagens de catálogo, está vazio: elas não dizem respeito a uma pessoa. Para fotos de avaliações e vídeos de usuários, é necessário.
Um pedido apaga tudo abaixo dele, e a resposta nomeia um número: quantos objetos e quantos arquivos foram. Esse número é o ponto do endpoint. Um portão de dados pessoais deve verificar a execução, não a intenção — uma linha marcada como excluída enquanto os bytes ainda estão no disco é uma exclusão que não aconteceu, e continuará não acontecendo até que alguém olhe.
A exclusão remove registros e bytes de uma vez, em vez de em um cronograma, e leva as cópias adiadas de versões anteriores com ela. É também a parte que torna o keepix utilizável a partir de um produto com suas próprias obrigações de GDPR: um fluxo de exclusão no código do cliente pode chamá-lo inline e ler a contagem de volta, em vez de confiar que um trabalho de limpeza em algum lugar irá resolver isso.
As chaves de assinatura funcionam da mesma forma.Um inquilino sempre tem duas em uso, porque com uma rotação de chave significa tempo de inatividade — e o tempo de inatividade é o motivo pelo qual a rotação é adiada para sempre. O segredo é mostrado uma vez na emissão e nunca devolvido ao painel de controle: ser capaz de assinar uma solicitação é o direito de escrever no armazenamento de outra pessoa.
12Uma API assinada e reconciliação
Cada solicitação privada carrega quatro cabeçalhos — inquilino, id da chave, timestamp e assinatura — e a assinatura é HMAC-SHA256 sobre o método, o caminho completo com consulta, o timestamp e o hash do corpo. A janela é de 300 segundos. Uma solicitação assinada idêntica repetida dentro do mesmo segundo é recusada como uma repetição, que é a proteção funcionando como pretendido, e o contrato diz isso claramente em vez de deixar os integradores descobrirem.
O conjunto de endpoints é pequeno e cada um responde a uma pergunta operacional real:
colocar— aceitar um original;colocar-variável— aceitar uma cópia já finalizada sem re-encodificá-la, para mover o que um cliente já possui. Re-encodificar uma cópia finalizada significa perder qualidade sem necessidade.resolvereresolver-lote(até 1000 chaves) — quais endereços esta chave possui. Esta é uma ferramenta de reparo: se um registro estiver perdido, você pergunta em vez de adivinhar.reconciliar— uma verificação a seco, até 1000 registros por vez, que não muda nada e respondeok/faltando/incompatibilidade/pendentepor registro mais um resumo do lote.inventário— a exportação que executa a comparação na outra direção, a lista do serviço contra a do cliente, paginada pela chave em si para que a página não deslize enquanto as coisas estão sendo aceitas durante o processo.objeto,apagar,cota,ping, e um não assinadohealthzque diz que o front end está vivo e nada mais — sem versão, sem estado do banco de dados.
A reconciliação merece sua própria nota, porque é o endpoint que justifica todo o contrato. Após uma grande migração, há exatamente uma pergunta que importa: tudo passou? Respondê-la um arquivo de cada vez significa tantas solicitações quantos são os arquivos, então ninguém faz isso — e então uma migração é declarada concluída com base no script de upload não ter travado. A reconciliação em lote torna a resposta honesta barata o suficiente para realmente ser obtida.
13Painel, uso e faturamento
O painel é uma biblioteca sem código algum: pastas, arrastando arquivos com o mouse, busca por título, descrição e tags. Funciona totalmente sem JavaScript — o script adiciona conveniência, não a capacidade de trabalhar. Isso não é nostalgia; é a maneira mais barata de garantir que o painel permaneça utilizável em uma conexão ruim e continue testável sem um motor de navegador.
O uso é contado desde o início do mês e dividido por dia: quanto armazenamento, quanto tráfego de entrega e quantas operações ocorreram em cada data, quanto do pacote foi consumido e o que veio a mais. A divisão importa mais do que o total — uma conta que você não pode atribuir a um dia é uma conta com a qual você não pode discutir.
Três decisões na cobrança merecem ser mencionadas:
- O armazenamento é a média ao longo do período, não o pico.Um único dia com um grande upload não deve precificar o mês inteiro.
- O tráfego de entrega são os bytes realmente entregues, retirados do log do servidor — não "tamanho do arquivo × número de solicitações", que exagera cada solicitação de intervalo e cada download abandonado.
- As tarifas são mantidas em centésimos de centavo.Um gigabyte pode custar menos de um centavo; arredondar para centavos inteiros consumiria toda a fatura medida e transformaria a fatura em ficção.
No plano gratuito, não há cobrança medida: a captação para em vez de começar silenciosamente a gastar o dinheiro do cliente. Um serviço que decide por conta própria cobrar alguém que nunca inseriu um cartão é um serviço que ninguém recomenda duas vezes.
14Pilha de tecnologia
Escolhemos a pilha para um serviço cujo caminho quente é um servidor web entregando um arquivo:
- PHP 8.4 para a API e o painel de controle — maduro, rápido o suficiente nesse caminho e barato para manter em funcionamento, o que é importante para um produto com um nível gratuito.
- Um host de entrega dedicado servindo diretamente do disco, sem código de aplicação no caminho da solicitação.
- WebP para imagens com qualidade fixa, H.264 + AAC em HLS para vídeo com um fallback progressivo em MP4.
- Uma fila para trabalho de vídeo, então uma transcodificação nunca fica dentro de um pedido de upload.
- HMAC-SHA256 assinatura de pedido com duas chaves ativas por inquilino e uma janela de 300 segundos.
- Uma árvore fria de originais fora do caminho servido, que é o que torna novas variantes e reconstruções possíveis mais tarde.
O serviço é deliberadamente conservador no que depende. Ele não faz solicitações externas por conta própria, não usa CDN de terceiros e não mantém registros sobre os usuários do cliente além de inquilino, chave, tipo, contagem de bytes e variantes. Cada dependência que você não tem é uma dependência que não pode quebrar sua mídia em uma terça-feira.
15Design e UX
O site público tinha uma única tarefa: tornar um produto de infraestrutura legível para o engenheiro que realmente irá integrá-lo. Assim, a primeira tela mostra o pedido real e a resposta real — os endereços retornando em JSON — em vez de uma abstração deles. Um integrador decide em cerca de trinta segundos se um serviço de mídia se encaixa em seu código, e eles decidem olhando para a forma de sua resposta.
O restante do site é escrito da mesma forma. Cada capacidade é declarada junto com sua restrição: variantes nomeadas epor que larguras arbitrárias são recusadas; um cache eternoeo hash no endereço que o torna seguro; um ponto final de apagamentoeo número com o qual ele responde. Documentação que apenas lista o que um serviço pode fazer deixa o leitor descobrir as bordas em produção.
No painel, o mesmo princípio se transforma na linha de base sem JavaScript e na divisão do uso dia a dia: nada na tela que o leitor não possa verificar, e nada que pare de funcionar quando um script falha ao carregar.
16Como trabalhamos
O projeto foi realizado em etapas, cada uma terminando em algo demonstrável:
- Contrato primeiro.Escrevemos o contrato da API — esquema de assinatura, pontos finais, códigos de recusa, formas de resposta — antes da implementação, porque o contrato é a parte contra a qual os clientes constroem e a parte que é cara de mudar.
- Recepção e variantes.O pipeline, em sua ordem fixa, com as duas regras sobre não esticar e não armazenar duplicatas incorporadas desde o início.
- Entrega.O host separado, o conjunto de cabeçalhos, o endereçamento com hash de conteúdo que torna o cache eterno seguro.
- Vídeo.A escada, o cartaz e a pré-visualização, e a fila que continua a transcoder a partir da solicitação de upload.
- Multi-inquilino.Domínios, tipos, variantes, limites e o modelo de rotação de duas chaves.
- Faturamento e painel.Contagem medida com um detalhamento dia a dia, depois a interface da biblioteca em cima disso.
- Uma migração real.Movemos um catálogo ativo para o serviço e o reconciliamos em lotes — que é como o endpoint de reconciliação ganhou sua forma.
Essa última etapa valeu mais do que qualquer quantidade de testes internos. Mover centenas de milhares de arquivos reais encontrou as coisas que um conjunto de testes não faz: objetos que o serviço aceitou e perdeu, registros cujo endereço armazenado havia se desviado, e a diferença entre uma verificação que verifica hashes e uma verificação que apenas confirma que uma linha existe. Uma verificação com nada mais a verificar relata sucesso — então fizemos o modo fraco dizer em qual modo está.
17O resultado
O que saiu é um host de mídia no qual um produto pode se apoiar: um pedido assinado entrando, endereços finalizados saindo, servidos do domínio do cliente com um cache que pode ser mantido para sempre.
- Variantes nomeadas e uma escada HLS, construídas uma vez e armazenadas em cache para sempre atrás de um endereço com hash de conteúdo.
- O subdomínio próprio do cliente: o leitor vê a marca dele, não a nossa.
- Segurança incorporada no caminho de entrada — tipo analisado, recusa de verificação de vírus, re-encodificação, metadados removidos, SVG recusado em ambas as extremidades.
- Apagamento que responde com um número, para que um portão de dados pessoais possa verificar a execução em vez da intenção.
- Multi-inquilino com próprios domínios, próprios limites e rotação de duas chaves sem tempo de inatividade.
- Cobrança medida mantida em centésimos de centavo, detalhada por dia, e um plano gratuito que para em vez de gastar.
18Principais aprendizados
keepix é um caso onde a maior parte da engenharia foi dedicada a decidir o que o serviço faria recusar fazer. Sem larguras arbitrárias, sem endereços computados, sem SVG, sem solicitações de saída, sem manter os bytes originais no caminho servido, sem cobrança no plano gratuito. Cada um desses remove uma classe inteira de falhas em vez de lidar com uma.
A principal lição que levaríamos para o próximo projeto de infraestrutura: tornar a resposta honesta barata de obter. Reconciliação em lotes, uso detalhado por dia, uma exclusão que retorna uma contagem, uma resposta de entrada que nomeia o que foi pulado — em todos os casos, a alternativa não era uma resposta errada, mas nenhuma resposta, e nenhuma resposta é o que as equipes silenciosamente aceitam.
Se você precisa de um serviço de mídia sob seu próprio domínio, um pipeline de arquivos que precisa ser seguro com os uploads de outras pessoas, ou um produto com API em primeiro lugar onde o contrato importa mais do que as telas, este é o tipo de trabalho que fazemos de ponta a ponta.



