Handbook - Architecture - Extension boundaries

Storage adapter

Implement the storage-read / storage-write port against your database.

On this page

Two services own the storage port: core/storage-write (mutations) and core/storage-read (queries and live fanout). Adapter implementations live in internal/adapters/<database>/ within each service. The v1 adapter is SurrealDB.

What you must implement

  • storage-writer port — persist canonical telemetry idempotently for the same command ID, trace ID, span ID, and generated log event key.
  • storage-reader port — support filter pushdown, counts, grouping, sorting, cursors, and bounded facet queries inside the database, not in Go post-processing.
  • readiness checks and schema initialization for your backend.
  • authorization preparation — projections must respect project boundaries.
  • service ownership — storage-write remains the only telemetry mutator and storage-read remains the only telemetry reader. A storage adapter must not be imported by the BFF, frontend, collector, or public API clients.

A sketch

package mybackend

type Writer struct{ /* ... */ }

func (w *Writer) PersistTrace(ctx context.Context, cmd PersistCommand) error {
    // 1) translate cmd into the backend's bulk-insert payload
    // 2) write with an idempotency key derived from (cmdId, traceId, spanId)
    // 3) return nil on commit, BridgeError on retryable failure
    return nil
}

Idempotency keys

EntityKey
Span(traceId, spanId)
LogEvent(traceId, spanId, generatedLogId)
MetricPoint(descriptorId, attributesHash, ts)
DatasetItemRun(experimentRunId, datasetItemId)
EvalResult(targetKind, targetId, scorerId, scorerVersion)
Optimization candidate(experimentRunId, promptVersionHash)

Last updated .