docs: remove all Architecture Decision Record (ADR) documents.
This commit is contained in:
@@ -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
|
||||
|
||||
- ...
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
Reference in New Issue
Block a user