# 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: ```bash cd tauri-app && npm test -- src/lib/db.test.ts src/App.test.tsx src/components/ChatView.test.tsx ``` Expected: PASS **Step 3: Commit** ```bash 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: ```bash cargo test db -- --nocapture ``` Expected: PASS **Step 5: Commit** ```bash 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: ```bash cargo test repository -- --nocapture cargo test service -- --nocapture ``` Expected: PASS **Step 5: Commit** ```bash 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: ```bash cd tauri-app && npm test -- src/lib/backend-client.test.ts ``` Expected: PASS **Step 5: Commit** ```bash 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: ```bash cd tauri-app && npm test ``` Expected: PASS **Step 5: Commit** ```bash 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: ```bash cargo test import_legacy -- --nocapture cd tauri-app && npm test -- src/lib/legacy-db-export.ts ``` Expected: PASS **Step 6: Commit** ```bash 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** ```bash 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: ```bash cd tauri-app && npm test cd tauri-app && npm run build ``` Expected: PASS **Step 4: Commit** ```bash 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** ```bash cargo test -- --nocapture ``` **Step 2: Rodar testes frontend** ```bash 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** ```bash 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.