Skip to content

v0.4.0 — Multi-tenant cost attribution

Choose a tag to compare

@mahimairaja mahimairaja released this 12 May 01:38
· 781 commits to main since this release

v0.4.0 — Multi-tenant cost attribution

VoiceGateway now tags every voice session with an optional tenant_id so a single deployment can serve many customers and account for each one separately. Three independent surfaces set the tenant: an attach_session(tenant_id=...) kwarg, an inference.set_tenant("…") ContextVar API, and scoped virtual API keys that auto-attribute at the auth layer. Every cost row, metric row, and replay event for an attributed session lands tagged; pre-v0.4.0 rows stay in the "unattributed" bucket (NULL tenant_id).

Highlights

  • REQ-VG-TENANT-001 (tag sessions with a tenant dimension): tenant_id_ctx ContextVar + attach_session kwarg + log_request UPSERT with COALESCE so the first tenant-bearing request stamps the session for its lifetime. Every cost / metric / replay row tagged via T08's repo-level propagation.
  • REQ-VG-TENANT-002 (slice the dashboard by tenant): new /api/tenants + /api/tenants/{id} endpoints; existing /api/costs, /api/sessions, /api/metrics, /api/logs, /api/latency accept a tenant query param. New FilterBar + TenantFilter (200ms-debounced typeahead) + TenantPill components with URL persistence. Costs / Sessions / Metrics pages and the SessionDetail modal all rescope when a tenant is selected.
  • REQ-VG-TENANT-003 (issue virtual API keys): new virtual_keys table (bcrypt-hashed at cost 12, 8-char visible prefix indexed) + virtual_keys_repo (issue / verify / soft-revoke / list / mark-used / list-stale) + VirtualKeys.tsx dashboard page with the show-key-once modal. voicegw tenant list / show <id> CLI is read-only by design.
  • REQ-VG-TENANT-004 (auto-attribute calls with virtual key): auth middleware in voicegateway/server/main.py::build_app detects vk_-prefixed bearer tokens, resolves them, sets tenant_id_ctx if scoped, returns 403 on body-tenant + key-scope conflict.

Migration notes

None breaking. Migration 0005 is idempotent and adds tenant_id nullable across sessions, requests, and (conditionally on prior migrations having run) turns, dead_air_events, and the four replay_* tables. Pre-v0.4.0 rows stay tenant_id = NULL and the FE renders them as a muted "unattributed" pill — no backfill happens. The new bcrypt>=4.0 dependency lands automatically with pip install -e ".[dev]" or any cloud-extra reinstall.

Five Foundry Open Questions locked in this release: vk_+32 base32 key shape (OQ1), 128-char UTF-8 tenant cap (OQ2), no backfill (OQ3), sqlite_master ALTER guard (OQ4), soft revoke (OQ5).

Out of scope this release: no automatic backfill of pre-v0.4.0 sessions, no CLI key issuance, no voicegw costs --tenant flag, no re-tag affordance for already-attributed sessions, no RBAC scopes on virtual keys. The multi-tenant quickstart guide enumerates these explicitly.

Refinery and Foundry