Mídia Local-First e Promoção para Storage Durável

Como manter rascunhos e variantes no dispositivo, reduzir tráfego e promover somente os arquivos que precisam ser duráveis.

Status: FASE IMEDIATA IMPLEMENTADA NO WORKSPACE; EXPANSÃO PLANEJADA — a gravação automática de rascunhos no Supabase foi desativada, o IndexedDB armazena os Blobs locais e a arte escolhida é promovida pelo fluxo durável do produto. Ainda não há deploy desta rodada em produção. RustFS, R2 e a integração final com o banco local permanecem como próximas fases.


0. Estado Atual vs. Implementado nesta Rodada

Funcionalidade / ComponenteEstadoDetalhe
Flag AI_IMAGE_STORAGE_MODE=localImplementadaDefault seguro local; supabase preserva o rollback legado
Gravação automática de drafts no SupabaseDesabilitadaGeração e remoção de fundo não fazem upload/insert no modo local
Banco IndexedDB para Blobs locaisImplementadoWebappAI_DB v3, metadados separados dos binários em image_blobs
Miniaturas WebP locaisBest effort implementadoCanvas/OffscreenCanvas; o original local segue disponível sem miniatura
APIs navigator.storage.persist/estimateImplementadasPersistência, estimativa de quota e erro tipado de espaço esgotado
Promoção de arte escolhidaImplementadaarte-local é resolvida no ProductPage e enviada por upload-art; a composição usa composite
Fallback pesado de miniaturasRemovidoFalha de transformação retorna 404 cacheável, nunca redireciona ao original
Integração com Cloudflare R2 / CDNPlanejadoAdaptação para distribuição de mídias públicas com zero egress fee
RustFS S3-compatible localPlanejadoServidor de mídias local compatível com S3 para uso do homelab

1. Classificação e Durabilidade de Mídias

A separação lógica de mídias otimiza o uso de largura de banda e espaço de disco:

CategoriaTipo de MídiaArmazenamento PropostoJustificativa
Drafts / Variantes AIRascunhos de design gerados no navegadorNavegador (IndexedDB)Alta rotatividade de iterações de design pelo usuário, que não devem saturar a nuvem.
Avatar do UsuárioFoto de perfil do usuário logadoNuvem (Supabase Storage / R2)Dimensões reduzidas, aceitável envio direto por possuir tráfego insignificante.
Orçamentos (Quotes)Composições anexadas a cotaçõesStorage Durável (Backend)Exige durabilidade de médio prazo para revisão administrativa.
Arte Confirmada de PedidoAtivo final de alta resolução para impressãoStorage Durável (Backend)Necessário para o processo físico de produção no homelab.

2. Persistência no Navegador: IndexedDB Agora, OPFS Depois

O armazenamento local no cliente segue uma evolução estruturada:

  • localStorage: reservado a preferências pequenas, flags e hints reconstruíveis. Imagens, base64, filas de promoção, secrets e metadados extensos não pertencem a Web Storage, que é síncrono e limitado.
  • IndexedDB (Fase 1, implementada): contém arquivos Blob nativos e miniaturas WebP em um object store separado. Os metadados usam idb-image:<id>; strings base64 e Blob URLs não são gravadas como referência durável.
  • OPFS (Fase 2): O uso do Origin Private File System é planejado como evolução futura para gerenciar arquivos de design massivos de forma otimizada com fluxos de leitura e escrita nativos de baixo nível.
  • Prevenção de Eviction: a aplicação usa navigator.storage.persist() e navigator.storage.estimate(). Uma interface de aviso/limpeza e exportação de rascunhos ainda é uma melhoria planejada.

WebappAI_DB deve ser preservado durante a refatoração para src/lib/db/device/indexeddb; o caminho antigo mantém reexport até a migração dos consumidores. Ownership por usuário, troca de conta, múltiplas abas, quota e limpeza fazem parte do contrato local. A política transversal está em Dados no dispositivo, dentro da Arquitetura de Dados Agnóstica.


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

O ecossistema real de pedidos consome endpoints específicos para cada etapa da jornada de compra:

Usuário (Navegador)               Páginas / Rota Backend                 Storage Remoto
        │                                    │                                  │
        │─── Efetua seleção ────────────────►│ ProductPage                      │
        │                                    │                                  │
        │─── Envia arquivo de arte ─────────►│ upload-art                       │
        │                                    │ ─── Grava arquivo original ─────►│
        │                                    │                                  │
        │─── Realiza personalização ────────►│ composite                        │
        │                                    │ ─── Grava imagem composta ──────►│

Detalhes do Fluxo de Produção:

  1. Seleção de Produto: O cliente define as opções de tamanho, cor e quantidade na página de produto (ProductPage).
  2. Envio da Arte: O arquivo de arte fornecido pelo cliente é submetido através da rota upload-art, que realiza o upload do arquivo bruto para o storage.
  3. Composição Visual: O processamento da estampa simulada sobre o produto gera a imagem composta final através da rota composite, salvando o ativo durável no backend.
  4. Promoção Direta de Draft Local: o parâmetro arte-local transporta somente o ID. Antes de salvar a personalização, o ProductPage materializa o Blob e usa upload-art; somente então grava a referência durável e gera a composição por composite.

4. Roadmap de Engenharia

Próximas etapas estimadas, sem incluir aquisição/configuração física do servidor:

  1. Deploy controlado e observação (0,5–1 dia): publicar a flag local, fazer smoke test em navegadores reais e acompanhar o Usage Dashboard.
  2. ObjectStore agnóstico (2–4 dias): contrato comum, adaptadores Supabase/R2/RustFS, hashes e testes de integração.
  3. Storage local e dual-read (2–4 dias): RustFS, URLs assinadas, migrador em lote e fallback R2/Supabase.
  4. Banco principal local (3–7 dias): ligar os metadados ao Postgres local e validar o transporte essencial descrito em local-first-continuity.md.
  5. Teste de indisponibilidade (1–2 dias): queda do nó local, enfileiramento leve no Supabase, reconciliação e retorno ao primário.

5. Expansão do Storage e ObjectStore Agnóstico (Planejado)

Para mídias duráveis promovidas ao backend, o projeto prevê uma interface de storage agnóstica:

  • RustFS: Servidor de armazenamento local compatível com S3 escrito em Rust, implantado na infraestrutura local do homelab. É planejado para receber arquivos originais e mídias privadas, reduzindo os custos de transferência com a nuvem central.
  • Cloudflare R2: candidato para mídias públicas e ativos estáticos de alta disponibilidade. O modelo de preços atual não cobra egress para a Internet, mas tarifa armazenamento e operações; preços e limites devem ser confirmados antes do rollout.
  • Mapeamento e Hash: A sincronização assíncrona (dual-read) valida a integridade física de arquivos por checksums SHA-256 calculados na origem e destino.

6. Relação com o Banco de Dados Local-First

A sincronização de arquivos binários pesados é completamente isolada da replicação lógica transacional:

  • Desacoplamento de Fila: a fila processa apenas metadados leves em JSON e caminhos textuais indexados pelos UUIDs estáveis já gerados pela aplicação. Nenhum arquivo binário trafega na fila de comandos.
  • Autenticação Unificada: O servidor local valida a sessão do usuário contra o Supabase Cloud central antes de autorizar escritas de metadados no banco local.

7. Rollout, Métricas e Egress

  • Rollout: A transição das mídias para R2/S3 deve ocorrer de forma faseada sob shadow deployment, acompanhando as métricas de latência e consumo de operações Classe A e B. A política de rollback prevê o chaveamento imediato de volta para a rota do Supabase Storage legado em caso de anomalias.
  • A Realidade do Egress: A otimização dos fluxos de imagens e a prevenção de acessos diretos desnecessários protegem contra o consumo de rede futuro. Esse redirecionamento não anula ou estorna cobranças de egress que já tenham sido faturadas em períodos passados pelo provedor de nuvem.

8. Referências Técnicas