You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A recent cross-product (DP + CP + Dashboard) engineering and documentation audit surfaced a number of improvement opportunities across three areas: architecture clarity, documentation organization, and concept abstraction. This issue is the consolidated tracking issue, ordered by priority.
1. Canonical JSON Schema as config source of truth — cross-repo
Problem: Today our config surface is fragmented:
DP: config.example.yaml + hand-written field descriptions in docs/configuration/
CP: Go struct + GORM AutoMigrate (28 tables), no exported schema
Dashboard forms: hand-coded validation, prone to drift from CP/DP
Consequences: new fields get added in one place and forgotten elsewhere; dashboard validation is reimplemented; API/config docs are hand-maintained and drift over time.
Proposal: Two categories of schema (three files), plus OpenAPI generation downstream of the resource schema.
(a) Resource Schema (shared between DP and CP, single source of truth)
Covers Model / ApiKey / ProviderKey / CachePolicy / Guardrail / RateLimit / ObservabilityExporter / Routing (and any future resources).
Location: api7/ai-gateway/schemas/ (DP is the strict consumer, so co-locating with DP keeps schema and release in sync)
AISIX-Cloud pulls via git submodule or pinned tag, regenerates Go types
DP uses the jsonschema crate to validate etcd watch payloads; failed payloads go to the existing dpmgr_rejected_resources table
CP uses gojsonschema for REST API request validation; dashboard uses RJSF (or similar) to auto-render JSON Schema → React forms
Docs auto-generate field references from schema — eliminates hand-maintained drift
DP tried utoipa derive macros and walked away. The comment in openapi.rs:15-19 records the rationale: "Small enough that maintaining it by hand is less effort than wiring utoipa derive macros across every handler; the surface is stable enough that drift is easy to spot in review." The unused utoipa* deps can be cleaned up.
Structurally inverted. Customer-facing CP user APIs (41+ endpoints, PAT/JWT/mTLS multi-auth) are unspecified; the internal DP admin API (~10 endpoints, stable) has a spec. This is path-dependent history, not a design choice. CP work is 3-5× the DP work.
(d) OpenAPI generation (downstream of resource schema)
Once the resource JSON Schema lands ((a)), it should drive OpenAPI for both surfaces:
DP — refactor, do not rewrite:
Keep the existing hand-written openapi.rs
Replace inline schemas objects with $ref to the canonical resource JSON Schema files
Single source of truth for resource shapes; eliminates DP-code / DP-OpenAPI / CP-OpenAPI triple maintenance
Clean up unused utoipa / utoipa-axum / utoipa-scalar deps from Cargo.toml
CP — build from scratch, schema-first:
Cannot use DP's "hand-write a small JSON" approach — CP surface is too large and varied
Author OpenAPI 3.1 files where components/schemas$refs the canonical resource schema
Use oapi-codegen to generate Go route handlers and DTOs from OpenAPI — compiler-enforced no-drift
Split by audience (cleaner than tag-based separation):
File
Audience
Auth
Public?
openapi/cp-admin.yaml
Customer PAT scripts
Bearer PAT
Yes (publish SDK)
openapi/cp-dashboard.yaml
Dashboard internal
JWT (Better Auth)
No
openapi/cp-internal.yaml
DP → CP calls
mTLS
No
Stripe webhook stays out (third-party-defined contract).
Phased rollout (folded into the #1 effort estimate):
Phase 1 (with PR #1: Scaffold Cargo workspace, UI skeleton, and CI pipeline #1 — first 2-3 weeks): land resource schema + CP customer-PAT API spec (~10 endpoints: env / model / api_key / provider_key / budget / guardrail CRUD). Validate oapi-codegen flow without migrating all handlers. Refactor DP openapi.rs to $ref.
Phase 2 (separate, 2-4 weeks): extend to dashboard + internal API; migrate dashboard to generated client.
Versioning: Add a top-level version: 1|2 field to handle semantic-breaking changes (e.g. empty array [] meaning "allow all" in v1 vs. "deny all" in v2). Critical for forward-compatible migration.
Problem: Today docs/reference/provider-compatibility.md is just a matrix table. Users diagnosing provider-specific behavior (e.g. how Anthropic upstream preserves cache_control, thinking blocks, and tool_use as byte-level passthrough) have to grep the source.
Proposal:
Split per-provider pages for the 4 full-feature providers: OpenAI / Anthropic / Gemini / DeepSeek (Cohere / Jina rerank-only stay in the matrix)
Fixed template per page:
Overview
Supported Operations matrix
For each op: Request Parameters table → field types hyperlinked to crates/aisix-core/src/models/*.rs GitHub permalinks
Special Message Handling (e.g. Anthropic byte-level passthrough specifics)
3. Architecture deep-dive documents (at least 3) — documentationP1
Problem: Platform engineers evaluating our gateway cannot find engineering-depth design explanations. docs/overview/core-concepts.md is product-flavored; there is no engineering-RFC-grade content. This is a real procurement decision blocker.
Proposal: 3 architecture docs under docs/architecture/:
Problem: Today our APIKey resource bundles authentication credential + allowed_models whitelist + rate_limit + team binding. The name "API Key" reads as "auth credential", but the resource is really a governance/policy entity. The industry has converged on "Virtual Key (VK)" for this concept (Stripe restricted keys, OpenRouter, Portkey, etc.).
Proposal:
Docs: rename references to "Virtual Key" where the entity is discussed at the policy/governance level; reserve "API key string" for the literal secret value
Dashboard UI labels: update visible labels (DB column name + Go struct stay as-is to avoid migration risk)
Add docs/overview/glossary.md (or extend existing): "Virtual Key (VK) — a policy-bound credential combining model whitelist, rate limit, and team/budget association"
6. Symmetric hook execution + tri-state fallback control — enhancement
Problem: Today our aisix-guardrails pipeline runs pre/during/post hooks in forward order. There is no guaranteed reverse-order cleanup of already-executed pre-hooks on short-circuit. Additionally, plugins/hooks have no way to signal "this short-circuit should/shouldn't trigger fallback routing."
Proposal:
Refactor GuardrailEngine: PreHooks execute forward, PostHooks execute reverse (LIFO). On short-circuit, only already-fired PreHooks have their corresponding PostHook called (symmetric cleanup).
Add AllowFallbacks: Option<bool> to the short-circuit response: None = default policy / Some(true) = force fallback / Some(false) = forbid fallback. The routing layer reads this to decide whether to walk the fallback chain.
Apply the same semantics to the future plugin system.
Problem: We already emit x-aisix-cache: hit|miss, but no canonical doc spells out: (a) which x-aisix-* response headers the gateway emits; (b) which x-aisix-* request headers clients can set to control gateway behavior; (c) the reserved-prefix contract (what gets stripped vs. forwarded upstream).
Proposal: Add a "Reserved Header Namespace" section to docs/reference/headers-and-error-codes.md:
Declare x-aisix-* as the gateway's reserved prefix
List all response headers the gateway emits (request-id, cache status, which fallback target was used, etc.)
List all request headers clients can actively set (cache TTL override, disable cache, force/disable fallback, etc.)
Clarify which headers are stripped before forwarding upstream (Authorization and other sensitive headers)
8. Error messages with embedded operational guidance (doc-as-error) — enhancementdocumentation
Problem: Today crates/aisix-core/src/errors.rs and various error responses describe "what went wrong" but not "what to do next." Industry best practice: error messages include the actionable next step ("set X in config" / "in dashboard go to Y > Z").
Proposal:
Audit every user-facing error variant
For each, add a "next step" sentence covering: the config key to change, the dashboard path to navigate, or the doc URL to read
Put the text directly in the error Display impl — no dependency on external docs
Example transformation:
Before: "request timed out"
After: "request timed out after 30s. Increase proxy.request_timeout_seconds in bootstrap config, or override per-model via Dashboard > Models > {model} > Network Config."
Problem: Users adopting AI coding assistants (Claude Code, Cursor, Codex CLI, Zed, OpenCode, LibreChat, etc.) need step-by-step recipes for pointing those clients at our gateway. Today we only have OpenAI/Anthropic SDK quickstarts — no client-specific recipes. This is a high-SEO, high-conversion content category.
Proposal: Add docs/integrations/cli-agents/ (or docs/cookbook/cli-agents/) with at least 3-5 recipes:
Claude Code → ai-gateway
Cursor → ai-gateway
Codex CLI / Aider → ai-gateway
Zed → ai-gateway
LibreChat / Open-WebUI → ai-gateway
Each recipe: ~500-800 words, with config snippet, verification step, common pitfalls.
MCP client mode (gateway connects to external MCP servers)
MCP server mode (gateway exposes tools to MCP-aware clients like Claude Desktop)
Agent Mode with auto-execute tool whitelist (selected tools execute without per-call approval)
Forward-looking: Code Mode — a sandboxed Python/Starlark execution layer that lets the LLM author multi-tool orchestrations (vs. multi-turn tool_call loops). Empirical reports from comparable products: -50% tokens, -40% latency vs. multi-turn. Recommend storing this design in the PRD as a candidate for future differentiation; do not block initial MCP delivery on it.
Owner: PM + senior engineer (design phase)
11. Multi-DP cluster patterns (strategic observation only — no action yet)
Current architecture: DP nodes are stateless, kine-on-PG is the single source of truth — sufficient for current scale.
When multi-region DP federation or autonomous DP clusters become a real requirement, evaluate split-transport cluster patterns: gossip for membership/liveness (low-churn, short messages) + gRPC for application state sync (higher-throughput, structured payloads). No action until the requirement materializes.
Anti-patterns to actively avoid (architecture-alignment notes)
For team alignment, we explicitly do NOT plan to adopt:
Monolithic Provider interface — our Bridge trait (4-6 methods) is cleaner than putting OCR/Container/CachedContent/Speech/Batch all on a single interface. Document this as a deliberate design choice in the architecture doc series (feat(core): Model, ApiKey, RateLimit entities + JSON Schema validators #3).
DP-bundled persistence SDK — DP stays stateless; ConfigStore / LogStore / VectorStore must live on the CP side.
DP-bundled Web UI — UI is a Cloud-only concept; DP exposes admin API only. This is a hard requirement of the multi-tenant architecture.
More than 4 budget tiers — Org → Env → APIKey → ProviderKey is sufficient.
The resource schema in #1 is a single file (not one per side). If DP and CP each maintain their own copy, drift over time is inevitable as fields are added.
Resource schema = 1 file, shared between DP and CP, lives in the ai-gateway repo
DP bootstrap schema = 1 file, lives in the ai-gateway repo
CP process config schema = 1 file, lives in the AISIX-Cloud repo
Background
A recent cross-product (DP + CP + Dashboard) engineering and documentation audit surfaced a number of improvement opportunities across three areas: architecture clarity, documentation organization, and concept abstraction. This issue is the consolidated tracking issue, ordered by priority.
Cross-repo items (#1 / #4 / #5) also touch AISIX-Cloud — flagged inline.
High Priority (recommended this quarter)
1. Canonical JSON Schema as config source of truth —
cross-repoProblem: Today our config surface is fragmented:
config.example.yaml+ hand-written field descriptions indocs/configuration/Consequences: new fields get added in one place and forgotten elsewhere; dashboard validation is reimplemented; API/config docs are hand-maintained and drift over time.
Proposal: Two categories of schema (three files), plus OpenAPI generation downstream of the resource schema.
(a) Resource Schema (shared between DP and CP, single source of truth)
Covers
Model/ApiKey/ProviderKey/CachePolicy/Guardrail/RateLimit/ObservabilityExporter/Routing(and any future resources).api7/ai-gateway/schemas/(DP is the strict consumer, so co-locating with DP keeps schema and release in sync)jsonschemacrate to validate etcd watch payloads; failed payloads go to the existingdpmgr_rejected_resourcestablegojsonschemafor REST API request validation; dashboard uses RJSF (or similar) to auto-render JSON Schema → React forms(b) DP bootstrap schema —
ai-gateway/schemas/bootstrap.schema.jsonCovers etcd connection, proxy/admin ports, TLS, observability, cache backend, managed-mode toggle, and other process-level config.
(c) CP process config schema —
AISIX-Cloud/schemas/cp-config.schema.jsonCovers DB URL, JWT issuer, Stripe key, dashboard URL, etc.
Current OpenAPI state (audit before scoping (d))
A quick fact-check found a structural asymmetry that shapes the OpenAPI plan:
crates/aisix-admin/src/openapi.rs/admin/v1/*); proxy/v1/*deliberately excluded (defers to OpenAI's published spec)utoipa/utoipa-axum/utoipa-scalardeclared in Cargo.toml but 0 actual usageGET /admin/openapi.json+GET /admin/openapi-scalar(Scalar UI)docs/configuration/admin-api.md,docs/reference/admin-api-reference.mdTwo signals worth noting:
utoipaderive macros and walked away. The comment inopenapi.rs:15-19records the rationale: "Small enough that maintaining it by hand is less effort than wiringutoipaderive macros across every handler; the surface is stable enough that drift is easy to spot in review." The unusedutoipa*deps can be cleaned up.(d) OpenAPI generation (downstream of resource schema)
Once the resource JSON Schema lands ((a)), it should drive OpenAPI for both surfaces:
DP — refactor, do not rewrite:
openapi.rsschemasobjects with$refto the canonical resource JSON Schema filesutoipa/utoipa-axum/utoipa-scalardeps from Cargo.tomlCP — build from scratch, schema-first:
components/schemas$refs the canonical resource schemaoapi-codegento generate Go route handlers and DTOs from OpenAPI — compiler-enforced no-driftopenapi-typescript+openapi-fetchto generate TS types and client — replaces hand-written fetchersopenapi/cp-admin.yamlopenapi/cp-dashboard.yamlopenapi/cp-internal.yamlStripe webhook stays out (third-party-defined contract).
Phased rollout (folded into the #1 effort estimate):
oapi-codegenflow without migrating all handlers. Refactor DPopenapi.rsto$ref.Versioning: Add a top-level
version: 1|2field to handle semantic-breaking changes (e.g. empty array[]meaning "allow all" in v1 vs. "deny all" in v2). Critical for forward-compatible migration.Effort: 2-3 weeks for Phase 1 (resource schema + bootstrap schemas + CP customer-PAT OpenAPI + DP
openapi.rs$refrefactor); Phase 2 separate.Owner: platform engineer + tech writer
Touches: ai-gateway (schemas/, refactor
openapi.rs, drop unusedutoipa*deps), AISIX-Cloud (schemas/, 3 OpenAPI files,oapi-codegentoolchain), dashboard (generated client in Phase 2)2. Provider documentation template + schema-rooted links —
documentationP1Problem: Today
docs/reference/provider-compatibility.mdis just a matrix table. Users diagnosing provider-specific behavior (e.g. how Anthropic upstream preservescache_control, thinking blocks, and tool_use as byte-level passthrough) have to grep the source.Proposal:
crates/aisix-core/src/models/*.rsGitHub permalinksLocation:
docs/providers/{provider}.mdEffort: 1 week
Owner: tech writer + provider crate owner review
Touches: ai-gateway docs
3. Architecture deep-dive documents (at least 3) —
documentationP1Problem: Platform engineers evaluating our gateway cannot find engineering-depth design explanations.
docs/overview/core-concepts.mdis product-flavored; there is no engineering-RFC-grade content. This is a real procurement decision blocker.Proposal: 3 architecture docs under
docs/architecture/:snapshot-and-watch.md— etcd watch → ArcSwap → lock-free read pathtwo-phase-rate-limit.md— RPM/RPD immediate check (pre-commit) + TPM/TPD deferred counting (post-commit)protocol-translation.md—/v1/messagesas a first-class endpointEach doc: 3-5 Mermaid diagrams, ~2-3k words.
Effort: 1 week (one senior engineer drafts, tech writer polishes)
Owner: senior engineer + tech writer
Touches: ai-gateway docs
4. AGENTS.md / project-specific AI agent navigation —
documentationcross-repoProblem: Today the root
CLAUDE.mdis generic behavioral guidelines (think-before-code, surgical changes, etc.), not codebase navigation. AI agents (Claude Code / Cursor / Copilot etc.) entering our repos lack a project-specific entry-point document, hurting output quality.Proposal: One file per repo.
ai-gateway/AGENTS.mdcovers:Bridgetrait,AisixSnapshot,ProxyStateAISIX-Cloud/AGENTS.mdcovers:internal/cpapi/*/handlers.go)Effort: 0.5 day per repo
Owner: senior engineer + tech writer
Touches: ai-gateway, AISIX-Cloud
Medium Priority (consider next quarter)
5. "Virtual Key" concept repositioning —
documentationcross-repoProblem: Today our
APIKeyresource bundles authentication credential + allowed_models whitelist + rate_limit + team binding. The name "API Key" reads as "auth credential", but the resource is really a governance/policy entity. The industry has converged on "Virtual Key (VK)" for this concept (Stripe restricted keys, OpenRouter, Portkey, etc.).Proposal:
docs/overview/glossary.md(or extend existing): "Virtual Key (VK) — a policy-bound credential combining model whitelist, rate limit, and team/budget association"Effort: 2-3 days
Owner: PM + tech writer
Touches: ai-gateway docs, AISIX-Cloud docs, dashboard
6. Symmetric hook execution + tri-state fallback control —
enhancementProblem: Today our
aisix-guardrailspipeline runs pre/during/post hooks in forward order. There is no guaranteed reverse-order cleanup of already-executed pre-hooks on short-circuit. Additionally, plugins/hooks have no way to signal "this short-circuit should/shouldn't trigger fallback routing."Proposal:
GuardrailEngine: PreHooks execute forward, PostHooks execute reverse (LIFO). On short-circuit, only already-fired PreHooks have their corresponding PostHook called (symmetric cleanup).AllowFallbacks: Option<bool>to the short-circuit response:None= default policy /Some(true)= force fallback /Some(false)= forbid fallback. The routing layer reads this to decide whether to walk the fallback chain.Effort: 1 week (refactor + tests)
Owner: rust engineer
Touches: ai-gateway (aisix-guardrails, aisix-proxy)
7. Reserved header namespace documentation —
documentationProblem: We already emit
x-aisix-cache: hit|miss, but no canonical doc spells out: (a) whichx-aisix-*response headers the gateway emits; (b) whichx-aisix-*request headers clients can set to control gateway behavior; (c) the reserved-prefix contract (what gets stripped vs. forwarded upstream).Proposal: Add a "Reserved Header Namespace" section to
docs/reference/headers-and-error-codes.md:x-aisix-*as the gateway's reserved prefixEffort: 0.5-1 day
Owner: tech writer + engineer review
Touches: ai-gateway docs
8. Error messages with embedded operational guidance (doc-as-error) —
enhancementdocumentationProblem: Today
crates/aisix-core/src/errors.rsand various error responses describe "what went wrong" but not "what to do next." Industry best practice: error messages include the actionable next step ("set X in config" / "in dashboard go to Y > Z").Proposal:
Displayimpl — no dependency on external docsExample transformation:
proxy.request_timeout_secondsin bootstrap config, or override per-model via Dashboard > Models > {model} > Network Config."Effort: 1-2 days
Owner: backend + tech writer
Touches: ai-gateway core, ai-gateway docs (cross-reference)
9. CLI agent integration cookbook —
documentationProblem: Users adopting AI coding assistants (Claude Code, Cursor, Codex CLI, Zed, OpenCode, LibreChat, etc.) need step-by-step recipes for pointing those clients at our gateway. Today we only have OpenAI/Anthropic SDK quickstarts — no client-specific recipes. This is a high-SEO, high-conversion content category.
Proposal: Add
docs/integrations/cli-agents/(ordocs/cookbook/cli-agents/) with at least 3-5 recipes:Each recipe: ~500-800 words, with config snippet, verification step, common pitfalls.
Effort: 1 week (3-5 recipes)
Owner: tech writer + DevRel
Touches: ai-gateway docs
Strategic / Forward-Looking
10. MCP support —
P1enhancementAlready on the P1 roadmap (#58). Scope reminder:
Owner: PM + senior engineer (design phase)
11. Multi-DP cluster patterns (strategic observation only — no action yet)
Current architecture: DP nodes are stateless, kine-on-PG is the single source of truth — sufficient for current scale.
When multi-region DP federation or autonomous DP clusters become a real requirement, evaluate split-transport cluster patterns: gossip for membership/liveness (low-churn, short messages) + gRPC for application state sync (higher-throughput, structured payloads). No action until the requirement materializes.
Anti-patterns to actively avoid (architecture-alignment notes)
For team alignment, we explicitly do NOT plan to adopt:
Bridgetrait (4-6 methods) is cleaner than putting OCR/Container/CachedContent/Speech/Batch all on a single interface. Document this as a deliberate design choice in the architecture doc series (feat(core): Model, ApiKey, RateLimit entities + JSON Schema validators #3).Action item summary
JSON Schema placement (clarification on #1)
The resource schema in #1 is a single file (not one per side). If DP and CP each maintain their own copy, drift over time is inevitable as fields are added.
Three independent files, no overlap.