Skip to content

feat(openapi): auto-generate OpenAPI spec via Fuego - #3073

Closed
0-don wants to merge 5406 commits into
QuantumNous:mainfrom
0-don:feat/openapi-fuego
Closed

feat(openapi): auto-generate OpenAPI spec via Fuego#3073
0-don wants to merge 5406 commits into
QuantumNous:mainfrom
0-don:feat/openapi-fuego

Conversation

@0-don

@0-don 0-don commented Mar 1, 2026

Copy link
Copy Markdown
Contributor

Summary

Replace static docs/openapi/api.json and docs/openapi/relay.json with auto-generated OpenAPI spec via Fuego. Gin remains the HTTP runtime; Fuego only generates the spec at startup. Gated by ENABLE_OPENAPI=true env var (off by default).

Related: #907, #2348, #2353, #1128, #2502

This supersedes the static JSON approach from #2348/#2353. Specs are now generated from code, so they never go stale.

How it works

  • 201 routes use native Fuego typed handlers; 92 remain as raw gin.HandlerFunc (relay streaming, OAuth sessions, webhooks, redirects that need raw *gin.Context)
  • GinResp[T]() / GinBody[T]() annotations document raw Gin routes in the OpenAPI spec regardless
  • Endpoints: GET /openapi.json (spec), GET /swagger (Scalar UI)

Changes

New dto/ package (25+ files)

  • dto/router.go: wrapper providing typed route registration helpers (Get, PostB, PutB, Delete, etc.) that register in both Gin and the OpenAPI spec simultaneously
  • dto/responses.go: Response[T], Ok/Fail helpers, PageData[T] for consistent typed API responses
  • DTOs for all domains: channel, token, user, subscription, deployment, performance, custom_oauth, checkin, 2FA, topup, codex, etc.

Controller refactoring (all controllers)

  • Refactored from raw gin.Context to Fuego typed handlers with proper request/response types
  • withJSONBody() helper ensures all body-accepting routes use application/json in the spec
  • GinBody[T]() annotates remaining raw Gin handlers with typed request bodies

Type reorganization

  • Move shared types to types/ package to break dto > model > relay/common > dto import cycle
  • channel_settings.go, user_settings.go, openai_video.go moved from dto/ to types/
  • Re-exported via dto/type_aliases.go for backwards compatibility

Other

  • router/openapi.go: spec serving and Scalar UI setup
  • Bump Go to 1.25+, add go-fuego/fuego dependency
  • model/user.go: add omitempty to Password validate tag (Fuego runs validation before handler)
image

Known limitations (all acceptable)

  • fuegogin.Params() is a stub: all 41 call sites use dto.ParseParams[P](c) instead
  • sanitizeSchemaNames does raw string replacement: no type-name collisions exist today
  • Ok[T] returns *Response[T]: workaround for Go 1.25.x ICE with large generic types

Test plan

  • go build ./... succeeds
  • ENABLE_OPENAPI=true: /openapi.json returns valid spec, /swagger shows Scalar UI
  • ENABLE_OPENAPI=false (default): routes still work, no spec served
  • Existing API + relay endpoints work as before

Calcium-Ion and others added 30 commits February 6, 2026 23:08
fix: /v1/chat/completions -> /v1/responses json_schema
将散落在多个文件中的预扣费/结算/退款逻辑抽象为统一的 BillingSession 生命周期管理:

- 新增 BillingSettler 接口 (relay/common/billing.go) 避免循环引用
- 新增 FundingSource 接口 + WalletFunding / SubscriptionFunding 实现 (service/funding_source.go)
- 新增 BillingSession 封装预扣/结算/退款原子操作 (service/billing_session.go)
- 新增 SettleBilling 统一结算辅助函数,替换各 handler 中的 quotaDelta 模式
- 重写 PreConsumeBilling 为 BillingSession 工厂入口
- controller/relay.go 退款守卫改用 BillingSession.Refund()

修复的 Bug:
- 令牌额度泄漏:PreConsumeTokenQuota 成功但 DecreaseUserQuota 失败时未回滚
- 订阅退款遗漏:FinalPreConsumedQuota=0 但 SubscriptionPreConsumed>0 时跳过退款
- 订阅多扣费:subConsume 强制为 1 但 FinalPreConsumedQuota 不同步
- 退款路径不统一:钱包/订阅退款逻辑现统一由 FundingSource.Refund 分派
- Settle 部分失败保护:新增 fundingSettled 标记,资金来源提交后
  令牌调整失败不再导致 Refund 误退已结算的资金
- 订阅多扣费修复:trySubscription 传 subConsume 而非 preConsumedQuota
  给 preConsume,保证三者(amount/preConsume/FinalPreConsumedQuota)一致
- 令牌回滚错误记录:preConsume 中 funding 失败时令牌回滚错误不再丢弃
- 移除钱包路径死代码:用户额度不足的 strings.Contains 匹配不可能命中
- WalletFunding.Refund 不重试:IncreaseUserQuota 非幂等,重试会多退
…e recharge card tabs

- Defaulting to subscriptions when available and avoiding initial flash when no plans exist.
- Adjust the wide-screen layout to place wallet and invite sections side by side, simplify the subscription header and controls, and add padding to prevent card borders from clipping.
- Update related i18n strings by adding the new tab label and removing the obsolete subscription blurb.
…-when-no-plans

✨ refactor(wallet): Top-up layout to embed subscription plans into the recharge card tabs
refactor: 抽象统一计费会话 BillingSession
Add a lightweight active-subscription check to skip subscription pre-consume when none exist, reducing unnecessary transactions and locks. In the subscription UI, disable subscription-first options when no active plan is available, show the effective fallback to wallet with a clear notice, and distinguish “invalidated” from “expired” states. Update i18n strings across supported locales to reflect the new messages and status labels.
Aligns the error variable types in the subscription-first path so that quota fallback checks use the correct NewAPIError.
This prevents build failures and preserves the intended wallet fallback when subscription pre-consume returns an insufficient quota error.
Routes quota alerts through a subscription-specific check when billing from subscriptions, preventing wallet-based thresholds from triggering false warnings.
Updates the notification settings description and localization keys to clarify that both wallet and subscription balances are monitored.
🔔 feat: Add subscription-aware quota notifications and update UI copy
…-fallback

✨ chore: Improve subscription billing fallback and UI states
当上游为 AWS Bedrock 时,message_delta 的 usage 可能缺少 input_tokens、
cache_creation_input_tokens、cache_read_input_tokens 等字段,导致与原生
Anthropic 格式不一致。从 message_start 积累的 claudeInfo 中补全这些字段后
重新序列化,确保客户端收到一致的 usage 格式。
Modified the formatUserLogs function to include a startIdx parameter, allowing for more flexible log ID assignment. Updated calls to this function in GetLogByTokenId and GetUserLogs to pass the appropriate starting index.
feat: add Codex channel disclaimer (i18n, OpenAI terms)
feat: Force beta=true parameter for Anthropic channel
feat(oauth): implement custom OAuth provider
fix: Claude stream block index/type transitions
fix: add paragraph breaks between reasoning summary chunks
# Conflicts:
#	service/openaicompat/chat_to_responses.go
fix: 使用openai兼容接口调用部分渠道在最终端点为claude原生端点下还是走了openai扣减input_token的逻辑
fix: 补全 streaming message_delta 事件缺失的 input_tokens 和 cache 相关字段
…rable

feat: make 5m cache-creation ratio configurable
@0-don
0-don force-pushed the feat/openapi-fuego branch 2 times, most recently from 30eb261 to f071a31 Compare March 10, 2026 18:47
@0-don
0-don force-pushed the feat/openapi-fuego branch from f071a31 to 93cfaf5 Compare March 12, 2026 23:17
@0-don
0-don force-pushed the feat/openapi-fuego branch from 93cfaf5 to 30bd781 Compare March 14, 2026 15:59
seefs001 and others added 7 commits March 15, 2026 00:23
…cff3f3572f535919

feat: add logs content tooltip
Replace static docs/openapi/*.json files with auto-generated OpenAPI
spec using Fuego's fuegogin adapter. Gin remains the HTTP runtime;
Fuego only generates the spec at startup.

Key changes:
- Add dto/router.go wrapper providing typed route registration helpers
  (Get, PostB, PutB, Delete, etc.) that register in both Gin and the
  OpenAPI spec simultaneously
- Add dto/responses.go with Response[T], Ok/Fail helpers, PageData[T]
  for consistent typed API responses
- Refactor all controllers from raw gin.Context to Fuego typed handlers
  with proper request/response types
- Add 25+ DTO files (channel, token, user, subscription, deployment,
  performance, custom_oauth, etc.)
- Move shared types to types/ package to break dto>model>relay import
  cycle (channel_settings, user_settings, openai_video, oauth_errors)
- Add router/openapi.go for spec serving (/openapi.json) and Scalar UI
  (/swagger)
- Gated by ENABLE_OPENAPI=true env var (off by default)
- Bump Go to 1.25+, add go-fuego/fuego dependency

Stats: 201 routes use native Fuego typed handlers, 92 remain as raw
gin.HandlerFunc (relay streaming, OAuth sessions, webhooks)

Related: #907, #2348, #2353, #1128, #2502
@0-don

0-don commented Mar 17, 2026

Copy link
Copy Markdown
Contributor Author

Addressed remaining CodeRabbit feedback:

  • encoding/json in channel.go: Migrated all 5 direct json.* calls to common.Marshal/common.Unmarshal, removed the encoding/json import entirely.
  • epay userId guard: Added userId <= 0 validation in subscription_payment_epay.go before downstream operations.
  • stripe nil deref: Already fixed with proper nil check on GetUserById result.
  • user.go EmailBind session guard: Already safe via comma-ok type assertion pattern.
  • custom_oauth raw errors: Acknowledged as a broader refactor; the pattern matches upstream code and will be addressed separately.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.