feat(analytics): live request log, per-model cost, and visualization …#230
Open
jahin-abrar-official wants to merge 6 commits into
Open
feat(analytics): live request log, per-model cost, and visualization …#230jahin-abrar-official wants to merge 6 commits into
jahin-abrar-official wants to merge 6 commits into
Conversation
- Keep per-model paid-equivalent pricing via applyModelPricing - Keep pinned request tracking (summary + by-model) - Keep interactive by-model table with sortable columns - Keep live request log with filter and drawer details - Remove obsolete costStats query and migrateModelsV23Cost Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
MLuqmanBR
pushed a commit
to MLuqmanBR/api-gateway
that referenced
this pull request
Jun 7, 2026
…shfeenahmed#230) Redesign custom providers from a per-model {baseUrl, modelId, apiKey} blob into first-class platform objects that work like the built-in ones. The operator adds a provider once (slug + display name + base URL), then adds as many models as they like under it. Multiple API keys for the same custom provider now round- robin across a single shared base URL. Server: - server/src/db/index.ts — new custom_providers table (id, slug UNIQUE, display_name, base_url, created_at) + V23 migration that re-points any existing 'custom' rows to a synthetic 'legacy-custom' provider row, so no data is lost on upgrade. - shared/types.ts — Platform no longer includes 'custom'. New CustomProvider/CustomProviderCreate/CustomProviderUpdate/CustomModel* types. Model.platform and ApiKey.platform are relaxed to string so they can hold any custom slug. - server/src/providers/index.ts — add buildProviderFor(platformSlug): returns the registered singleton for built-ins, or constructs an OpenAICompatProvider bound to the custom_providers row's base_url for custom slugs. The old resolveProvider(platform, baseUrl) overload is gone. - server/src/routes/custom.ts — new, 8 endpoints: GET /api/custom-providers POST /api/custom-providers PATCH /api/custom-providers/:slug DELETE /api/custom-providers/:slug (cascades to models, api_keys, fallback_config) GET /api/custom-providers/:slug/models POST /api/custom-providers/:slug/models PATCH /api/custom-models/:id DELETE /api/custom-models/:id Slug regex ^[a-z0-9][a-z0-9-]{1,30}[a-z0-9]$ (2-32 chars, no leading/trailing dash). Built-in slugs (google/groq/...) are deny-listed. PATCH on custom_providers keeps api_keys.base_url in lockstep. - server/src/routes/keys.ts — drop POST /api/keys/custom. POST /api/keys now validates platform via buildProviderFor and stores base_url on the key row for custom slugs. PATCH /api/keys/platform/:platform now accepts custom slugs (verified against custom_providers). - server/src/services/router.ts — uses buildProviderFor(entry.platform). Drop the 'custom && key_id != null' branch; the models.key_id column is now a denormalized legacy column that the router doesn't consult. - server/src/services/health.ts — uses buildProviderFor(row.platform). - server/src/app.ts — mount customRouter behind a path-aware requireAuth guard so /api/ping and /api/auth/* stay public. The guard regex-scopes requireAuth to /api/custom-providers/* and /api/custom-models/* only. Tests: - server/src/__tests__/routes/custom-providers.test.ts — 16 tests across provider CRUD, model CRUD, cascade deletes, slug-collision rejection, buildProviderFor integration. - server/src/__tests__/routes/proxy-empty-completion.test.ts, server/src/__tests__/routes/responses-tool-args-repair.test.ts — add buildProviderFor: () => fakeProvider to the vi.mock factory for the new provider-lookup function. Client: - client/src/pages/KeysPage.tsx — full rewrite. New components: AddPlatformModal, EditPlatformModal, PlatformTile, PlatformsSection, CustomModelsSection. Custom provider tiles get Edit/Remove; the 'Add New Platform' tile is always last in the provider list. Docs: - README.md — update the custom-provider blurb and add a 'Custom platforms and models' subsection covering slug rules, modal fields, model form essential-vs-advanced toggle, and cascade-on-delete behavior. Behavior change worth highlighting: the 'model belongs to one specific key' binding (the models.key_id column) is intentionally dropped. Any enabled key for the custom provider can now serve any model on it.
MLuqmanBR
added a commit
to MLuqmanBR/api-gateway
that referenced
this pull request
Jun 7, 2026
…shfeenahmed#230) Redesign custom providers from a per-model {baseUrl, modelId, apiKey} blob into first-class platform objects that work like the built-in ones. The operator adds a provider once (slug + display name + base URL), then adds as many models as they like under it. Multiple API keys for the same custom provider now round- robin across a single shared base URL. Server: - server/src/db/index.ts — new custom_providers table (id, slug UNIQUE, display_name, base_url, created_at) + V23 migration that re-points any existing 'custom' rows to a synthetic 'legacy-custom' provider row, so no data is lost on upgrade. - shared/types.ts — Platform no longer includes 'custom'. New CustomProvider/CustomProviderCreate/CustomProviderUpdate/CustomModel* types. Model.platform and ApiKey.platform are relaxed to string so they can hold any custom slug. - server/src/providers/index.ts — add buildProviderFor(platformSlug): returns the registered singleton for built-ins, or constructs an OpenAICompatProvider bound to the custom_providers row's base_url for custom slugs. The old resolveProvider(platform, baseUrl) overload is gone. - server/src/routes/custom.ts — new, 8 endpoints: GET /api/custom-providers POST /api/custom-providers PATCH /api/custom-providers/:slug DELETE /api/custom-providers/:slug (cascades to models, api_keys, fallback_config) GET /api/custom-providers/:slug/models POST /api/custom-providers/:slug/models PATCH /api/custom-models/:id DELETE /api/custom-models/:id Slug regex ^[a-z0-9][a-z0-9-]{1,30}[a-z0-9]$ (2-32 chars, no leading/trailing dash). Built-in slugs (google/groq/...) are deny-listed. PATCH on custom_providers keeps api_keys.base_url in lockstep. - server/src/routes/keys.ts — drop POST /api/keys/custom. POST /api/keys now validates platform via buildProviderFor and stores base_url on the key row for custom slugs. PATCH /api/keys/platform/:platform now accepts custom slugs (verified against custom_providers). - server/src/services/router.ts — uses buildProviderFor(entry.platform). Drop the 'custom && key_id != null' branch; the models.key_id column is now a denormalized legacy column that the router doesn't consult. - server/src/services/health.ts — uses buildProviderFor(row.platform). - server/src/app.ts — mount customRouter behind a path-aware requireAuth guard so /api/ping and /api/auth/* stay public. The guard regex-scopes requireAuth to /api/custom-providers/* and /api/custom-models/* only. Tests: - server/src/__tests__/routes/custom-providers.test.ts — 16 tests across provider CRUD, model CRUD, cascade deletes, slug-collision rejection, buildProviderFor integration. - server/src/__tests__/routes/proxy-empty-completion.test.ts, server/src/__tests__/routes/responses-tool-args-repair.test.ts — add buildProviderFor: () => fakeProvider to the vi.mock factory for the new provider-lookup function. Client: - client/src/pages/KeysPage.tsx — full rewrite. New components: AddPlatformModal, EditPlatformModal, PlatformTile, PlatformsSection, CustomModelsSection. Custom provider tiles get Edit/Remove; the 'Add New Platform' tile is always last in the provider list. Docs: - README.md — update the custom-provider blurb and add a 'Custom platforms and models' subsection covering slug rules, modal fields, model form essential-vs-advanced toggle, and cascade-on-delete behavior. Behavior change worth highlighting: the 'model belongs to one specific key' binding (the models.key_id column) is intentionally dropped. Any enabled key for the custom provider can now serve any model on it.
Author
…atAxisLabel, remove unused ModelsTabs import
…ns via V23 migration in db/index.ts
MLuqmanBR
added a commit
to MLuqmanBR/api-gateway
that referenced
this pull request
Jun 10, 2026
…shfeenahmed#230) Redesign custom providers from a per-model {baseUrl, modelId, apiKey} blob into first-class platform objects that work like the built-in ones. The operator adds a provider once (slug + display name + base URL), then adds as many models as they like under it. Multiple API keys for the same custom provider now round- robin across a single shared base URL. Server: - server/src/db/index.ts — new custom_providers table (id, slug UNIQUE, display_name, base_url, created_at) + V23 migration that re-points any existing 'custom' rows to a synthetic 'legacy-custom' provider row, so no data is lost on upgrade. - shared/types.ts — Platform no longer includes 'custom'. New CustomProvider/CustomProviderCreate/CustomProviderUpdate/CustomModel* types. Model.platform and ApiKey.platform are relaxed to string so they can hold any custom slug. - server/src/providers/index.ts — add buildProviderFor(platformSlug): returns the registered singleton for built-ins, or constructs an OpenAICompatProvider bound to the custom_providers row's base_url for custom slugs. The old resolveProvider(platform, baseUrl) overload is gone. - server/src/routes/custom.ts — new, 8 endpoints: GET /api/custom-providers POST /api/custom-providers PATCH /api/custom-providers/:slug DELETE /api/custom-providers/:slug (cascades to models, api_keys, fallback_config) GET /api/custom-providers/:slug/models POST /api/custom-providers/:slug/models PATCH /api/custom-models/:id DELETE /api/custom-models/:id Slug regex ^[a-z0-9][a-z0-9-]{1,30}[a-z0-9]$ (2-32 chars, no leading/trailing dash). Built-in slugs (google/groq/...) are deny-listed. PATCH on custom_providers keeps api_keys.base_url in lockstep. - server/src/routes/keys.ts — drop POST /api/keys/custom. POST /api/keys now validates platform via buildProviderFor and stores base_url on the key row for custom slugs. PATCH /api/keys/platform/:platform now accepts custom slugs (verified against custom_providers). - server/src/services/router.ts — uses buildProviderFor(entry.platform). Drop the 'custom && key_id != null' branch; the models.key_id column is now a denormalized legacy column that the router doesn't consult. - server/src/services/health.ts — uses buildProviderFor(row.platform). - server/src/app.ts — mount customRouter behind a path-aware requireAuth guard so /api/ping and /api/auth/* stay public. The guard regex-scopes requireAuth to /api/custom-providers/* and /api/custom-models/* only. Tests: - server/src/__tests__/routes/custom-providers.test.ts — 16 tests across provider CRUD, model CRUD, cascade deletes, slug-collision rejection, buildProviderFor integration. - server/src/__tests__/routes/proxy-empty-completion.test.ts, server/src/__tests__/routes/responses-tool-args-repair.test.ts — add buildProviderFor: () => fakeProvider to the vi.mock factory for the new provider-lookup function. Client: - client/src/pages/KeysPage.tsx — full rewrite. New components: AddPlatformModal, EditPlatformModal, PlatformTile, PlatformsSection, CustomModelsSection. Custom provider tiles get Edit/Remove; the 'Add New Platform' tile is always last in the provider list. Docs: - README.md — update the custom-provider blurb and add a 'Custom platforms and models' subsection covering slug rules, modal fields, model form essential-vs-advanced toggle, and cascade-on-delete behavior. Behavior change worth highlighting: the 'model belongs to one specific key' binding (the models.key_id column) is intentionally dropped. Any enabled key for the custom provider can now serve any model on it.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



added some feature for better annalysis . hope you guys will love it . if this is approvable please approve it . and add me as contributor . this will be my 1st contribution
Live Request Log backend Added. GET /api/analytics/live-requests endpoint that returns the last 100 requests with provider, model display name, status, latency, error, and timestamp. Supports an errorsOnly=true query filter.
Live Request Log UI Added a new full-width "Live Request Log" panel under Per-Model Breakdown with an All / Errors Only toggle. Rows are clickable and open a side drawer showing full request details + error payload.
Per-Model timeline endpoint� Added GET /api/analytics/by-model-timeline that returns per-model daily/hourly aggregates with requests, tokens, and cost for time-series visualization.
Per-Model Breakdown UI enhancements Added two toggle sets:
Total / Over Time switches between aggregated totals and time-series trends.
Table / Chart / Pie switches visualization type. Pie is disabled in Over Time mode.
Added a new Cost column in the table view with clickable column sorting.
Over Time chart tooltip Added a custom styled tooltip with background that shows timestamp, provider, model, requests, and cost.
Tests Added test coverage for the live-requests endpoint and errorsOnly filter in the analytics route tests.
Build verification Both client and server builds pass; all existing analytics tests pass.
Analytics Charts & UI
Fixed Over Time chart — added dual Y-axis (requests left, cost right)
Added 1h filter — minute-level buckets (HH:MM) alongside 24h/7d/30d
Human-readable time labels — formatAxisLabel() formats 1h→06:42, 24h→6 AM, 7d/30d→Jun 5
Wrapped X-axis labels — wrapLabel() splits long model names into multi-line SVG text so they don't overlap
Smart latency formatting — ≥1000ms renders as 1.5s instead of 1500ms across charts and Live Request Log
Pie chart label toggle — added "Labels" button to show/hide pie slice percentages
Live Request Log
Upgraded from "Recent errors" to full request log with All / Errors Only filter
Color-coded status badges (200 OK, 429 Rate Limit, 502 Bad Gateway, etc.)
Click any row to open drawer with full request details
Pricing Page (new)
Backend