VoiceGateway // DOCS

Storage

VoiceGateway uses SQLite via `aiosqlite` for all persistent data: request logs, cost tracking, managed configuration, and audit trails.

Storage

VoiceGateway uses SQLite via aiosqlite for all persistent data: request logs, cost tracking, managed configuration, and audit trails.

File: src/voicegateway/storage/sqlite.py

Database Location

The database path is resolved in this priority order:

  1. VOICEGW_DB_PATH environment variable
  2. cost_tracking.db_path in voicegw.yaml
  3. Default: ~/.config/voicegateway/voicegw.db

The parent directory is created automatically on first access.

Schema Overview

requests PK TEXT id REAL timestamp TEXT project TEXT modality TEXT model_id TEXT provider REAL input_units REAL output_units REAL cost_usd REAL ttfb_ms REAL total_latency_ms TEXT status TEXT fallback_from TEXT error_message TEXT metadata managed_providers PK TEXT provider_id TEXT provider_type TEXT api_key_encrypted TEXT base_url TEXT extra_config REAL created_at REAL updated_at managed_models PK TEXT model_id TEXT modality TEXT provider_id TEXT model_name TEXT display_name TEXT default_language TEXT default_voice TEXT extra_config INTEGER enabled REAL created_at REAL updated_at managed_projects PK TEXT project_id TEXT name TEXT description REAL daily_budget TEXT budget_action TEXT default_stack TEXT stt_model TEXT llm_model TEXT tts_model TEXT tags REAL created_at REAL updated_at config_audit_log PK INTEGER id REAL timestamp TEXT entity_type TEXT entity_id TEXT action TEXT changes_json TEXT source provider_id

Tables

requests

The primary table for all inference request logs. Every call through the Gateway that completes (or fails) is recorded here.

ColumnTypeDescription
idTEXT PKUUID v4
timestampREALUnix epoch (seconds)
projectTEXTProject ID (default: "default")
modalityTEXT"stt", "llm", or "tts"
model_idTEXTFull model ID, e.g. "deepgram/nova-3"
providerTEXTProvider name, e.g. "deepgram"
input_unitsREALMinutes (STT), input tokens (LLM), characters (TTS)
output_unitsREALOutput tokens (LLM only)
cost_usdREALCalculated cost in USD
ttfb_msREALTime to first byte in milliseconds
total_latency_msREALTotal request latency in milliseconds
statusTEXT"success" or "error"
fallback_fromTEXTOriginal model ID if this was a fallback
error_messageTEXTError details if status is "error"
metadataTEXTJSON blob for additional data

managed_providers

Providers added via the dashboard or MCP server (as opposed to YAML). API keys are encrypted with Fernet.

ColumnTypeDescription
provider_idTEXT PKUnique identifier (e.g. "my-openai")
provider_typeTEXTProvider type from registry (e.g. "openai")
api_key_encryptedTEXTFernet-encrypted API key
base_urlTEXTCustom base URL (for proxies or self-hosted)
extra_configTEXTJSON blob for additional config
created_atREALUnix epoch
updated_atREALUnix epoch

managed_models

Models registered via the dashboard or MCP server.

ColumnTypeDescription
model_idTEXT PKFull model ID (e.g. "openai/gpt-4.1-mini")
modalityTEXT"stt", "llm", or "tts"
provider_idTEXTReferences managed_providers.provider_id
model_nameTEXTActual model name sent to the provider API
display_nameTEXTHuman-readable name for the dashboard
default_languageTEXTDefault language code for STT
default_voiceTEXTDefault voice ID for TTS
extra_configTEXTJSON blob
enabledINTEGER1 = active, 0 = disabled
created_atREALUnix epoch
updated_atREALUnix epoch

managed_projects

Projects created via the dashboard or MCP server.

ColumnTypeDescription
project_idTEXT PKUnique identifier
nameTEXTDisplay name
descriptionTEXTProject description
daily_budgetREALDaily budget in USD (0 = unlimited)
budget_actionTEXT"warn", "throttle", or "block"
default_stackTEXTDefault stack name
stt_modelTEXTDefault STT model ID
llm_modelTEXTDefault LLM model ID
tts_modelTEXTDefault TTS model ID
tagsTEXTJSON array of tag strings
created_atREALUnix epoch
updated_atREALUnix epoch

config_audit_log

Records all changes to managed resources for compliance and debugging.

ColumnTypeDescription
idINTEGER PKAuto-increment
timestampREALUnix epoch
entity_typeTEXT"provider", "model", or "project"
entity_idTEXTID of the affected entity
actionTEXT"create", "update", or "delete"
changes_jsonTEXTJSON blob describing what changed
sourceTEXT"api", "mcp", or "dashboard"

Views

daily_costs

Aggregates request data by day, modality, model, and provider.

SQL
CREATE VIEW daily_costs AS
SELECT
    date(timestamp, 'unixepoch') as day,
    modality,
    model_id,
    provider,
    COUNT(*) as request_count,
    SUM(cost_usd) as total_cost,
    AVG(ttfb_ms) as avg_ttfb,
    AVG(total_latency_ms) as avg_latency
FROM requests
GROUP BY day, modality, model_id, provider;

project_daily_costs

Aggregates request data by project, day, modality, and model.

SQL
CREATE VIEW project_daily_costs AS
SELECT
    project,
    date(timestamp, 'unixepoch') as day,
    modality,
    model_id,
    COUNT(*) as request_count,
    SUM(cost_usd) as total_cost,
    AVG(ttfb_ms) as avg_ttfb
FROM requests
GROUP BY project, day, modality, model_id;

Indexes

IndexTableColumn(s)Purpose
idx_requests_timestamprequeststimestampTime-range queries
idx_requests_modelrequestsmodel_idPer-model aggregation
idx_requests_modalityrequestsmodalityFilter by STT/LLM/TTS
idx_requests_projectrequestsprojectPer-project queries
idx_requests_project_timestamprequestsproject, timestampProject cost summaries
idx_audit_timestampconfig_audit_logtimestampRecent audit entries
idx_audit_entityconfig_audit_logentity_type, entity_idEntity history lookup
idx_managed_providers_typemanaged_providersprovider_typeFilter by provider type
idx_managed_models_modalitymanaged_modelsmodalityFilter by modality
idx_managed_models_providermanaged_modelsprovider_idModels per provider

Connection Management

SQLiteStorage opens a fresh aiosqlite connection per call and closes it in a finally block. There is no connection pooling -- this keeps things simple and avoids connection state issues with async code.

On first connection, the schema DDL is executed via executescript(), and a migration check adds the project column to older databases. The _initialized flag prevents re-running the schema on subsequent connections.

Auto-Migration

When VoiceGateway opens a database created by an older version:

  1. Missing project column: automatically added with ALTER TABLE and DEFAULT 'default'
  2. Plaintext API keys: detected via is_fernet_token() and re-encrypted in place with a warning log

On this page