Ir para o conteúdo

Metadata Schema — ContextStore (v1)

Spec de produto pré-implementação · mindflow v0.3 · 2026-06-21


Contexto

O ContextStore usa SQLite com a tabela events:

CREATE TABLE events (
    id         INTEGER PRIMARY KEY AUTOINCREMENT,
    source     TEXT NOT NULL,    -- "mindflow", "mural", "web", "telegram"
    kind       TEXT NOT NULL,    -- "nota", "ideia", "gratidao", "briefing", "setup" ...
    payload    TEXT NOT NULL,    -- JSON livre — aqui mora o problema
    created_at TEXT NOT NULL
);

Antes da v0.3, o payload era livre: cada chamador salvava o que queria. Resultado:

Origem Payload real salvo
POST /api/event (web/telegram) {"text": "..."}
briefing_routine {"text": "...", "actions": [...]}
Nenhum evento de setup existia ainda

Isso impede filtros consistentes, renderização uniforme no histórico e rastreamento de canal.


Schema unificado (v1)

Todo evento novo (a partir da v0.3) deve ter o payload no seguinte formato:

{
    # OBRIGATÓRIO
    "text": str,

    # METADADOS SEMÂNTICOS
    "type": "capture" | "routine_result" | "system",
    "routine_id": str | None,   # "briefing", "brisa", "setup" ou None para captures
    "source": "web" | "telegram",

    # IMPORTÂNCIA E TAGS
    "importance": 1 | 2 | 3,   # 1=normal, 2=marcante, 3=épico
    "tags": list[str],          # ex: ["ideia", "decisão", "gratidão"]

    # VERSIONAMENTO
    "version": "1"
}

Campos explicados

text — conteúdo principal. Sempre presente. É o campo lido por briefing_routine, build_timeline e api_chat para montar contexto.

type — categoria semântica do evento: - "capture" — entrada direta do usuário (nota, ideia, gratidão, brisei) - "routine_result" — output de uma rotina (briefing, brisa) - "system" — evento de sistema (setup completo, reindex, etc.)

routine_id — qual rotina gerou o evento. None para captures manuais. Permite filtrar histórico por rotina (api_routine_history já faz isso via kind, mas routine_id no payload é mais explícito e tolerante a colisões de nomenclatura).

source — canal de entrada do usuário. Duplica a coluna SQL para que leitores do payload não precisem do dict externo.

importance — escala 1-3, substituindo a inferência atual do timeline/builder.py via _KIND_IMPORTANCE. Com o campo explícito, o frontend pode filtrar sem lógica derivada.

tags — lista aberta de tags semânticas. Pode ser vazia ([]). Não há taxonomia fechada na v0.3 — tags são livres e geradas pelo chamador.

version — versão do schema para facilitar migrations futuras. Sempre "1" na v0.3.


Defaults por chamador

Chamador type routine_id source importance tags
POST /api/event kind=nota "capture" None "web" ou "telegram" 1 []
POST /api/event kind=ideia "capture" None "web" ou "telegram" 2 ["ideia"]
POST /api/event kind=gratidao "capture" None "web" ou "telegram" 3 ["gratidão"]
POST /api/event kind=brisei "capture" None "web" ou "telegram" 1 []
briefing_routine "routine_result" "briefing" "web" 1 []
rotina "brisa" (v0.3) "routine_result" "brisa" "web" 1 []
setup completo "system" "setup" "web" 2 ["setup", "perfil"]

A importância por kind de capture replica e torna explícita a lógica atual do _KIND_IMPORTANCE em timeline/builder.py.


Payload completo do evento de setup

store.log_event("web", "setup", {
    "text": "Perfil configurado",
    "type": "system",
    "routine_id": "setup",
    "source": "web",
    "importance": 2,
    "tags": ["setup", "perfil"],
    "version": "1",
    "profile": {
        "name": str,
        "areas": list[str],          # ["saúde", "trabalho", "relacionamentos", ...]
        "tone": "direto" | "amigável",
        "context": str               # texto livre — contexto inicial do usuário
    }
})

O campo profile é específico de eventos kind="setup" — não é parte do schema base.


Compatibilidade retroativa

Eventos existentes no banco (antes da v0.3) não são migrados. A lógica de leitura deve tolerar payloads sem os novos campos:

# Padrão de leitura retrocompatível
payload = event.get("payload", {})

text       = payload.get("text", "")
event_type = payload.get("type", "capture")
source     = payload.get("source") or event.get("source", "web")
importance = payload.get(
    "importance",
    _KIND_IMPORTANCE.get(event.get("kind", "nota"), 1)  # fallback para lógica antiga
)
tags       = payload.get("tags", [])
version    = payload.get("version", "0")  # "0" = formato pré-v0.3

Regra: se version está ausente ou é "0", o código trata o evento como legacy e usa os fallbacks acima. Nenhuma query SQL nova é necessária — a retrocompatibilidade é tratada em Python na camada de leitura.


Arquivos afetados na implementação

Arquivo O que muda
mindflow/api/server.pyapi_event() Enriquecer payload com campos do schema v1
mindflow/routines/briefing.pybriefing_routine() Adicionar type, routine_id, source, importance, version ao log_event
mindflow/timeline/builder.pybuild_timeline() Leitura retrocompatível; remover dependência de _KIND_IMPORTANCE para eventos v1
mindflow/api/server.py — novo endpoint GET /api/context/setup-status
mindflow/routines/ — nova rotina setup Salvar evento kind="setup" com payload completo

O que NÃO muda

  • Schema SQL da tabela events — nenhuma coluna nova
  • A coluna kind SQL — permanece como identificador primário de tipo para queries
  • ContextStore.log_event() e ContextStore.recent_events() — assinatura inalterada
  • Eventos existentes no /data/brisa.db — lidos com fallback, não migrados