OmniRoute Database Migrations and Domain Module Structure: Complete Developer Guide
OmniRoute manages database schema evolution through 84 version-controlled SQLite migrations in src/lib/db/migrations/ and organizes business logic into clean-architecture domain modules under src/domain/.
This guide examines how OmniRoute's migration system and domain layer work together to provide a reliable foundation for LLM routing, quota management, and provider resilience. We'll analyze the actual source code from the release/v3.8.50 branch to understand the schema design patterns and domain module implementation.
How OmniRoute Database Migrations Work
The migration system in OmniRoute follows a strict lexical ordering convention that ensures deterministic schema evolution across all deployment nodes.
Migration File Naming and Location
All migrations reside in src/lib/db/migrations/ and use the pattern ###_description.sql:
src/lib/db/migrations/
├── 001_initial_schema.sql
├── 002_mcp_a2a_tables.sql
├── 003_provider_node_custom_paths.sql
...
├── 088_quota_groups.sql
├── 093_proxy_enable_toggles.sql
└── 126_reasoning_routing_rules.sql
The three-digit numeric prefix controls execution order. Gaps in numbering are intentional, allowing future migrations to insert between existing versions without renaming files.
Key Migrations by Feature Area
From the 84 migration files in the current release, these core migrations establish OmniRoute's data model:
| Migration | Tables/Features Created |
|---|---|
001_initial_schema.sql |
providers, api_keys, model_capability_overrides, foundational routing tables |
002_mcp_a2a_tables.sql |
MCP/A2A messaging framework tables |
003_provider_node_custom_paths.sql |
Provider-specific path routing configuration |
010_model_combo_mappings.sql |
combo_call_log_targets, combo_sort_order for multi-model routing |
014_unified_log_artifacts.sql |
Consolidated observability schema |
025_call_logs_summary_storage.sql |
Optimized call log aggregation |
040_oneproxy_proxy_fields.sql |
One-proxy abstraction layer |
058_command_code_auth_sessions.sql |
Command-code session authentication |
070_webhooks_kind_metadata.sql |
Webhook kind and metadata extensions |
079_provider_plans.sql |
Provider plan configuration tables |
088_quota_groups.sql |
quota_pools, quota_groups, quota_consumption tables |
093_proxy_enable_toggles.sql |
Per-provider proxy activation flags |
126_reasoning_routing_rules.sql |
Latest reasoning engine routing rules |
Migration Runner Implementation
The src/lib/db/migrationRunner.ts file implements transactional, idempotent schema upgrades:
import { runMigrations } from '@/lib/db/migrationRunner';
async function initDatabase() {
await runMigrations();
}
initDatabase();
The runner executes each migration within a SQLite transaction and records progress in the schema_migrations table. This design guarantees:
- Atomicity: Failed migrations roll back completely
- Idempotency: Applied migrations are skipped on subsequent runs
- Cluster convergence: All nodes reach identical schema states
OmniRoute Domain Module Architecture
Domain modules in src/domain/ implement clean architecture principles, isolating business logic from infrastructure concerns. Each module operates on tables defined by the migration layer.
Core Domain Files and Responsibilities
src/domain/types.ts — Shared TypeScript Interfaces
Defines the contracts used across all domain modules, including request/response shapes and internal model types. This file establishes type safety between the database layer and business logic.
src/domain/policyEngine.ts — Request Validation
Evaluates cost rules, lock-out policies, and fallback strategies before dispatch:
import { evaluatePolicy } from '@/domain/policyEngine';
import { getDbInstance } from '@/lib/db/core';
async function canProceed(request) {
const db = getDbInstance();
const result = await evaluatePolicy(db, request);
return result.allowed;
}
The policy engine queries tables established by migrations 001, 058, and 126 to make routing decisions.
src/domain/comboResolver.ts — Multi-Model Routing
Resolves "combo" requests into ordered target model lists using combo_call_log_targets and combo_sort_order tables (migration 010).
src/domain/quotaCache.ts — Rate Limit Enforcement
Reads from migration 088's quota tables to enforce limits:
quota_pools— Aggregate capacity allocationquota_groups— Per-tenant or per-key groupingsquota_consumption— Real-time usage tracking
src/domain/modelAvailability.ts — Capability Filtering
Checks whether models can handle specific requests by querying:
model_capability_overrides(migration001)model_intelligence(migration001)
import { getModelOverrides } from '@/domain/modelAvailability';
import { getDbInstance } from '@/lib/db/core';
async function listOverrides(modelId: string) {
const db = getDbInstance();
return await getModelOverrides(db, modelId);
}
Resilience Domain Modules
OmniRoute implements a three-layer resilience mechanism across dedicated domain modules:
| Module | Purpose | Migration Dependencies |
|---|---|---|
fallbackPolicy.ts |
Provider fallback chain selection | provider_breaker_state |
lockoutPolicy.ts |
Model-level lockout enforcement | connection_runtime_state |
These modules operate on circuit breaker and cooldown tables introduced in earlier migrations.
Assessment and Self-Healing Framework
The src/domain/assessment/ subdirectory contains:
selfHealer.ts— Automated recovery from routing failures- Categorization logic for audit table analysis
These utilities operate on audit schema generated by assessment_migration.sql.
How Migrations and Domain Modules Integrate
The architecture enforces a unidirectional dependency: domain modules import from src/lib/db/ but migrations never reference domain code.
Schema-to-Code Mapping Example
Migration 088_quota_groups.sql creates quota tables → quotaCache.ts provides typed access:
Migration Layer (DDL) Domain Layer (Business Logic)
───────────────────── ─────────────────────────────
quota_groups ───────────────> quotaCache.ts
quota_pools ───────────────> ├── getPoolCapacity()
quota_consumption ───────────> ├── consumeQuota()
└── checkGroupLimits()
Adding New Features: Developer Workflow
When extending OmniRoute, the typical pattern is:
- Create migration in
src/lib/db/migrations/###_feature_name.sql - Update domain types in
src/domain/types.tsif new entities are introduced - Implement domain module or extend existing module in
src/domain/ - Export public API from domain module for use by handlers and executors
Migration Best Practices from OmniRoute Source
The release/v3.8.50 codebase demonstrates several schema evolution patterns:
- Additive changes only: No migrations drop columns or tables; deprecation happens in domain logic
- Index creation: Separate from table creation, often in dedicated migrations for large tables
- Data transformations: Some migrations include
INSERT ... SELECTstatements to populate new columns from existing data - Feature flags: Migrations
093and later introduce toggles that domain modules check at runtime
Summary
- 84 SQLite migrations in
src/lib/db/migrations/define OmniRoute's schema, numbered001through126with intentional gaps for future insertions - Migration runner (
src/lib/db/migrationRunner.ts) executes files transactionally and tracks state inschema_migrations - Domain modules in
src/domain/implement clean architecture with zero dependencies on the migration layer - Core modules:
policyEngine.ts,comboResolver.ts,quotaCache.ts,modelAvailability.ts,fallbackPolicy.ts,lockoutPolicy.ts - Resilience pattern: Three-layer circuit breaker implemented across
fallbackPolicy.tsandlockoutPolicy.ts - Assessment framework: Self-healing utilities in
src/domain/assessment/operate on migration-generated audit tables
Frequently Asked Questions
Where are OmniRoute database migrations stored?
All migrations live in src/lib/db/migrations/ and follow the ###_description.sql naming pattern. The three-digit prefix ensures lexical execution order. The current release contains 84 migration files ranging from 001_initial_schema.sql to 126_reasoning_routing_rules.sql.
How does the migration runner ensure schema consistency across nodes?
The migrationRunner.ts executes each migration within a SQLite transaction and records the applied version in the schema_migrations table. On startup, nodes compare their recorded version against available migrations and apply only pending changes. This guarantees all cluster members converge on identical schema states.
What tables support OmniRoute's quota and rate limiting system?
Migration 088_quota_groups.sql introduced quota_pools, quota_groups, and quota_consumption tables. The quotaCache.ts domain module provides typed access to these tables, implementing per-key and per-provider limit enforcement with configurable pool capacities.
How do domain modules access database tables without tight coupling?
Domain modules import database connections through src/lib/db/core.ts and use TypeScript interfaces from src/domain/types.ts. The architecture enforces clean separation: migrations define schema (DDL), domain modules implement business logic (DML), and neither layer imports from the other.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →