* fix: add server-side sorting to user list, prevent client-side sort on paged data
The user management table applied client-side sorting to the current
page slice while pagination was handled server-side, causing ID-asc
views to show pages out of order (e.g. 23-42, 3-22, 1-2).
Backend: add sort_by/sort_order query params to GetAllUsers and
SearchUsers with a column whitelist for safe ORDER BY generation.
Frontend: pass sorting state to the API and reset to page 1 on sort
change. Generic useDataTable hook now disables client-side sorted row
model and sort UI for tables with manual pagination but no server-side
sort handler.
* fix: add id tie-breaker to non-unique sort columns, remove side effect from state updater
Append secondary ORDER BY id DESC when sorting by non-unique columns
(quota, created_at, etc.) to prevent row duplication/skipping across
OFFSET pages.
Move onPaginationChange out of setSorting updater to avoid side effects
inside a pure function (React Strict Mode double-invocation safety).
* fix: purge authentication data on hard user deletion
* fix: fail closed when 2FA status lookup fails
* fix: reject stale Telegram login callbacks
* fix(twofa): prevent concurrent backup code and lockout bypasses
* fix(auth): harden user deletion and Telegram verification
* refactor: consolidate relay protocol converters
* refactor relayconvert text converters
* feat: refine relay converters and advanced custom routing
* refactor: enhance logging and add thought signature handling for Gemini requests
* refactor: enhance channel cache and pricing endpoint handling for advanced custom models
* feat: preserve billing usage semantics
* feat: add protocol-aware billing usage
* Delete useless files
* chore: update action versions in workflow files
* chore: update Docker action versions in workflow files
* fix: harden billing usage settlement and hot-path route matching
- estimate Gemini completion tokens locally when billable usageMetadata is
prompt-only but output content was received (e.g. client aborts the stream
before the final chunk), and rebuild the attached billing_usage as estimated
so settlement does not bill zero output tokens
- guard NewClaudeMessagesBillingUsage against all-zero ClaudeUsage, matching
the OpenAI/Gemini constructors, so a zero billing_usage cannot override a
non-zero top-level usage during settlement
- cache compiled advanced-custom route model regexes; they run on the request
hot path and were recompiled per request
- move the effectiveBillingUsage remap to PostTextConsumeQuota only, and
document that calculateTextQuotaSummary expects remapped usage
- document the updatePricingLock -> channelSyncLock lock ordering that
InitChannelCache/CacheUpdateChannel rely on, and the aux-struct pitfall in
GeminiChatResponse.UnmarshalJSON
* feat(subscription): add admin quota reset actions
* fix(subscription): keep quota reset in plan row actions
* refactor(subscription): move user subscription actions into menu
Thread int32 saturation clamps from tiered settlement and video task
recompute into the consume/task logs under admin_info, so oversized or
malformed billing inputs stay auditable. Clamp negative audio duration
before token conversion and gate the saturation UI markers on admin.
- normalize emails (trim + lowercase) and enforce uniqueness across
registration, OAuth auto-registration, and email binding
- serialize concurrent writers on the same normalized email within a
transaction to avoid duplicate accounts
- resolve password reset to a single matching account and reject
ambiguous or absent matches
- require an existing password before self-service password change and
reject login for accounts without a usable password
Async task usage logs (LogQuotaData node dimension) were recorded
under whichever node happened to poll the task to completion, not the
node that submitted it. For token/adaptor-billed video tasks the
pre-deduction is often 0, so the entire quota landed on the last
polling node.
Snapshot common.NodeName into TaskPrivateData at submit time and use
it when writing the settlement consume log; fall back to the current
node when empty so existing tasks stay compatible.
* feat: add system instance reporting
* feat: show system instance resources
* fix: update translations for heartbeat messages in Russian and Vietnamese
* fix: support SMTP STARTTLS mode and NTLM auth
Add explicit SMTP STARTTLS configuration for 587-style connections and keep SSL/TLS as the implicit TLS mode.
Prefer PLAIN when advertised, keep LOGIN compatibility, and add NTLM as a fallback for Exchange SMTP servers that require it after STARTTLS.
* fix: respect explicit SMTP encryption mode
* fix: preserve SMTP TLS compatibility
Replace the per-batch ClickHouse mutation loop with a single
ALTER TABLE ... DELETE, since ClickHouse DELETE is a heavy mutation
that rewrites data parts and per-batch mutations are pathologically
slow. Add deterministic unit tests covering ClickHouse DSN handling,
main-database rejection, TTL DDL generation, log ordering, request_id
backfill, and display id assignment.
* feat(dashboard): add traffic flow sankey chart
Add dashboard flow APIs and a Sankey-based flow view with user, optional API key, model, and channel layers.\n\nReuse the dashboard VChart palette, add precise link/node tooltips and interactions, and cover filtering, layer ordering, color stability, and error states with tests.
* feat: build flow chart from quota data
---------
Co-authored-by: CaIon <i@caion.me>
The idx_created_at_id composite index on the logs table was defined as
(id, created_at) because the GORM `priority` values on Id and CreatedAt were
swapped. Since `id` is the auto-increment primary key, a secondary composite
index leading with `id` is redundant with the PK and cannot accelerate
`created_at` range scans (a range column must sit at the index prefix).
This defeats the common log-listing queries
(`WHERE created_at BETWEEN ? AND ? ORDER BY id DESC LIMIT n` in
GetAllLogs/GetUserLogs) that the index name implies it should serve — the
optimizer falls back to scanning the primary key, degrading to near full-table
scans on large logs tables.
Swap the priorities so the column order becomes (created_at, id), matching the
index name and its intended purpose. idx_user_id_id and idx_created_at_type are
unaffected.
Note: GORM AutoMigrate does not change the column order of an already-existing
index with the same name, so existing deployments must rebuild the index
manually (see PR description for per-database DDL).
Co-authored-by: wuyupeng <wuyupeng@floatmiracle.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Resolve verified V1 frontend feedback by improving channel workflows, auth behavior, API key interactions, user filtering, layout persistence, subscription quota handling, i18n text, pricing metadata, and stale frontend cache recovery.
- Add a global frontend cache version cleanup to prevent old frontend localStorage from causing page errors after upgrades.
- Fix channel copy refresh, model mapping input focus loss, create-channel fetch-model title state, upstream model update confirmation, and batch test toast behavior.
- Respect password login settings and improve Turnstile, forgot-password, registration, and invite-link flows.
- Make user role/status filtering server-side and preserve table page size in URLs.
- Improve API key edit validation feedback and prefetch real keys for reliable copy actions.
- Fix rankings access fail-open behavior, double scrollbars, subscription received amount conversion/display, token i18n wording, model deletion confirmation grammar, and Claude pricing context inference.
- Add clearer Playground model/group loading errors.
Validation:
- bun run typecheck
- bun run i18n:sync
- gofmt on modified Go files
- go test ./controller ./model -run '^$'
* 🐛 fix(channel): evict auto-disabled multi-key channels from cache
Ensure multi-key channels are removed from the in-memory routing cache when all keys become auto-disabled, preventing subsequent requests from repeatedly selecting channels with no available keys.
Also make multi-key status updates more robust by handling missing key matches, checking actual enabled key availability, and restoring the channel status when a key is re-enabled. Add regression coverage for disabled cached channels and multi-key cache eviction.