diff --git a/.github/prompts/changelog-update.md b/.github/prompts/changelog-update.md
index f32dbe8b0..9f066fa6b 100644
--- a/.github/prompts/changelog-update.md
+++ b/.github/prompts/changelog-update.md
@@ -1,6 +1,6 @@
# CHANGELOG.md 更新 Prompt
-你是 Claude Code Hub 项目的 Changelog 编辑专家。请根据变更报告更新项目的 CHANGELOG.md 文件。
+你是 CC Hub 项目的 Changelog 编辑专家。请根据变更报告更新项目的 CHANGELOG.md 文件。
## 变更报告
diff --git a/.github/prompts/docs-update.md b/.github/prompts/docs-update.md
index 9f679da7d..a9fb18301 100644
--- a/.github/prompts/docs-update.md
+++ b/.github/prompts/docs-update.md
@@ -1,6 +1,6 @@
# docs-site 文档更新 Prompt
-你是 Claude Code Hub 项目的文档维护专家。请根据变更报告更新在线文档站点。
+你是 CC Hub 项目的文档维护专家。请根据变更报告更新在线文档站点。
## 变更报告
@@ -45,12 +45,12 @@ title: 更新日志
nextjs:
metadata:
title: 更新日志
- description: Claude Code Hub 各版本更新记录
+ description: CC Hub 各版本更新记录
---
# 更新日志
-本页面记录 Claude Code Hub 各版本的更新内容。
+本页面记录 CC Hub 各版本的更新内容。
---
diff --git a/.github/prompts/release-analysis.md b/.github/prompts/release-analysis.md
index 5db686c56..484ba6f3c 100644
--- a/.github/prompts/release-analysis.md
+++ b/.github/prompts/release-analysis.md
@@ -1,6 +1,6 @@
# Release 变更分析 Prompt
-你是 Claude Code Hub 项目的发布文档专家。请分析以下代码变更并生成结构化的变更报告。
+你是 CC Hub 项目的发布文档专家。请分析以下代码变更并生成结构化的变更报告。
## 版本信息
diff --git a/.github/prompts/release-notes.md b/.github/prompts/release-notes.md
index f09c5678f..05a3e5a28 100644
--- a/.github/prompts/release-notes.md
+++ b/.github/prompts/release-notes.md
@@ -1,6 +1,6 @@
# GitHub Release Notes 生成 Prompt
-你是 Claude Code Hub 项目的发布说明撰写专家。请根据变更报告生成适合 GitHub Release 的发布说明。
+你是 CC Hub 项目的发布说明撰写专家。请根据变更报告生成适合 GitHub Release 的发布说明。
## 变更报告
@@ -23,7 +23,7 @@
### 2. 格式模板
```markdown
-## Claude Code Hub {{ VERSION }}
+## CC Hub {{ VERSION }}
{{ SUMMARY }}
diff --git a/.github/workflows/claude-unified-docs.yml b/.github/workflows/claude-unified-docs.yml
index 389ee26a2..05070e2cd 100644
--- a/.github/workflows/claude-unified-docs.yml
+++ b/.github/workflows/claude-unified-docs.yml
@@ -88,7 +88,7 @@ jobs:
github_token: ${{ secrets.GITHUB_TOKEN || secrets.GH_PAT }}
prompt: |
- 你是 Claude Code Hub 项目的发布文档专家。请执行完整的文档更新流程。
+ 你是 CC Hub 项目的发布文档专家。请执行完整的文档更新流程。
## 发布信息
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index d45c95c54..7599035fd 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -24,7 +24,7 @@
### 1. 介绍 Introduction
-Claude Code Hub 是一个面向团队的 AI API 代理平台,支持统一管理多家供应商、智能分流和现代化运维工具。本文档说明如何按照项目既定流程参与贡献,帮助你提交高质量的 Pull Request(PR)。
+CC Hub 是一个面向团队的 AI API 代理平台,支持统一管理多家供应商、智能分流和现代化运维工具。本文档说明如何按照项目既定流程参与贡献,帮助你提交高质量的 Pull Request(PR)。
### 2. 行为准则 Code of Conduct
@@ -166,7 +166,7 @@ docker compose build
### 1. Introduction
-Claude Code Hub centralizes multiple AI providers with smart routing, tenant controls, and observability. This document explains how to deliver high-quality Pull Requests (PRs) that align with the project roadmap.
+CC Hub centralizes multiple AI providers with smart routing, tenant controls, and observability. This document explains how to deliver high-quality Pull Requests (PRs) that align with the project roadmap.
### 2. Code of Conduct
@@ -272,4 +272,4 @@ GitHub Actions runs `Docker Build Test` on every PR to `dev` and `main`; see `.g
---
-感谢你为 Claude Code Hub 做出的贡献!Thanks for helping improve Claude Code Hub!
+感谢你为 CC Hub 做出的贡献!Thanks for helping improve CC Hub!
diff --git a/Makefile b/Makefile
index c68f28f18..430343618 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
# ================================
-# Claude Code Hub - 根目录快捷命令
+# CC Hub - 根目录快捷命令
# ================================
#
# 这个 Makefile 将命令转发到 dev/Makefile
diff --git a/README.en.md b/README.en.md
index 11706cdbb..8cfc9d081 100644
--- a/README.en.md
+++ b/README.en.md
@@ -4,7 +4,7 @@
-# Claude Code Hub
+# CC Hub
**🚀 Intelligent AI API relay platform — the control center for multi-provider onboarding, elastic routing, and granular operations**
@@ -14,7 +14,7 @@
[](https://t.me/ygxz_group)
[](https://deepwiki.com/ding113/claude-code-hub)
-Claude Code Hub combines Next.js 15, Hono, PostgreSQL, and Redis to deliver a Claude/OpenAI-compatible API gateway with smart load balancing, live observability, price governance, and automated documentation, enabling teams to manage multiple AI vendors safely and transparently.
+CC Hub combines Next.js 16, Hono, PostgreSQL, and Redis to deliver a Claude/OpenAI-compatible API gateway with smart load balancing, live observability, price governance, and automated documentation, enabling teams to manage multiple AI vendors safely and transparently.
💬 **Join the discussion**: Questions about deployment, features or technical issues? Join our [Telegram community](https://t.me/ygxz_group)!
@@ -25,7 +25,7 @@ Claude Code Hub combines Next.js 15, Hono, PostgreSQL, and Redis to deliver a Cl
> [!IMPORTANT]
> **This project is currently under active refactoring**
>
-> Claude Code Hub Plus, the refactored version of Claude Code Hub, is expected to be open-sourced under the AGPL license in Q3. Claude Code Hub Plus is dedicated to building a high-performance, stable, commercial-grade LLM gateway, offering comprehensive commercial features such as format conversion, privacy filtering, a model marketplace, and top-up billing, while significantly improving the theoretical performance of the forwarding core. During development of the refactored version, progress and community support for the Node.js version may be delayed — thank you for your understanding.
+> CC Hub Plus, the refactored version of CC Hub, is expected to be open-sourced under the AGPL license in Q3. CC Hub Plus is dedicated to building a high-performance, stable, commercial-grade LLM gateway, offering comprehensive commercial features such as format conversion, privacy filtering, a model marketplace, and top-up billing, while significantly improving the theoretical performance of the forwarding core. During development of the refactored version, progress and community support for the Node.js version may be delayed — thank you for your understanding.
@@ -233,7 +233,7 @@ Once started:
Clients / CLI / Integrations
│
▼
-Next.js 15 App Router (v1 API routes)
+Next.js 16 App Router (v1 API routes)
│
Hono + Proxy Pipeline (Auth → Session Allocation → Rate Limiting → Provider Selection → Forwarding → Response Handling)
│
@@ -392,3 +392,7 @@ This project builds on [zsio/claude-code-hub](https://github.com/zsio/claude-cod
## 📜 License
Released under the [MIT License](LICENSE). You’re welcome to use and extend the project as long as you comply with the license and retain the attribution.
+
+---
+
+CC Hub is not an official Anthropic project and is not affiliated with Anthropic. Claude Code and Claude are trademarks of Anthropic.
diff --git a/README.md b/README.md
index 803adc68d..a1a366063 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@
-# Claude Code Hub
+# CC Hub
**🚀 智能 AI API 代理中转服务平台|面向团队的多供应商统一接入、弹性调度与精细化运营中心**
@@ -14,7 +14,7 @@
[](https://t.me/ygxz_group)
[](https://deepwiki.com/ding113/claude-code-hub)
-Claude Code Hub 通过 Next.js 15 + Hono + PostgreSQL + Redis 组合,实现 Claude/OpenAI 兼容 API 代理、智能负载均衡、实时监控、价格管理与自动化文档,帮助团队安全、可观测地管理多家 AI 服务商。
+CC Hub 通过 Next.js 16 + Hono + PostgreSQL + Redis 组合,实现 Claude/OpenAI 兼容 API 代理、智能负载均衡、实时监控、价格管理与自动化文档,帮助团队安全、可观测地管理多家 AI 服务商。
💬 **加入讨论**:有部署、功能或技术问题?欢迎加入 [Telegram 交流群](https://t.me/ygxz_group) 与社区一起讨论!
@@ -25,7 +25,7 @@ Claude Code Hub 通过 Next.js 15 + Hono + PostgreSQL + Redis 组合,实现 Cl
> [!IMPORTANT]
> **当前项目正处于积极重构阶段**
>
-> Claude Code Hub 的重构版本 Claude Code Hub Plus 预计将于第三季度以 AGPL 形式开源。Claude Code Hub Plus 致力于打造高性能、稳定的商用级 LLM 网关,提供格式转换、隐私过滤、模型广场、充值计费等完善的商用功能,并显著提升转发核心的理论性能。重构版本开发期间,Node.js 版本的开发进度和社区支持可能延误,敬请理解。
+> CC Hub 的重构版本 CC Hub Plus 预计将于第三季度以 AGPL 形式开源。CC Hub Plus 致力于打造高性能、稳定的商用级 LLM 网关,提供格式转换、隐私过滤、模型广场、充值计费等完善的商用功能,并显著提升转发核心的理论性能。重构版本开发期间,Node.js 版本的开发进度和社区支持可能延误,敬请理解。
@@ -238,7 +238,7 @@ Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process -Force
客户端 / CLI / 第三方系统
│
▼
-Next.js 15 App Router (v1 API 路由)
+Next.js 16 App Router (v1 API 路由)
│
Hono + Proxy Pipeline (认证 → Session 分配 → 限流 → 供应商选择 → 请求转发 → 响应处理)
│
@@ -405,3 +405,7 @@ cch doctor # 诊断集群与部署状态
## 📜 许可证 License
本项目采用 [MIT License](LICENSE),可自由使用与二次开发,仍需遵守条款并保留致谢信息。
+
+---
+
+CC Hub 并非 Anthropic 官方项目,与其无任何关联。Claude Code、Claude 等均属 Anthropic 公司的商标。
diff --git a/deploy/k8s/README.md b/deploy/k8s/README.md
index cea90cbda..fd707fbd6 100644
--- a/deploy/k8s/README.md
+++ b/deploy/k8s/README.md
@@ -1,4 +1,4 @@
-# Claude Code Hub — K8s Manifests
+# CC Hub — K8s Manifests
本目录是 Kubernetes 部署清单模板,由 `scripts/deploy-k8s.sh` 在部署时做占位符替换后下发到集群。
不建议直接 `kubectl apply -f` 本目录 — 文件中包含 `{{VAR}}` 占位符,需先渲染。
diff --git a/dev/Makefile b/dev/Makefile
index c03ff4cc6..9c64ead38 100644
--- a/dev/Makefile
+++ b/dev/Makefile
@@ -1,5 +1,5 @@
# ================================
-# Claude Code Hub - dev 工具链
+# CC Hub - dev 工具链
# ================================
#
# 目标:
@@ -35,7 +35,7 @@ LOCAL_REDIS_URL ?= redis://$(REDIS_HOST):$(REDIS_PORT)
help:
@echo ""
- @echo "Claude Code Hub - dev 工具链"
+ @echo "CC Hub - dev 工具链"
@echo ""
@echo "常用命令:"
@echo " make db 启动 PostgreSQL + Redis(Docker)"
diff --git a/docs/api-authentication-guide.md b/docs/api-authentication-guide.md
index 4372f5328..57a9b8100 100644
--- a/docs/api-authentication-guide.md
+++ b/docs/api-authentication-guide.md
@@ -2,7 +2,7 @@
## 概述
-Claude Code Hub 的新版管理 API 位于 `/api/v1/*`。它和代理 API `/v1/*`
+CC Hub 的新版管理 API 位于 `/api/v1/*`。它和代理 API `/v1/*`
互相独立,也和已弃用的 Server Action 适配层 `/api/actions/*` 独立。
新版管理 API 支持三种凭据传递方式:
@@ -35,7 +35,7 @@ Cookie 认证的写操作需要 CSRF 保护:先调用 `GET /api/v1/auth/csrf`
适合浏览器内测试和 Scalar/Swagger UI。
-1. 访问 Claude Code Hub 登录页面。
+1. 访问 CC Hub 登录页面。
2. 使用 `ADMIN_TOKEN` 或允许 Web UI 登录的用户 API Key 登录。
3. 浏览器会设置 `auth-token` Cookie。
4. 在同一浏览器访问 `/api/v1/scalar` 或 `/api/v1/docs`,文档页会自动携带
diff --git a/docs/api-docs-summary.md b/docs/api-docs-summary.md
index bfa2abafd..df88932bb 100644
--- a/docs/api-docs-summary.md
+++ b/docs/api-docs-summary.md
@@ -158,5 +158,5 @@ $ bun run typecheck
---
-**维护者**: Claude Code Hub Team
+**维护者**: CC Hub Team
**最后更新**: 2025-12-17
diff --git a/docs/api/v1/README.md b/docs/api/v1/README.md
index ee5d467b7..2e2bebff5 100644
--- a/docs/api/v1/README.md
+++ b/docs/api/v1/README.md
@@ -1,6 +1,6 @@
# Management REST API v1
-`/api/v1/*` is the REST management API for Claude Code Hub. Its HTTP surface is
+`/api/v1/*` is the REST management API for CC Hub. Its HTTP surface is
mounted separately from:
- `/v1/*`: Claude/OpenAI-compatible proxy endpoints.
diff --git a/docs/architecture-claude-code-hub-2025-11-29.md b/docs/architecture-claude-code-hub-2025-11-29.md
index 2ea401975..211206fbb 100644
--- a/docs/architecture-claude-code-hub-2025-11-29.md
+++ b/docs/architecture-claude-code-hub-2025-11-29.md
@@ -11,7 +11,7 @@
## Document Overview
-This document defines the system architecture for Claude Code Hub. It provides the technical blueprint for implementation, addressing all functional and non-functional requirements from the PRD.
+This document defines the system architecture for CC Hub. It provides the technical blueprint for implementation, addressing all functional and non-functional requirements from the PRD.
**Related Documents:**
@@ -22,7 +22,7 @@ This document defines the system architecture for Claude Code Hub. It provides t
## Executive Summary
-Claude Code Hub (CCH) is an intelligent AI API proxy platform built on a **Modular Monolith** architecture using Next.js 15 with App Router and Hono. The system provides multi-provider management, intelligent load balancing, circuit breaker patterns, and comprehensive monitoring for AI coding tools like Claude Code and Codex.
+CC Hub (CCH) is an intelligent AI API proxy platform built on a **Modular Monolith** architecture using Next.js 16 with App Router and Hono. The system provides multi-provider management, intelligent load balancing, circuit breaker patterns, and comprehensive monitoring for AI coding tools like Claude Code and Codex.
The architecture emphasizes:
@@ -61,7 +61,7 @@ These requirements heavily influence architectural decisions:
### High-Level Architecture
-Claude Code Hub follows a **Modular Monolith** pattern with clear internal boundaries:
+CC Hub follows a **Modular Monolith** pattern with clear internal boundaries:
```
┌─────────────────────────────────────────────────────────────────────────────┐
@@ -75,7 +75,7 @@ Claude Code Hub follows a **Modular Monolith** pattern with clear internal bound
┌─────────────────────────────────────────────────────────────────────────────┐
│ API GATEWAY LAYER │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
-│ │ Next.js 15 + Hono Router │ │
+│ │ Next.js 16 + Hono Router │ │
│ │ ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌───────────┐ │ │
│ │ │ /v1/ │ │ /api/ │ │ /settings │ │ /dashboard│ │ │
│ │ │ messages │ │ actions │ │ (UI) │ │ (UI) │ │ │
@@ -217,11 +217,11 @@ flowchart TB
### Frontend
-**Choice:** Next.js 15 (App Router) + React 19 + Tailwind CSS + shadcn/ui
+**Choice:** Next.js 16 (App Router) + React 19 + Tailwind CSS + shadcn/ui
**Rationale:**
-- **Next.js 15**: Latest stable with App Router, Server Components, and Server Actions
+- **Next.js 16**: Latest stable with App Router, Server Components, and Server Actions
- **React 19**: Latest features for optimal performance
- **Tailwind CSS**: Utility-first CSS for rapid UI development
- **shadcn/ui**: High-quality, accessible component library
@@ -1780,7 +1780,7 @@ _To continue: Run `/workflow-status` to see your progress and next recommended w
| Category | Choice | Alternatives Considered | Key Factor |
| ---------- | ---------- | ----------------------- | -------------------------- |
-| Framework | Next.js 15 | Remix, Nuxt | SSR + API in one |
+| Framework | Next.js 16 | Remix, Nuxt | SSR + API in one |
| Router | Hono | Express, Fastify | Performance |
| ORM | Drizzle | Prisma, TypeORM | Type safety + SQL |
| Database | PostgreSQL | MySQL, SQLite | JSON support + reliability |
diff --git a/docs/k8s-deployment.md b/docs/k8s-deployment.md
index 84826a4ea..fcd6798ec 100644
--- a/docs/k8s-deployment.md
+++ b/docs/k8s-deployment.md
@@ -1,6 +1,6 @@
# Kubernetes / k3s 部署指南
-本文说明如何把 Claude Code Hub 部署到 Kubernetes(含轻量级 k3s)集群。若你只需要单机 Docker 部署,请参考 [`scripts/deploy.sh`](../scripts/deploy.sh) 与 [`docker-compose.yaml`](../docker-compose.yaml)。
+本文说明如何把 CC Hub 部署到 Kubernetes(含轻量级 k3s)集群。若你只需要单机 Docker 部署,请参考 [`scripts/deploy.sh`](../scripts/deploy.sh) 与 [`docker-compose.yaml`](../docker-compose.yaml)。
---
@@ -106,7 +106,7 @@ bash scripts/deploy-k8s.sh --install-k3s -y
```console
+================================================================+
-| Claude Code Hub Deployment Complete! |
+| CC Hub Deployment Complete! |
+================================================================+
Access URL: http://:
diff --git a/docs/prd-claude-code-hub-2025-11-29.md b/docs/prd-claude-code-hub-2025-11-29.md
index 0dac00621..f6d2ce5a6 100644
--- a/docs/prd-claude-code-hub-2025-11-29.md
+++ b/docs/prd-claude-code-hub-2025-11-29.md
@@ -11,7 +11,7 @@
## Document Overview
-This Product Requirements Document (PRD) defines the functional and non-functional requirements for Claude Code Hub. It serves as the source of truth for what will be built and provides traceability from requirements through implementation.
+This Product Requirements Document (PRD) defines the functional and non-functional requirements for CC Hub. It serves as the source of truth for what will be built and provides traceability from requirements through implementation.
**Related Documents:**
@@ -21,7 +21,7 @@ This Product Requirements Document (PRD) defines the functional and non-function
## Executive Summary
-Claude Code Hub is an intelligent AI API proxy platform designed for agile development teams, AI-driven development teams, startups, and small-medium software companies. It provides observable, highly available AI coding infrastructure with multi-provider auto-switching, circuit breaker, seamless retry, complete logging, and billing management - ideal for team collaboration and shared usage scenarios.
+CC Hub is an intelligent AI API proxy platform designed for agile development teams, AI-driven development teams, startups, and small-medium software companies. It provides observable, highly available AI coding infrastructure with multi-provider auto-switching, circuit breaker, seamless retry, complete logging, and billing management - ideal for team collaboration and shared usage scenarios.
---
@@ -29,17 +29,17 @@ Claude Code Hub is an intelligent AI API proxy platform designed for agile devel
### Business Objectives
-- Establish CCH as the recognized open-source AI Coding proxy platform
+- Establish CC Hub as the recognized open-source AI Coding proxy platform
- Grow community awareness and adoption
-- Build a community willing to use and contribute to CCH
+- Build a community willing to use and contribute to CC Hub
- Sustainable development through sponsorship model
- Expand product line (server + client versions in future)
### Success Metrics
- Community recognition and adoption
-- Users willing to use CCH
-- Contributors willing to help maintain CCH
+- Users willing to use CC Hub
+- Contributors willing to help maintain CC Hub
- Growing awareness in the AI Coding tool ecosystem
- KOL recommendations in developer community
@@ -1109,7 +1109,7 @@ Implement the foundational proxy functionality that routes requests to upstream
**Priority:** Must Have
**Business Value:**
-This is the core value proposition of CCH - without this, there is no product. Enables seamless multi-provider experience with high availability.
+This is the core value proposition of CC Hub - without this, there is no product. Enables seamless multi-provider experience with high availability.
---
@@ -1178,7 +1178,7 @@ Implement admin dashboard with comprehensive system management capabilities.
**Priority:** Should Have
**Business Value:**
-Enables system administrators to manage CCH effectively without direct database access or code changes.
+Enables system administrators to manage CC Hub effectively without direct database access or code changes.
---
@@ -1200,7 +1200,7 @@ Implement API endpoints compatible with major AI coding tool formats.
**Priority:** Must Have
**Business Value:**
-Enables CCH to work with all major AI coding tools without client-side changes.
+Enables CC Hub to work with all major AI coding tools without client-side changes.
---
@@ -1255,7 +1255,7 @@ These are preliminary stories. Detailed stories will be created in Phase 4 (Impl
### EPIC-001: Core Proxy Engine
-- As a **developer**, I want to connect my Claude Code CLI to CCH so that I can use AI assistance without managing provider configuration.
+- As a **developer**, I want to connect my Claude Code CLI to CC Hub so that I can use AI assistance without managing provider configuration.
- As a **developer**, I want my requests to automatically failover to backup providers so that I experience uninterrupted service.
- As an **admin**, I want to add multiple providers with different weights so that I can distribute load according to my service agreements.
- As a **developer**, I want session stickiness so that my conversation context is maintained and cache hits improve.
@@ -1282,7 +1282,7 @@ These are preliminary stories. Detailed stories will be created in Phase 4 (Impl
- As a **developer using Claude Code**, I want to use standard Claude API endpoints so that I don't need special configuration.
- As a **developer using Codex CLI**, I want to use Response API format so that my existing tooling works.
-- As a **developer**, I want to access API documentation so that I can integrate CCH into custom tools.
+- As a **developer**, I want to access API documentation so that I can integrate CC Hub into custom tools.
---
@@ -1362,31 +1362,31 @@ These are preliminary stories. Detailed stories will be created in Phase 4 (Impl
## User Flows
-### Flow 1: Developer Connects to CCH
+### Flow 1: Developer Connects to CC Hub
1. Admin provides developer with API key
-2. Developer sets CCH URL as API endpoint in Claude Code
+2. Developer sets CC Hub URL as API endpoint in Claude Code
3. Developer sets provided API key as authentication
-4. Claude Code connects through CCH transparently
+4. Claude Code connects through CC Hub transparently
5. Developer uses AI coding as normal
### Flow 2: Admin Adds New Provider
-1. Admin logs into CCH admin dashboard
+1. Admin logs into CC Hub admin dashboard
2. Admin navigates to Provider Management
3. Admin clicks "Add Provider"
4. Admin enters provider details (name, URL, API key, type)
5. Admin configures weight, priority, limits
6. Admin enables provider
-7. CCH begins routing traffic to new provider
+7. CC Hub begins routing traffic to new provider
### Flow 3: Automatic Failover During Outage
-1. Developer sends request to CCH
-2. CCH routes to primary provider
+1. Developer sends request to CC Hub
+2. CC Hub routes to primary provider
3. Primary provider returns error
4. Circuit breaker records failure
-5. CCH automatically retries on secondary provider
+5. CC Hub automatically retries on secondary provider
6. Secondary provider returns success
7. Developer receives response (unaware of failover)
8. After threshold, circuit breaker opens for primary
diff --git a/docs/product-brief-claude-code-hub-2025-11-29.md b/docs/product-brief-claude-code-hub-2025-11-29.md
index 33f98d96d..ceea9b2b7 100644
--- a/docs/product-brief-claude-code-hub-2025-11-29.md
+++ b/docs/product-brief-claude-code-hub-2025-11-29.md
@@ -10,7 +10,7 @@
## Executive Summary
-Claude Code Hub is an intelligent AI API proxy platform designed for agile development teams, AI-driven development teams, startups, and small-medium software companies. It provides observable, highly available AI coding infrastructure with multi-provider auto-switching, circuit breaker, seamless retry, complete logging, and billing management - ideal for team collaboration and shared usage scenarios.
+CC Hub is an intelligent AI API proxy platform designed for agile development teams, AI-driven development teams, startups, and small-medium software companies. It provides observable, highly available AI coding infrastructure with multi-provider auto-switching, circuit breaker, seamless retry, complete logging, and billing management - ideal for team collaboration and shared usage scenarios.
---
diff --git a/docs/public-status-api.md b/docs/public-status-api.md
index 964af5fec..0b489c622 100644
--- a/docs/public-status-api.md
+++ b/docs/public-status-api.md
@@ -2,7 +2,7 @@
## 概述
-Claude Code Hub 提供两条无需认证的公开状态接口:
+CC Hub 提供两条无需认证的公开状态接口:
- `GET /api/public-status`
- `GET /api/public-site-meta`
@@ -121,8 +121,8 @@ curl "http://localhost:23000/api/public-status?groupSlug=anthropic&status=failed
]
},
"meta": {
- "siteTitle": "Claude Code Hub",
- "siteDescription": "Claude Code Hub public status",
+ "siteTitle": "CC Hub",
+ "siteDescription": "CC Hub public status",
"timeZone": "UTC"
},
"groups": []
@@ -213,8 +213,8 @@ curl "http://localhost:23000/api/public-site-meta"
```json
{
"available": true,
- "siteTitle": "Claude Code Hub",
- "siteDescription": "Claude Code Hub public status",
+ "siteTitle": "CC Hub",
+ "siteDescription": "CC Hub public status",
"timeZone": "UTC",
"source": "projection"
}
diff --git a/drizzle/0115_breezy_polaris.sql b/drizzle/0115_breezy_polaris.sql
new file mode 100644
index 000000000..015460b76
--- /dev/null
+++ b/drizzle/0115_breezy_polaris.sql
@@ -0,0 +1,2 @@
+ALTER TABLE "system_settings" ALTER COLUMN "site_title" SET DEFAULT 'CC Hub';--> statement-breakpoint
+UPDATE "system_settings" SET "site_title" = 'CC Hub' WHERE "site_title" = 'Claude Code Hub';
diff --git a/drizzle/meta/0115_snapshot.json b/drizzle/meta/0115_snapshot.json
new file mode 100644
index 000000000..6e187e044
--- /dev/null
+++ b/drizzle/meta/0115_snapshot.json
@@ -0,0 +1,5175 @@
+{
+ "id": "6ef3f512-a210-4d69-801a-9cd1ee9e1e52",
+ "prevId": "63b9d353-72a5-432c-88ff-77e871ddfb68",
+ "version": "7",
+ "dialect": "postgresql",
+ "tables": {
+ "public.audit_log": {
+ "name": "audit_log",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "action_category": {
+ "name": "action_category",
+ "type": "varchar(32)",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "action_type": {
+ "name": "action_type",
+ "type": "varchar(64)",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "target_type": {
+ "name": "target_type",
+ "type": "varchar(32)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "target_id": {
+ "name": "target_id",
+ "type": "varchar(64)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "target_name": {
+ "name": "target_name",
+ "type": "varchar(256)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "before_value": {
+ "name": "before_value",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "after_value": {
+ "name": "after_value",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "operator_user_id": {
+ "name": "operator_user_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "operator_user_name": {
+ "name": "operator_user_name",
+ "type": "varchar(128)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "operator_key_id": {
+ "name": "operator_key_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "operator_key_name": {
+ "name": "operator_key_name",
+ "type": "varchar(128)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "operator_ip": {
+ "name": "operator_ip",
+ "type": "varchar(45)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "user_agent": {
+ "name": "user_agent",
+ "type": "varchar(512)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "success": {
+ "name": "success",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "error_message": {
+ "name": "error_message",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "idx_audit_log_category_created_at": {
+ "name": "idx_audit_log_category_created_at",
+ "columns": [
+ {
+ "expression": "action_category",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": false,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_audit_log_operator_user_created_at": {
+ "name": "idx_audit_log_operator_user_created_at",
+ "columns": [
+ {
+ "expression": "operator_user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": false,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "where": "\"audit_log\".\"operator_user_id\" IS NOT NULL",
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_audit_log_operator_ip_created_at": {
+ "name": "idx_audit_log_operator_ip_created_at",
+ "columns": [
+ {
+ "expression": "operator_ip",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": false,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "where": "\"audit_log\".\"operator_ip\" IS NOT NULL",
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_audit_log_target": {
+ "name": "idx_audit_log_target",
+ "columns": [
+ {
+ "expression": "target_type",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "target_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "where": "\"audit_log\".\"target_type\" IS NOT NULL",
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_audit_log_created_at_id": {
+ "name": "idx_audit_log_created_at_id",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": false,
+ "nulls": "last"
+ },
+ {
+ "expression": "id",
+ "isExpression": false,
+ "asc": false,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.cloud_pricing_catalog": {
+ "name": "cloud_pricing_catalog",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "version": {
+ "name": "version",
+ "type": "varchar(64)",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "currency": {
+ "name": "currency",
+ "type": "varchar(16)",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'USD'"
+ },
+ "refreshed_at": {
+ "name": "refreshed_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "providers": {
+ "name": "providers",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "vendors": {
+ "name": "vendors",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "model_count": {
+ "name": "model_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "synced_at": {
+ "name": "synced_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.error_rules": {
+ "name": "error_rules",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "pattern": {
+ "name": "pattern",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "match_type": {
+ "name": "match_type",
+ "type": "varchar(20)",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'regex'"
+ },
+ "category": {
+ "name": "category",
+ "type": "varchar(50)",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "description": {
+ "name": "description",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "override_response": {
+ "name": "override_response",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "override_status_code": {
+ "name": "override_status_code",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "is_enabled": {
+ "name": "is_enabled",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": true
+ },
+ "is_default": {
+ "name": "is_default",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "priority": {
+ "name": "priority",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "idx_error_rules_enabled": {
+ "name": "idx_error_rules_enabled",
+ "columns": [
+ {
+ "expression": "is_enabled",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "priority",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "unique_pattern": {
+ "name": "unique_pattern",
+ "columns": [
+ {
+ "expression": "pattern",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_category": {
+ "name": "idx_category",
+ "columns": [
+ {
+ "expression": "category",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_match_type": {
+ "name": "idx_match_type",
+ "columns": [
+ {
+ "expression": "match_type",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.keys": {
+ "name": "keys",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "key": {
+ "name": "key",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "name": {
+ "name": "name",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "is_enabled": {
+ "name": "is_enabled",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false,
+ "default": true
+ },
+ "expires_at": {
+ "name": "expires_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "can_login_web_ui": {
+ "name": "can_login_web_ui",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false,
+ "default": false
+ },
+ "limit_5h_usd": {
+ "name": "limit_5h_usd",
+ "type": "numeric(10, 2)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "limit_5h_reset_mode": {
+ "name": "limit_5h_reset_mode",
+ "type": "daily_reset_mode",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'rolling'"
+ },
+ "limit_daily_usd": {
+ "name": "limit_daily_usd",
+ "type": "numeric(10, 2)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "daily_reset_mode": {
+ "name": "daily_reset_mode",
+ "type": "daily_reset_mode",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'fixed'"
+ },
+ "daily_reset_time": {
+ "name": "daily_reset_time",
+ "type": "varchar(5)",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'00:00'"
+ },
+ "limit_weekly_usd": {
+ "name": "limit_weekly_usd",
+ "type": "numeric(10, 2)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "limit_monthly_usd": {
+ "name": "limit_monthly_usd",
+ "type": "numeric(10, 2)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "limit_total_usd": {
+ "name": "limit_total_usd",
+ "type": "numeric(10, 2)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "cost_reset_at": {
+ "name": "cost_reset_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "limit_concurrent_sessions": {
+ "name": "limit_concurrent_sessions",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "default": 0
+ },
+ "provider_group": {
+ "name": "provider_group",
+ "type": "varchar(200)",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "'default'"
+ },
+ "cache_ttl_preference": {
+ "name": "cache_ttl_preference",
+ "type": "varchar(10)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "now()"
+ },
+ "deleted_at": {
+ "name": "deleted_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "idx_keys_user_id": {
+ "name": "idx_keys_user_id",
+ "columns": [
+ {
+ "expression": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_keys_key": {
+ "name": "idx_keys_key",
+ "columns": [
+ {
+ "expression": "key",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_keys_created_at": {
+ "name": "idx_keys_created_at",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_keys_deleted_at": {
+ "name": "idx_keys_deleted_at",
+ "columns": [
+ {
+ "expression": "deleted_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.message_request": {
+ "name": "message_request",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "provider_id": {
+ "name": "provider_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "key": {
+ "name": "key",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "model": {
+ "name": "model",
+ "type": "varchar(128)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "duration_ms": {
+ "name": "duration_ms",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "cost_usd": {
+ "name": "cost_usd",
+ "type": "numeric(21, 15)",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "'0'"
+ },
+ "cost_multiplier": {
+ "name": "cost_multiplier",
+ "type": "numeric(10, 4)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "group_cost_multiplier": {
+ "name": "group_cost_multiplier",
+ "type": "numeric(10, 4)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "cost_breakdown": {
+ "name": "cost_breakdown",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "session_id": {
+ "name": "session_id",
+ "type": "varchar(64)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "request_sequence": {
+ "name": "request_sequence",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "default": 1
+ },
+ "provider_chain": {
+ "name": "provider_chain",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "routing_trace": {
+ "name": "routing_trace",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "status_code": {
+ "name": "status_code",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "api_type": {
+ "name": "api_type",
+ "type": "varchar(20)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "endpoint": {
+ "name": "endpoint",
+ "type": "varchar(256)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "original_model": {
+ "name": "original_model",
+ "type": "varchar(128)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "actual_response_model": {
+ "name": "actual_response_model",
+ "type": "varchar(128)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "input_tokens": {
+ "name": "input_tokens",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "output_tokens": {
+ "name": "output_tokens",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "ttfb_ms": {
+ "name": "ttfb_ms",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "first_byte_ms": {
+ "name": "first_byte_ms",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "cache_creation_input_tokens": {
+ "name": "cache_creation_input_tokens",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "cache_read_input_tokens": {
+ "name": "cache_read_input_tokens",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "cache_creation_5m_input_tokens": {
+ "name": "cache_creation_5m_input_tokens",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "cache_creation_1h_input_tokens": {
+ "name": "cache_creation_1h_input_tokens",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "cache_ttl_applied": {
+ "name": "cache_ttl_applied",
+ "type": "varchar(10)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "context_1m_applied": {
+ "name": "context_1m_applied",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false,
+ "default": false
+ },
+ "swap_cache_ttl_applied": {
+ "name": "swap_cache_ttl_applied",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false,
+ "default": false
+ },
+ "special_settings": {
+ "name": "special_settings",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "hedge_losers": {
+ "name": "hedge_losers",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "error_message": {
+ "name": "error_message",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "error_stack": {
+ "name": "error_stack",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "error_cause": {
+ "name": "error_cause",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "blocked_by": {
+ "name": "blocked_by",
+ "type": "varchar(50)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "blocked_reason": {
+ "name": "blocked_reason",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "user_agent": {
+ "name": "user_agent",
+ "type": "varchar(512)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "client_ip": {
+ "name": "client_ip",
+ "type": "varchar(45)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "messages_count": {
+ "name": "messages_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "cache_compatibility_key": {
+ "name": "cache_compatibility_key",
+ "type": "varchar(64)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "cache_score_eligible": {
+ "name": "cache_score_eligible",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "cache_score_excluded_reason": {
+ "name": "cache_score_excluded_reason",
+ "type": "varchar(32)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "theoretical_cache_tokens": {
+ "name": "theoretical_cache_tokens",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "cache_ttl_bucket": {
+ "name": "cache_ttl_bucket",
+ "type": "varchar(10)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "now()"
+ },
+ "deleted_at": {
+ "name": "deleted_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "idx_message_request_user_date_cost": {
+ "name": "idx_message_request_user_date_cost",
+ "columns": [
+ {
+ "expression": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "cost_usd",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "where": "\"message_request\".\"deleted_at\" IS NULL",
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_message_request_user_created_at_cost_stats": {
+ "name": "idx_message_request_user_created_at_cost_stats",
+ "columns": [
+ {
+ "expression": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "cost_usd",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "where": "\"message_request\".\"deleted_at\" IS NULL AND (\"message_request\".\"blocked_by\" IS NULL OR \"message_request\".\"blocked_by\" <> 'warmup')",
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_message_request_user_query": {
+ "name": "idx_message_request_user_query",
+ "columns": [
+ {
+ "expression": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "where": "\"message_request\".\"deleted_at\" IS NULL",
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_message_request_provider_created_at_active": {
+ "name": "idx_message_request_provider_created_at_active",
+ "columns": [
+ {
+ "expression": "provider_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "where": "\"message_request\".\"deleted_at\" IS NULL AND (\"message_request\".\"blocked_by\" IS NULL OR \"message_request\".\"blocked_by\" <> 'warmup')",
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_message_request_provider_created_at_finalized_active": {
+ "name": "idx_message_request_provider_created_at_finalized_active",
+ "columns": [
+ {
+ "expression": "provider_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": false,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "where": "\"message_request\".\"deleted_at\" IS NULL AND \"message_request\".\"status_code\" IS NOT NULL",
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_message_request_session_id": {
+ "name": "idx_message_request_session_id",
+ "columns": [
+ {
+ "expression": "session_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "where": "\"message_request\".\"deleted_at\" IS NULL",
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_message_request_session_id_prefix": {
+ "name": "idx_message_request_session_id_prefix",
+ "columns": [
+ {
+ "expression": "\"session_id\" varchar_pattern_ops",
+ "asc": true,
+ "isExpression": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "where": "\"message_request\".\"deleted_at\" IS NULL AND (\"message_request\".\"blocked_by\" IS NULL OR \"message_request\".\"blocked_by\" <> 'warmup')",
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_message_request_session_seq": {
+ "name": "idx_message_request_session_seq",
+ "columns": [
+ {
+ "expression": "session_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "request_sequence",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "where": "\"message_request\".\"deleted_at\" IS NULL",
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_message_request_endpoint": {
+ "name": "idx_message_request_endpoint",
+ "columns": [
+ {
+ "expression": "endpoint",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "where": "\"message_request\".\"deleted_at\" IS NULL",
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_message_request_blocked_by": {
+ "name": "idx_message_request_blocked_by",
+ "columns": [
+ {
+ "expression": "blocked_by",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "where": "\"message_request\".\"deleted_at\" IS NULL",
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_message_request_provider_id": {
+ "name": "idx_message_request_provider_id",
+ "columns": [
+ {
+ "expression": "provider_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_message_request_user_id": {
+ "name": "idx_message_request_user_id",
+ "columns": [
+ {
+ "expression": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_message_request_key": {
+ "name": "idx_message_request_key",
+ "columns": [
+ {
+ "expression": "key",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_message_request_key_created_at_id": {
+ "name": "idx_message_request_key_created_at_id",
+ "columns": [
+ {
+ "expression": "key",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": false,
+ "nulls": "last"
+ },
+ {
+ "expression": "id",
+ "isExpression": false,
+ "asc": false,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "where": "\"message_request\".\"deleted_at\" IS NULL",
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_message_request_key_model_active": {
+ "name": "idx_message_request_key_model_active",
+ "columns": [
+ {
+ "expression": "key",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "model",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "where": "\"message_request\".\"deleted_at\" IS NULL AND \"message_request\".\"model\" IS NOT NULL AND (\"message_request\".\"blocked_by\" IS NULL OR \"message_request\".\"blocked_by\" <> 'warmup')",
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_message_request_key_endpoint_active": {
+ "name": "idx_message_request_key_endpoint_active",
+ "columns": [
+ {
+ "expression": "key",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "endpoint",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "where": "\"message_request\".\"deleted_at\" IS NULL AND \"message_request\".\"endpoint\" IS NOT NULL AND (\"message_request\".\"blocked_by\" IS NULL OR \"message_request\".\"blocked_by\" <> 'warmup')",
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_message_request_created_at_id_active": {
+ "name": "idx_message_request_created_at_id_active",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": false,
+ "nulls": "last"
+ },
+ {
+ "expression": "id",
+ "isExpression": false,
+ "asc": false,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "where": "\"message_request\".\"deleted_at\" IS NULL",
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_message_request_model_active": {
+ "name": "idx_message_request_model_active",
+ "columns": [
+ {
+ "expression": "model",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "where": "\"message_request\".\"deleted_at\" IS NULL AND \"message_request\".\"model\" IS NOT NULL",
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_message_request_status_code_active": {
+ "name": "idx_message_request_status_code_active",
+ "columns": [
+ {
+ "expression": "status_code",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "where": "\"message_request\".\"deleted_at\" IS NULL AND \"message_request\".\"status_code\" IS NOT NULL",
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_message_request_created_at": {
+ "name": "idx_message_request_created_at",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_message_request_deleted_at": {
+ "name": "idx_message_request_deleted_at",
+ "columns": [
+ {
+ "expression": "deleted_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_message_request_key_last_active": {
+ "name": "idx_message_request_key_last_active",
+ "columns": [
+ {
+ "expression": "key",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": false,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "where": "\"message_request\".\"deleted_at\" IS NULL AND (\"message_request\".\"blocked_by\" IS NULL OR \"message_request\".\"blocked_by\" <> 'warmup')",
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_message_request_key_cost_active": {
+ "name": "idx_message_request_key_cost_active",
+ "columns": [
+ {
+ "expression": "key",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "cost_usd",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "where": "\"message_request\".\"deleted_at\" IS NULL AND (\"message_request\".\"blocked_by\" IS NULL OR \"message_request\".\"blocked_by\" <> 'warmup')",
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_message_request_session_user_info": {
+ "name": "idx_message_request_session_user_info",
+ "columns": [
+ {
+ "expression": "session_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "key",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "where": "\"message_request\".\"deleted_at\" IS NULL",
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_message_request_client_ip_created_at": {
+ "name": "idx_message_request_client_ip_created_at",
+ "columns": [
+ {
+ "expression": "client_ip",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": false,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "where": "\"message_request\".\"deleted_at\" IS NULL AND \"message_request\".\"client_ip\" IS NOT NULL",
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.model_prices": {
+ "name": "model_prices",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "model_name": {
+ "name": "model_name",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "price_data": {
+ "name": "price_data",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "source": {
+ "name": "source",
+ "type": "varchar(20)",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'cloud'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "idx_model_prices_latest": {
+ "name": "idx_model_prices_latest",
+ "columns": [
+ {
+ "expression": "model_name",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": false,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_model_prices_model_name": {
+ "name": "idx_model_prices_model_name",
+ "columns": [
+ {
+ "expression": "model_name",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_model_prices_created_at": {
+ "name": "idx_model_prices_created_at",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": false,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_model_prices_source": {
+ "name": "idx_model_prices_source",
+ "columns": [
+ {
+ "expression": "source",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_model_prices_vendor": {
+ "name": "idx_model_prices_vendor",
+ "columns": [
+ {
+ "expression": "((\"price_data\" ->> 'vendor'))",
+ "asc": true,
+ "isExpression": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_model_prices_aliases": {
+ "name": "idx_model_prices_aliases",
+ "columns": [
+ {
+ "expression": "((\"price_data\" -> 'aliases'))",
+ "asc": true,
+ "isExpression": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "gin",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.notification_settings": {
+ "name": "notification_settings",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "enabled": {
+ "name": "enabled",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "use_legacy_mode": {
+ "name": "use_legacy_mode",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "circuit_breaker_enabled": {
+ "name": "circuit_breaker_enabled",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "circuit_breaker_webhook": {
+ "name": "circuit_breaker_webhook",
+ "type": "varchar(512)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "daily_leaderboard_enabled": {
+ "name": "daily_leaderboard_enabled",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "daily_leaderboard_webhook": {
+ "name": "daily_leaderboard_webhook",
+ "type": "varchar(512)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "daily_leaderboard_time": {
+ "name": "daily_leaderboard_time",
+ "type": "varchar(10)",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "'09:00'"
+ },
+ "daily_leaderboard_top_n": {
+ "name": "daily_leaderboard_top_n",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "default": 5
+ },
+ "cost_alert_enabled": {
+ "name": "cost_alert_enabled",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "cost_alert_webhook": {
+ "name": "cost_alert_webhook",
+ "type": "varchar(512)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "cost_alert_threshold": {
+ "name": "cost_alert_threshold",
+ "type": "numeric(5, 2)",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "'0.80'"
+ },
+ "cost_alert_check_interval": {
+ "name": "cost_alert_check_interval",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "default": 60
+ },
+ "cache_hit_rate_alert_enabled": {
+ "name": "cache_hit_rate_alert_enabled",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "cache_hit_rate_alert_webhook": {
+ "name": "cache_hit_rate_alert_webhook",
+ "type": "varchar(512)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "cache_hit_rate_alert_window_mode": {
+ "name": "cache_hit_rate_alert_window_mode",
+ "type": "varchar(10)",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "'auto'"
+ },
+ "cache_hit_rate_alert_check_interval": {
+ "name": "cache_hit_rate_alert_check_interval",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "default": 5
+ },
+ "cache_hit_rate_alert_historical_lookback_days": {
+ "name": "cache_hit_rate_alert_historical_lookback_days",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "default": 7
+ },
+ "cache_hit_rate_alert_min_eligible_requests": {
+ "name": "cache_hit_rate_alert_min_eligible_requests",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "default": 20
+ },
+ "cache_hit_rate_alert_min_eligible_tokens": {
+ "name": "cache_hit_rate_alert_min_eligible_tokens",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "default": 0
+ },
+ "cache_hit_rate_alert_abs_min": {
+ "name": "cache_hit_rate_alert_abs_min",
+ "type": "numeric(5, 4)",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "'0.05'"
+ },
+ "cache_hit_rate_alert_drop_rel": {
+ "name": "cache_hit_rate_alert_drop_rel",
+ "type": "numeric(5, 4)",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "'0.3'"
+ },
+ "cache_hit_rate_alert_drop_abs": {
+ "name": "cache_hit_rate_alert_drop_abs",
+ "type": "numeric(5, 4)",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "'0.1'"
+ },
+ "cache_hit_rate_alert_cooldown_minutes": {
+ "name": "cache_hit_rate_alert_cooldown_minutes",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "default": 30
+ },
+ "cache_hit_rate_alert_top_n": {
+ "name": "cache_hit_rate_alert_top_n",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "default": 10
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.notification_target_bindings": {
+ "name": "notification_target_bindings",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "notification_type": {
+ "name": "notification_type",
+ "type": "notification_type",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "target_id": {
+ "name": "target_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "is_enabled": {
+ "name": "is_enabled",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": true
+ },
+ "schedule_cron": {
+ "name": "schedule_cron",
+ "type": "varchar(100)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "schedule_timezone": {
+ "name": "schedule_timezone",
+ "type": "varchar(50)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "template_override": {
+ "name": "template_override",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "unique_notification_target_binding": {
+ "name": "unique_notification_target_binding",
+ "columns": [
+ {
+ "expression": "notification_type",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "target_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_notification_bindings_type": {
+ "name": "idx_notification_bindings_type",
+ "columns": [
+ {
+ "expression": "notification_type",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "is_enabled",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_notification_bindings_target": {
+ "name": "idx_notification_bindings_target",
+ "columns": [
+ {
+ "expression": "target_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "is_enabled",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "notification_target_bindings_target_id_webhook_targets_id_fk": {
+ "name": "notification_target_bindings_target_id_webhook_targets_id_fk",
+ "tableFrom": "notification_target_bindings",
+ "tableTo": "webhook_targets",
+ "columnsFrom": [
+ "target_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.provider_batch_apply_operations": {
+ "name": "provider_batch_apply_operations",
+ "schema": "",
+ "columns": {
+ "claim_key": {
+ "name": "claim_key",
+ "type": "varchar(256)",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "preview_token": {
+ "name": "preview_token",
+ "type": "varchar(256)",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "payload_fingerprint": {
+ "name": "payload_fingerprint",
+ "type": "varchar(128)",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "operation_id": {
+ "name": "operation_id",
+ "type": "varchar(256)",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "undo_token": {
+ "name": "undo_token",
+ "type": "varchar(256)",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "undo_expires_at": {
+ "name": "undo_expires_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "undo_consumed_at": {
+ "name": "undo_consumed_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "status": {
+ "name": "status",
+ "type": "varchar(32)",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "result": {
+ "name": "result",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "expires_at": {
+ "name": "expires_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "uniq_provider_batch_apply_operations_preview_token": {
+ "name": "uniq_provider_batch_apply_operations_preview_token",
+ "columns": [
+ {
+ "expression": "preview_token",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "uniq_provider_batch_apply_operations_operation_id": {
+ "name": "uniq_provider_batch_apply_operations_operation_id",
+ "columns": [
+ {
+ "expression": "operation_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "uniq_provider_batch_apply_operations_undo_token": {
+ "name": "uniq_provider_batch_apply_operations_undo_token",
+ "columns": [
+ {
+ "expression": "undo_token",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_provider_batch_apply_operations_expires_at": {
+ "name": "idx_provider_batch_apply_operations_expires_at",
+ "columns": [
+ {
+ "expression": "expires_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.provider_cache_effectiveness": {
+ "name": "provider_cache_effectiveness",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "provider_id": {
+ "name": "provider_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "model": {
+ "name": "model",
+ "type": "varchar(128)",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "cache_ttl_bucket": {
+ "name": "cache_ttl_bucket",
+ "type": "varchar(10)",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "window_start": {
+ "name": "window_start",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "window_end": {
+ "name": "window_end",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "sample_count": {
+ "name": "sample_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "eligible_count": {
+ "name": "eligible_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "theoretical_cache_tokens": {
+ "name": "theoretical_cache_tokens",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "observed_cache_read_tokens": {
+ "name": "observed_cache_read_tokens",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "raw_effectiveness_bp": {
+ "name": "raw_effectiveness_bp",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "confidence_bp": {
+ "name": "confidence_bp",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "effectiveness_bp": {
+ "name": "effectiveness_bp",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "idx_provider_cache_effectiveness_window": {
+ "name": "idx_provider_cache_effectiveness_window",
+ "columns": [
+ {
+ "expression": "provider_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "model",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "window_start",
+ "isExpression": false,
+ "asc": false,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.provider_endpoint_probe_logs": {
+ "name": "provider_endpoint_probe_logs",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "endpoint_id": {
+ "name": "endpoint_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "source": {
+ "name": "source",
+ "type": "varchar(20)",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'scheduled'"
+ },
+ "ok": {
+ "name": "ok",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "status_code": {
+ "name": "status_code",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "latency_ms": {
+ "name": "latency_ms",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "error_type": {
+ "name": "error_type",
+ "type": "varchar(64)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "error_message": {
+ "name": "error_message",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "idx_provider_endpoint_probe_logs_endpoint_created_at": {
+ "name": "idx_provider_endpoint_probe_logs_endpoint_created_at",
+ "columns": [
+ {
+ "expression": "endpoint_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": false,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_provider_endpoint_probe_logs_created_at": {
+ "name": "idx_provider_endpoint_probe_logs_created_at",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "provider_endpoint_probe_logs_endpoint_id_provider_endpoints_id_fk": {
+ "name": "provider_endpoint_probe_logs_endpoint_id_provider_endpoints_id_fk",
+ "tableFrom": "provider_endpoint_probe_logs",
+ "tableTo": "provider_endpoints",
+ "columnsFrom": [
+ "endpoint_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.provider_endpoints": {
+ "name": "provider_endpoints",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "vendor_id": {
+ "name": "vendor_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "provider_type": {
+ "name": "provider_type",
+ "type": "varchar(20)",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'claude'"
+ },
+ "url": {
+ "name": "url",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "label": {
+ "name": "label",
+ "type": "varchar(200)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "sort_order": {
+ "name": "sort_order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "is_enabled": {
+ "name": "is_enabled",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": true
+ },
+ "last_probed_at": {
+ "name": "last_probed_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "last_probe_ok": {
+ "name": "last_probe_ok",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "last_probe_status_code": {
+ "name": "last_probe_status_code",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "last_probe_latency_ms": {
+ "name": "last_probe_latency_ms",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "last_probe_error_type": {
+ "name": "last_probe_error_type",
+ "type": "varchar(64)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "last_probe_error_message": {
+ "name": "last_probe_error_message",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "now()"
+ },
+ "deleted_at": {
+ "name": "deleted_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "uniq_provider_endpoints_vendor_type_url": {
+ "name": "uniq_provider_endpoints_vendor_type_url",
+ "columns": [
+ {
+ "expression": "vendor_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "provider_type",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "url",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "where": "\"provider_endpoints\".\"deleted_at\" IS NULL",
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_provider_endpoints_vendor_type": {
+ "name": "idx_provider_endpoints_vendor_type",
+ "columns": [
+ {
+ "expression": "vendor_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "provider_type",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "where": "\"provider_endpoints\".\"deleted_at\" IS NULL",
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_provider_endpoints_enabled": {
+ "name": "idx_provider_endpoints_enabled",
+ "columns": [
+ {
+ "expression": "is_enabled",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "vendor_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "provider_type",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "where": "\"provider_endpoints\".\"deleted_at\" IS NULL",
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_provider_endpoints_pick_enabled": {
+ "name": "idx_provider_endpoints_pick_enabled",
+ "columns": [
+ {
+ "expression": "vendor_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "provider_type",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "is_enabled",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "sort_order",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "where": "\"provider_endpoints\".\"deleted_at\" IS NULL",
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_provider_endpoints_created_at": {
+ "name": "idx_provider_endpoints_created_at",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_provider_endpoints_deleted_at": {
+ "name": "idx_provider_endpoints_deleted_at",
+ "columns": [
+ {
+ "expression": "deleted_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "provider_endpoints_vendor_id_provider_vendors_id_fk": {
+ "name": "provider_endpoints_vendor_id_provider_vendors_id_fk",
+ "tableFrom": "provider_endpoints",
+ "tableTo": "provider_vendors",
+ "columnsFrom": [
+ "vendor_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.provider_groups": {
+ "name": "provider_groups",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "name": {
+ "name": "name",
+ "type": "varchar(200)",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "cost_multiplier": {
+ "name": "cost_multiplier",
+ "type": "numeric(10, 4)",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'1.0'"
+ },
+ "description": {
+ "name": "description",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {
+ "provider_groups_name_unique": {
+ "name": "provider_groups_name_unique",
+ "nullsNotDistinct": false,
+ "columns": [
+ "name"
+ ]
+ }
+ },
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.provider_vendors": {
+ "name": "provider_vendors",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "website_domain": {
+ "name": "website_domain",
+ "type": "varchar(255)",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "display_name": {
+ "name": "display_name",
+ "type": "varchar(200)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "website_url": {
+ "name": "website_url",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "favicon_url": {
+ "name": "favicon_url",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "uniq_provider_vendors_website_domain": {
+ "name": "uniq_provider_vendors_website_domain",
+ "columns": [
+ {
+ "expression": "website_domain",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_provider_vendors_created_at": {
+ "name": "idx_provider_vendors_created_at",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.providers": {
+ "name": "providers",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "name": {
+ "name": "name",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "description": {
+ "name": "description",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "url": {
+ "name": "url",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "key": {
+ "name": "key",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "provider_vendor_id": {
+ "name": "provider_vendor_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "is_enabled": {
+ "name": "is_enabled",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": true
+ },
+ "weight": {
+ "name": "weight",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 1
+ },
+ "priority": {
+ "name": "priority",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "group_priorities": {
+ "name": "group_priorities",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "'null'::jsonb"
+ },
+ "cost_multiplier": {
+ "name": "cost_multiplier",
+ "type": "numeric(10, 4)",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "'1.0'"
+ },
+ "group_tag": {
+ "name": "group_tag",
+ "type": "varchar(255)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "provider_type": {
+ "name": "provider_type",
+ "type": "varchar(20)",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'claude'"
+ },
+ "preserve_client_ip": {
+ "name": "preserve_client_ip",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "disable_session_reuse": {
+ "name": "disable_session_reuse",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "model_redirects": {
+ "name": "model_redirects",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "allowed_models": {
+ "name": "allowed_models",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "'null'::jsonb"
+ },
+ "allowed_clients": {
+ "name": "allowed_clients",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'[]'::jsonb"
+ },
+ "blocked_clients": {
+ "name": "blocked_clients",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'[]'::jsonb"
+ },
+ "active_time_start": {
+ "name": "active_time_start",
+ "type": "varchar(5)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "active_time_end": {
+ "name": "active_time_end",
+ "type": "varchar(5)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "codex_instructions_strategy": {
+ "name": "codex_instructions_strategy",
+ "type": "varchar(20)",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "'auto'"
+ },
+ "mcp_passthrough_type": {
+ "name": "mcp_passthrough_type",
+ "type": "varchar(20)",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'none'"
+ },
+ "mcp_passthrough_url": {
+ "name": "mcp_passthrough_url",
+ "type": "varchar(512)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "limit_5h_usd": {
+ "name": "limit_5h_usd",
+ "type": "numeric(10, 2)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "limit_5h_reset_mode": {
+ "name": "limit_5h_reset_mode",
+ "type": "daily_reset_mode",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'rolling'"
+ },
+ "limit_daily_usd": {
+ "name": "limit_daily_usd",
+ "type": "numeric(10, 2)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "daily_reset_mode": {
+ "name": "daily_reset_mode",
+ "type": "daily_reset_mode",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'fixed'"
+ },
+ "daily_reset_time": {
+ "name": "daily_reset_time",
+ "type": "varchar(5)",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'00:00'"
+ },
+ "limit_weekly_usd": {
+ "name": "limit_weekly_usd",
+ "type": "numeric(10, 2)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "limit_monthly_usd": {
+ "name": "limit_monthly_usd",
+ "type": "numeric(10, 2)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "limit_total_usd": {
+ "name": "limit_total_usd",
+ "type": "numeric(10, 2)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "total_cost_reset_at": {
+ "name": "total_cost_reset_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "limit_concurrent_sessions": {
+ "name": "limit_concurrent_sessions",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "default": 0
+ },
+ "max_retry_attempts": {
+ "name": "max_retry_attempts",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "circuit_breaker_failure_threshold": {
+ "name": "circuit_breaker_failure_threshold",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "default": 5
+ },
+ "circuit_breaker_open_duration": {
+ "name": "circuit_breaker_open_duration",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "default": 1800000
+ },
+ "circuit_breaker_half_open_success_threshold": {
+ "name": "circuit_breaker_half_open_success_threshold",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "default": 2
+ },
+ "proxy_url": {
+ "name": "proxy_url",
+ "type": "varchar(512)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "proxy_fallback_to_direct": {
+ "name": "proxy_fallback_to_direct",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false,
+ "default": false
+ },
+ "custom_headers": {
+ "name": "custom_headers",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "first_byte_timeout_streaming_ms": {
+ "name": "first_byte_timeout_streaming_ms",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "streaming_idle_timeout_ms": {
+ "name": "streaming_idle_timeout_ms",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "request_timeout_non_streaming_ms": {
+ "name": "request_timeout_non_streaming_ms",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "website_url": {
+ "name": "website_url",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "favicon_url": {
+ "name": "favicon_url",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "cache_ttl_preference": {
+ "name": "cache_ttl_preference",
+ "type": "varchar(10)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "swap_cache_ttl_billing": {
+ "name": "swap_cache_ttl_billing",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "context_1m_preference": {
+ "name": "context_1m_preference",
+ "type": "varchar(20)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "codex_reasoning_effort_preference": {
+ "name": "codex_reasoning_effort_preference",
+ "type": "varchar(20)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "codex_reasoning_summary_preference": {
+ "name": "codex_reasoning_summary_preference",
+ "type": "varchar(20)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "codex_text_verbosity_preference": {
+ "name": "codex_text_verbosity_preference",
+ "type": "varchar(10)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "codex_parallel_tool_calls_preference": {
+ "name": "codex_parallel_tool_calls_preference",
+ "type": "varchar(10)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "codex_image_generation_preference": {
+ "name": "codex_image_generation_preference",
+ "type": "varchar(10)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "codex_service_tier_preference": {
+ "name": "codex_service_tier_preference",
+ "type": "varchar(20)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "anthropic_max_tokens_preference": {
+ "name": "anthropic_max_tokens_preference",
+ "type": "varchar(20)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "anthropic_thinking_budget_preference": {
+ "name": "anthropic_thinking_budget_preference",
+ "type": "varchar(20)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "anthropic_adaptive_thinking": {
+ "name": "anthropic_adaptive_thinking",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "'null'::jsonb"
+ },
+ "gemini_google_search_preference": {
+ "name": "gemini_google_search_preference",
+ "type": "varchar(20)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "tpm": {
+ "name": "tpm",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "default": 0
+ },
+ "rpm": {
+ "name": "rpm",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "default": 0
+ },
+ "rpd": {
+ "name": "rpd",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "default": 0
+ },
+ "cc": {
+ "name": "cc",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "default": 0
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "now()"
+ },
+ "deleted_at": {
+ "name": "deleted_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "idx_providers_enabled_priority": {
+ "name": "idx_providers_enabled_priority",
+ "columns": [
+ {
+ "expression": "is_enabled",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "priority",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "weight",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "where": "\"providers\".\"deleted_at\" IS NULL",
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_providers_group": {
+ "name": "idx_providers_group",
+ "columns": [
+ {
+ "expression": "group_tag",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "where": "\"providers\".\"deleted_at\" IS NULL",
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_providers_vendor_type_url_active": {
+ "name": "idx_providers_vendor_type_url_active",
+ "columns": [
+ {
+ "expression": "provider_vendor_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "provider_type",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "url",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "where": "\"providers\".\"deleted_at\" IS NULL",
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_providers_created_at": {
+ "name": "idx_providers_created_at",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_providers_deleted_at": {
+ "name": "idx_providers_deleted_at",
+ "columns": [
+ {
+ "expression": "deleted_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_providers_vendor_type": {
+ "name": "idx_providers_vendor_type",
+ "columns": [
+ {
+ "expression": "provider_vendor_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "provider_type",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "where": "\"providers\".\"deleted_at\" IS NULL",
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_providers_enabled_vendor_type": {
+ "name": "idx_providers_enabled_vendor_type",
+ "columns": [
+ {
+ "expression": "provider_vendor_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "provider_type",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "where": "\"providers\".\"deleted_at\" IS NULL AND \"providers\".\"is_enabled\" = true AND \"providers\".\"provider_vendor_id\" IS NOT NULL AND \"providers\".\"provider_vendor_id\" > 0",
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "providers_provider_vendor_id_provider_vendors_id_fk": {
+ "name": "providers_provider_vendor_id_provider_vendors_id_fk",
+ "tableFrom": "providers",
+ "tableTo": "provider_vendors",
+ "columnsFrom": [
+ "provider_vendor_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "restrict",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.replay_payloads": {
+ "name": "replay_payloads",
+ "schema": "",
+ "columns": {
+ "replay_id": {
+ "name": "replay_id",
+ "type": "varchar(64)",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "verifier": {
+ "name": "verifier",
+ "type": "varchar(64)",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "scope_tag": {
+ "name": "scope_tag",
+ "type": "varchar(16)",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "key_id": {
+ "name": "key_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "format": {
+ "name": "format",
+ "type": "varchar(16)",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "model": {
+ "name": "model",
+ "type": "varchar(128)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "status_code": {
+ "name": "status_code",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "headers_json": {
+ "name": "headers_json",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "payload": {
+ "name": "payload",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "byte_size": {
+ "name": "byte_size",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "source_message_request_id": {
+ "name": "source_message_request_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "now()"
+ },
+ "expires_at": {
+ "name": "expires_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {
+ "idx_replay_payloads_key_id": {
+ "name": "idx_replay_payloads_key_id",
+ "columns": [
+ {
+ "expression": "key_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_replay_payloads_expires_at": {
+ "name": "idx_replay_payloads_expires_at",
+ "columns": [
+ {
+ "expression": "expires_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.request_filters": {
+ "name": "request_filters",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "name": {
+ "name": "name",
+ "type": "varchar(100)",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "description": {
+ "name": "description",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "scope": {
+ "name": "scope",
+ "type": "varchar(20)",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "action": {
+ "name": "action",
+ "type": "varchar(30)",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "match_type": {
+ "name": "match_type",
+ "type": "varchar(20)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "target": {
+ "name": "target",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "replacement": {
+ "name": "replacement",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "priority": {
+ "name": "priority",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "is_enabled": {
+ "name": "is_enabled",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": true
+ },
+ "binding_type": {
+ "name": "binding_type",
+ "type": "varchar(20)",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'global'"
+ },
+ "provider_ids": {
+ "name": "provider_ids",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "group_tags": {
+ "name": "group_tags",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "rule_mode": {
+ "name": "rule_mode",
+ "type": "varchar(20)",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'simple'"
+ },
+ "execution_phase": {
+ "name": "execution_phase",
+ "type": "varchar(20)",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'guard'"
+ },
+ "operations": {
+ "name": "operations",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "idx_request_filters_enabled": {
+ "name": "idx_request_filters_enabled",
+ "columns": [
+ {
+ "expression": "is_enabled",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "priority",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_request_filters_scope": {
+ "name": "idx_request_filters_scope",
+ "columns": [
+ {
+ "expression": "scope",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_request_filters_action": {
+ "name": "idx_request_filters_action",
+ "columns": [
+ {
+ "expression": "action",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_request_filters_binding": {
+ "name": "idx_request_filters_binding",
+ "columns": [
+ {
+ "expression": "is_enabled",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "binding_type",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_request_filters_phase": {
+ "name": "idx_request_filters_phase",
+ "columns": [
+ {
+ "expression": "is_enabled",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "execution_phase",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.sensitive_words": {
+ "name": "sensitive_words",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "word": {
+ "name": "word",
+ "type": "varchar(255)",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "match_type": {
+ "name": "match_type",
+ "type": "varchar(20)",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'contains'"
+ },
+ "description": {
+ "name": "description",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "is_enabled": {
+ "name": "is_enabled",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": true
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "idx_sensitive_words_enabled": {
+ "name": "idx_sensitive_words_enabled",
+ "columns": [
+ {
+ "expression": "is_enabled",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "match_type",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_sensitive_words_created_at": {
+ "name": "idx_sensitive_words_created_at",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.system_settings": {
+ "name": "system_settings",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "site_title": {
+ "name": "site_title",
+ "type": "varchar(128)",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'CC Hub'"
+ },
+ "allow_global_usage_view": {
+ "name": "allow_global_usage_view",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "currency_display": {
+ "name": "currency_display",
+ "type": "varchar(10)",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'USD'"
+ },
+ "billing_model_source": {
+ "name": "billing_model_source",
+ "type": "varchar(20)",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'original'"
+ },
+ "codex_priority_billing_source": {
+ "name": "codex_priority_billing_source",
+ "type": "varchar(20)",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'requested'"
+ },
+ "bill_non_successful_requests": {
+ "name": "bill_non_successful_requests",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "bill_hedge_losers": {
+ "name": "bill_hedge_losers",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": true
+ },
+ "discovery_enabled": {
+ "name": "discovery_enabled",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "discovery_concurrency": {
+ "name": "discovery_concurrency",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 2
+ },
+ "max_discovery_rounds": {
+ "name": "max_discovery_rounds",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 2
+ },
+ "discovery_sla_ms": {
+ "name": "discovery_sla_ms",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 10000
+ },
+ "sticky_sla_ms": {
+ "name": "sticky_sla_ms",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 20000
+ },
+ "racing_total_timeout_ms": {
+ "name": "racing_total_timeout_ms",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 60000
+ },
+ "sticky_timeout_cooldown_ms": {
+ "name": "sticky_timeout_cooldown_ms",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 300000
+ },
+ "timezone": {
+ "name": "timezone",
+ "type": "varchar(64)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "enable_auto_cleanup": {
+ "name": "enable_auto_cleanup",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false,
+ "default": false
+ },
+ "cleanup_retention_days": {
+ "name": "cleanup_retention_days",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "default": 30
+ },
+ "cleanup_schedule": {
+ "name": "cleanup_schedule",
+ "type": "varchar(50)",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "'0 2 * * *'"
+ },
+ "cleanup_batch_size": {
+ "name": "cleanup_batch_size",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "default": 10000
+ },
+ "enable_client_version_check": {
+ "name": "enable_client_version_check",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "verbose_provider_error": {
+ "name": "verbose_provider_error",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "pass_through_upstream_error_message": {
+ "name": "pass_through_upstream_error_message",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": true
+ },
+ "enable_http2": {
+ "name": "enable_http2",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "enable_openai_responses_websocket": {
+ "name": "enable_openai_responses_websocket",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": true
+ },
+ "enable_high_concurrency_mode": {
+ "name": "enable_high_concurrency_mode",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "intercept_anthropic_warmup_requests": {
+ "name": "intercept_anthropic_warmup_requests",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "enable_thinking_signature_rectifier": {
+ "name": "enable_thinking_signature_rectifier",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": true
+ },
+ "enable_thinking_budget_rectifier": {
+ "name": "enable_thinking_budget_rectifier",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": true
+ },
+ "enable_thinking_effort_conflict_rectifier": {
+ "name": "enable_thinking_effort_conflict_rectifier",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": true
+ },
+ "enable_gemini_function_id_rectifier": {
+ "name": "enable_gemini_function_id_rectifier",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": true
+ },
+ "enable_billing_header_rectifier": {
+ "name": "enable_billing_header_rectifier",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": true
+ },
+ "enable_response_input_rectifier": {
+ "name": "enable_response_input_rectifier",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": true
+ },
+ "allow_non_conversation_endpoint_provider_fallback": {
+ "name": "allow_non_conversation_endpoint_provider_fallback",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": true
+ },
+ "fake_streaming_whitelist": {
+ "name": "fake_streaming_whitelist",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "enable_codex_session_id_completion": {
+ "name": "enable_codex_session_id_completion",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": true
+ },
+ "enable_claude_metadata_user_id_injection": {
+ "name": "enable_claude_metadata_user_id_injection",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": true
+ },
+ "enable_response_fixer": {
+ "name": "enable_response_fixer",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": true
+ },
+ "response_fixer_config": {
+ "name": "response_fixer_config",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "'{\"fixTruncatedJson\":true,\"fixSseFormat\":true,\"fixEncoding\":true,\"maxJsonDepth\":200,\"maxFixSize\":1048576}'::jsonb"
+ },
+ "quota_db_refresh_interval_seconds": {
+ "name": "quota_db_refresh_interval_seconds",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "default": 10
+ },
+ "quota_lease_percent_5h": {
+ "name": "quota_lease_percent_5h",
+ "type": "numeric(5, 4)",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "'0.05'"
+ },
+ "quota_lease_percent_daily": {
+ "name": "quota_lease_percent_daily",
+ "type": "numeric(5, 4)",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "'0.05'"
+ },
+ "quota_lease_percent_weekly": {
+ "name": "quota_lease_percent_weekly",
+ "type": "numeric(5, 4)",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "'0.05'"
+ },
+ "quota_lease_percent_monthly": {
+ "name": "quota_lease_percent_monthly",
+ "type": "numeric(5, 4)",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "'0.05'"
+ },
+ "quota_lease_cap_usd": {
+ "name": "quota_lease_cap_usd",
+ "type": "numeric(10, 2)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "ip_extraction_config": {
+ "name": "ip_extraction_config",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "ip_geo_lookup_enabled": {
+ "name": "ip_geo_lookup_enabled",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": true
+ },
+ "public_status_window_hours": {
+ "name": "public_status_window_hours",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 24
+ },
+ "public_status_aggregation_interval_minutes": {
+ "name": "public_status_aggregation_interval_minutes",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 5
+ },
+ "stream_gate_mode": {
+ "name": "stream_gate_mode",
+ "type": "varchar(10)",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'enforce'"
+ },
+ "affinity_ignore_client_session_id": {
+ "name": "affinity_ignore_client_session_id",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": true
+ },
+ "replay_enabled": {
+ "name": "replay_enabled",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "cache_effectiveness_enabled": {
+ "name": "cache_effectiveness_enabled",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.usage_ledger": {
+ "name": "usage_ledger",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "request_id": {
+ "name": "request_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "key": {
+ "name": "key",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "provider_id": {
+ "name": "provider_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "final_provider_id": {
+ "name": "final_provider_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "model": {
+ "name": "model",
+ "type": "varchar(128)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "original_model": {
+ "name": "original_model",
+ "type": "varchar(128)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "actual_response_model": {
+ "name": "actual_response_model",
+ "type": "varchar(128)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "endpoint": {
+ "name": "endpoint",
+ "type": "varchar(256)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "api_type": {
+ "name": "api_type",
+ "type": "varchar(20)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "session_id": {
+ "name": "session_id",
+ "type": "varchar(64)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "status_code": {
+ "name": "status_code",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "is_success": {
+ "name": "is_success",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "success_rate_outcome": {
+ "name": "success_rate_outcome",
+ "type": "varchar(16)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "blocked_by": {
+ "name": "blocked_by",
+ "type": "varchar(50)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "cost_usd": {
+ "name": "cost_usd",
+ "type": "numeric(21, 15)",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "'0'"
+ },
+ "cost_multiplier": {
+ "name": "cost_multiplier",
+ "type": "numeric(10, 4)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "group_cost_multiplier": {
+ "name": "group_cost_multiplier",
+ "type": "numeric(10, 4)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "input_tokens": {
+ "name": "input_tokens",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "output_tokens": {
+ "name": "output_tokens",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "cache_creation_input_tokens": {
+ "name": "cache_creation_input_tokens",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "cache_read_input_tokens": {
+ "name": "cache_read_input_tokens",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "cache_creation_5m_input_tokens": {
+ "name": "cache_creation_5m_input_tokens",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "cache_creation_1h_input_tokens": {
+ "name": "cache_creation_1h_input_tokens",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "cache_ttl_applied": {
+ "name": "cache_ttl_applied",
+ "type": "varchar(10)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "context_1m_applied": {
+ "name": "context_1m_applied",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false,
+ "default": false
+ },
+ "swap_cache_ttl_applied": {
+ "name": "swap_cache_ttl_applied",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false,
+ "default": false
+ },
+ "duration_ms": {
+ "name": "duration_ms",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "ttfb_ms": {
+ "name": "ttfb_ms",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "first_byte_ms": {
+ "name": "first_byte_ms",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "client_ip": {
+ "name": "client_ip",
+ "type": "varchar(45)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {
+ "idx_usage_ledger_request_id": {
+ "name": "idx_usage_ledger_request_id",
+ "columns": [
+ {
+ "expression": "request_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_usage_ledger_user_created_at": {
+ "name": "idx_usage_ledger_user_created_at",
+ "columns": [
+ {
+ "expression": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "where": "\"usage_ledger\".\"blocked_by\" IS NULL",
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_usage_ledger_key_created_at": {
+ "name": "idx_usage_ledger_key_created_at",
+ "columns": [
+ {
+ "expression": "key",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "where": "\"usage_ledger\".\"blocked_by\" IS NULL",
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_usage_ledger_provider_created_at": {
+ "name": "idx_usage_ledger_provider_created_at",
+ "columns": [
+ {
+ "expression": "final_provider_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "where": "\"usage_ledger\".\"blocked_by\" IS NULL",
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_usage_ledger_created_at_minute": {
+ "name": "idx_usage_ledger_created_at_minute",
+ "columns": [
+ {
+ "expression": "date_trunc('minute', \"created_at\" AT TIME ZONE 'UTC')",
+ "asc": true,
+ "isExpression": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_usage_ledger_created_at_desc_id": {
+ "name": "idx_usage_ledger_created_at_desc_id",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": false,
+ "nulls": "last"
+ },
+ {
+ "expression": "id",
+ "isExpression": false,
+ "asc": false,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_usage_ledger_session_id": {
+ "name": "idx_usage_ledger_session_id",
+ "columns": [
+ {
+ "expression": "session_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "where": "\"usage_ledger\".\"session_id\" IS NOT NULL",
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_usage_ledger_model": {
+ "name": "idx_usage_ledger_model",
+ "columns": [
+ {
+ "expression": "model",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "where": "\"usage_ledger\".\"model\" IS NOT NULL",
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_usage_ledger_key_cost": {
+ "name": "idx_usage_ledger_key_cost",
+ "columns": [
+ {
+ "expression": "key",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "cost_usd",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "endpoint",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "where": "\"usage_ledger\".\"blocked_by\" IS NULL",
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_usage_ledger_user_cost_cover": {
+ "name": "idx_usage_ledger_user_cost_cover",
+ "columns": [
+ {
+ "expression": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "cost_usd",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "endpoint",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "where": "\"usage_ledger\".\"blocked_by\" IS NULL",
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_usage_ledger_provider_cost_cover": {
+ "name": "idx_usage_ledger_provider_cost_cover",
+ "columns": [
+ {
+ "expression": "final_provider_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "cost_usd",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "endpoint",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "where": "\"usage_ledger\".\"blocked_by\" IS NULL",
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_usage_ledger_key_created_at_desc_cover": {
+ "name": "idx_usage_ledger_key_created_at_desc_cover",
+ "columns": [
+ {
+ "expression": "key",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "\"created_at\" DESC NULLS LAST",
+ "asc": true,
+ "isExpression": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "final_provider_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "where": "\"usage_ledger\".\"blocked_by\" IS NULL",
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.users": {
+ "name": "users",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "name": {
+ "name": "name",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "description": {
+ "name": "description",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "role": {
+ "name": "role",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "'user'"
+ },
+ "rpm_limit": {
+ "name": "rpm_limit",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "daily_limit_usd": {
+ "name": "daily_limit_usd",
+ "type": "numeric(10, 2)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "provider_group": {
+ "name": "provider_group",
+ "type": "varchar(200)",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "'default'"
+ },
+ "tags": {
+ "name": "tags",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "'[]'::jsonb"
+ },
+ "limit_5h_usd": {
+ "name": "limit_5h_usd",
+ "type": "numeric(10, 2)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "limit_5h_reset_mode": {
+ "name": "limit_5h_reset_mode",
+ "type": "daily_reset_mode",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'rolling'"
+ },
+ "limit_weekly_usd": {
+ "name": "limit_weekly_usd",
+ "type": "numeric(10, 2)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "limit_monthly_usd": {
+ "name": "limit_monthly_usd",
+ "type": "numeric(10, 2)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "limit_total_usd": {
+ "name": "limit_total_usd",
+ "type": "numeric(10, 2)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "cost_reset_at": {
+ "name": "cost_reset_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "limit_5h_cost_reset_at": {
+ "name": "limit_5h_cost_reset_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "limit_concurrent_sessions": {
+ "name": "limit_concurrent_sessions",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "daily_reset_mode": {
+ "name": "daily_reset_mode",
+ "type": "daily_reset_mode",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'fixed'"
+ },
+ "daily_reset_time": {
+ "name": "daily_reset_time",
+ "type": "varchar(5)",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'00:00'"
+ },
+ "is_enabled": {
+ "name": "is_enabled",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": true
+ },
+ "expires_at": {
+ "name": "expires_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "allowed_clients": {
+ "name": "allowed_clients",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "'[]'::jsonb"
+ },
+ "allowed_models": {
+ "name": "allowed_models",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "'[]'::jsonb"
+ },
+ "blocked_clients": {
+ "name": "blocked_clients",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'[]'::jsonb"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "now()"
+ },
+ "deleted_at": {
+ "name": "deleted_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "idx_users_active_role_sort": {
+ "name": "idx_users_active_role_sort",
+ "columns": [
+ {
+ "expression": "deleted_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "role",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "where": "\"users\".\"deleted_at\" IS NULL",
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_users_enabled_expires_at": {
+ "name": "idx_users_enabled_expires_at",
+ "columns": [
+ {
+ "expression": "is_enabled",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "expires_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "where": "\"users\".\"deleted_at\" IS NULL",
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_users_tags_gin": {
+ "name": "idx_users_tags_gin",
+ "columns": [
+ {
+ "expression": "tags",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "where": "\"users\".\"deleted_at\" IS NULL",
+ "concurrently": false,
+ "method": "gin",
+ "with": {}
+ },
+ "idx_users_created_at": {
+ "name": "idx_users_created_at",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "idx_users_deleted_at": {
+ "name": "idx_users_deleted_at",
+ "columns": [
+ {
+ "expression": "deleted_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.webhook_targets": {
+ "name": "webhook_targets",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "name": {
+ "name": "name",
+ "type": "varchar(100)",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "provider_type": {
+ "name": "provider_type",
+ "type": "webhook_provider_type",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "webhook_url": {
+ "name": "webhook_url",
+ "type": "varchar(1024)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "telegram_bot_token": {
+ "name": "telegram_bot_token",
+ "type": "varchar(256)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "telegram_chat_id": {
+ "name": "telegram_chat_id",
+ "type": "varchar(64)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "dingtalk_secret": {
+ "name": "dingtalk_secret",
+ "type": "varchar(256)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "custom_template": {
+ "name": "custom_template",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "custom_headers": {
+ "name": "custom_headers",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "proxy_url": {
+ "name": "proxy_url",
+ "type": "varchar(512)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "proxy_fallback_to_direct": {
+ "name": "proxy_fallback_to_direct",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false,
+ "default": false
+ },
+ "is_enabled": {
+ "name": "is_enabled",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": true
+ },
+ "last_test_at": {
+ "name": "last_test_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "last_test_result": {
+ "name": "last_test_result",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ }
+ },
+ "enums": {
+ "public.daily_reset_mode": {
+ "name": "daily_reset_mode",
+ "schema": "public",
+ "values": [
+ "fixed",
+ "rolling"
+ ]
+ },
+ "public.notification_type": {
+ "name": "notification_type",
+ "schema": "public",
+ "values": [
+ "circuit_breaker",
+ "daily_leaderboard",
+ "cost_alert",
+ "cache_hit_rate_alert"
+ ]
+ },
+ "public.webhook_provider_type": {
+ "name": "webhook_provider_type",
+ "schema": "public",
+ "values": [
+ "wechat",
+ "feishu",
+ "dingtalk",
+ "telegram",
+ "custom"
+ ]
+ }
+ },
+ "schemas": {},
+ "sequences": {},
+ "roles": {},
+ "policies": {},
+ "views": {},
+ "_meta": {
+ "columns": {},
+ "schemas": {},
+ "tables": {}
+ }
+}
\ No newline at end of file
diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json
index 1f2b7527e..45894cb76 100644
--- a/drizzle/meta/_journal.json
+++ b/drizzle/meta/_journal.json
@@ -806,6 +806,13 @@
"when": 1784952018550,
"tag": "0114_overconfident_ronan",
"breakpoints": true
+ },
+ {
+ "idx": 115,
+ "version": "7",
+ "when": 1785418573335,
+ "tag": "0115_breezy_polaris",
+ "breakpoints": true
}
]
}
\ No newline at end of file
diff --git a/messages/en/auth.json b/messages/en/auth.json
index 4feeabdd7..309289e26 100644
--- a/messages/en/auth.json
+++ b/messages/en/auth.json
@@ -20,11 +20,9 @@
"confirm": "Are you sure you want to log out?",
"success": "Logged out successfully"
},
- "placeholders": {
- "apiKeyExample": "e.g. sk-xxxxxxxx"
- },
"brand": {
- "tagline": "Unified API management console"
+ "tagline": "Unified API management console",
+ "disclaimer": "CC Hub is not an official Anthropic project and is not affiliated with Anthropic. Claude Code and Claude are trademarks of Anthropic."
},
"actions": {
"enterConsole": "Enter Console",
diff --git a/messages/en/bigScreen.json b/messages/en/bigScreen.json
index 6e24be785..76b58a467 100644
--- a/messages/en/bigScreen.json
+++ b/messages/en/bigScreen.json
@@ -1,7 +1,7 @@
{
- "pageTitle": "Realtime big screen - Claude Code Hub",
- "pageDescription": "Claude Code Hub realtime monitoring big screen",
- "title": "CLAUDE CODE HUB",
+ "pageTitle": "Realtime big screen - CC Hub",
+ "pageDescription": "CC Hub realtime monitoring big screen",
+ "title": "CC HUB",
"subtitle": "REALTIME DATA MONITOR",
"metrics": {
"concurrent": "Concurrency",
diff --git a/messages/en/settings/config.json b/messages/en/settings/config.json
index 77fa27be1..046025372 100644
--- a/messages/en/settings/config.json
+++ b/messages/en/settings/config.json
@@ -108,7 +108,7 @@
"saveSuccess": "Saved successfully",
"siteTitle": "Site Title",
"siteTitleDesc": "Used to set browser tab title and system default display name.",
- "siteTitlePlaceholder": "e.g. Claude Code Hub",
+ "siteTitlePlaceholder": "e.g. CC Hub",
"siteTitleRequired": "Site title cannot be empty",
"ipLoggingInvalidJson": "IP extraction config is not valid JSON: {message}",
"ipLoggingInvalidShape": "IP extraction config must be an object with a `headers` array.",
diff --git a/messages/en/settings/providers/form/url.json b/messages/en/settings/providers/form/url.json
index 94efd5f4c..a35aab0c6 100644
--- a/messages/en/settings/providers/form/url.json
+++ b/messages/en/settings/providers/form/url.json
@@ -2,5 +2,5 @@
"label": "API Address",
"placeholder": "e.g. https://open.bigmodel.cn/api/anthropic",
"description": "Use your provider's base address. For request forwarding, preview, and provider testing, you can also paste a version path or exact endpoint here.",
- "tooltip": "Examples: https://relay.example.com/openai, https://relay.example.com/openai/v1, https://relay.example.com/openai/v1/responses. Claude Code Hub reuses the path you provide instead of appending the same endpoint twice."
+ "tooltip": "Examples: https://relay.example.com/openai, https://relay.example.com/openai/v1, https://relay.example.com/openai/v1/responses. CC Hub reuses the path you provide instead of appending the same endpoint twice."
}
diff --git a/messages/en/usage.json b/messages/en/usage.json
index 7c8a4f18a..9b3daef6e 100644
--- a/messages/en/usage.json
+++ b/messages/en/usage.json
@@ -1,5 +1,5 @@
{
- "pageTitle": "Claude Code Hub Usage Documentation",
+ "pageTitle": "CC Hub Usage Documentation",
"pageDescription": "Complete integration guide for Claude Code, Codex, and Droid CLI",
"skipLinks": {
diff --git a/messages/ja/auth.json b/messages/ja/auth.json
index 68658e5ce..d0dbe3e92 100644
--- a/messages/ja/auth.json
+++ b/messages/ja/auth.json
@@ -20,11 +20,9 @@
"confirm": "本当にログアウトしてもよろしいですか?",
"success": "ログアウトしました"
},
- "placeholders": {
- "apiKeyExample": "例: sk-xxxxxxxx"
- },
"brand": {
- "tagline": "統合API管理コンソール"
+ "tagline": "統合API管理コンソール",
+ "disclaimer": "CC Hub は Anthropic の公式プロジェクトではなく、いかなる関係もありません。Claude Code、Claude などは Anthropic 社の商標です。"
},
"actions": {
"enterConsole": "コンソールに入る",
diff --git a/messages/ja/bigScreen.json b/messages/ja/bigScreen.json
index f28eeb53e..dbfc4edcc 100644
--- a/messages/ja/bigScreen.json
+++ b/messages/ja/bigScreen.json
@@ -1,7 +1,7 @@
{
- "pageTitle": "リアルタイム大画面 - Claude Code Hub",
- "pageDescription": "Claude Code Hub のリアルタイム監視ダッシュボード",
- "title": "CLAUDE CODE HUB",
+ "pageTitle": "リアルタイム大画面 - CC Hub",
+ "pageDescription": "CC Hub のリアルタイム監視ダッシュボード",
+ "title": "CC HUB",
"subtitle": "リアルタイムデータモニター",
"metrics": {
"concurrent": "同時接続数",
diff --git a/messages/ja/settings/config.json b/messages/ja/settings/config.json
index ddb081fb3..e3e63a162 100644
--- a/messages/ja/settings/config.json
+++ b/messages/ja/settings/config.json
@@ -108,7 +108,7 @@
"saveSuccess": "正常に保存されました",
"siteTitle": "サイトタイトル",
"siteTitleDesc": "ブラウザタブのタイトルとシステムのデフォルト表示名を設定するために使用されます。",
- "siteTitlePlaceholder": "例:Claude Code Hub",
+ "siteTitlePlaceholder": "例:CC Hub",
"siteTitleRequired": "サイトタイトルは空にできません",
"ipLoggingInvalidJson": "IP 抽出設定が有効な JSON ではありません:{message}",
"ipLoggingInvalidShape": "IP 抽出設定は `headers` 配列を持つオブジェクトである必要があります。",
diff --git a/messages/ja/settings/providers/form/url.json b/messages/ja/settings/providers/form/url.json
index 3d4415fc5..e36b99999 100644
--- a/messages/ja/settings/providers/form/url.json
+++ b/messages/ja/settings/providers/form/url.json
@@ -2,5 +2,5 @@
"label": "API アドレス",
"placeholder": "例: https://open.bigmodel.cn/api/anthropic",
"description": "通常はプロバイダーの基本アドレスを入力してください。リクエスト転送、プレビュー、provider testing では、バージョン付きのパスや完全なエンドポイントもそのまま使えます。",
- "tooltip": "例: https://relay.example.com/openai、https://relay.example.com/openai/v1、https://relay.example.com/openai/v1/responses。Claude Code Hub は入力されたパスを再利用し、同じ endpoint を二重に付けません。"
+ "tooltip": "例: https://relay.example.com/openai、https://relay.example.com/openai/v1、https://relay.example.com/openai/v1/responses。CC Hub は入力されたパスを再利用し、同じ endpoint を二重に付けません。"
}
diff --git a/messages/ja/usage.json b/messages/ja/usage.json
index 9030d23e4..fcc08402d 100644
--- a/messages/ja/usage.json
+++ b/messages/ja/usage.json
@@ -1,5 +1,5 @@
{
- "pageTitle": "Claude Code Hub 使用ドキュメント",
+ "pageTitle": "CC Hub 使用ドキュメント",
"pageDescription": "Claude Code、Codex、Droid CLIの完全な統合ガイド",
"skipLinks": {
diff --git a/messages/ru/auth.json b/messages/ru/auth.json
index de91560a7..7f32dc3ff 100644
--- a/messages/ru/auth.json
+++ b/messages/ru/auth.json
@@ -20,11 +20,9 @@
"confirm": "Вы уверены, что хотите выйти?",
"success": "Вы успешно вышли"
},
- "placeholders": {
- "apiKeyExample": "например sk-xxxxxxxx"
- },
"brand": {
- "tagline": "Единая консоль управления API"
+ "tagline": "Единая консоль управления API",
+ "disclaimer": "CC Hub не является официальным проектом Anthropic и никак с ним не связан. Claude Code, Claude и другие являются товарными знаками компании Anthropic."
},
"actions": {
"enterConsole": "Перейти в консоль",
diff --git a/messages/ru/bigScreen.json b/messages/ru/bigScreen.json
index e13aaf30e..2f7eeb0c3 100644
--- a/messages/ru/bigScreen.json
+++ b/messages/ru/bigScreen.json
@@ -1,7 +1,7 @@
{
- "pageTitle": "Панель реального времени - Claude Code Hub",
- "pageDescription": "Большой экран мониторинга в реальном времени Claude Code Hub",
- "title": "CLAUDE CODE HUB",
+ "pageTitle": "Панель реального времени - CC Hub",
+ "pageDescription": "Большой экран мониторинга в реальном времени CC Hub",
+ "title": "CC HUB",
"subtitle": "МОНИТОР ДАННЫХ В РЕАЛЬНОМ ВРЕМЕНИ",
"metrics": {
"concurrent": "Параллельные подключения",
diff --git a/messages/ru/settings/config.json b/messages/ru/settings/config.json
index 5781aab60..00d57f702 100644
--- a/messages/ru/settings/config.json
+++ b/messages/ru/settings/config.json
@@ -108,7 +108,7 @@
"saveSuccess": "Сохранено успешно",
"siteTitle": "Название сайта",
"siteTitleDesc": "Используется для установки заголовка вкладки браузера и имени системы по умолчанию.",
- "siteTitlePlaceholder": "например: Claude Code Hub",
+ "siteTitlePlaceholder": "например: CC Hub",
"siteTitleRequired": "Название сайта не может быть пустым",
"ipLoggingInvalidJson": "Конфигурация извлечения IP не является валидным JSON: {message}",
"ipLoggingInvalidShape": "Конфигурация извлечения IP должна быть объектом с массивом `headers`.",
diff --git a/messages/ru/settings/providers/form/url.json b/messages/ru/settings/providers/form/url.json
index d2b2ab671..b23fc247a 100644
--- a/messages/ru/settings/providers/form/url.json
+++ b/messages/ru/settings/providers/form/url.json
@@ -2,5 +2,5 @@
"label": "Адрес API",
"placeholder": "например: https://open.bigmodel.cn/api/anthropic",
"description": "Обычно сюда вводят базовый адрес провайдера. Для маршрутизации запросов, предпросмотра и provider testing поле также принимает путь с версией или полный URL конечной точки.",
- "tooltip": "Примеры: https://relay.example.com/openai, https://relay.example.com/openai/v1, https://relay.example.com/openai/v1/responses. Claude Code Hub переиспользует указанный путь и не дописывает тот же endpoint повторно."
+ "tooltip": "Примеры: https://relay.example.com/openai, https://relay.example.com/openai/v1, https://relay.example.com/openai/v1/responses. CC Hub переиспользует указанный путь и не дописывает тот же endpoint повторно."
}
diff --git a/messages/ru/usage.json b/messages/ru/usage.json
index daf293e31..2e2463a1e 100644
--- a/messages/ru/usage.json
+++ b/messages/ru/usage.json
@@ -1,5 +1,5 @@
{
- "pageTitle": "Документация по использованию Claude Code Hub",
+ "pageTitle": "Документация по использованию CC Hub",
"pageDescription": "Полное руководство по интеграции Claude Code, Codex и Droid CLI",
"skipLinks": {
diff --git a/messages/zh-CN/auth.json b/messages/zh-CN/auth.json
index 9cb3f1934..39daa0213 100644
--- a/messages/zh-CN/auth.json
+++ b/messages/zh-CN/auth.json
@@ -24,11 +24,9 @@
"apiKeyInvalidOrExpired": "API Key 无效或已过期",
"serverError": "登录失败,请稍后重试"
},
- "placeholders": {
- "apiKeyExample": "例如 sk-xxxxxxxx"
- },
"brand": {
- "tagline": "统一 API 管理控制台"
+ "tagline": "统一 API 管理控制台",
+ "disclaimer": "CC Hub 并非 Anthropic 官方项目,与其无任何关联。Claude Code、Claude 等均属 Anthropic 公司的商标。"
},
"actions": {
"enterConsole": "进入控制台",
diff --git a/messages/zh-CN/bigScreen.json b/messages/zh-CN/bigScreen.json
index aa9fcfa26..9477626d1 100644
--- a/messages/zh-CN/bigScreen.json
+++ b/messages/zh-CN/bigScreen.json
@@ -1,7 +1,7 @@
{
- "pageTitle": "实时数据大屏 - Claude Code Hub",
- "pageDescription": "Claude Code Hub 实时监控数据大屏",
- "title": "CLAUDE CODE HUB",
+ "pageTitle": "实时数据大屏 - CC Hub",
+ "pageDescription": "CC Hub 实时监控数据大屏",
+ "title": "CC HUB",
"subtitle": "实时数据监控中台",
"metrics": {
"concurrent": "并发数",
diff --git a/messages/zh-CN/settings/config.json b/messages/zh-CN/settings/config.json
index ae3d6ff7c..1ddf67b51 100644
--- a/messages/zh-CN/settings/config.json
+++ b/messages/zh-CN/settings/config.json
@@ -17,7 +17,7 @@
},
"form": {
"siteTitle": "站点标题",
- "siteTitlePlaceholder": "例如:Claude Code Hub",
+ "siteTitlePlaceholder": "例如:CC Hub",
"siteTitleRequired": "站点标题不能为空",
"ipLoggingInvalidJson": "IP 提取配置不是合法的 JSON:{message}",
"ipLoggingInvalidShape": "IP 提取配置必须是包含 `headers` 数组的对象。",
diff --git a/messages/zh-CN/settings/providers/form/url.json b/messages/zh-CN/settings/providers/form/url.json
index 9aee1d8c8..6556b1f40 100644
--- a/messages/zh-CN/settings/providers/form/url.json
+++ b/messages/zh-CN/settings/providers/form/url.json
@@ -2,5 +2,5 @@
"label": "API 地址",
"placeholder": "例如: https://open.bigmodel.cn/api/anthropic",
"description": "填写供应商的基础地址即可。在请求转发、预览和 provider testing 中,这里也支持版本路径或完整接口地址。",
- "tooltip": "例如:https://relay.example.com/openai、https://relay.example.com/openai/v1、https://relay.example.com/openai/v1/responses。Claude Code Hub 会复用你提供的路径,不会把同一个 endpoint 再追加一次。"
+ "tooltip": "例如:https://relay.example.com/openai、https://relay.example.com/openai/v1、https://relay.example.com/openai/v1/responses。CC Hub 会复用你提供的路径,不会把同一个 endpoint 再追加一次。"
}
diff --git a/messages/zh-CN/usage.json b/messages/zh-CN/usage.json
index 8bbd02ee3..98d38a23c 100644
--- a/messages/zh-CN/usage.json
+++ b/messages/zh-CN/usage.json
@@ -1,5 +1,5 @@
{
- "pageTitle": "Claude Code Hub 使用文档",
+ "pageTitle": "CC Hub 使用文档",
"pageDescription": "完整的 Claude Code、Codex 和 Droid CLI 集成指南",
"skipLinks": {
diff --git a/messages/zh-TW/auth.json b/messages/zh-TW/auth.json
index 439ca9dca..c3d3cbce2 100644
--- a/messages/zh-TW/auth.json
+++ b/messages/zh-TW/auth.json
@@ -20,11 +20,9 @@
"confirm": "確定要登出嗎?",
"success": "已登出"
},
- "placeholders": {
- "apiKeyExample": "例如 sk-xxxxxxxx"
- },
"brand": {
- "tagline": "統一 API 管理控制台"
+ "tagline": "統一 API 管理控制台",
+ "disclaimer": "CC Hub 並非 Anthropic 官方專案,與其無任何關聯。Claude Code、Claude 等均屬 Anthropic 公司的商標。"
},
"actions": {
"enterConsole": "進入控制台",
diff --git a/messages/zh-TW/bigScreen.json b/messages/zh-TW/bigScreen.json
index 7727998a4..415b33a9c 100644
--- a/messages/zh-TW/bigScreen.json
+++ b/messages/zh-TW/bigScreen.json
@@ -1,7 +1,7 @@
{
- "pageTitle": "即時資料大屏 - Claude Code Hub",
- "pageDescription": "Claude Code Hub 即時監控資料大屏",
- "title": "CLAUDE CODE HUB",
+ "pageTitle": "即時資料大屏 - CC Hub",
+ "pageDescription": "CC Hub 即時監控資料大屏",
+ "title": "CC HUB",
"subtitle": "即時資料監控中台",
"metrics": {
"concurrent": "並發數",
diff --git a/messages/zh-TW/settings/config.json b/messages/zh-TW/settings/config.json
index 991b84948..72b104637 100644
--- a/messages/zh-TW/settings/config.json
+++ b/messages/zh-TW/settings/config.json
@@ -108,7 +108,7 @@
"saveSuccess": "儲存成功",
"siteTitle": "站台標題",
"siteTitleDesc": "用於設定瀏覽器分頁標題以及系統預設顯示名稱。",
- "siteTitlePlaceholder": "例:Claude Code Hub",
+ "siteTitlePlaceholder": "例:CC Hub",
"siteTitleRequired": "站台標題不能為空",
"ipLoggingInvalidJson": "IP 擷取設定不是合法的 JSON:{message}",
"ipLoggingInvalidShape": "IP 擷取設定必須是包含 `headers` 陣列的物件。",
diff --git a/messages/zh-TW/settings/providers/form/url.json b/messages/zh-TW/settings/providers/form/url.json
index a135fc6b0..d20599990 100644
--- a/messages/zh-TW/settings/providers/form/url.json
+++ b/messages/zh-TW/settings/providers/form/url.json
@@ -2,5 +2,5 @@
"label": "API 位址",
"placeholder": "例如:https://open.bigmodel.cn/api/anthropic",
"description": "填入供應商的基礎位址即可。在請求轉發、預覽與 provider testing 中,這裡也支援版本路徑或完整介面位址。",
- "tooltip": "例如:https://relay.example.com/openai、https://relay.example.com/openai/v1、https://relay.example.com/openai/v1/responses。Claude Code Hub 會重用你提供的路徑,不會把同一個 endpoint 再追加一次。"
+ "tooltip": "例如:https://relay.example.com/openai、https://relay.example.com/openai/v1、https://relay.example.com/openai/v1/responses。CC Hub 會重用你提供的路徑,不會把同一個 endpoint 再追加一次。"
}
diff --git a/messages/zh-TW/usage.json b/messages/zh-TW/usage.json
index bb274fc27..74a3a25a5 100644
--- a/messages/zh-TW/usage.json
+++ b/messages/zh-TW/usage.json
@@ -1,5 +1,5 @@
{
- "pageTitle": "Claude Code Hub 使用文檔",
+ "pageTitle": "CC Hub 使用文檔",
"pageDescription": "完整的 Claude Code、Codex 和 Droid CLI 集成指南",
"skipLinks": {
diff --git a/scripts/cch b/scripts/cch
index d3dede2be..5e5ef3be2 100755
--- a/scripts/cch
+++ b/scripts/cch
@@ -1,5 +1,5 @@
#!/usr/bin/env bash
-# cch - Claude Code Hub Kubernetes Management CLI
+# cch - CC Hub Kubernetes Management CLI
# 兼容 k3s 与标准 Kubernetes,通过 env / ~/.config/cch/config 可覆盖默认值
# Reference: docs/k8s-deployment.md
set -euo pipefail
@@ -274,7 +274,7 @@ cmd_update() {
local TIMESTAMP
TIMESTAMP=$(date +%Y%m%d%H%M%S)
echo -e "${CYAN}=========================================${NC}"
- echo -e "${CYAN} Claude Code Hub Upgrade - $TIMESTAMP${NC}"
+ echo -e "${CYAN} CC Hub Upgrade - $TIMESTAMP${NC}"
echo -e "${CYAN}=========================================${NC}"
echo ""
@@ -695,7 +695,7 @@ cmd_uninstall() {
###############################################################################
cmd_help() {
cat < [args]
diff --git a/scripts/clear-session-bindings.ts b/scripts/clear-session-bindings.ts
index 24174b3b8..5d42fe6c4 100644
--- a/scripts/clear-session-bindings.ts
+++ b/scripts/clear-session-bindings.ts
@@ -852,7 +852,7 @@ async function runCleanup(
async function main(): Promise {
console.log("=".repeat(60));
- console.log(" Claude Code Hub - Session 绑定清理工具");
+ console.log(" CC Hub - Session 绑定清理工具");
console.log("=".repeat(60));
const options = parseCliArgs(process.argv.slice(2));
diff --git a/scripts/deploy-k8s.sh b/scripts/deploy-k8s.sh
index 8b0f1cf06..efef60273 100755
--- a/scripts/deploy-k8s.sh
+++ b/scripts/deploy-k8s.sh
@@ -1,5 +1,5 @@
#!/usr/bin/env bash
-# Claude Code Hub - Kubernetes / k3s One-Click Deployment
+# CC Hub - Kubernetes / k3s One-Click Deployment
# 兼容 k3s 与标准 Kubernetes (EKS/GKE/AKS/self-hosted)
# 详见: docs/k8s-deployment.md
set -euo pipefail
@@ -123,7 +123,7 @@ REDIS_PASSWORD=""
###############################################################################
show_help() {
cat << EOF
-Claude Code Hub - K8s/k3s One-Click Deployment Script v${VERSION}
+CC Hub - K8s/k3s One-Click Deployment Script v${VERSION}
Usage: $0 [OPTIONS]
@@ -225,7 +225,7 @@ print_header() {
echo -e "${BLUE}"
echo "+=================================================================+"
echo "| |"
- echo "| Claude Code Hub - K8s / k3s One-Click Deployment |"
+ echo "| CC Hub - K8s / k3s One-Click Deployment |"
echo "| Version ${VERSION} |"
echo "| |"
echo "+=================================================================+"
@@ -864,9 +864,9 @@ print_success_message() {
echo -e "${GREEN}+================================================================+${NC}"
echo -e "${GREEN}| |${NC}"
if [[ "$UPDATE_MODE" == true ]]; then
- echo -e "${GREEN}| Claude Code Hub Upgrade Complete! |${NC}"
+ echo -e "${GREEN}| CC Hub Upgrade Complete! |${NC}"
else
- echo -e "${GREEN}| Claude Code Hub Deployment Complete! |${NC}"
+ echo -e "${GREEN}| CC Hub Deployment Complete! |${NC}"
fi
echo -e "${GREEN}| |${NC}"
echo -e "${GREEN}+================================================================+${NC}"
diff --git a/scripts/deploy.ps1 b/scripts/deploy.ps1
index 930d98ec0..e2a5faa1b 100644
--- a/scripts/deploy.ps1
+++ b/scripts/deploy.ps1
@@ -1,4 +1,4 @@
-# Claude Code Hub - One-Click Deployment Script for Windows
+# CC Hub - One-Click Deployment Script for Windows
# PowerShell 5.1+ required
#Requires -Version 5.1
@@ -52,7 +52,7 @@ $script:FORCE_NEW = $false
function Show-Help {
$helpText = @"
-Claude Code Hub - One-Click Deployment Script v$VERSION
+CC Hub - One-Click Deployment Script v$VERSION
Usage: .\deploy.ps1 [OPTIONS]
@@ -148,7 +148,7 @@ function Write-ColorOutput {
function Show-Header {
Write-ColorOutput "+=================================================================+" -Type Header
Write-ColorOutput "| |" -Type Header
- Write-ColorOutput "| Claude Code Hub - One-Click Deployment |" -Type Header
+ Write-ColorOutput "| CC Hub - One-Click Deployment |" -Type Header
Write-ColorOutput "| Version $VERSION |" -Type Header
Write-ColorOutput "| |" -Type Header
Write-ColorOutput "+=================================================================+" -Type Header
@@ -752,10 +752,10 @@ function Show-SuccessMessage {
Write-Host "+================================================================+" -ForegroundColor Green
Write-Host "| |" -ForegroundColor Green
if ($script:UPDATE_MODE) {
- Write-Host "| Claude Code Hub Updated Successfully! |" -ForegroundColor Green
+ Write-Host "| CC Hub Updated Successfully! |" -ForegroundColor Green
}
else {
- Write-Host "| Claude Code Hub Deployed Successfully! |" -ForegroundColor Green
+ Write-Host "| CC Hub Deployed Successfully! |" -ForegroundColor Green
}
Write-Host "| |" -ForegroundColor Green
Write-Host "+================================================================+" -ForegroundColor Green
diff --git a/scripts/deploy.sh b/scripts/deploy.sh
index 2d8a02d9a..c80a5d6bf 100755
--- a/scripts/deploy.sh
+++ b/scripts/deploy.sh
@@ -54,7 +54,7 @@ NON_INTERACTIVE=false
show_help() {
cat << EOF
-Claude Code Hub - One-Click Deployment Script v${VERSION}
+CC Hub - One-Click Deployment Script v${VERSION}
Usage: $0 [OPTIONS]
@@ -208,7 +208,7 @@ print_header() {
echo -e "${BLUE}"
echo "+=================================================================+"
echo "| |"
- echo "| Claude Code Hub - One-Click Deployment |"
+ echo "| CC Hub - One-Click Deployment |"
echo "| Version ${VERSION} |"
echo "| |"
echo "+=================================================================+"
@@ -791,9 +791,9 @@ print_success_message() {
echo -e "${GREEN}+================================================================+${NC}"
echo -e "${GREEN}| |${NC}"
if [[ "$UPDATE_MODE" == true ]]; then
- echo -e "${GREEN}| Claude Code Hub Updated Successfully! |${NC}"
+ echo -e "${GREEN}| CC Hub Updated Successfully! |${NC}"
else
- echo -e "${GREEN}| Claude Code Hub Deployed Successfully! |${NC}"
+ echo -e "${GREEN}| CC Hub Deployed Successfully! |${NC}"
fi
echo -e "${GREEN}| |${NC}"
echo -e "${GREEN}+================================================================+${NC}"
diff --git a/src/app/[locale]/login/page.tsx b/src/app/[locale]/login/page.tsx
index b444ba978..067958834 100644
--- a/src/app/[locale]/login/page.tsx
+++ b/src/app/[locale]/login/page.tsx
@@ -202,7 +202,7 @@ function LoginPageContent() {
const isLoading = status === "submitting" || status === "success";
return (
-
+
{/* Fullscreen Loading Overlay */}
{isLoading && (
{/* Main Layout */}
-
+
{/* Brand Panel - Desktop Only */}
{t("form.title")}
- {t("form.description")}
+
+ {t("form.description")}
+
@@ -340,7 +342,6 @@ function LoginPageContent() {
id="apiKey"
ref={apiKeyInputRef}
type={showPassword ? "text" : "password"}
- placeholder={t("placeholders.apiKeyExample")}
value={apiKey}
onChange={(e) => setApiKey(e.target.value)}
className="pl-9 pr-10"
@@ -406,7 +407,7 @@ function LoginPageContent() {
{/* Page Footer */}
-
+
+
+ {t("brand.disclaimer")}
+
+
{versionInfo?.current ? (
- © {year} Claude Code Hub · v{version}
+ © {year} CC Hub · v{version}
{
// since getSystemSettings creates default row if not exists
return {
id: 0,
- siteTitle: "Claude Code Hub",
+ siteTitle: DEFAULT_SITE_TITLE,
allowGlobalUsageView: false,
currencyDisplay: "USD",
billingModelSource: "original",
diff --git a/src/lib/layout-site-metadata.ts b/src/lib/layout-site-metadata.ts
index 62a872874..e55829602 100644
--- a/src/lib/layout-site-metadata.ts
+++ b/src/lib/layout-site-metadata.ts
@@ -1,6 +1,5 @@
import { logger } from "@/lib/logger";
-
-const FALLBACK_SITE_TITLE = "Claude Code Hub";
+import { DEFAULT_SITE_TITLE as FALLBACK_SITE_TITLE } from "@/lib/site-title";
export async function resolveDefaultSiteMetadataSource(): Promise<{
siteTitle: string;
diff --git a/src/lib/public-status/config-publisher.ts b/src/lib/public-status/config-publisher.ts
index a479970c2..06c6d082c 100644
--- a/src/lib/public-status/config-publisher.ts
+++ b/src/lib/public-status/config-publisher.ts
@@ -14,6 +14,7 @@ import {
publishCurrentPublicStatusConfigPointers,
publishInternalPublicStatusConfigSnapshot,
publishPublicStatusConfigSnapshot,
+ readCurrentPublicStatusConfigSnapshot,
resolvePublicStatusSiteDescription,
} from "./config-snapshot";
import { MAX_PUBLIC_STATUS_RANGE_HOURS, PUBLIC_STATUS_INTERVAL_SET } from "./constants";
@@ -176,3 +177,17 @@ export async function publishCurrentPublicStatusConfigProjection(input: {
groupCount: enabledGroups.length,
};
}
+
+export async function reconcilePublicStatusSiteTitleProjection(): Promise
{
+ const settings = await getSystemSettings();
+ const currentSnapshot = await readCurrentPublicStatusConfigSnapshot();
+ if (currentSnapshot?.siteTitle?.trim() === settings.siteTitle.trim()) {
+ return true;
+ }
+ const result = await publishCurrentPublicStatusConfigProjection({
+ reason: "startup-site-title-reconciliation",
+ ...(currentSnapshot ? { configVersion: currentSnapshot.configVersion } : {}),
+ });
+
+ return result.written;
+}
diff --git a/src/lib/public-status/config-snapshot.ts b/src/lib/public-status/config-snapshot.ts
index 2818aad14..89dd704ff 100644
--- a/src/lib/public-status/config-snapshot.ts
+++ b/src/lib/public-status/config-snapshot.ts
@@ -1,5 +1,5 @@
import { getRedisClient } from "@/lib/redis";
-import { normalizeSiteTitle } from "@/lib/site-title";
+import { DEFAULT_SITE_TITLE, normalizeSiteTitle } from "@/lib/site-title";
import {
buildPublicStatusConfigSnapshotKey,
buildPublicStatusConfigVersionPointerKey,
@@ -225,7 +225,7 @@ export async function publishPublicStatusConfigSnapshot(input: {
input.snapshot ??
buildPublicStatusConfigSnapshot({
configVersion: `cfg-${Date.now()}`,
- siteTitle: "Claude Code Hub Status",
+ siteTitle: `${DEFAULT_SITE_TITLE} Status`,
siteDescription: DEFAULT_PUBLIC_STATUS_SITE_DESCRIPTION,
timeZone: null,
defaultIntervalMinutes: 5,
diff --git a/src/lib/public-status/openapi.ts b/src/lib/public-status/openapi.ts
index 291586c83..9b0db65f6 100644
--- a/src/lib/public-status/openapi.ts
+++ b/src/lib/public-status/openapi.ts
@@ -367,8 +367,8 @@ export function appendPublicStatusOpenApi(
include: ["meta", "defaults", "groups", "timeline"],
},
meta: {
- siteTitle: "Claude Code Hub",
- siteDescription: "Claude Code Hub public status",
+ siteTitle: "CC Hub",
+ siteDescription: "CC Hub public status",
timeZone: "UTC",
},
groups: [
@@ -503,8 +503,8 @@ export function appendPublicStatusOpenApi(
summary: "projection 可用",
value: {
available: true,
- siteTitle: "Claude Code Hub",
- siteDescription: "Claude Code Hub public status",
+ siteTitle: "CC Hub",
+ siteDescription: "CC Hub public status",
timeZone: "UTC",
source: "projection",
},
diff --git a/src/lib/public-status/startup-reconciliation.ts b/src/lib/public-status/startup-reconciliation.ts
new file mode 100644
index 000000000..56bfbf211
--- /dev/null
+++ b/src/lib/public-status/startup-reconciliation.ts
@@ -0,0 +1,17 @@
+import { logger } from "@/lib/logger";
+import { reconcilePublicStatusSiteTitleProjection } from "./config-publisher";
+
+export async function reconcilePublicStatusSiteTitleAtStartup(): Promise {
+ try {
+ const written = await reconcilePublicStatusSiteTitleProjection();
+ if (!written) {
+ logger.warn("[Instrumentation] Public status site title reconciliation deferred", {
+ reason: "redis-projection-unavailable",
+ });
+ }
+ } catch (error) {
+ logger.warn("[Instrumentation] Public status site title reconciliation failed", {
+ error: error instanceof Error ? error.message : String(error),
+ });
+ }
+}
diff --git a/src/lib/site-title.ts b/src/lib/site-title.ts
index fc11a4f00..9a1bd5948 100644
--- a/src/lib/site-title.ts
+++ b/src/lib/site-title.ts
@@ -1,4 +1,4 @@
-export const DEFAULT_SITE_TITLE = "Claude Code Hub";
+export const DEFAULT_SITE_TITLE = "CC Hub";
export function normalizeSiteTitle(value: unknown): string | null {
if (typeof value !== "string") {
diff --git a/src/repository/_shared/transformers.test.ts b/src/repository/_shared/transformers.test.ts
index 69ac7e8cb..b7f82e7dc 100644
--- a/src/repository/_shared/transformers.test.ts
+++ b/src/repository/_shared/transformers.test.ts
@@ -273,7 +273,7 @@ describe("src/repository/_shared/transformers.ts", () => {
it("dbSettings 缺失时返回默认值", () => {
const result = toSystemSettings(undefined);
expect(result.id).toBe(0);
- expect(result.siteTitle).toBe("Claude Code Hub");
+ expect(result.siteTitle).toBe("CC Hub");
expect(result.allowGlobalUsageView).toBe(true);
expect(result.currencyDisplay).toBe("USD");
expect(result.billingModelSource).toBe("original");
diff --git a/src/repository/_shared/transformers.ts b/src/repository/_shared/transformers.ts
index e57c69a43..e9fcbca37 100644
--- a/src/repository/_shared/transformers.ts
+++ b/src/repository/_shared/transformers.ts
@@ -1,5 +1,6 @@
import { PROVIDER_TIMEOUT_DEFAULTS } from "@/lib/constants/provider.constants";
import { normalizeProviderModelRedirectRules } from "@/lib/provider-model-redirects";
+import { DEFAULT_SITE_TITLE } from "@/lib/site-title";
import { formatCostForStorage } from "@/lib/utils/currency";
import type { Key } from "@/types/key";
import type { MessageRequest } from "@/types/message";
@@ -244,7 +245,7 @@ export function toSystemSettings(dbSettings: any): SystemSettings {
return {
id: dbSettings?.id ?? 0,
- siteTitle: dbSettings?.siteTitle ?? "Claude Code Hub",
+ siteTitle: dbSettings?.siteTitle ?? DEFAULT_SITE_TITLE,
allowGlobalUsageView: dbSettings?.allowGlobalUsageView ?? true,
currencyDisplay: dbSettings?.currencyDisplay ?? "USD",
billingModelSource: dbSettings?.billingModelSource ?? "original",
diff --git a/tests/README.md b/tests/README.md
index 532f69eaa..8f927585f 100644
--- a/tests/README.md
+++ b/tests/README.md
@@ -1,4 +1,4 @@
-# 🧪 Claude Code Hub 测试指南
+# 🧪 CC Hub 测试指南
> **统一 Vitest 框架** | 38 个基础测试 + 103 个集成测试 ✅
@@ -279,7 +279,7 @@ bun run test
---
-**维护者**: Claude Code Hub Team
+**维护者**: CC Hub Team
**测试框架**: Vitest 4.0.16
**基础测试**: 100% (38/38)
**最后更新**: 2025-12-17
diff --git a/tests/api/api-openapi-spec.test.ts b/tests/api/api-openapi-spec.test.ts
index ca6000c58..ee8fa8e9a 100644
--- a/tests/api/api-openapi-spec.test.ts
+++ b/tests/api/api-openapi-spec.test.ts
@@ -98,7 +98,7 @@ describe("OpenAPI 规范验证", () => {
test("应该符合 OpenAPI 3.1.0 规范", () => {
expect(openApiDoc.openapi).toBe("3.1.0");
expect(openApiDoc.info).toBeDefined();
- expect(openApiDoc.info.title).toBe("Claude Code Hub API");
+ expect(openApiDoc.info.title).toBe("CC Hub API");
expect(openApiDoc.info.version).toBeDefined();
});
diff --git a/tests/api/v1/system/system-config.test.ts b/tests/api/v1/system/system-config.test.ts
index 306ee3b1a..2409e9e3b 100644
--- a/tests/api/v1/system/system-config.test.ts
+++ b/tests/api/v1/system/system-config.test.ts
@@ -37,7 +37,7 @@ const userSession = {
const settings: SystemSettings = {
id: 1,
- siteTitle: "Claude Code Hub",
+ siteTitle: "CC Hub",
allowGlobalUsageView: true,
currencyDisplay: "USD",
billingModelSource: "original",
@@ -105,7 +105,7 @@ describe("v1 system config endpoints", () => {
});
expect(got.response.status).toBe(200);
expect(got.json).toMatchObject({
- siteTitle: "Claude Code Hub",
+ siteTitle: "CC Hub",
updatedAt: "2026-04-28T00:00:00.000Z",
});
@@ -144,7 +144,7 @@ describe("v1 system config endpoints", () => {
expect(got.response.status).toBe(200);
expect(got.json).toEqual({
- siteTitle: "Claude Code Hub",
+ siteTitle: "CC Hub",
currencyDisplay: "USD",
billingModelSource: "original",
});
diff --git a/tests/e2e/v1-management-smoke.test.ts b/tests/e2e/v1-management-smoke.test.ts
index 89756accb..bd44870ae 100644
--- a/tests/e2e/v1-management-smoke.test.ts
+++ b/tests/e2e/v1-management-smoke.test.ts
@@ -20,7 +20,7 @@ run("v1 management REST API live smoke", () => {
expect(openapi.headers.get("X-API-Version")).toBe("1.0.0");
await expect(openapi.json()).resolves.toMatchObject({
openapi: "3.1.0",
- info: { title: "Claude Code Hub Management API", version: "1.0.0" },
+ info: { title: "CC Hub Management API", version: "1.0.0" },
});
});
diff --git a/tests/integration/public-status/config-publish.test.ts b/tests/integration/public-status/config-publish.test.ts
index 8c24a21f1..c90c284fa 100644
--- a/tests/integration/public-status/config-publish.test.ts
+++ b/tests/integration/public-status/config-publish.test.ts
@@ -83,14 +83,14 @@ describe("public-status config publish integration", () => {
});
mockUpdateSystemSettings.mockResolvedValue({
id: 1,
- siteTitle: "Claude Code Hub",
+ siteTitle: "CC Hub",
timezone: "UTC",
publicStatusWindowHours: 24,
publicStatusAggregationIntervalMinutes: 5,
});
mockGetSystemSettings.mockResolvedValue({
id: 1,
- siteTitle: "Claude Code Hub",
+ siteTitle: "CC Hub",
timezone: "UTC",
publicStatusWindowHours: 24,
publicStatusAggregationIntervalMinutes: 5,
diff --git a/tests/unit/actions/admin-user-insights.test.ts b/tests/unit/actions/admin-user-insights.test.ts
index fa62e9c58..1f14d0659 100644
--- a/tests/unit/actions/admin-user-insights.test.ts
+++ b/tests/unit/actions/admin-user-insights.test.ts
@@ -74,7 +74,7 @@ function createMockOverview() {
function createMockSettings() {
return {
id: 1,
- siteTitle: "Claude Code Hub",
+ siteTitle: "CC Hub",
allowGlobalUsageView: false,
currencyDisplay: "USD",
billingModelSource: "original",
diff --git a/tests/unit/actions/system-config-fake-streaming-setting.test.ts b/tests/unit/actions/system-config-fake-streaming-setting.test.ts
index aa225c120..9df9b7b33 100644
--- a/tests/unit/actions/system-config-fake-streaming-setting.test.ts
+++ b/tests/unit/actions/system-config-fake-streaming-setting.test.ts
@@ -65,7 +65,7 @@ const DEFAULT_FAKE_STREAMING_MODELS: { model: string; groupTags: string[] }[] =
function createSettings(overrides: Record = {}) {
return {
id: 1,
- siteTitle: "Claude Code Hub",
+ siteTitle: "CC Hub",
allowGlobalUsageView: false,
currencyDisplay: "USD",
billingModelSource: "original",
@@ -134,14 +134,14 @@ describe("fake streaming whitelist system setting", () => {
const fromNullField = toSystemSettings({
id: 1,
- siteTitle: "Claude Code Hub",
+ siteTitle: "CC Hub",
fakeStreamingWhitelist: null,
});
expect(fromNullField.fakeStreamingWhitelist).toEqual(DEFAULT_FAKE_STREAMING_MODELS);
const fromMissingField = toSystemSettings({
id: 1,
- siteTitle: "Claude Code Hub",
+ siteTitle: "CC Hub",
});
expect(fromMissingField.fakeStreamingWhitelist).toEqual(DEFAULT_FAKE_STREAMING_MODELS);
});
@@ -151,7 +151,7 @@ describe("fake streaming whitelist system setting", () => {
const result = toSystemSettings({
id: 1,
- siteTitle: "Claude Code Hub",
+ siteTitle: "CC Hub",
fakeStreamingWhitelist: [],
});
@@ -168,7 +168,7 @@ describe("fake streaming whitelist system setting", () => {
const result = toSystemSettings({
id: 1,
- siteTitle: "Claude Code Hub",
+ siteTitle: "CC Hub",
fakeStreamingWhitelist: persisted,
});
diff --git a/tests/unit/actions/system-config-gemini-function-id-setting.test.ts b/tests/unit/actions/system-config-gemini-function-id-setting.test.ts
index 183183994..24b50ccbe 100644
--- a/tests/unit/actions/system-config-gemini-function-id-setting.test.ts
+++ b/tests/unit/actions/system-config-gemini-function-id-setting.test.ts
@@ -7,9 +7,9 @@ describe("enableGeminiFunctionIdRectifier system setting", () => {
const { toSystemSettings } = await import("@/repository/_shared/transformers");
expect(toSystemSettings(undefined).enableGeminiFunctionIdRectifier).toBe(true);
- expect(
- toSystemSettings({ id: 1, siteTitle: "Claude Code Hub" }).enableGeminiFunctionIdRectifier
- ).toBe(true);
+ expect(toSystemSettings({ id: 1, siteTitle: "CC Hub" }).enableGeminiFunctionIdRectifier).toBe(
+ true
+ );
expect(
toSystemSettings({ id: 1, enableGeminiFunctionIdRectifier: false })
.enableGeminiFunctionIdRectifier
diff --git a/tests/unit/actions/system-config-non-chat-retry-setting.test.ts b/tests/unit/actions/system-config-non-chat-retry-setting.test.ts
index 86f1784b6..991c2d768 100644
--- a/tests/unit/actions/system-config-non-chat-retry-setting.test.ts
+++ b/tests/unit/actions/system-config-non-chat-retry-setting.test.ts
@@ -63,7 +63,7 @@ vi.mock("@/lib/utils/timezone", () => ({
function createSettings(overrides: Record = {}) {
return {
id: 1,
- siteTitle: "Claude Code Hub",
+ siteTitle: "CC Hub",
allowGlobalUsageView: false,
currencyDisplay: "USD",
billingModelSource: "original",
@@ -137,7 +137,7 @@ describe("non-chat fallback system setting", () => {
expect(
toSystemSettings({
id: 1,
- siteTitle: "Claude Code Hub",
+ siteTitle: "CC Hub",
}).allowNonConversationEndpointProviderFallback
).toBe(true);
diff --git a/tests/unit/actions/system-config-stream-gate-affinity-settings.test.ts b/tests/unit/actions/system-config-stream-gate-affinity-settings.test.ts
index 74870c9dc..93802a3e8 100644
--- a/tests/unit/actions/system-config-stream-gate-affinity-settings.test.ts
+++ b/tests/unit/actions/system-config-stream-gate-affinity-settings.test.ts
@@ -8,12 +8,10 @@ describe("streamGateMode / affinityIgnoreClientSessionId system settings", () =>
expect(toSystemSettings(undefined).streamGateMode).toBe("enforce");
expect(toSystemSettings(undefined).affinityIgnoreClientSessionId).toBe(true);
- expect(toSystemSettings({ id: 1, siteTitle: "Claude Code Hub" }).streamGateMode).toBe(
- "enforce"
+ expect(toSystemSettings({ id: 1, siteTitle: "CC Hub" }).streamGateMode).toBe("enforce");
+ expect(toSystemSettings({ id: 1, siteTitle: "CC Hub" }).affinityIgnoreClientSessionId).toBe(
+ true
);
- expect(
- toSystemSettings({ id: 1, siteTitle: "Claude Code Hub" }).affinityIgnoreClientSessionId
- ).toBe(true);
expect(toSystemSettings({ id: 1, streamGateMode: "shadow" }).streamGateMode).toBe("shadow");
// varchar 脏值回落产品默认
expect(toSystemSettings({ id: 1, streamGateMode: "bogus" }).streamGateMode).toBe("enforce");
diff --git a/tests/unit/actions/system-config-thinking-effort-conflict-setting.test.ts b/tests/unit/actions/system-config-thinking-effort-conflict-setting.test.ts
index c1f980722..4d42c68e0 100644
--- a/tests/unit/actions/system-config-thinking-effort-conflict-setting.test.ts
+++ b/tests/unit/actions/system-config-thinking-effort-conflict-setting.test.ts
@@ -8,8 +8,7 @@ describe("enableThinkingEffortConflictRectifier system setting", () => {
expect(toSystemSettings(undefined).enableThinkingEffortConflictRectifier).toBe(true);
expect(
- toSystemSettings({ id: 1, siteTitle: "Claude Code Hub" })
- .enableThinkingEffortConflictRectifier
+ toSystemSettings({ id: 1, siteTitle: "CC Hub" }).enableThinkingEffortConflictRectifier
).toBe(true);
expect(
toSystemSettings({ id: 1, enableThinkingEffortConflictRectifier: false })
diff --git a/tests/unit/api/public-site-meta-route.test.ts b/tests/unit/api/public-site-meta-route.test.ts
index 764e00d28..cf89bb431 100644
--- a/tests/unit/api/public-site-meta-route.test.ts
+++ b/tests/unit/api/public-site-meta-route.test.ts
@@ -33,7 +33,7 @@ describe("GET /api/public-site-meta", () => {
}: {
siteTitle?: string | null;
siteDescription?: string | null;
- }) => siteDescription?.trim() || `${siteTitle ?? "Claude Code Hub"} public status`
+ }) => siteDescription?.trim() || `${siteTitle ?? "CC Hub"} public status`
);
const mod = await import("@/app/api/public-site-meta/route");
diff --git a/tests/unit/api/public-status-api-contract.test.ts b/tests/unit/api/public-status-api-contract.test.ts
index 37f3bfb58..3cfc8593f 100644
--- a/tests/unit/api/public-status-api-contract.test.ts
+++ b/tests/unit/api/public-status-api-contract.test.ts
@@ -167,8 +167,8 @@ describe("GET /api/public-status contract", () => {
vi.clearAllMocks();
mockReadCurrentPublicStatusConfigSnapshot.mockResolvedValue({
configVersion: "cfg-1",
- siteTitle: "Claude Code Hub",
- siteDescription: "Claude Code Hub public status",
+ siteTitle: "CC Hub",
+ siteDescription: "CC Hub public status",
timeZone: "UTC",
defaultIntervalMinutes: 5,
defaultRangeHours: 24,
@@ -255,8 +255,8 @@ describe("GET /api/public-status contract", () => {
include: ["meta", "defaults", "groups", "timeline"],
},
meta: {
- siteTitle: "Claude Code Hub",
- siteDescription: "Claude Code Hub public status",
+ siteTitle: "CC Hub",
+ siteDescription: "CC Hub public status",
timeZone: "UTC",
},
groups: [
@@ -375,7 +375,7 @@ describe("GET /api/public-status contract", () => {
expect(response.status).toBe(200);
await expect(response.json()).resolves.toMatchObject({
meta: {
- siteTitle: "Claude Code Hub",
+ siteTitle: "CC Hub",
},
defaults: {
intervalMinutes: 5,
diff --git a/tests/unit/api/v1/api-client-actions.test.ts b/tests/unit/api/v1/api-client-actions.test.ts
index 5ce5534c5..5b111aab4 100644
--- a/tests/unit/api/v1/api-client-actions.test.ts
+++ b/tests/unit/api/v1/api-client-actions.test.ts
@@ -128,13 +128,13 @@ describe("v1 action compatibility client", () => {
})
)
.mockResolvedValueOnce({
- siteTitle: "Claude Code Hub",
+ siteTitle: "CC Hub",
currencyDisplay: "USD",
billingModelSource: "original",
});
await expect(systemConfig.getSystemSettings()).resolves.toEqual({
- siteTitle: "Claude Code Hub",
+ siteTitle: "CC Hub",
currencyDisplay: "USD",
billingModelSource: "original",
});
diff --git a/tests/unit/api/v1/docs-routes.test.ts b/tests/unit/api/v1/docs-routes.test.ts
index 73d5bccc9..99ef69e35 100644
--- a/tests/unit/api/v1/docs-routes.test.ts
+++ b/tests/unit/api/v1/docs-routes.test.ts
@@ -40,7 +40,7 @@ describe("v1 management docs routes", () => {
expect(response.status).toBe(200);
expect(document.openapi).toBe("3.1.0");
- expect(document.info.title).toBe("Claude Code Hub Management API");
+ expect(document.info.title).toBe("CC Hub Management API");
expect(document.info.version).toBe("1.0.0");
expect(document.servers?.[0]?.url).toBe("/");
expect(document.components?.securitySchemes).toHaveProperty("bearerAuth");
diff --git a/tests/unit/auth/login-page-site-title.test.tsx b/tests/unit/auth/login-page-site-title.test.tsx
index 9a012fe1e..e22d4f7a4 100644
--- a/tests/unit/auth/login-page-site-title.test.tsx
+++ b/tests/unit/auth/login-page-site-title.test.tsx
@@ -37,7 +37,7 @@ vi.mock("next-themes", () => ({
}));
const globalFetch = global.fetch;
-const DEFAULT_SITE_TITLE = "Claude Code Hub";
+const DEFAULT_SITE_TITLE = "CC Hub";
function getRequestPath(input: string | URL | Request): string {
if (typeof input === "string") {
@@ -142,4 +142,54 @@ describe("login page site title", () => {
container.querySelector('[data-testid="login-site-title-footer"]')?.textContent
).toBe(DEFAULT_SITE_TITLE);
});
+
+ it("shows the trademark disclaimer and leaves the API key field without a placeholder", async () => {
+ (global.fetch as ReturnType).mockImplementation(() =>
+ Promise.resolve(mockJsonResponse({ current: "1.0.0", hasUpdate: false }))
+ );
+
+ await render();
+ await flushMicrotasks();
+
+ expect(
+ container.querySelector('[data-testid="login-disclaimer"]')?.textContent
+ ).toBe("t:brand.disclaimer");
+ expect(container.querySelector("#apiKey")?.getAttribute("placeholder")).toBe(
+ null
+ );
+ });
+
+ it("keeps the disclaimer footer in page flow on short viewports", async () => {
+ (global.fetch as ReturnType).mockImplementation(() =>
+ Promise.resolve(mockJsonResponse({ current: "1.0.0", hasUpdate: false }))
+ );
+
+ await render();
+ await flushMicrotasks();
+
+ const disclaimer = container.querySelector('[data-testid="login-disclaimer"]');
+ const footer = disclaimer?.parentElement;
+ const page = footer?.parentElement;
+
+ expect(footer?.className).not.toMatch(/\babsolute\b/);
+ expect(page?.className).toContain("overflow-x-hidden");
+ expect(page?.className).not.toMatch(/\boverflow-hidden\b/);
+ expect(page?.lastElementChild).toBe(footer);
+ });
+
+ it("balances card description wrapping and widens the disclaimer on large screens", async () => {
+ (global.fetch as ReturnType).mockImplementation(() =>
+ Promise.resolve(mockJsonResponse({ current: "1.0.0", hasUpdate: false }))
+ );
+
+ await render();
+ await flushMicrotasks();
+
+ const description = container.querySelector('[data-slot="card-description"]');
+ const disclaimer = container.querySelector('[data-testid="login-disclaimer"]');
+
+ expect(description?.className).toContain("text-balance");
+ expect(disclaimer?.className).toContain("text-balance");
+ expect(disclaimer?.className).toContain("lg:max-w-lg");
+ });
});
diff --git a/tests/unit/drizzle/site-title-migration.test.ts b/tests/unit/drizzle/site-title-migration.test.ts
new file mode 100644
index 000000000..b3f77c1e8
--- /dev/null
+++ b/tests/unit/drizzle/site-title-migration.test.ts
@@ -0,0 +1,78 @@
+import { readFileSync } from "node:fs";
+import { resolve } from "node:path";
+import { describe, expect, it } from "vitest";
+
+interface JournalEntry {
+ idx: number;
+ tag: string;
+}
+
+interface MigrationJournal {
+ entries: JournalEntry[];
+}
+
+const readMigrationFile = (path: string): string =>
+ readFileSync(resolve(process.cwd(), path), "utf8");
+
+describe("site title migration", () => {
+ it("runs after the TTFB migration and preserves both schema changes", () => {
+ const journal = JSON.parse(
+ readMigrationFile("drizzle/meta/_journal.json")
+ ) as MigrationJournal;
+ const indexes = journal.entries.map(({ idx }) => idx);
+ const tags = journal.entries.map(({ tag }) => tag);
+ const ttfbMigrationIndex = tags.indexOf("0114_overconfident_ronan");
+ const siteTitleMigrationIndex = tags.indexOf("0115_breezy_polaris");
+ const snapshot = JSON.parse(readMigrationFile("drizzle/meta/0115_snapshot.json"));
+
+ expect(new Set(indexes).size).toBe(indexes.length);
+ expect(tags.filter((tag) => tag === "0114_overconfident_ronan")).toHaveLength(1);
+ expect(tags.filter((tag) => tag === "0115_breezy_polaris")).toHaveLength(1);
+ expect(ttfbMigrationIndex).toBeGreaterThanOrEqual(0);
+ expect(siteTitleMigrationIndex).toBeGreaterThan(ttfbMigrationIndex);
+ expect(journal.entries[ttfbMigrationIndex]).toMatchObject({
+ idx: 114,
+ tag: "0114_overconfident_ronan",
+ });
+ expect(journal.entries[siteTitleMigrationIndex]).toMatchObject({
+ idx: 115,
+ tag: "0115_breezy_polaris",
+ });
+ expect(snapshot).toMatchObject({
+ tables: {
+ "public.message_request": {
+ columns: {
+ first_byte_ms: {
+ name: "first_byte_ms",
+ type: "integer",
+ primaryKey: false,
+ notNull: false,
+ },
+ },
+ },
+ "public.system_settings": {
+ columns: {
+ site_title: {
+ name: "site_title",
+ type: "varchar(128)",
+ primaryKey: false,
+ notNull: true,
+ default: "'CC Hub'",
+ },
+ },
+ },
+ },
+ });
+ });
+
+ it("updates only titles that still use the legacy default", () => {
+ const migration = readMigrationFile("drizzle/0115_breezy_polaris.sql");
+
+ expect(migration).toContain(
+ `ALTER TABLE "system_settings" ALTER COLUMN "site_title" SET DEFAULT 'CC Hub'`
+ );
+ expect(migration).toContain(
+ `UPDATE "system_settings" SET "site_title" = 'CC Hub' WHERE "site_title" = 'Claude Code Hub'`
+ );
+ });
+});
diff --git a/tests/unit/i18n/auth-login-keys.test.ts b/tests/unit/i18n/auth-login-keys.test.ts
index 146f1018d..88b9c1ab2 100644
--- a/tests/unit/i18n/auth-login-keys.test.ts
+++ b/tests/unit/i18n/auth-login-keys.test.ts
@@ -38,7 +38,7 @@ describe("auth.json locale key parity", () => {
it("English baseline has expected top-level sections", () => {
const topLevel = Object.keys(enAuth).sort();
expect(topLevel).toEqual(
- ["actions", "brand", "errors", "form", "login", "logout", "placeholders", "security"].sort()
+ ["actions", "brand", "errors", "form", "login", "logout", "security"].sort()
);
});
diff --git a/tests/unit/layout-site-metadata.test.ts b/tests/unit/layout-site-metadata.test.ts
index 4ab5090ca..74858d2f7 100644
--- a/tests/unit/layout-site-metadata.test.ts
+++ b/tests/unit/layout-site-metadata.test.ts
@@ -29,8 +29,8 @@ describe("layout-site-metadata", () => {
const mod = await import("@/lib/layout-site-metadata");
await expect(mod.resolveDefaultSiteMetadataSource()).resolves.toEqual({
- siteTitle: "Claude Code Hub",
- siteDescription: "Claude Code Hub",
+ siteTitle: "CC Hub",
+ siteDescription: "CC Hub",
});
expect(mockLoggerWarn).toHaveBeenCalled();
});
diff --git a/tests/unit/lib/config/system-settings-cache.test.ts b/tests/unit/lib/config/system-settings-cache.test.ts
index ffae5c4c2..ffdf98166 100644
--- a/tests/unit/lib/config/system-settings-cache.test.ts
+++ b/tests/unit/lib/config/system-settings-cache.test.ts
@@ -28,7 +28,7 @@ vi.mock("@/lib/logger", () => ({
function createSettings(overrides: Partial = {}): SystemSettings {
const base: SystemSettings = {
id: 1,
- siteTitle: "Claude Code Hub",
+ siteTitle: "CC Hub",
allowGlobalUsageView: false,
currencyDisplay: "USD",
billingModelSource: "original",
@@ -154,7 +154,7 @@ describe("SystemSettingsCache", () => {
const settings = await getCachedSystemSettings();
expect(settings).toEqual(
expect.objectContaining({
- siteTitle: "Claude Code Hub",
+ siteTitle: "CC Hub",
enableHttp2: false,
enableHighConcurrencyMode: false,
interceptAnthropicWarmupRequests: false,
diff --git a/tests/unit/lib/timezone/timezone-resolver.test.ts b/tests/unit/lib/timezone/timezone-resolver.test.ts
index 2580764f7..51520bbeb 100644
--- a/tests/unit/lib/timezone/timezone-resolver.test.ts
+++ b/tests/unit/lib/timezone/timezone-resolver.test.ts
@@ -40,7 +40,7 @@ const getEnvConfigMock = vi.mocked(getEnvConfig);
function createSettings(overrides: Partial = {}): SystemSettings {
return {
id: 1,
- siteTitle: "Claude Code Hub",
+ siteTitle: "CC Hub",
allowGlobalUsageView: false,
currencyDisplay: "USD",
billingModelSource: "original",
diff --git a/tests/unit/public-site-meta.test.ts b/tests/unit/public-site-meta.test.ts
index 8e3f7ddde..1e317de41 100644
--- a/tests/unit/public-site-meta.test.ts
+++ b/tests/unit/public-site-meta.test.ts
@@ -67,8 +67,8 @@ describe("readPublicSiteMeta", () => {
const { readPublicSiteMeta } = await import("@/lib/public-site-meta");
await expect(readPublicSiteMeta()).resolves.toEqual({
- siteTitle: "Claude Code Hub",
- siteDescription: "Claude Code Hub public status",
+ siteTitle: "CC Hub",
+ siteDescription: "CC Hub public status",
});
expect(mockLoggerWarn).toHaveBeenCalledWith(
"readPublicSiteMeta: failed to load system settings; falling back to defaults",
diff --git a/tests/unit/public-status/config-publisher.test.ts b/tests/unit/public-status/config-publisher.test.ts
index b537c69f4..890ac1d09 100644
--- a/tests/unit/public-status/config-publisher.test.ts
+++ b/tests/unit/public-status/config-publisher.test.ts
@@ -6,6 +6,7 @@ const mockFindLatestPricesByModels = vi.hoisted(() => vi.fn());
const mockPublishInternalPublicStatusConfigSnapshot = vi.hoisted(() => vi.fn());
const mockPublishPublicStatusConfigSnapshot = vi.hoisted(() => vi.fn());
const mockPublishCurrentPublicStatusConfigPointers = vi.hoisted(() => vi.fn());
+const mockReadCurrentPublicStatusConfigSnapshot = vi.hoisted(() => vi.fn());
const mockGetRedisClient = vi.hoisted(() => vi.fn());
vi.mock("@/repository/system-config", () => ({
@@ -34,6 +35,7 @@ vi.mock("@/lib/public-status/config-snapshot", async () => {
publishInternalPublicStatusConfigSnapshot: mockPublishInternalPublicStatusConfigSnapshot,
publishPublicStatusConfigSnapshot: mockPublishPublicStatusConfigSnapshot,
publishCurrentPublicStatusConfigPointers: mockPublishCurrentPublicStatusConfigPointers,
+ readCurrentPublicStatusConfigSnapshot: mockReadCurrentPublicStatusConfigSnapshot,
};
});
@@ -42,12 +44,14 @@ describe("public-status config publisher", () => {
vi.clearAllMocks();
mockGetSystemSettings.mockResolvedValue({
- siteTitle: "Claude Code Hub",
+ siteTitle: "CC Hub",
timezone: "UTC",
publicStatusAggregationIntervalMinutes: 5,
publicStatusWindowHours: 24,
});
mockGetRedisClient.mockReturnValue({});
+ mockFindAllProviderGroups.mockResolvedValue([]);
+ mockReadCurrentPublicStatusConfigSnapshot.mockResolvedValue(null);
mockPublishInternalPublicStatusConfigSnapshot.mockResolvedValue({
configVersion: "cfg-test",
key: "internal",
@@ -96,7 +100,7 @@ describe("public-status config publisher", () => {
expect(mockPublishPublicStatusConfigSnapshot).toHaveBeenCalledWith(
expect.objectContaining({
snapshot: expect.objectContaining({
- siteDescription: "Claude Code Hub public status",
+ siteDescription: "CC Hub public status",
groups: [
expect.objectContaining({
models: [
@@ -118,6 +122,90 @@ describe("public-status config publisher", () => {
);
}, 80_000);
+ it("publishes the database title when the current snapshot is missing", async () => {
+ const mod = await import("@/lib/public-status/config-publisher");
+
+ const written = await mod.reconcilePublicStatusSiteTitleProjection();
+
+ expect(written).toBe(true);
+ expect(mockPublishPublicStatusConfigSnapshot).toHaveBeenCalledWith(
+ expect.objectContaining({
+ reason: "startup-site-title-reconciliation",
+ snapshot: expect.objectContaining({ siteTitle: "CC Hub" }),
+ })
+ );
+ });
+
+ it("skips Redis writes when the current snapshot title already matches", async () => {
+ mockReadCurrentPublicStatusConfigSnapshot.mockResolvedValue({
+ configVersion: "cfg-current",
+ siteTitle: " CC Hub ",
+ });
+ const mod = await import("@/lib/public-status/config-publisher");
+
+ const written = await mod.reconcilePublicStatusSiteTitleProjection();
+
+ expect(written).toBe(true);
+ expect(mockPublishInternalPublicStatusConfigSnapshot).not.toHaveBeenCalled();
+ expect(mockPublishPublicStatusConfigSnapshot).not.toHaveBeenCalled();
+ expect(mockPublishCurrentPublicStatusConfigPointers).not.toHaveBeenCalled();
+ });
+
+ it("reuses the current config version when replacing a stale title", async () => {
+ mockReadCurrentPublicStatusConfigSnapshot.mockResolvedValue({
+ configVersion: "cfg-current",
+ siteTitle: "Claude Code Hub",
+ });
+ const mod = await import("@/lib/public-status/config-publisher");
+
+ const written = await mod.reconcilePublicStatusSiteTitleProjection();
+
+ expect(written).toBe(true);
+ expect(mockPublishPublicStatusConfigSnapshot).toHaveBeenCalledWith(
+ expect.objectContaining({
+ reason: "startup-site-title-reconciliation",
+ snapshot: expect.objectContaining({ configVersion: "cfg-current", siteTitle: "CC Hub" }),
+ })
+ );
+ expect(mockPublishCurrentPublicStatusConfigPointers).toHaveBeenCalledWith(
+ expect.objectContaining({ configVersion: "cfg-current" })
+ );
+ });
+
+ it("republishes a snapshot missing siteTitle while reusing its configVersion", async () => {
+ mockReadCurrentPublicStatusConfigSnapshot.mockResolvedValue({
+ configVersion: "cfg-legacy",
+ });
+ const mod = await import("@/lib/public-status/config-publisher");
+
+ const written = await mod.reconcilePublicStatusSiteTitleProjection();
+
+ expect(written).toBe(true);
+ expect(mockPublishPublicStatusConfigSnapshot).toHaveBeenCalledWith(
+ expect.objectContaining({
+ reason: "startup-site-title-reconciliation",
+ snapshot: expect.objectContaining({ configVersion: "cfg-legacy", siteTitle: "CC Hub" }),
+ })
+ );
+ expect(mockPublishCurrentPublicStatusConfigPointers).toHaveBeenCalledWith(
+ expect.objectContaining({ configVersion: "cfg-legacy" })
+ );
+ });
+
+ it("reports when a missing Redis projection cannot be written", async () => {
+ mockPublishInternalPublicStatusConfigSnapshot.mockResolvedValue({
+ configVersion: "cfg-test",
+ key: "internal",
+ written: false,
+ });
+ const mod = await import("@/lib/public-status/config-publisher");
+
+ const written = await mod.reconcilePublicStatusSiteTitleProjection();
+
+ expect(written).toBe(false);
+ expect(mockPublishCurrentPublicStatusConfigPointers).not.toHaveBeenCalled();
+ });
+
it("uses shared model-prefix matching for vendor icons without changing request type badges", async () => {
mockFindAllProviderGroups.mockResolvedValue([
{
diff --git a/tests/unit/public-status/config-snapshot.test.ts b/tests/unit/public-status/config-snapshot.test.ts
index 2cbf2ab9a..488613646 100644
--- a/tests/unit/public-status/config-snapshot.test.ts
+++ b/tests/unit/public-status/config-snapshot.test.ts
@@ -104,7 +104,7 @@ describe("public-status config snapshot", () => {
const snapshot = mod.buildPublicStatusConfigSnapshot({
configVersion: "cfg-2",
- siteTitle: "Claude Code Hub Status",
+ siteTitle: "CC Hub Status",
siteDescription: "Request-derived public status",
defaultIntervalMinutes: 5,
defaultRangeHours: 24,
@@ -130,7 +130,7 @@ describe("public-status config snapshot", () => {
expect(snapshot).toMatchObject({
configVersion: "cfg-2",
- siteTitle: "Claude Code Hub Status",
+ siteTitle: "CC Hub Status",
siteDescription: "Request-derived public status",
groups: [
{
@@ -165,14 +165,14 @@ describe("public-status config snapshot", () => {
.mockResolvedValueOnce(
JSON.stringify({
configVersion: "cfg-2",
- siteTitle: "Claude Code Hub Status",
+ siteTitle: "CC Hub Status",
siteDescription: "Request-derived public status",
})
),
};
await expect(mod.readPublicStatusSiteMetadata({ redis })).resolves.toEqual({
- siteTitle: "Claude Code Hub Status",
+ siteTitle: "CC Hub Status",
siteDescription: "Request-derived public status",
});
});
diff --git a/tests/unit/public-status/layout-metadata.test.ts b/tests/unit/public-status/layout-metadata.test.ts
index 04dbd0e26..8e887ed86 100644
--- a/tests/unit/public-status/layout-metadata.test.ts
+++ b/tests/unit/public-status/layout-metadata.test.ts
@@ -34,7 +34,7 @@ describe("public-status layout metadata", () => {
it("reads site metadata from the public site meta loader for public status requests", async () => {
mockLoadPublicSiteMeta.mockResolvedValue({
available: true,
- siteTitle: "Claude Code Hub Status",
+ siteTitle: "CC Hub Status",
siteDescription: "Projection-only public status",
timeZone: "UTC",
source: "projection",
@@ -45,7 +45,7 @@ describe("public-status layout metadata", () => {
);
await expect(mod.resolveSiteMetadataSource()).resolves.toEqual({
- siteTitle: "Claude Code Hub Status",
+ siteTitle: "CC Hub Status",
siteDescription: "Projection-only public status",
});
@@ -73,7 +73,7 @@ describe("public-status layout metadata", () => {
it("reads timezone from the public site meta loader for public status requests", async () => {
mockLoadPublicSiteMeta.mockResolvedValue({
available: true,
- siteTitle: "Claude Code Hub Status",
+ siteTitle: "CC Hub Status",
siteDescription: "Projection-only public status",
timeZone: "Asia/Shanghai",
source: "projection",
diff --git a/tests/unit/public-status/public-api-loader.test.ts b/tests/unit/public-status/public-api-loader.test.ts
index 020466f80..305a4d005 100644
--- a/tests/unit/public-status/public-api-loader.test.ts
+++ b/tests/unit/public-status/public-api-loader.test.ts
@@ -43,8 +43,8 @@ describe("public status public API loader", () => {
include: ["meta", "defaults", "groups", "timeline"],
},
meta: {
- siteTitle: "Claude Code Hub",
- siteDescription: "Claude Code Hub public status",
+ siteTitle: "CC Hub",
+ siteDescription: "CC Hub public status",
timeZone: "UTC",
},
groups: [
@@ -71,7 +71,7 @@ describe("public status public API loader", () => {
expect(request.url).toBe("http://localhost/api/public-status?groupSlug=anthropic");
expect(result.status).toBe("ready");
- expect(result.siteTitle).toBe("Claude Code Hub");
+ expect(result.siteTitle).toBe("CC Hub");
expect(result.timeZone).toBe("UTC");
expect(result.initialPayload.groups).toHaveLength(1);
});
@@ -143,8 +143,8 @@ describe("public status public API loader", () => {
new Response(
JSON.stringify({
available: true,
- siteTitle: "Claude Code Hub",
- siteDescription: "Claude Code Hub public status",
+ siteTitle: "CC Hub",
+ siteDescription: "CC Hub public status",
timeZone: "UTC",
source: "projection",
}),
@@ -161,8 +161,8 @@ describe("public status public API loader", () => {
await expect(loadPublicSiteMeta()).resolves.toEqual({
available: true,
- siteTitle: "Claude Code Hub",
- siteDescription: "Claude Code Hub public status",
+ siteTitle: "CC Hub",
+ siteDescription: "CC Hub public status",
timeZone: "UTC",
source: "projection",
});
diff --git a/tests/unit/public-status/rebuild-worker.test.ts b/tests/unit/public-status/rebuild-worker.test.ts
index c9d3343b7..05c6f4bfc 100644
--- a/tests/unit/public-status/rebuild-worker.test.ts
+++ b/tests/unit/public-status/rebuild-worker.test.ts
@@ -404,7 +404,7 @@ describe("public-status rebuild worker", () => {
mockReadCurrentInternalPublicStatusConfigSnapshot.mockResolvedValue({
configVersion: "cfg-1",
generatedAt: "2026-04-21T10:00:00.000Z",
- siteTitle: "Claude Code Hub Status",
+ siteTitle: "CC Hub Status",
siteDescription: "Request-derived public status",
defaultIntervalMinutes: 5,
defaultRangeHours: 24,
@@ -493,7 +493,7 @@ describe("public-status rebuild worker", () => {
mockReadCurrentInternalPublicStatusConfigSnapshot.mockResolvedValue({
configVersion: "cfg-1",
generatedAt: "2026-04-21T10:00:00.000Z",
- siteTitle: "Claude Code Hub Status",
+ siteTitle: "CC Hub Status",
siteDescription: "Request-derived public status",
defaultIntervalMinutes: 5,
defaultRangeHours: 24,
@@ -552,7 +552,7 @@ describe("public-status rebuild worker", () => {
.mockResolvedValueOnce({
configVersion: "cfg-1",
generatedAt: "2026-04-21T10:00:00.000Z",
- siteTitle: "Claude Code Hub Status",
+ siteTitle: "CC Hub Status",
siteDescription: "Request-derived public status",
defaultIntervalMinutes: 5,
defaultRangeHours: 24,
diff --git a/tests/unit/public-status/startup-reconciliation.test.ts b/tests/unit/public-status/startup-reconciliation.test.ts
new file mode 100644
index 000000000..cc0196a4b
--- /dev/null
+++ b/tests/unit/public-status/startup-reconciliation.test.ts
@@ -0,0 +1,57 @@
+import { beforeEach, describe, expect, it, vi } from "vitest";
+
+const mockReconcilePublicStatusSiteTitleProjection = vi.hoisted(() => vi.fn());
+const mockWarn = vi.hoisted(() => vi.fn());
+
+vi.mock("@/lib/public-status/config-publisher", () => ({
+ reconcilePublicStatusSiteTitleProjection: mockReconcilePublicStatusSiteTitleProjection,
+}));
+
+vi.mock("@/lib/logger", () => ({
+ logger: { warn: mockWarn },
+}));
+
+describe("public-status startup reconciliation", () => {
+ beforeEach(() => {
+ vi.clearAllMocks();
+ });
+
+ it("stays silent when the site-title projection is current", async () => {
+ mockReconcilePublicStatusSiteTitleProjection.mockResolvedValue(true);
+ const { reconcilePublicStatusSiteTitleAtStartup } = await import(
+ "@/lib/public-status/startup-reconciliation"
+ );
+
+ await reconcilePublicStatusSiteTitleAtStartup();
+
+ expect(mockWarn).not.toHaveBeenCalled();
+ });
+
+ it("warns without blocking startup when Redis cannot store the projection", async () => {
+ mockReconcilePublicStatusSiteTitleProjection.mockResolvedValue(false);
+ const { reconcilePublicStatusSiteTitleAtStartup } = await import(
+ "@/lib/public-status/startup-reconciliation"
+ );
+
+ await expect(reconcilePublicStatusSiteTitleAtStartup()).resolves.toBeUndefined();
+
+ expect(mockWarn).toHaveBeenCalledWith(
+ "[Instrumentation] Public status site title reconciliation deferred",
+ { reason: "redis-projection-unavailable" }
+ );
+ });
+
+ it("warns without blocking startup when reconciliation throws", async () => {
+ mockReconcilePublicStatusSiteTitleProjection.mockRejectedValue(new Error("redis unavailable"));
+ const { reconcilePublicStatusSiteTitleAtStartup } = await import(
+ "@/lib/public-status/startup-reconciliation"
+ );
+
+ await expect(reconcilePublicStatusSiteTitleAtStartup()).resolves.toBeUndefined();
+
+ expect(mockWarn).toHaveBeenCalledWith(
+ "[Instrumentation] Public status site title reconciliation failed",
+ { error: "redis unavailable" }
+ );
+ });
+});
diff --git a/tests/unit/public-status/status-page-locale.test.ts b/tests/unit/public-status/status-page-locale.test.ts
index 61f03ac87..fb0f0fa4a 100644
--- a/tests/unit/public-status/status-page-locale.test.ts
+++ b/tests/unit/public-status/status-page-locale.test.ts
@@ -90,11 +90,11 @@ describe("PublicStatusPage locale handling", () => {
intervalMinutes: 5,
rangeHours: 24,
followServerDefaults: true,
- siteTitle: "Claude Code Hub",
+ siteTitle: "CC Hub",
timeZone: "UTC",
meta: {
- siteTitle: "Claude Code Hub",
- siteDescription: "Claude Code Hub public status",
+ siteTitle: "CC Hub",
+ siteDescription: "CC Hub public status",
timeZone: "UTC",
},
response: {} as never,
@@ -151,11 +151,11 @@ describe("PublicStatusPage locale handling", () => {
intervalMinutes: 5,
rangeHours: 24,
followServerDefaults: true,
- siteTitle: "Claude Code Hub",
+ siteTitle: "CC Hub",
timeZone: "UTC",
meta: {
- siteTitle: "Claude Code Hub",
- siteDescription: "Claude Code Hub public status",
+ siteTitle: "CC Hub",
+ siteDescription: "CC Hub public status",
timeZone: "UTC",
},
response: {} as never,
diff --git a/tests/unit/public-status/status-page-title.test.tsx b/tests/unit/public-status/status-page-title.test.tsx
index 8151ad012..e7ac9ea3d 100644
--- a/tests/unit/public-status/status-page-title.test.tsx
+++ b/tests/unit/public-status/status-page-title.test.tsx
@@ -30,11 +30,11 @@ describe("public status page title", () => {
intervalMinutes: 5,
rangeHours: 24,
followServerDefaults: true,
- siteTitle: "Claude Code Hub",
+ siteTitle: "CC Hub",
timeZone: "UTC",
meta: {
- siteTitle: "Claude Code Hub",
- siteDescription: "Claude Code Hub public status",
+ siteTitle: "CC Hub",
+ siteDescription: "CC Hub public status",
timeZone: "UTC",
},
});
@@ -47,7 +47,7 @@ describe("public status page title", () => {
expect(mockPublicStatusView).toHaveBeenCalledWith(
expect.objectContaining({
- siteTitle: "Claude Code Hub",
+ siteTitle: "CC Hub",
}),
undefined
);
@@ -110,11 +110,11 @@ describe("public status page title", () => {
intervalMinutes: 5,
rangeHours: 24,
followServerDefaults: true,
- siteTitle: "Claude Code Hub",
+ siteTitle: "CC Hub",
timeZone: "UTC",
meta: {
- siteTitle: "Claude Code Hub",
- siteDescription: "Claude Code Hub public status",
+ siteTitle: "CC Hub",
+ siteDescription: "CC Hub public status",
timeZone: "UTC",
},
});
diff --git a/tests/unit/public-status/status-slug-page.test.tsx b/tests/unit/public-status/status-slug-page.test.tsx
index ec4ba15dd..48e3232d8 100644
--- a/tests/unit/public-status/status-slug-page.test.tsx
+++ b/tests/unit/public-status/status-slug-page.test.tsx
@@ -45,11 +45,11 @@ describe("public status slug page", () => {
intervalMinutes: 5,
rangeHours: 24,
followServerDefaults: true,
- siteTitle: "Claude Code Hub",
+ siteTitle: "CC Hub",
timeZone: "UTC",
meta: {
- siteTitle: "Claude Code Hub",
- siteDescription: "Claude Code Hub public status",
+ siteTitle: "CC Hub",
+ siteDescription: "CC Hub public status",
timeZone: "UTC",
},
response: {} as never,
@@ -62,7 +62,7 @@ describe("public status slug page", () => {
expect(mockLoadPublicStatusPageData).toHaveBeenCalledWith({ groupSlug: "anthropic" });
expect(metadata).toMatchObject({
- title: "Anthropic · Claude Code Hub",
+ title: "Anthropic · CC Hub",
description: "Anthropic public models",
});
});
@@ -80,11 +80,11 @@ describe("public status slug page", () => {
intervalMinutes: 5,
rangeHours: 24,
followServerDefaults: true,
- siteTitle: "Claude Code Hub",
+ siteTitle: "CC Hub",
timeZone: "UTC",
meta: {
- siteTitle: "Claude Code Hub",
- siteDescription: "Claude Code Hub public status",
+ siteTitle: "CC Hub",
+ siteDescription: "CC Hub public status",
timeZone: "UTC",
},
response: {} as never,
@@ -113,11 +113,11 @@ describe("public status slug page", () => {
intervalMinutes: 5,
rangeHours: 24,
followServerDefaults: true,
- siteTitle: "Claude Code Hub",
+ siteTitle: "CC Hub",
timeZone: "UTC",
meta: {
- siteTitle: "Claude Code Hub",
- siteDescription: "Claude Code Hub public status",
+ siteTitle: "CC Hub",
+ siteDescription: "CC Hub public status",
timeZone: "UTC",
},
response: {} as never,
@@ -129,7 +129,7 @@ describe("public status slug page", () => {
})) as Metadata;
expect(metadata).toEqual({
- title: "Claude Code Hub",
+ title: "CC Hub",
});
expect(mockNotFound).not.toHaveBeenCalled();
});
@@ -154,11 +154,11 @@ describe("public status slug page", () => {
intervalMinutes: 5,
rangeHours: 24,
followServerDefaults: true,
- siteTitle: "Claude Code Hub",
+ siteTitle: "CC Hub",
timeZone: "UTC",
meta: {
- siteTitle: "Claude Code Hub",
- siteDescription: "Claude Code Hub public status",
+ siteTitle: "CC Hub",
+ siteDescription: "CC Hub public status",
timeZone: "UTC",
},
response: {} as never,
@@ -170,7 +170,7 @@ describe("public status slug page", () => {
})) as Metadata;
expect(metadata).toMatchObject({
- title: "Platform · Claude Code Hub",
+ title: "Platform · CC Hub",
description: "Default group status",
});
diff --git a/tests/unit/public-status/system-config-publish.test.ts b/tests/unit/public-status/system-config-publish.test.ts
index caeb5b998..d0448275e 100644
--- a/tests/unit/public-status/system-config-publish.test.ts
+++ b/tests/unit/public-status/system-config-publish.test.ts
@@ -51,11 +51,11 @@ describe("system settings public-status republish", () => {
});
mockGetSystemSettings.mockResolvedValue({
id: 1,
- siteTitle: "Claude Code Hub",
+ siteTitle: "CC Hub",
});
mockUpdateSystemSettings.mockResolvedValue({
id: 1,
- siteTitle: "Claude Code Hub",
+ siteTitle: "CC Hub",
publicStatusWindowHours: 24,
publicStatusAggregationIntervalMinutes: 5,
});
diff --git a/tests/unit/repository/system-config-degradation-ladder.test.ts b/tests/unit/repository/system-config-degradation-ladder.test.ts
index 9afac3765..0996e8b72 100644
--- a/tests/unit/repository/system-config-degradation-ladder.test.ts
+++ b/tests/unit/repository/system-config-degradation-ladder.test.ts
@@ -248,7 +248,7 @@ describe("SystemSettings:列降级阶梯的尝试序列锁定", () => {
createResolvingSelectQuery([
{
id: 1,
- siteTitle: "Claude Code Hub",
+ siteTitle: "CC Hub",
allowGlobalUsageView: false,
currencyDisplay: "USD",
billingModelSource: "original",
@@ -367,7 +367,7 @@ describe("SystemSettings:列降级阶梯的尝试序列锁定", () => {
createResolvingSelectQuery([
{
id: 1,
- siteTitle: "Claude Code Hub",
+ siteTitle: "CC Hub",
allowGlobalUsageView: false,
currencyDisplay: "USD",
billingModelSource: "original",
@@ -432,7 +432,7 @@ describe("SystemSettings:列降级阶梯的尝试序列锁定", () => {
createResolvingSelectQuery([
{
id: 1,
- siteTitle: "Claude Code Hub",
+ siteTitle: "CC Hub",
allowGlobalUsageView: false,
currencyDisplay: "USD",
billingModelSource: "original",
diff --git a/tests/unit/repository/system-config-update-missing-columns.test.ts b/tests/unit/repository/system-config-update-missing-columns.test.ts
index b03d055dc..9b26aed05 100644
--- a/tests/unit/repository/system-config-update-missing-columns.test.ts
+++ b/tests/unit/repository/system-config-update-missing-columns.test.ts
@@ -45,7 +45,7 @@ describe("SystemSettings:数据库缺列时的保存兜底", () => {
const selectQuery = createThenableQuery([
{
id: 1,
- siteTitle: "AutoBits Claude Code Hub",
+ siteTitle: "AutoBits CC Hub",
allowGlobalUsageView: false,
currencyDisplay: "USD",
billingModelSource: "original",
@@ -127,7 +127,7 @@ describe("SystemSettings:数据库缺列时的保存兜底", () => {
const selectQuery = createThenableQuery([
{
id: 1,
- siteTitle: "Claude Code Hub",
+ siteTitle: "CC Hub",
allowGlobalUsageView: false,
currencyDisplay: "USD",
billingModelSource: "original",
@@ -164,7 +164,7 @@ describe("SystemSettings:数据库缺列时的保存兜底", () => {
const { updateSystemSettings } = await import("@/repository/system-config");
- await expect(updateSystemSettings({ siteTitle: "AutoBits Claude Code Hub" })).rejects.toThrow(
+ await expect(updateSystemSettings({ siteTitle: "AutoBits CC Hub" })).rejects.toThrow(
"system_settings 表列缺失"
);
@@ -181,7 +181,7 @@ describe("SystemSettings:数据库缺列时的保存兜底", () => {
const selectQuery = createThenableQuery([
{
id: 1,
- siteTitle: "Claude Code Hub",
+ siteTitle: "CC Hub",
allowGlobalUsageView: false,
currencyDisplay: "USD",
billingModelSource: "original",
@@ -207,7 +207,7 @@ describe("SystemSettings:数据库缺列时的保存兜底", () => {
const { updateSystemSettings } = await import("@/repository/system-config");
- await expect(updateSystemSettings({ siteTitle: "AutoBits Claude Code Hub" })).rejects.toThrow(
+ await expect(updateSystemSettings({ siteTitle: "AutoBits CC Hub" })).rejects.toThrow(
"系统设置数据表不存在"
);
@@ -228,7 +228,7 @@ describe("SystemSettings:数据库缺列时的保存兜底", () => {
createThenableQuery([
{
id: 1,
- siteTitle: "Claude Code Hub",
+ siteTitle: "CC Hub",
allowGlobalUsageView: false,
currencyDisplay: "USD",
billingModelSource: "original",
@@ -307,7 +307,7 @@ describe("SystemSettings:数据库缺列时的保存兜底", () => {
createThenableQuery([
{
id: 1,
- siteTitle: "Claude Code Hub",
+ siteTitle: "CC Hub",
allowGlobalUsageView: false,
currencyDisplay: "USD",
billingModelSource: "original",
@@ -336,7 +336,7 @@ describe("SystemSettings:数据库缺列时的保存兜底", () => {
// 降级读取成功(未抛错),缺失列由 transformer 落默认值。
expect(selectMock).toHaveBeenCalledTimes(2);
- expect(result.siteTitle).toBe("Claude Code Hub");
+ expect(result.siteTitle).toBe("CC Hub");
expect(result.enableHttp2).toBe(true);
expect(result.affinityIgnoreClientSessionId).toBe(true);
expect(result.streamGateMode).toBe("enforce");
@@ -372,7 +372,7 @@ describe("SystemSettings:数据库缺列时的保存兜底", () => {
createThenableQuery([
{
id: 1,
- siteTitle: "Claude Code Hub",
+ siteTitle: "CC Hub",
allowGlobalUsageView: false,
currencyDisplay: "USD",
billingModelSource: "original",
@@ -404,12 +404,12 @@ describe("SystemSettings:数据库缺列时的保存兜底", () => {
const result = await getSystemSettings();
- expect(result.siteTitle).toBe("Claude Code Hub");
+ expect(result.siteTitle).toBe("CC Hub");
expect(result.codexPriorityBillingSource).toBe("requested");
expect(insertMock).toHaveBeenCalledTimes(2);
expect(legacyInsertQuery.values).toHaveBeenCalledWith(
expect.objectContaining({
- siteTitle: "Claude Code Hub",
+ siteTitle: "CC Hub",
allowGlobalUsageView: false,
currencyDisplay: "USD",
billingModelSource: "original",
@@ -443,7 +443,7 @@ describe("SystemSettings:数据库缺列时的保存兜底", () => {
createThenableQuery([
{
id: 1,
- siteTitle: "Claude Code Hub",
+ siteTitle: "CC Hub",
allowGlobalUsageView: false,
currencyDisplay: "USD",
billingModelSource: "original",
@@ -526,7 +526,7 @@ describe("SystemSettings:数据库缺列时的保存兜底", () => {
createThenableQuery([
{
id: 1,
- siteTitle: "Claude Code Hub",
+ siteTitle: "CC Hub",
allowGlobalUsageView: false,
currencyDisplay: "USD",
billingModelSource: "original",
@@ -584,7 +584,7 @@ describe("SystemSettings:数据库缺列时的保存兜底", () => {
createThenableQuery([
{
id: 1,
- siteTitle: "Claude Code Hub",
+ siteTitle: "CC Hub",
allowGlobalUsageView: false,
currencyDisplay: "USD",
billingModelSource: "original",
diff --git a/tests/unit/settings/system-settings-form-fake-streaming.test.tsx b/tests/unit/settings/system-settings-form-fake-streaming.test.tsx
index f49341474..f142e8581 100644
--- a/tests/unit/settings/system-settings-form-fake-streaming.test.tsx
+++ b/tests/unit/settings/system-settings-form-fake-streaming.test.tsx
@@ -32,7 +32,7 @@ const sonnerMocks = vi.hoisted(() => ({
vi.mock("sonner", () => sonnerMocks);
const baseSettings = {
- siteTitle: "Claude Code Hub",
+ siteTitle: "CC Hub",
allowGlobalUsageView: true,
currencyDisplay: "USD",
billingModelSource: "original",
diff --git a/tests/unit/settings/system-settings-form-ip-extraction.test.tsx b/tests/unit/settings/system-settings-form-ip-extraction.test.tsx
index b11abfe0c..b1c01b355 100644
--- a/tests/unit/settings/system-settings-form-ip-extraction.test.tsx
+++ b/tests/unit/settings/system-settings-form-ip-extraction.test.tsx
@@ -39,7 +39,7 @@ function loadMessages() {
}
const baseSettings = {
- siteTitle: "Claude Code Hub",
+ siteTitle: "CC Hub",
allowGlobalUsageView: true,
currencyDisplay: "USD",
billingModelSource: "redirected",
diff --git a/tests/unit/settings/system-settings-form-non-chat-fallback.test.tsx b/tests/unit/settings/system-settings-form-non-chat-fallback.test.tsx
index fd0d92a0c..2cb675678 100644
--- a/tests/unit/settings/system-settings-form-non-chat-fallback.test.tsx
+++ b/tests/unit/settings/system-settings-form-non-chat-fallback.test.tsx
@@ -27,7 +27,7 @@ const sonnerMocks = vi.hoisted(() => ({
vi.mock("sonner", () => sonnerMocks);
const baseSettings = {
- siteTitle: "Claude Code Hub",
+ siteTitle: "CC Hub",
allowGlobalUsageView: true,
currencyDisplay: "USD",
billingModelSource: "original",
diff --git a/tests/unit/settings/system-settings-form-replay-cache-toggles.test.tsx b/tests/unit/settings/system-settings-form-replay-cache-toggles.test.tsx
index e38519796..712aad6de 100644
--- a/tests/unit/settings/system-settings-form-replay-cache-toggles.test.tsx
+++ b/tests/unit/settings/system-settings-form-replay-cache-toggles.test.tsx
@@ -32,7 +32,7 @@ const sonnerMocks = vi.hoisted(() => ({
vi.mock("sonner", () => sonnerMocks);
const baseSettings = {
- siteTitle: "Claude Code Hub",
+ siteTitle: "CC Hub",
allowGlobalUsageView: true,
currencyDisplay: "USD",
billingModelSource: "original",
diff --git a/tests/unit/settings/system-settings-form-upstream-error-message.test.tsx b/tests/unit/settings/system-settings-form-upstream-error-message.test.tsx
index 1cb15641c..465e00561 100644
--- a/tests/unit/settings/system-settings-form-upstream-error-message.test.tsx
+++ b/tests/unit/settings/system-settings-form-upstream-error-message.test.tsx
@@ -72,7 +72,7 @@ function loadMessages() {
}
const baseSettings: FormSettings = {
- siteTitle: "Claude Code Hub",
+ siteTitle: "CC Hub",
allowGlobalUsageView: true,
currencyDisplay: "USD",
billingModelSource: "redirected",