Files
ForgeLM/docs/plans/2026-04-03-tauri-physical-sqlite-migration.md

18 KiB

Tauri Physical SQLite Migration Implementation Plan

For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.

Goal: Migrar o armazenamento atual baseado em sql.js + localStorage para um SQLite físico real no Tauri, com melhor performance, durabilidade e estrutura de recuperação de contexto adequada para workloads de IA e memória.

Architecture: A migração será feita de forma incremental, introduzindo primeiro uma camada de acesso a dados em Rust/Tauri com SQLite físico como source of truth, enquanto mantemos um caminho de compatibilidade temporária para importação do banco legado do localStorage. O frontend não consultará banco diretamente em nenhuma hipótese: toda leitura e escrita passará pelo backend via comandos/APIs Tauri orientados a domínio (chat, message, memory, migration, search, summary), reduzindo acoplamento, melhorando performance e preparando a base para estratégias de compressão/recall que economizam tokens.

Tech Stack: Tauri + Rust, SQLite físico local, comandos Tauri (invoke), React/TypeScript frontend, migração do legado sql.js, Vitest + testes Rust.


Recomendação explícita: caminho ideal

Escolha recomendada

Implementar SQLite físico via backend Rust/Tauri como source of truth, com DAO/repositórios tipados e API de domínio para o frontend.

Motivo

Esse é o melhor caminho para o seu produto porque oferece:

  • mais performance real que sql.js + localStorage
  • durabilidade de verdade (arquivo físico)
  • concorrência/controlabilidade melhores
  • ferramentas reais de inspeção e manutenção (sqlite3, DB Browser for SQLite, LiteCLI, Datasette, SQLx/rusqlite)
  • base ideal para memória, recall, sumarização e deduplicação, que são as partes que mais ajudam a reduzir tokens em apps de IA

Escolha técnica recomendada de biblioteca Rust

Recomendação principal: rusqlite

Motivo:

  • simples
  • rápido
  • excelente para SQLite local embedded
  • controle fino sobre pragmas, índices, transações, FTS5
  • ideal para Tauri desktop local-first

Escolha de schema para IA/memória

Recomendação principal: SQLite relacional + FTS5 + tabelas de memória estruturadas

Motivo:

  • reduz tokens ao permitir:
    • recall seletivo por chat
    • busca lexical rápida com FTS5
    • consolidação e deduplicação de memória
    • recuperação por categoria/confiança/recência
  • evita mandar histórico bruto inteiro ao modelo

O que muda conceitualmente

Hoje

  • banco em memória (sql.js)
  • persistência em localStorage
  • frontend executa SQL diretamente
  • schema simples, pouca rastreabilidade para memória

Depois

  • banco físico em arquivo SQLite real
  • backend Rust controla schema, migração e consultas
  • frontend usa API de domínio, não SQL cru
  • schema otimizado para:
    • chats n - mensagens
    • memória de chat
    • memória de usuário
    • FTS para recuperação
    • jobs de processamento
    • metadados de compressão/contexto

Benefícios esperados para IA e economia de tokens

1. Recuperação seletiva

Em vez de reenviar 20+ mensagens sempre, o app poderá consultar:

  • últimas mensagens do chat
  • memórias de chat com alta confiança
  • memórias de usuário relevantes
  • snippets recuperados por FTS5

2. Context packing mais barato

Você poderá montar prompts com:

  • fatos duráveis
  • resumo do chat
  • poucos trechos relevantes
  • não o histórico bruto completo

3. Estrutura para compressão e summaries

SQLite físico facilita adicionar depois:

  • tabela de chat_summaries
  • snapshots de contexto
  • fragments de recall
  • ranking por recência/relevância/confiança

4. Ferramentas melhores

Você ganha ferramentas de inspeção e tuning reais:

  • sqlite3
  • DB Browser for SQLite
  • EXPLAIN QUERY PLAN
  • FTS5
  • índices compostos
  • WAL mode

Arquitetura alvo recomendada

Camada 1 — Storage engine

Arquivo físico SQLite, por exemplo em:

  • diretório de app data do Tauri
  • ex.: ForgeLM/forgelm.sqlite3

Pragmas recomendados

  • journal_mode = WAL
  • synchronous = NORMAL
  • foreign_keys = ON
  • temp_store = MEMORY
  • cache_size ajustado

Esses pragmas equilibram performance e segurança para desktop local.

Camada 2 — Backend service layer (source of truth)

Criar módulos Rust como:

  • chat_service.rs
  • message_service.rs
  • memory_service.rs
  • migration_service.rs
  • search_service.rs
  • summary_service.rs

Esses serviços usam repositórios SQLite internamente, mas expõem contratos estáveis para a camada de API.

Camada 3 — Backend API / Tauri commands

O backend deve servir tudo que o frontend precisar. O frontend não acessa banco, SQL, arquivo SQLite, sql.js ou localStorage como fonte operacional.

Exemplos de endpoints/commands:

  • chat_list
  • chat_get
  • chat_create
  • chat_rename
  • chat_delete
  • message_list_by_chat
  • message_create_user
  • message_create_assistant
  • message_update
  • message_delete
  • memory_chat_list
  • memory_user_list
  • memory_reprocess_chat
  • memory_consolidate_user
  • context_search
  • summary_get_by_chat
  • legacy_import
  • db_health

Camada 4 — Frontend API client

No frontend, criar uma camada única de acesso:

  • tauri-app/src/lib/backend-client.ts

Ela substitui qualquer acesso direto a banco e fala apenas com o backend via invoke().


Schema recomendado

Tabela chats

Manter, com pequenos aprimoramentos. Campos:

  • id
  • title
  • created_at
  • updated_at
  • archived_at NULL
  • summary_updated_at NULL

Tabela messages

Campos:

  • id
  • chat_id
  • role
  • content
  • reasoning_content
  • display_mode
  • forgeagent_state
  • prompt_tokens
  • completion_tokens
  • total_tokens
  • tokens_per_second
  • memory_processed
  • content_hash
  • created_at

Tabela chat_memories

Para memórias derivadas de um chat.

Tabela user_memories

Versão nova consolidada.

Tabela memory_jobs

Controle de processamento.

Tabela chat_summaries

Recomendação importante: já criar a tabela, mesmo que não seja usada imediatamente. Campos sugeridos:

  • id
  • chat_id
  • summary_type (rolling, milestone, session)
  • summary_text
  • source_message_start_id
  • source_message_end_id
  • created_at

Tabela virtual FTS5

Recomendação forte:

  • message_search via FTS5 sobre messages.content
  • possivelmente FTS também sobre memórias/summaries depois

Isso será um dos maiores ganhos para reduzir tokens no futuro.


Estratégia de migração segura

Fase 0 — Compatibilidade

Não remover o sql.js imediatamente.

Fase 1 — Criar banco físico e schema novo

  • app continua funcionando
  • banco físico nasce vazio

Fase 2 — Implementar importador do legado

  • ler forgelm_db_v2 do localStorage
  • converter para o schema novo
  • importar uma única vez com flag de migração

Fase 3 — Trocar frontend para db-client

  • componentes deixam de falar SQL direto
  • passam a chamar Tauri commands

Fase 4 — Desligar sql.js

  • só depois de validar import, escrita, leitura, edição e build

Plano por fases

Task 1: Congelar comportamento atual com testes de regressão

Files:

  • Modify: tauri-app/src/lib/db.test.ts
  • Modify: tauri-app/src/App.test.tsx
  • Modify: tauri-app/src/components/ChatView.test.tsx

Step 1: Escrever testes de comportamento atual Cobrir:

  • criar chat
  • carregar histórico
  • inserir mensagem user/assistant
  • editar/deletar
  • persistir métricas

Step 2: Rodar testes Run:

cd tauri-app && npm test -- src/lib/db.test.ts src/App.test.tsx src/components/ChatView.test.tsx

Expected: PASS

Step 3: Commit

git add tauri-app/src/lib/db.test.ts tauri-app/src/App.test.tsx tauri-app/src/components/ChatView.test.tsx
git commit -m "test: freeze current chat db behavior before sqlite migration"

Task 2: Introduzir backend SQLite físico no Rust/Tauri

Files:

  • Create: src-tauri/src/db/mod.rs
  • Create: src-tauri/src/db/schema.rs
  • Create: src-tauri/src/db/connection.rs
  • Modify: src-tauri/src/main.rs
  • Test: Rust unit tests in src-tauri/src/db/*

Step 1: Escrever testes falhos de inicialização Cobrir:

  • cria arquivo físico
  • aplica schema
  • ativa pragmas corretos

Step 2: Implementar conexão SQLite com rusqlite

  • path em diretório de app data do Tauri
  • abrir conexão singleton ou pool simples controlado

Step 3: Aplicar schema inicial Criar tabelas chats, messages, user_memories, chat_memories, memory_jobs, chat_summaries, FTS5.

Step 4: Rodar testes Rust Run:

cargo test db -- --nocapture

Expected: PASS

Step 5: Commit

git add src-tauri/src/db src-tauri/src/main.rs
git commit -m "feat: add physical sqlite backend for tauri"

Task 3: Implementar repositórios Rust e service layer orientados a domínio

Files:

  • Create: src-tauri/src/db/chat_repository.rs
  • Create: src-tauri/src/db/message_repository.rs
  • Create: src-tauri/src/db/memory_repository.rs
  • Create: src-tauri/src/services/chat_service.rs
  • Create: src-tauri/src/services/message_service.rs
  • Create: src-tauri/src/services/memory_service.rs
  • Test: Rust tests per repository/service

Step 1: Escrever testes falhos por repositório e service Cobrir:

  • CRUD de chats
  • insert/list de mensagens
  • leitura por chat
  • atualização de timestamps
  • contratos de service retornando DTOs estáveis

Step 2: Implementar repositórios mínimos Acesso bruto ao SQLite.

Step 3: Implementar services Toda regra de negócio deve ficar aqui. Commands não devem montar SQL.

Step 4: Rodar testes Run:

cargo test repository -- --nocapture
cargo test service -- --nocapture

Expected: PASS

Step 5: Commit

git add src-tauri/src/db/chat_repository.rs src-tauri/src/db/message_repository.rs src-tauri/src/db/memory_repository.rs src-tauri/src/services/chat_service.rs src-tauri/src/services/message_service.rs src-tauri/src/services/memory_service.rs
git commit -m "feat: add sqlite repositories and backend service layer"

Task 4: Expor API/backend commands completos para o frontend

Files:

  • Modify: src-tauri/src/main.rs
  • Create: src-tauri/src/commands/chat_commands.rs
  • Create: src-tauri/src/commands/message_commands.rs
  • Create: src-tauri/src/commands/memory_commands.rs
  • Create: src-tauri/src/commands/system_commands.rs
  • Create: tauri-app/src/lib/backend-client.ts
  • Test: tauri-app/src/lib/backend-client.test.ts

Step 1: Escrever testes falhos do client Cobrir contratos como:

  • listChats()
  • getChat(chatId)
  • getMessages(chatId)
  • createChat()
  • createUserMessage()
  • createAssistantMessage()
  • listChatMemories()
  • listUserMemories()
  • healthCheck()

Step 2: Implementar commands Tauri Usar services Rust por trás. O frontend não deve conhecer SQL, schema ou detalhes de armazenamento.

Step 3: Implementar client TS Centralizar chamadas invoke() em backend-client.ts.

Step 4: Rodar testes Run:

cd tauri-app && npm test -- src/lib/backend-client.test.ts

Expected: PASS

Step 5: Commit

git add src-tauri/src/commands/chat_commands.rs src-tauri/src/commands/message_commands.rs src-tauri/src/commands/memory_commands.rs src-tauri/src/commands/system_commands.rs src-tauri/src/main.rs tauri-app/src/lib/backend-client.ts tauri-app/src/lib/backend-client.test.ts
git commit -m "feat: expose backend api for chats messages memory and system"

Task 5: Adaptar frontend para falar apenas com o backend

Files:

  • Modify: tauri-app/src/lib/db.ts
  • Modify: tauri-app/src/App.tsx
  • Modify: tauri-app/src/components/ChatView.tsx
  • Modify: arquivos que usam DB diretamente

Step 1: Escrever testes falhos de integração Cobrir o fluxo principal usando backend-client.

Step 2: Implementar camada de compatibilidade Recomendação: não apagar db.ts de imediato. Transformá-lo em façade legada ou adaptador temporário até toda a UI migrar.

Step 3: Migrar ChatView, App e demais módulos Substituir qualquer leitura/escrita local por chamadas ao backend.

Step 4: Rodar testes frontend Run:

cd tauri-app && npm test

Expected: PASS

Step 5: Commit

git add tauri-app/src/lib/db.ts tauri-app/src/App.tsx tauri-app/src/components/ChatView.tsx
git commit -m "refactor: make frontend consume backend api only"

Task 6: Implementar importador do banco legado do localStorage

Files:

  • Create: src-tauri/src/db/import_legacy.rs
  • Create: src-tauri/src/commands/migration_commands.rs
  • Create: tauri-app/src/lib/legacy-db-export.ts
  • Test: Rust + TS tests

Step 1: Escrever testes falhos para importação Cobrir:

  • chats importados
  • messages importadas
  • user_memories importadas
  • import idempotente

Step 2: Implementar exportador legado no frontend Transformar forgelm_db_v2 em JSON transferível.

Step 3: Implementar importador no Rust Receber JSON e inserir no SQLite físico dentro de transação.

Step 4: Criar flag de migração concluída Pode ser tabela app_meta ou arquivo de config.

Step 5: Rodar testes Run:

cargo test import_legacy -- --nocapture
cd tauri-app && npm test -- src/lib/legacy-db-export.ts

Expected: PASS

Step 6: Commit

git add src-tauri/src/db/import_legacy.rs src-tauri/src/commands/migration_commands.rs tauri-app/src/lib/legacy-db-export.ts
 git commit -m "feat: import legacy localStorage database into physical sqlite"

Task 7: Otimizar SQLite para workloads de IA e economia de tokens

Files:

  • Modify: src-tauri/src/db/connection.rs
  • Modify: src-tauri/src/db/schema.rs
  • Create: docs/sqlite-context-strategy.md
  • Test: Rust tests/query-plan checks if viable

Step 1: Ativar FTS5 Criar tabela virtual para busca textual eficiente em mensagens.

Step 2: Criar índices úteis Sugestões:

  • messages(chat_id, created_at)
  • messages(role, created_at)
  • chat_memories(chat_id, memory_category, confidence)
  • user_memories(memory_category, confidence, updated_at)

Step 3: Preparar schema para summaries e recall Criar chat_summaries e metadados de contexto.

Step 4: Documentar estratégia anti-token-bloat Ex.: usar FTS5 + summary + memory retrieval.

Step 5: Commit

git add src-tauri/src/db/connection.rs src-tauri/src/db/schema.rs docs/sqlite-context-strategy.md
 git commit -m "feat: optimize sqlite schema for ai context retrieval"

Task 8: Desligar persistência em localStorage e manter fallback controlado

Files:

  • Modify: tauri-app/src/lib/db.ts
  • Modify: tauri-app/src/App.tsx
  • Modify: tauri-app/src/lib/legacy-db-export.ts

Step 1: Escrever testes falhos de pós-migração Cobrir:

  • app lê do SQLite físico
  • localStorage não é mais source of truth

Step 2: Remover persist() como mecanismo principal Pode manter apenas como utilitário legado temporário, não mais ativo.

Step 3: Rodar testes Run:

cd tauri-app && npm test
cd tauri-app && npm run build

Expected: PASS

Step 4: Commit

git add tauri-app/src/lib/db.ts tauri-app/src/App.tsx tauri-app/src/lib/legacy-db-export.ts
 git commit -m "refactor: disable localStorage db persistence after sqlite migration"

Task 9: Validação final ponta a ponta

Files:

  • No new files required initially

Step 1: Rodar testes Rust

cargo test -- --nocapture

Step 2: Rodar testes frontend

cd tauri-app && npm test
cd tauri-app && npm run build

Step 3: Verificação manual Validar:

  • criar chat
  • enviar mensagens
  • reiniciar app e confirmar persistência real
  • importar banco legado
  • editar/deletar mensagens
  • inspecionar arquivo SQLite físico com ferramenta externa

Step 4: Commit final

git add .
git commit -m "feat: migrate app storage to physical sqlite in tauri"

Ferramentas recomendadas após a migração

Para desenvolvimento e debugging:

  • DB Browser for SQLite — melhor opção visual simples
  • sqlite3 CLI — excelente para scripts e inspeção rápida
  • LiteCLI — autocomplete SQL
  • Datasette (opcional) — excelente para explorar dados localmente

Para economia de tokens no futuro:

  • FTS5 para recall lexical barato
  • chat_summaries para compaction
  • chat_memories / user_memories para fatos duráveis
  • ranking por confiança + recência para montar prompt enxuto

Riscos e mitigação

Risco 1: quebrar o frontend ao remover db.ts

Mitigação: manter adaptador temporário e migrar por etapas.

Risco 2: migração incompleta do legado

Mitigação: importador idempotente + flag de migração + logs claros.

Risco 3: latência do invoke() no Tauri

Mitigação: commands orientados a domínio, não excessivamente granulares.

Risco 4: schema ainda inadequado para IA no futuro

Mitigação: já criar FTS5 + summaries + memória estruturada nesta migração.


Critérios de aceitação

  1. O app usa SQLite físico real como source of truth.
  2. O banco persiste entre reinícios do app sem depender de localStorage.
  3. Chats, mensagens e memórias são mantidos corretamente.
  4. Existe caminho de importação do banco legado.
  5. O frontend não depende mais de SQL direto via sql.js para operação normal.
  6. O schema já suporta estratégias futuras de redução de tokens.
  7. Build e testes seguem verdes.

Resumo executivo

O que eu recomendo implementar

  • SQLite físico real em Rust/Tauri com rusqlite
  • API de domínio para o frontend
  • FTS5 + schema preparado para memória e summaries
  • migração incremental do legado localStorage

Por que isso é o melhor para IA

Porque essa base permite fazer direito, depois:

  • memória estruturada
  • busca local eficiente
  • resumos incrementais
  • recall seletivo
  • menos contexto bruto enviado ao modelo
  • menor consumo de tokens

Aprovação para execução

Se você aprovar, eu recomendo começar por esta ordem:

  1. Task 1 — congelar comportamento atual
  2. Task 2 — subir o SQLite físico no Tauri
  3. Task 4 — expor commands ao frontend
  4. Task 6 — importação do legado

Essa é a sequência com menor risco.