Estudo de Caso: Storage Agnóstico e Redução de Egress

Como miniaturas, cache, mídia local-first e um ObjectStore compatível com S3/R2 reduzem tráfego sem prender o domínio ao Supabase Storage.

Escopo: este artigo registra o caso de mídia e egress. O contrato geral de providers está na arquitetura de dados agnóstica, e a política para localStorage, IndexedDB e OPFS está em Dados no dispositivo.

O Cenário de Egress Descontrolado

O Supabase Storage fornece uma API conveniente para manipulação de arquivos, mas dependendo de como as mídias e otimizações são arquitetadas, os custos de transferência de dados de saída (egress de rede) podem crescer consideravelmente.

Este artigo estuda um caso real de egress excessivo de rede, detalha o gargalo de cache causado por redirecionamentos temporários e apresenta uma arquitetura de armazenamento agnóstico compatível com a API S3 e Cloudflare R2, incluindo um fluxo otimizado de migração em tempo de execução e a transição para uma abordagem de mídias local-first.


O Caso Real: Redirecionamentos e Miniaturas Ausentes

A raiz do consumo excessivo de tráfego reside em falhas de arquitetura no fluxo de redimensionamento e cache do CDN:

Cliente                     Worker / App Server                     Storage
   │                                 │                                 │
   │─── Requisita miniatura ────────►│                                 │
   │                                 │─── Executa bypass/fetch ───────►│
   │                                 │    do original completo         │
   │                                 │                                 │
   │                                 │◄── Retorna original ────────────│
   │                                 │                                 │
   │◄── Retorna HTTP 307 (Redirect) ─│                                 │
   │    ao original completo         │                                 │
   │                                 │                                 │
   │─── Solicita arquivo original ────────────────────────────────────►│
   │◄── Baixa original completo ───────────────────────────────────────│

Análise do Gargalo Técnico

  1. Redirecionamento Ineficiente (HTTP 307): Em vez de processar e entregar a imagem otimizada em cache, a rota de miniatura realizava o fetch do original do storage e retornava um status 307 apontando temporariamente para o arquivo original completo.
  2. Zero Persistência de Miniaturas: Nenhuma miniatura era de fato persistida ou gravada no storage no momento do upload. A geração dependia inteiramente de requisições sob demanda.
  3. Egress de Imagens Originais: Sem cache ou persistência, cada visualização forçava o download de arquivos originais completos (na ordem de poucos megabytes) para fins de renderização em dimensões reduzidas, acumulando custos de tráfego desnecessários na nuvem.

A Solução Arquitetural: Camada ObjectStore Agnóstica

A solução consiste em desacoplar a aplicação do provedor de storage físico através de uma porta abstrata e persistir as miniaturas geradas ativamente no momento do upload.

Interface ObjectStore Cloudflare-Compatible

Para garantir compatibilidade com ambientes modernos como Cloudflare Workers, a interface opera estritamente com estruturas baseadas em Web APIs:

export interface ObjectStore {
  putObject(key: string, body: Uint8Array | ArrayBuffer | ReadableStream, contentType: string): Promise<void>;
  getObject(key: string): Promise<ReadableStream | ArrayBuffer>;
  deleteObject(key: string): Promise<void>;
  getSignedUrl(key: string, expiresInSeconds: number): Promise<string>;
}

Backends Flexíveis e Custos Controlados

  • Servidor RustFS: Um Object Storage compatível com a API S3 escrito em Rust, configurado localmente no homelab para armazenar originais e mídias privadas de forma local e econômica.
  • Cloudflare R2: candidato para a camada pública. O modelo atual não cobra egress para a Internet, mas cobra armazenamento e operações; confirme preços e limites antes do rollout.
  • AWS S3 / Outros S3-compatíveis: Opção clássica para contingência ou armazenamento em nuvens privadas.

Protocolo de Migração Otimizado via Dual-Read

A migração de mídias ativas de produção do storage legado para o novo R2/S3 deve ocorrer de forma invisível. Em vez de passar todos os bytes de mídias públicas pelo Worker principal da aplicação — o que geraria alto consumo de memória e egress duplicado no Worker —, o design adota uma resolução de redirecionamento combinada com processamento assíncrono:

sequenceDiagram
    autonumber
    actor Cliente
    participant App as App Worker (Edge)
    participant Novo as Novo Storage (R2/S3)
    participant Antigo as Storage Antigo (Supabase)
    participant Migrator as Background Migrator

    Cliente->>App: GET /media/foto.jpg
    App->>Novo: HEAD /foto.jpg (Valida se existe)

    alt Arquivo já migrado
        Novo-->>App: 200 OK
        App-->>Cliente: Redireciona / Retorna URL R2
    else Arquivo não migrado (Miss)
        Novo-->>App: 404 Not Found
        App-->>Cliente: Redireciona para URL do Storage Antigo
        Note over App, Migrator: Envia sinal assíncrono leve
        App->>Migrator: Enfileira Migração("foto.jpg")
        Migrator->>Antigo: getObject("foto.jpg")
        Antigo-->>Migrator: Stream do Arquivo
        Migrator->>Novo: putObject("foto.jpg") com Checksum SHA-256
    end

A Evolução Imediata: Mídia Local-First

Para mitigar o envio prematuro de ativos ao storage remoto e eliminar custos desnecessários com armazenamento de mídias de rascunho, adota-se um fluxo baseado em mídias local-first.

[!NOTE] Nesta rodada, o workspace passou a usar AI_IMAGE_STORAGE_MODE=local, IndexedDB para os Blobs e promoção explícita da arte escolhida. A gravação automática de rascunhos no Supabase está desativada. O desenho completo está em Mídia local-first; a publicação em produção ainda depende do rollout.

1. Classificação Estratégica de Mídias

  • Browser Local: Rascunhos temporários e variações criadas por IA no navegador residem no cliente até a confirmação de compra, poupando armazenamento central.
  • Envio Direto Reduzido: Imagens leves, como avatares de usuários, podem ser enviadas diretamente à nuvem devido ao impacto de banda desprezível.
  • Storage Remoto Durável: Orçamentos (Quotes) e artes de pedidos confirmados exigem persistência em backend central por razões operacionais de fabricação.

2. Armazenamento com IndexedDB e OPFS

  • Fase 1 (IndexedDB, implementada no workspace): Blobs e miniaturas WebP ficam em um object store separado dos metadados. Base64 e Blob URLs não são usados como referência durável.
  • Fase 2 (OPFS): Utilização futura do Origin Private File System para acesso de baixo nível e alto desempenho em mídias de grandes dimensões.
  • Estabilidade e Quotas: Prevenção de descarte via navigator.storage.persist() e acompanhamento de quota por navigator.storage.estimate(). A interface de exportação/limpeza ainda é evolução futura.

3. O Fluxo de Seleção e Mídias

O processamento real de mídias de pedidos segue caminhos estabelecidos:

  • O usuário faz a seleção do item na página de produto (ProductPage).
  • O upload da mídia física da arte fornecida é submetido pela rota upload-art.
  • A composição final da estampa simulada sobre o mockup é gerada e salva pela rota composite para processamento no backend.
  • Ao escolher uma arte local, a navegação carrega somente seu ID. Antes de salvar a personalização, o ProductPage a promove pela rota upload-art; a composição durável continua sendo gerada por composite.

Relação com Banco de Dados Local-First

A sincronização física de arquivos é dissociada da replicação lógica transacional:

  • Metadados e ID Estável: O banco local armazena os metadados (checksum SHA-256 e dimensões) e caminhos indexados por UUIDs estáveis para garantir integridade referencial imediata.
  • Desacoplamento de Fila: A fila de sincronização de continuidade offline não carrega dados binários de mídias para evitar gargalos na transmissão de mensagens. As imagens são transmitidas em conexões HTTP independentes com fluxos de retry específicos.
  • Auth Hospedado: O app server local valida as credenciais do usuário contra o Supabase Cloud hospedado antes de autorizar escritas físicas no banco local.

Rollout e a Realidade Financeira do Egress

O plano de implantação deve ser acompanhado de verificações de métricas de tráfego e latência de rede em fases shadow, com monitoramento ativo de cache hit ratios no CDN e chamadas de operações no R2. Em caso de anomalias operacionais, a lógica reverte o tráfego temporariamente para o Supabase Storage legado (rollback).

[!CAUTION] A otimização dos fluxos de mídia e a interrupção de requisições redundantes de imagens reduzem drasticamente o consumo de banda e tráfego futuros. Contudo, essa implementação não anula, estorna ou reduz os custos de egress já faturados e contabilizados pelo provedor nas faturas anteriores.


Referências Técnicas