Skip to content

release v0.7.1 - #1071

Merged
ding113 merged 88 commits into
mainfrom
dev
Apr 24, 2026
Merged

release v0.7.1#1071
ding113 merged 88 commits into
mainfrom
dev

Conversation

@ding113

@ding113 ding113 commented Apr 22, 2026

Copy link
Copy Markdown
Owner

Summary

Release v0.7.1 — consolidates 50+ commits from 20+ feature and fix PRs merged into dev since v0.6.8. This release adds provider groups with cost multipliers, a public status page, IP geolocation and audit logging, K8s deployment manifests with health probes, 5h rate-limit reset modes, and numerous proxy/UX fixes.

Major Features

Provider Groups & Cost Breakdown

  • Add provider_groups table with name, cost multiplier, and description
  • Providers can be assigned to groups; group cost multiplier is applied to all requests
  • Request detail view shows itemized cost breakdown (base cost x multiplier x group multiplier)
  • Group management UI in settings with create/edit/delete operations
  • Related to 【建议】是否能加ccr中那种模型路由功能 #1036 (model routing capability)

Public Status Page

  • New /[locale]/status page with Redis-projected uptime data
  • Configurable aggregation window and time range via system settings
  • Public branding with site title and logo
  • Admin settings UI at /[locale]/settings/status-page for model selection and config
  • Related to 希望供应商管理可以加一个状态站网址 #974 (provider status page URL request)

IP Recording, Audit Logs & IP Geolocation

  • New audit_log table tracking all admin operations (provider/key/user/config changes)
  • Client IP extraction with configurable strategies (X-Forwarded-For, X-Real-IP, CF-Connecting-IP, etc.)
  • IP geolocation lookup via external API with interactive detail dialog
  • Full i18n for audit log labels (5 languages)

K8s Deployment & Health Probes

5-Hour Rate Limit Reset Modes

Leaderboard Enhancements

Session Message Detail

Bug Fixes

Database Migrations (7 files)

Migration Description
0088 Index on message_request for provider+created_at
0089 Create audit_log and provider_groups tables; add client_ip, cost_breakdown, group_cost_multiplier columns; update fn_upsert_usage_ledger trigger
0090 Fix provider_groups NOT NULL constraints on timestamps
0091 Add public_status_window_hours and public_status_aggregation_interval_minutes to system_settings
0092 Add limit_5h_reset_mode to keys, providers, users
0093 Change provider_groups.description from varchar(500) to text
0094 Add limit_5h_cost_reset_at to users

Stats

  • 487 files changed across src, tests, i18n, migrations, K8s manifests, and docs
  • 146 test files added/modified
  • 88 i18n message files across 5 languages (en, ja, ru, zh-CN, zh-TW)
  • Version: 0.6.80.7.0

Test plan

  • bun run typecheck passes
  • bun run lint passes
  • bun run test — all unit tests pass
  • Manual: Create provider group, assign providers, verify cost multiplier in request logs
  • Manual: Visit /status and verify public status page renders with data
  • Manual: Trigger audit events and verify entries in audit log page
  • Manual: Click IP address in logs table, verify geolocation dialog
  • Manual: Test 5h fixed reset mode — set mode to "fixed", verify auto-reset after window
  • Manual: Test user 5h manual reset button
  • Manual: Deploy K8s manifests, verify health probes (/api/health/live, /api/health/ready)

Description enhanced by Claude AI

Greptile Summary

This is a large release PR consolidating 50+ commits into v0.7.1. Major additions include: provider groups with cost multipliers, a public status page backed by Redis projections, IP extraction and geolocation with audit logging, K8s deployment manifests, and a configurable 5h rate-limit reset mode (fixed/rolling). Seven sequential DB migrations bring schema to state 0094. The implementation is generally well-structured — fixed-5h Redis accounting uses atomic Lua scripts, the IP geo client validates and sanitises before caching, and the audit pipeline is wrapped in a fire-and-forget guard that swallows all failures.

Confidence Score: 5/5

Safe to merge — no P0/P1 issues found; all remaining findings are style or minor behavioural edge-case observations.

Extensive review of the security-sensitive paths (IP extraction, audit redaction, public status API, auth guard) shows correct implementation. The fixed-5h window Lua script is atomic and correct. DB migrations are sequential and coherent. The two P2 comments do not affect correctness today.

src/lib/rate-limit/service.ts — fixed-5h window counter reset on mode switch is worth a comment in docs or code.

Important Files Changed

Filename Overview
src/lib/rate-limit/service.ts Adds fixed-5h window via a Redis Lua script; key logic looks correct but the Lua script has a minor return-type inconsistency and the fixed-vs-rolling mode switch has a counter-reset edge case worth noting.
src/lib/ip-geo/client.ts New IP geolocation client with Redis caching; validates IP with isIP(), short-circuits private addresses, and validates the upstream response shape before caching. No issues found.
src/app/api/ip-geo/[ip]/route.ts Admin-only IP geolocation proxy; properly checks session and role before delegating to lookupIp. No security issues found.
src/lib/audit/emit.ts Fire-and-forget audit pipeline with outer catch-all; correctly redacts sensitive fields before persistence and tolerates partial auth module mocking in tests.
src/lib/public-status/rebuild-worker.ts Two-level distributed rebuild locking (in-process Map + Redis NX lock) with correct atomic release via Lua. Non-Lua fallback path has a non-atomic GET→DEL but is only exercised in tests.
drizzle/0089_curly_grey_gargoyle.sql Creates audit_log and provider_groups tables, adds client_ip/cost_breakdown columns, and replaces fn_upsert_usage_ledger trigger. SQL is correct; 0090 idempotently re-asserts NOT NULL on provider_groups timestamps.
src/lib/rate-limit/lease.ts buildLeaseKey now appends reset-mode suffix for 5h/daily windows, changing the Redis key format. Cold-cache impact on upgrade was flagged in a previous thread; no new issues.
src/app/v1/_lib/proxy/auth-guard.ts Centralises IP extraction and pre-auth key resolution; stores clientIp on session for downstream consumers. Logic looks correct.
src/drizzle/schema.ts Schema additions match the seven migrations; providerGroups, auditLog, and new columns (clientIp, costBreakdown, limit5hResetMode) are well-typed.
src/app/api/public-status/route.ts Public, unauthenticated status endpoint; properly clamps query params to an allowlist and only triggers rebuilds for the default interval/range combination to prevent DoS.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: src/lib/rate-limit/service.ts
Line: 121-131

Comment:
**Fixed-5h window silently resets when mode is switched at runtime**

When an entity switches from `rolling` to `fixed` mode (or vice versa), the two Redis keys (`cost_5h_rolling` ZSET and `cost_5h_fixed` string) are independent. Switching to `fixed` always starts the counter at 0 regardless of what was consumed in the previous rolling window, which effectively grants an extra quota window to any entity whose limit was toggled mid-window. Only admins can change this setting, so the blast radius is small, but it may be worth documenting that a mode switch is a soft reset.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: src/lib/rate-limit/service.ts
Line: 121-131

Comment:
**`TRACK_FIXED_COST_WINDOW_LUA``tonumber` return ignored but Lua type inconsistency**

The `else` branch returns `tonumber(ARGV[1])` (a Lua float), while the `if existing` branch returns the raw Bulk String from `INCRBYFLOAT`. These are different Redis return types. Since `trackFixedCostWindow` discards the return value (`Promise<void>`), this causes no observable bug today — but if the return value is ever used, the two branches will behave differently. Consider returning a consistent type:

```lua
local existing = redis.call("GET", KEYS[1])
if existing then
  return redis.call("INCRBYFLOAT", KEYS[1], ARGV[1])
end
redis.call("SET", KEYS[1], ARGV[1], "EX", ARGV[2])
return redis.call("INCRBYFLOAT", KEYS[1], 0)
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: src/lib/ip-geo/client.ts
Line: 27-30

Comment:
**`lang` is not sanitised before being used in the cache key**

`cacheKey` concatenates `ip` and `lang` with a bare `:` separator — `ipgeo:v1:${ip}:${lang}`. If a caller passes `lang=en:injected` the Redis key becomes `ipgeo:v1:1.2.3.4:en:injected`, which is harmless from a security standpoint but silently bypasses the intended key namespace. Using a separator not present in BCP-47 tags would be safer:

```typescript
function cacheKey(ip: string, lang: string): string {
  return `${CACHE_PREFIX}${ip}|${lang}`;
}
```

How can I resolve this? If you propose a fix, please make it concise.

Reviews (2): Last reviewed commit: "fix: support all model types in public s..." | Re-trigger Greptile

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:core area:i18n area:UI enhancement New feature or request size/XL Extra Large PR (> 1000 lines)

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

5小时消费上限 (USD) 无法 手动进行重置 feat: Add fixed/rolling window toggle for 5-hour rate limit

4 participants