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 / Componente | Estado | Detalhe |
|---|---|---|
Flag AI_IMAGE_STORAGE_MODE=local | Implementada | Default seguro local; supabase preserva o rollback legado |
| Gravação automática de drafts no Supabase | Desabilitada | Geração e remoção de fundo não fazem upload/insert no modo local |
| Banco IndexedDB para Blobs locais | Implementado | WebappAI_DB v3, metadados separados dos binários em image_blobs |
| Miniaturas WebP locais | Best effort implementado | Canvas/OffscreenCanvas; o original local segue disponível sem miniatura |
APIs navigator.storage.persist/estimate | Implementadas | Persistência, estimativa de quota e erro tipado de espaço esgotado |
| Promoção de arte escolhida | Implementada | arte-local é resolvida no ProductPage e enviada por upload-art; a composição usa composite |
| Fallback pesado de miniaturas | Removido | Falha de transformação retorna 404 cacheável, nunca redireciona ao original |
| Integração com Cloudflare R2 / CDN | Planejado | Adaptação para distribuição de mídias públicas com zero egress fee |
| RustFS S3-compatible local | Planejado | Servidor 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:
| Categoria | Tipo de Mídia | Armazenamento Proposto | Justificativa |
|---|---|---|---|
| Drafts / Variantes AI | Rascunhos de design gerados no navegador | Navegador (IndexedDB) | Alta rotatividade de iterações de design pelo usuário, que não devem saturar a nuvem. |
| Avatar do Usuário | Foto de perfil do usuário logado | Nuvem (Supabase Storage / R2) | Dimensões reduzidas, aceitável envio direto por possuir tráfego insignificante. |
| Orçamentos (Quotes) | Composições anexadas a cotações | Storage Durável (Backend) | Exige durabilidade de médio prazo para revisão administrativa. |
| Arte Confirmada de Pedido | Ativo final de alta resolução para impressão | Storage 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
Blobnativos e miniaturas WebP em um object store separado. Os metadados usamidb-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()enavigator.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:
- Seleção de Produto: O cliente define as opções de tamanho, cor e quantidade na página de produto (
ProductPage). - 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. - 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. - Promoção Direta de Draft Local: o parâmetro
arte-localtransporta somente o ID. Antes de salvar a personalização, o ProductPage materializa o Blob e usaupload-art; somente então grava a referência durável e gera a composição porcomposite.
4. Roadmap de Engenharia
Próximas etapas estimadas, sem incluir aquisição/configuração física do servidor:
- Deploy controlado e observação (0,5–1 dia): publicar a flag local, fazer smoke test em navegadores reais e acompanhar o Usage Dashboard.
- ObjectStore agnóstico (2–4 dias): contrato comum, adaptadores Supabase/R2/RustFS, hashes e testes de integração.
- Storage local e dual-read (2–4 dias): RustFS, URLs assinadas, migrador em lote e fallback R2/Supabase.
- Banco principal local (3–7 dias): ligar os metadados ao Postgres local e validar o transporte essencial descrito em
local-first-continuity.md. - 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.