diff --git a/docs/adr/000-template.md b/docs/adr/000-template.md deleted file mode 100644 index c11e2727..00000000 --- a/docs/adr/000-template.md +++ /dev/null @@ -1,31 +0,0 @@ -# Architecture Decision Record Template - -## ADR-XXX: [Title] - -**Date:** YYYY-MM-DD -**Status:** Accepted | Superseded | Deprecated -**Deciders:** @team - -## Context - -What is the issue we're seeing that motivates this decision? - -## Decision - -What is the change that we're proposing and/or doing? - -## Consequences - -What becomes easier or more difficult because of this change? - -### Positive - -- ... - -### Negative - -- ... - -### Neutral - -- ... diff --git a/docs/adr/001-sqlite-data-store.md b/docs/adr/001-sqlite-data-store.md deleted file mode 100644 index 4b9d53ef..00000000 --- a/docs/adr/001-sqlite-data-store.md +++ /dev/null @@ -1,44 +0,0 @@ -# ADR-001: SQLite as Primary Data Store - -**Date:** 2025-10-15 -**Status:** Accepted -**Deciders:** @diegosouzapw - -## Context - -OmniRoute needs to persist usage data, call logs, API keys, and configuration. Options considered: - -- PostgreSQL/MySQL — full RDBMS -- SQLite — embedded, zero-config -- JSON files (LowDB) — simple but fragile -- Redis — in-memory, ephemeral - -The project targets self-hosted, single-tenant deployments where operational simplicity is paramount. - -## Decision - -Use **SQLite** via `better-sqlite3` as the primary data store. - -- All usage tracking, call logs, API keys, and settings stored in a single `.db` file -- Synchronous reads (no async overhead for simple queries) -- WAL mode for concurrent read/write performance -- Automatic migration from legacy JSON format (`usageDb.json`) on first boot - -## Consequences - -### Positive - -- Zero infrastructure — no database server needed -- Single-file backup (`cp data/omniroute.db backup/`) -- Fast queries for dashboard stats (< 5ms typical) -- Easy migration path from JSON format - -### Negative - -- Single-writer limitation (acceptable for single-tenant) -- No built-in replication -- Would need migration to PostgreSQL for multi-tenant cloud deployment - -### Neutral - -- File-based storage works well in Docker volumes diff --git a/docs/adr/002-fallback-strategy.md b/docs/adr/002-fallback-strategy.md deleted file mode 100644 index b0f97296..00000000 --- a/docs/adr/002-fallback-strategy.md +++ /dev/null @@ -1,36 +0,0 @@ -# ADR-002: Multi-Provider Fallback Strategy - -**Date:** 2025-11-20 -**Status:** Accepted -**Deciders:** @diegosouzapw - -## Context - -OmniRoute routes requests to multiple LLM providers (OpenAI, Anthropic, Google, etc.). Providers may become unavailable due to rate limiting, outages, or credential expiry. The system needs a strategy to handle these failures gracefully. - -## Decision - -Implement a **declarative fallback chain** with three layers: - -1. **Credential Retry Loop** — Rotate through available credentials for the same provider before failing -2. **Model Fallback Policy** — Configurable fallback chain per model (e.g., `gpt-4o → azure-gpt-4o → anthropic-claude`) -3. **Circuit Breaker** — Trip open after consecutive failures to prevent cascading requests to broken providers - -The fallback policy is defined in `src/domain/fallbackPolicy.js` and integrates with the circuit breaker in `src/shared/utils/circuitBreaker.js`. - -## Consequences - -### Positive - -- Automatic failover with zero user intervention -- Per-model granularity — different models can have different fallback strategies -- Circuit breaker prevents wasting quota on broken providers - -### Negative - -- Fallback chain requires manual configuration per model -- Response latency increases when primary fails (retry + fallback time) - -### Neutral - -- Lockout policy (n consecutive failures → temporary block) complements but is separate from fallback diff --git a/docs/adr/003-oauth-strategy.md b/docs/adr/003-oauth-strategy.md deleted file mode 100644 index dbaa2d99..00000000 --- a/docs/adr/003-oauth-strategy.md +++ /dev/null @@ -1,47 +0,0 @@ -# ADR-003: OAuth Strategy — Multi-Flow Support - -**Date:** 2025-11-01 -**Status:** Accepted -**Deciders:** @diegosouzapw - -## Context - -OmniRoute supports 12+ providers, each with different OAuth implementations: - -- Authorization Code + PKCE (Claude, Codex, Gemini, Antigravity, iFlow) -- Device Code Flow (Qwen, GitHub, Kiro, Kilocode, Kimi-Coding, Cline) -- Token Import (Cursor — extracted from local SQLite) - -A unified approach is needed to manage authentication across all providers. - -## Decision - -Use a **base class + strategy pattern**: - -1. `OAuthService` base class (`src/lib/oauth/services/oauth.js`) — handles common authorization code flow with PKCE -2. Provider-specific subclasses (e.g., `GitHubService`, `ClaudeService`) — override authentication methods -3. Provider registry (`src/lib/oauth/providers.js`) — declarative config per provider with `flowType`, `buildAuthUrl`, `exchangeToken`, `mapTokens` -4. Constants centralized in `src/lib/oauth/constants/oauth.js` - -Each provider defines: - -- `flowType`: `authorization_code_pkce` | `authorization_code` | `device_code` | `import_token` -- Required hooks: `buildAuthUrl()`, `exchangeToken()`, `mapTokens()` -- Optional hooks: `postExchange()` for provider-specific post-auth logic - -## Consequences - -### Positive - -- Adding new providers requires only a config entry + optional subclass -- PKCE, state validation, and token exchange are shared (DRY) -- Device code flow providers share polling logic - -### Negative - -- Some providers have unique quirks (Kiro uses AWS SSO OIDC with client registration) -- Testing requires mocking external OAuth endpoints - -### Neutral - -- ~1050 lines in `providers.js` — could be further split per provider if needed diff --git a/docs/adr/004-javascript-jsdoc.md b/docs/adr/004-javascript-jsdoc.md deleted file mode 100644 index 4934987a..00000000 --- a/docs/adr/004-javascript-jsdoc.md +++ /dev/null @@ -1,43 +0,0 @@ -# ADR-004: JavaScript + JSDoc over TypeScript - -**Date:** 2025-10-01 -**Status:** Accepted -**Deciders:** @diegosouzapw - -## Context - -The project needs type safety and developer experience improvements. Options: - -1. **Full TypeScript migration** — `.ts` files, `tsconfig.json`, build step -2. **JavaScript + JSDoc + @ts-check** — type checking without compilation -3. **No type checking** — status quo - -## Decision - -Adopt **JavaScript with JSDoc annotations and `@ts-check`** instead of migrating to TypeScript. - -- Add `// @ts-check` to critical module files -- Use JSDoc `@param`, `@returns`, `@typedef` for type documentation -- TypeScript compiler used only for checking (via IDE), not for building -- Zod schemas for runtime validation at API boundaries - -## Consequences - -### Positive - -- No build step — `node src/proxy.js` runs directly -- Faster development iteration (no compile wait) -- Gradual adoption — files can be annotated one at a time -- IDE still provides autocomplete and type errors via JSDoc -- Lower barrier for contributors - -### Negative - -- JSDoc type syntax is more verbose than TypeScript -- Some advanced TypeScript features (generics, conditional types) are harder in JSDoc -- No `.d.ts` generation for consumers - -### Neutral - -- Existing Zod schemas provide runtime validation regardless of type system choice -- `@ts-check` can be added to any file without affecting others diff --git a/docs/adr/005-single-tenant.md b/docs/adr/005-single-tenant.md deleted file mode 100644 index fa793179..00000000 --- a/docs/adr/005-single-tenant.md +++ /dev/null @@ -1,39 +0,0 @@ -# ADR-005: Single-Tenant Architecture - -**Date:** 2025-10-01 -**Status:** Accepted -**Deciders:** @diegosouzapw - -## Context - -OmniRoute needs to decide between single-tenant and multi-tenant architecture. The primary use case is individuals and small teams running their own proxy instance. - -## Decision - -Adopt a **single-tenant architecture** where each deployment serves one user/team. - -- One SQLite database per instance -- One set of API keys and credentials per instance -- Password-based login (single admin user) -- No user management, roles, or permissions beyond admin -- Settings stored in a single `settings` table - -## Consequences - -### Positive - -- Dramatically simpler codebase (no tenant isolation, RBAC, or data partitioning) -- SQLite is perfectly suited (no concurrent multi-tenant writes) -- Easy deployment: one Docker container = one instance -- Complete data isolation between users (separate deployments) - -### Negative - -- Not suitable for SaaS or shared hosting without running multiple instances -- No built-in multi-user collaboration features -- Scaling requires deploying separate instances - -### Neutral - -- Cloud worker mode exists as a separate deployment target with different constraints -- Future multi-tenant support would require a PostgreSQL migration (see ADR-001) diff --git a/docs/adr/006-translator-registry.md b/docs/adr/006-translator-registry.md deleted file mode 100644 index 8fe6f06d..00000000 --- a/docs/adr/006-translator-registry.md +++ /dev/null @@ -1,48 +0,0 @@ -# ADR-006: Translator Registry Pattern - -**Date:** 2025-12-01 -**Status:** Accepted -**Deciders:** @diegosouzapw - -## Context - -OmniRoute translates requests between different LLM API formats (OpenAI ↔ Anthropic ↔ Google ↔ etc.). Each provider has a unique request/response schema. The translator must: - -- Convert incoming requests to the target provider's format -- Convert streaming responses back to the client's expected format -- Handle provider-specific features (tool calls, vision, system prompts) - -## Decision - -Use a **registry pattern** for translators: - -1. Each provider pair has a translator module in `src/sse/translators/` -2. Translators are registered by `(sourceFormat, targetFormat)` key -3. The `translateRequest()` function auto-detects source format and applies the appropriate translator -4. Translators handle both request translation and response stream mapping - -Key translators: - -- `openai → anthropic` (and reverse) -- `openai → google` (and reverse) -- `anthropic → google` (and reverse) -- Identity translators for same-format routing - -## Consequences - -### Positive - -- Adding a new provider requires only a new translator module -- Each translator is independently testable -- Auto-detection reduces configuration burden on users -- Supports chained translation (A → B → C) if needed - -### Negative - -- O(n²) translator combinations as providers grow (mitigated by identity translators) -- Some edge cases in format conversion (e.g., tool call schemas differ significantly) - -### Neutral - -- The Translator Playground UI provides visual testing of translation chains -- Performance overhead is minimal (JSON transformation, no network calls)