kdb as unified data plane

draft

Abstract

kdb-next (TiKV-backed, RFC-001 of kdb-next) evolui de "replacement relacional do kdb-Go atual" para substrate primário multi-model unificado da Koder Stack. Layers especializadas (relational, time-series, KV, vector, search, stream) compartilham o mesmo substrate distribuído (TiKV + MVCC + Raft + Percolator) e ganham ACID cross-model nativo. Componentes Koder param de manter Redis/ Timescale/Elasticsearch separados; passam a falar com kdb-next através de drivers SQL ou protocol-specific shims.

Três stores ficam legitimamente fora do kdb-next:

  • kdrive (object storage, S3-compat): blobs > 1 MB, pet-scale
  • Redis local em hot paths que provadamente exigem < 1ms p99
  • CRDT layer (Yjs/Automerge) pra collaborative state com

    consistência eventual

Pra tudo o resto (sessões, rate-limit counters, métricas, search index, audit logs, telemetry, vector embeddings, stream events), kdb-next é o destino.

Motivation

O problema atual

A Koder Stack hoje (2026-05-09) tem ~7 storage tiers diferentes em produção:

  • Postgres (kdb 18.3) em LXC kdb — relational principal
  • TimescaleDB em LXC kbull — time-series
  • Redis em alguns LXCs (sessões kbot, hot caches)
  • MinIO em LXC kdrive — S3-compat blobs
  • kdb-next em desenvolvimento (LXCs futuros) — relational

    hyperscale

  • Filesystem em vários componentes — flat-file state
  • In-memory maps em alguns serviços — não-persistent state

Cada tier tem:

  • Backup separado, com falhas correlacionadas em incidentes
  • Auth model próprio (Postgres roles, Redis ACLs, MinIO IAM)
  • Monitoring/alerting separado
  • Failure modes incompatíveis (Postgres ACID vs Redis eventually-

    consistent vs filesystem unreliable)

  • Migration path único por tier (mexer em schema → 7× operação)

Cross-tier transactions são impossíveis — uma operação que escreve credentials no kdb e invalida cache no Redis pode falhar no meio: cache stale + DB consistent. Cada componente reinventa saga / outbox pattern.

A vision

kdb-next (TiKV) substrate unificado, com layers específicas servindo cada padrão de acesso. Mesmo MVCC + Raft, mesmo backup, mesmo auth model, mesmo monitoring, transactions cross-model ACID nativo.

O pattern é TiDB ecosystem aplicado à Koder Stack:

TiDB ecosystem:        Koder Stack equivalente:
  TiKV   ─── KV          kdb-kv      (KV nativo, expor TiKV)
  TiDB   ─── SQL         kdb-next    (relational SQL)
  TiFlash─── OLAP        kdb-flash   (column-store, futuro)
  TiCDC  ─── change      kdb-cdc     (Raft log → consumers)

Plus layers específicas Koder:

  kdb-ts      time-series  (hypertable-style sobre TiKV ranges)
  kdb-vec     vector       (ANN sobre TiKV-stored embeddings)
  kdb-search  full-text    (Lucene-style index, derivado via CDC)
  kdb-stream  pub/sub      (Raft log → fan-out subscribers)

Result: um substrate, sete interfaces, ACID-cross-everything.

Exceção de substrato — kdb-obj (proposto, stack-RFC-006): o object/blob plane (§Non-goals 1) é a única extensão da família kdb que não roda sobre o substrato transacional TiKV. Multi-model ≠ multi-substrate: as sete interfaces acima são projeções sobre um substrato; kdb-obj compartilha marcaAPIauthCLInamespace com o resto do kdb, mas é internamente um substrato object-native (erasure coding, sem consenso nos bytes imutáveis, streamingrange IO, GC ref-counted). É o substituto Koder-native do MinIO/kdrive (par self-hosted em registries/self-hosted-pairs.md).

Goals

  • Substrate único pra toda persistent data em apps Koder (com 3

    exceções listadas em §Non-goals)

  • Multi-model (relational, KV, time-series, vector, search, stream)

    sobre o mesmo TiKV

  • ACID cross-model nativo (escrever em time-series + atualizar

    contador KV + emitir evento no stream = uma transação)

  • Multi-tenant-by-default (alinhado com `policies/multi-tenant-

    by-default.kmd`)

  • Multi-cluster + multi-region + active-active (alinhado com

    kdb-RFC-008 + kdb-RFC-009)

  • HA (Raft replication, auto-failover)
  • Read replicas (alinhado com kdb-RFC-011)
  • Hyperscale (100M+ tenants target, alinhado com kdb-RFC-001)
  • Operações simplificadas: 1 backup process, 1 monitoring stack,

    1 auth model

Non-goals (stay outside kdb-next)

Estas três categorias não convergem pro substrate, por design:

1. Object/blob storage

Bytes grandes (release artifacts > 1 MB, attachments, build outputs, user uploads, container images, video frames, audio waveforms) ficam em kdrive (MinIO ou sucessor S3-compat).

Razão técnica: TiKV não é otimizado pra blobs. Replicação Raft de um blob 100MB satura I/O sem ganho — Raft consensus pra dado que não muda é overkill. GC de blobs MVCC é complexo. Object store dedicado é pattern correto.

Coordenação: kdb-next armazena metadata + ACL + signed-URL config; kdrive serve bytes. É o pattern S3 + Postgres bem estabelecido.

Direção (proposto, stack-RFC-006): esta exceção evolui de "MinIO/S3-compat pra sempre" para um object store Koder-native sob a marca kdb — kdb-obj, uma layer da família kdb sobre um substrato object-native (não o core transacional kdb-next). Object storage como model da família é trivial na API (PUT/GET), mas exige um substrato próprio — não roteie bytes pelo WALMVCCRaft do kdb-next. Enquanto kdb-obj não shipa, MinIO/kdrive permanece o backend; kdb-obj é adição de marcaAPIsubstrato, não reescrita do core. O par self-hosted MinIO ↔ kdb-obj é rastreado em registries/self-hosted-pairs.md; consumidores aguardando o slot de object-store: Hub depot (Storage iface), kdrive, e os git objects do Flow (FLOW-147).

2. Edge cache (sub-ms hot paths)

Onde p99 < 1ms é requisito real e não negociável:

  • Auth token → user_id resolution (toda request passa por aí)
  • Rate-limit counters (incrementar em < 100µs)
  • Presence indicators (collaborative cursors, online users)

Estes ficam em Redis local in-process do componente, com keys prefixadas por tenant (tenant:<uid>:<key>).

kdb-next é source of truth; Redis é read-through cache + write queue, com TTL agressivo (segundos) e invalidação pelo CDC quando kdb-next muda.

Critério: hot path deve ser provadamente > 100× mais frequente que cold path e atender p99 < 5ms para justificar Redis. Caso contrário, kdb-next direto basta.

3. CRDT collaborative state

Live presence, OT cursors, real-time editing — modelo de consistência é eventual + merge functions. Forçar transações ACID adiciona latência demais e quebra o pattern.

Solução: Yjs/Automerge layer (in-process per-component, sincroniza P2P entre clients via WebSocket). Snapshot persistido em kdb-next periodicamente (cada N segundos ou no save explícito do user).

High-level architecture

┌──────────────────────────────────────────────────────────────────────┐
│ Application APIs                                                      │
│ (kode, hub, flow, kortex, gateway, jet, id, kbot, talk, drive, …)    │
└────────────────────────────┬─────────────────────────────────────────┘
                             │
            ┌────────────────┼────────────────┐
            ▼                ▼                ▼
       SQL driver      KV driver        TS driver
       (relational     (cache, hot      (metrics,
        + transac-      counters)        audit, logs)
        tions)
            │                │                │
            └────────────────┼────────────────┘
                             ▼
            ┌────────────────────────────────────┐
            │ kdb-next adapter layer             │
            │  - SQL parser/planner              │
            │  - KV expose                       │
            │  - TS hypertable layer             │
            │  - Vec ANN layer                   │
            │  - Search index (derived via CDC)  │
            │  - Stream (Raft log → fan-out)     │
            └────────────────┬───────────────────┘
                             ▼
            ┌────────────────────────────────────┐
            │ TiKV substrate                     │
            │  - MVCC                            │
            │  - Raft replication (3+ nodes)     │
            │  - Percolator distributed txn      │
            │  - PD (placement driver, multi-    │
            │    region geo-aware sharding)      │
            └────────────────────────────────────┘
                             │
                             ▼
                   ┌─────────────────┐ ┌─────────────────┐
                   │ kdrive          │ │ Redis local     │
                   │ (S3-compat blob)│ │ (hot cache,     │
                   │                 │ │  source-of-     │
                   │ kdb-next holds  │ │  truth in       │
                   │ metadata + ACL  │ │  kdb-next)      │
                   └─────────────────┘ └─────────────────┘

Layers detalhadas

Layer 1 — kdb-next SQL (relational)

Status: em desenvolvimento (RFC-001 do kdb-next; shadow-active).

Surface: SQL completo, drivers Postgres-compatible (apps falam SQL via lib pgxpqetc. sem mudanças).

Use cases:

  • User accounts (Koder ID)
  • Repositories (Flow)
  • Workspaces, memberships
  • Credentials (FLOW-003 hierarchy)
  • Permissions, ACLs
  • Tudo que tem queries com JOIN, GROUP BY, transações

ACID: full MVCC, distributed transactions via Percolator.

Layer 2 — kdb-kv (KV nativo)

Status: planejado (este RFC).

Surface: API estilo Redis (GET/SET/DEL/EXPIRE/HGET/SADD) ou native TiKV client.

Use cases (que hoje usam Redis):

  • Sessões SSO
  • Rate-limit counters
  • Background job queues (com transações pra garantir delivery)
  • Distributed locks (TiKV native suporta isso)
  • Session-presence (tracked com TTL)

Diferença vs Redis local: persistência + cross-region replication + ACID com outras layers. Latência: ~1-2ms vs ~50µs do Redis local.

Quando usar kdb-kv vs Redis local: ver §Non-goals item 2.

Layer 3 — kdb-ts (time-series)

Status: planejado (parcial em kdb-RFC-007).

Surface: hypertable-style API, similar ao TimescaleDB. Particionamento automático por tempo + tenant.

Use cases:

  • Token usage tracking (rate_limit observations) — *aso direto que

    motiva esta RFC*

  • Métricas Prometheus (component health, request rates)
  • Audit logs com retention
  • Telemetry de apps clients (kode/app, kbot)
  • Activity feeds (Koder ID profile activity)

Features:

  • Continuous aggregates (rollups)
  • Compression de chunks > 7 dias (factor ~10×)
  • Retention policies per-tenant
  • TimescaleDB-compat query syntax (gradual migration de kbull)

Layer 4 — kdb-vec (vector / ANN)

Status: planejado (futuro, sem RFC ainda).

Surface: API similar a pgvector ou Milvus.

Use cases:

  • Embeddings de docs pra search semantic (Krep, Kortex)
  • Embeddings de prompts/responses pra Claude history search
  • Recommendations (Hub package similarity)

Trade-off: layer dedicada (Milvus) é mais performática em escala massive (>100M vectors); kdb-vec basta pra <10M. Reavalia quando hit.

Layer 5 — kdb-search (full-text + structured)

Status: planejado (depois de kdb-vec).

Surface: query API similar a Elasticsearch.

Implementação: index Lucene-style derivado de tabelas relational via CDC. Quando uma row no Flow muda, índice atualiza. Latência de indexação: ~ms (single-region) ou ~100ms (cross-region).

Use cases:

  • Full-text search no Hub (apps, skills)
  • Code search complementar ao koder-krep (que cobre on-disk grep)
  • Search em issues, PRs, comments do Flow

Layer 6 — kdb-stream (pub/sub + change capture)

Status: planejado.

Surface:

  • Producer: TiKV Raft log → topic (toda mutation cabe em event)
  • Consumer: subscribe a topic via gRPC streaming

Use cases:

  • CDC pra fora (cliente integrações, ETL pra warehouse)
  • Webhooks (Flow webhooks ficam aqui em vez de table polling)
  • Notification fan-out (Hub release → notify followers)
  • Build trigger queues (commit → CI runner)

Substitui Kafka pra cargas internas. Externos (clientes B2B com Kafka existente) podem consumir via mirror.

Multi-tenancy alignment

Esta RFC e policies/multi-tenant-by-default.kmd são complementares:

  • A policy diz "todo dado tem koder_user_id/workspace_id"
  • Esta RFC diz "e o substrate único onde cada layer implementa

    isolamento na sua linguagem nativa é kdb-next/TiKV"

Cada layer implementa isolation conforme spec specs/multi-tenancy/contract.kmd:

Layer Isolation
kdb-next SQL Postgres-style RLS via current_setting('koder.uid')
kdb-kv Key prefix obrigatório (tenant:<uid>:)
kdb-ts Hypertable index (koder_user_id, time) + RLS
kdb-vec Filter por metadata {tenant: <uid>} em ANN
kdb-search Index per-tenant ou global com filter mandatory
kdb-stream Topic naming tenant.<uid>.<resource>

Cross-tenant queries: error by default. Admin path explícito com audit.

Multi-region

Alinhado com kdb-RFC-008 (multi-region replication) e kdb-RFC-009 (active-active).

Topology esperada (long-term):

  • 3+ regiões geográficas (ex: SP, EU, US)
  • Cada tenant tem home region (storage primary)
  • Replicação assíncrona pra outras regiões (read-only cross-region)
  • Active-active permite escrever em qualquer região; conflitos

    resolvidos via Lamport timestamps + LWW per-key (ou CRDT-like merges).

PD (Placement Driver) gerencia placement consciente de tenant home region.

HA

Alinhado com kdb-RFC-001 + kdb-RFC-011:

  • 3+ Raft replicas por shard (default 3, configurável 5 pra crítico)
  • Auto-failover < 5s
  • Read replicas standby (kdb-RFC-011) pra cargas pesadas de read
  • Backup contínuo via incremental WAL streaming pra object storage

Roadmap fasings

Fase atual = 0 (consolidação). kdb-next em shadow-active, RFC-001 do kdb-next + RFC-007 (timeseries) + RFC-008 (multi-region) + RFC-009 (active-active) + RFC-011 (read replicas) já desenhados. Layers KV, vector, search, stream ainda em conceito.

Fase 0 — hoje (consolidação relational)

  • kdb-next em shadow-active no monorepo
  • Postgres kdb corrente serve produção
  • 5 RFCs do kdb-next ratificadas (architecture, timeseries,

    multi-region, active-active, read-replicas)

Fase 1 — próximos 6 meses (kdb-next primary relational)

  • Flip kdb-next pra primary em todos componentes que usam Postgres
  • Foundation/id já tá nele; flow, hub, kortex seguem
  • Aposentar kdb (Postgres) — preservado pra recovery, não rota ativa

Fase 2 — kdb-ts (time-series unified)

  • services/ai/gateway token-usage tracker (proposta inicial deste

    RFC) é o caso piloto

  • Migrar kbull (TimescaleDB) pra kdb-ts
  • Métricas Prometheus passam por kdb-ts
  • Activity feeds, audit logs

Fase 3 — kdb-kv + Redis aposentadoria

  • Sessions, rate-limit counters, queues migram pra kdb-kv
  • Redis fica só onde provadamente justificado por p99 < 1ms

    (auth token resolution, hot rate-limit) — com kdb-next como source- of-truth

Fase 4 — kdb-search + kdb-stream + kdb-vec

  • Search Hub passa pra kdb-search
  • Webhook delivery passa pra kdb-stream
  • Vector search semantic passa pra kdb-vec (ou Milvus se escala

    exige)

Fase 5 — full convergência

  • Único storage stack: kdb-next + kdrive + Redis-em-edge-cases-

    específicos

  • 1 backup process, 1 monitoring stack, 1 auth model
  • Cross-model transactions usadas livremente

Tempo estimado realista: 3-5 anos com team focado. Comparáveis:

  • TiDB ecosystem maturou em ~7 anos (2015 → 2022)
  • Spanner ~5 anos antes do paper (2007 → 2012)
  • FoundationDB ainda evolui após 2015

Promotion gates (per-layer)

Cada layer (kdb-kv, kdb-ts, etc.) só vira default na Stack quando passar pelos 5 gates de policies/self-hosted-first.kmd:

  1. Feature parity: cobre todos use cases do incumbent
  2. Performance: bench a la koder-bench mostra kdb-<layer>

    incumbent em workload representativo

  3. Stability: 30 dias em prd shadow-active sem regressão
  4. Capability: features novas que o incumbent não tem (ACID

    cross-model, multi-region native)

  5. Critical-path readiness: smoke tests em todos consumers

    passam

Gate fails → layer fica shadow, incumbent permanece. Não force flip.

Costs / risks

Risk 1 — engenharia massiva

Implementar 6 layers sobre TiKV é trabalho de anos. Time pequeno.

Mitigação:

  • Adoção incremental (RFC-001 do kdb-next já é essa direção)
  • Reuso de tech upstream (TiKV é battle-tested)
  • Algumas layers (kdb-vec, kdb-stream) podem ser deferred 2-3 anos
  • Spec aceita usar terceiros temporariamente quando layer ainda

    não existe (Milvus pra vector enquanto kdb-vec não rola)

Risk 2 — vendor lock-in técnico

Stack Koder fica fortemente acoplada a TiKV. Se TiKV (PingCAP) sair do business, Koder herda manutenção do upstream.

Mitigação:

  • TiKV é Apache 2.0 license (não vendor-lock estrito)
  • TiKV é CNCF Graduated (community-managed)
  • Apesar disso, alternativas pro substrate (FoundationDB, etc.)

    ficam documented em policies/self-hosted-first.kmd como fallback option.

Risk 3 — performance ceiling local

Substrate distribuído > engine local em algumas cargas (Redis in-process). Forçar tudo em kdb-next degrada hot paths.

Mitigação:

  • §Non-goals lista as 3 categorias que ficam fora
  • Promotion gate #2 exige bench parity antes de flip

Risk 4 — operational complexity migration

Cada migration de layer requer dados-shadow + cutover + rollback plan. 6 migrations × 50 componentes = matrix big.

Mitigação:

  • RFC-001 do kdb-next já provou o padrão (shadow + diff + flip)
  • Migration tooling reusable (incus snapshots, mig-runners) já

    existe na stack

  • Faseamento conservador (1 layer por trimestre)

Open questions

  1. kdb-vec vs Milvus dedicated: ANN em scale > 100M vectors

    é genuinamente domínio especializado. Vale construir kdb-vec ou preservar Milvus como exception permanente igual kdrive?

  1. Active-active conflict resolution: LWW (last-write-wins)

    per-key é suficiente, ou precisamos CRDTs serializáveis pra alguns dados (ex: contadores)?

  1. Consumer migration tax: cada componente flip de Postgres →

    kdb-next, Redis → kdb-kv, Timescale → kdb-ts custa horas de refactor. Faseamento detalhado per-componente exige sub-RFCs.

  1. Backup story: cross-model snapshot consistente é trivial

    no TiKV (single MVCC timestamp). Mas restore pra um ponto-no- tempo cross-cluster precisa coordination — RFC dedicada provavelmente.

  1. Authn/authz unified: hoje cada storage tier tem seu auth.

    Kdb-next deveria delegar pra Koder ID nativamente? Quanto acoplamento?

Decision

Status: draft até owner ratificar. Após ratificação:

  • Vira referência canonical pra qualquer decisão de storage na Stack
  • IAs e engs novos consultam-no antes de propor "vamos botar Redis

    pra isso"

  • Sub-RFCs detalham cada layer (kdb-kv, kdb-ts, kdb-vec, kdb-search,

    kdb-stream) — abertas conforme prioridade

  • Roadmap entra em meta/docs/stack/registries/storage-convergence.md

    pra tracking de migration debt per-componente

  • infra/data/kdb/docs/rfcs/kdb-RFC-001 — substrate architecture
  • infra/data/kdb/docs/rfcs/kdb-RFC-007 — time-series storage
  • infra/data/kdb/docs/rfcs/kdb-RFC-008 — multi-region
  • infra/data/kdb/docs/rfcs/kdb-RFC-009 — active-active
  • infra/data/kdb/docs/rfcs/kdb-RFC-011 — read replicas
  • policies/multi-tenant-by-default.kmd — tenant isolation
  • policies/hyperscale-first.kmd — implementation principle
  • policies/self-hosted-first.kmd — promotion gate framework

Significance

Sem RFC, cada novo módulo da Stack escolhe storage isoladamente, acumulando débito técnico de divergência. Em 5 anos seriam 20+ storage tiers diferentes, multiplicando custo operacional e inviabilizando ACID cross-module.

Com RFC, a direção está pinada e qualquer escolha contrária precisa de justificativa explícita (e exception path em §Non-goals).

Esta é a equivalente da "always RDBMS" decision tomada por gigantes nos anos 2000 — exceto que hoje a apostamos é "always TiKV substrate" e ganhamos hyperscale + multi-model nativo.