Skip to content

feat(users): increase provider group length to 200#591

Merged
ding113 merged 2 commits intoding113:devfrom
Hwwwww-dev:group-length
Jan 12, 2026
Merged

feat(users): increase provider group length to 200#591
ding113 merged 2 commits intoding113:devfrom
Hwwwww-dev:group-length

Conversation

@Hwwwww-dev
Copy link
Contributor

@Hwwwww-dev Hwwwww-dev commented Jan 11, 2026

Summary

This PR increases the maximum length of the provider_group field from 50 to 200 characters for both users and keys, enabling support for longer provider group names.

Related Issues:

Greptile Overview

Greptile Summary

This PR increases the maximum length of the provider_group field from 50 to 200 characters for both users and keys tables. The change is comprehensive and touches all necessary layers of the application stack.

Changes Overview

Database Layer (3 files):

  • Migration script alters provider_group column type from varchar(50) to varchar(200) for both tables
  • Schema definition updated to match the new column length
  • Drizzle metadata files regenerated

Validation Layer (1 file):

  • Zod validation schemas updated to enforce max length of 200 characters for providerGroup fields
  • Applied consistently across CreateUserSchema, UpdateUserSchema, and KeyFormSchema

UI Layer (8 files):

  • All form components updated with maxTagLength={200} for provider group input fields
  • Error messages updated to reflect the new 200-character limit
  • Changes applied to: user creation/editing forms, key creation/editing forms, and the reusable ProviderGroupSelect component

Consistency Analysis

The changes demonstrate excellent consistency across the entire stack:

  1. Database → Schema → Validation → UI: All layers enforce the same 200-character constraint
  2. User forms and Key forms: Both entity types updated identically
  3. Create and Edit dialogs: Both operations validated consistently
  4. Error messages: UI feedback matches validation rules

Note on provider-form.tsx

The file src/app/[locale]/settings/providers/_components/forms/provider-form.tsx maintains GROUP_TAG_MAX_TOTAL_LENGTH = 50. This is correct—it manages provider groupTag (a different field used for categorizing providers), not user/key providerGroup fields.

Confidence Score: 5/5

  • This PR is safe to merge with minimal risk
  • The changes are straightforward, well-coordinated across all application layers, and maintain perfect consistency. The migration safely increases column width without data loss risk. All validation rules, UI constraints, and database schema are properly synchronized. Only one minor style issue found (missing newline at EOF in migration file).
  • No files require special attention

Important Files Changed

File Analysis

Filename Score Overview
drizzle/0053_watery_madame_hydra.sql 4/5 Database migration increases provider_group column from varchar(50) to varchar(200) for both keys and users tables. Missing newline at end of file (minor style issue).
src/drizzle/schema.ts 5/5 Schema definition correctly updated to reflect varchar(200) length for providerGroup field on both users and keys tables. Changes are consistent with migration.
src/lib/validation/schemas.ts 5/5 Validation schemas updated correctly to enforce max length of 200 characters for providerGroup in CreateUserSchema, UpdateUserSchema, and KeyFormSchema. All changes are consistent.
src/app/[locale]/dashboard/_components/user/forms/user-form.tsx 5/5 UI component updated with maxTagLength={200} for provider group input field (line 211) and error message updated to reflect 200 character limit (line 219). Consistent with schema changes.
src/app/[locale]/dashboard/_components/user/forms/provider-group-select.tsx 5/5 Reusable ProviderGroupSelect component updated with maxTagLength={200} (line 130). This component is used across multiple forms.
src/app/[locale]/dashboard/_components/user/forms/add-key-form.tsx 5/5 Add key form updated with maxTagLength={200} (line 192) and error message to reflect 200 character limit (line 206). Consistent with validation schema.
src/app/[locale]/dashboard/_components/user/forms/edit-key-form.tsx 5/5 Edit key form updated with maxTagLength={200} (line 215) and error message to reflect 200 character limit (line 229). Consistent with validation schema.

Sequence Diagram

sequenceDiagram
    participant User as User (Frontend)
    participant Form as User/Key Form Components
    participant Schema as Zod Validation Schema
    participant Action as Server Actions
    participant DB as PostgreSQL Database

    Note over User,DB: Provider Group Length Increase: 50 → 200 characters

    User->>Form: Edit provider_group field
    Form->>Form: maxTagLength={200}
    
    User->>Form: Submit form
    Form->>Schema: Validate input
    Schema->>Schema: Check max(200) constraint
    
    alt Validation passes
        Schema->>Action: Send validated data
        Action->>DB: UPDATE users/keys SET provider_group
        DB->>DB: Check varchar(200) constraint
        DB->>Action: Success
        Action->>Form: Return success
        Form->>User: Display success message
    else Validation fails (>200 chars)
        Schema->>Form: Return validation error
        Form->>User: Display error: "供应商分组不能超过200个字符"
    end

    Note over DB: Migration 0053 changes:<br/>ALTER COLUMN provider_group<br/>SET DATA TYPE varchar(200)
Loading

Migration

The database migration will run automatically when AUTO_MIGRATE=true (default behavior). This is a non-breaking change that expands the field length - existing data with provider groups ≤50 characters will be unaffected.

For manual migration:

bun run db:migrate

Testing

  • Existing provider groups (≤50 chars) continue to work
  • New provider groups up to 200 characters can be created
  • Validation errors display correctly for groups >200 characters
  • UI forms accept and display longer provider group names

Hwwwww-dev and others added 2 commits January 11, 2026 23:08
Extend users.provider_group from varchar(50) to varchar(200)

Extend keys.provider_group from varchar(50) to varchar(200)

Update frontend validation: maxTagLength 50 → 200

Update backend Zod schemas: max(50) → max(200)

Keep providers.group_tag at varchar(50) unchanged

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@coderabbitai
Copy link

coderabbitai bot commented Jan 11, 2026

📝 Walkthrough

概述

本次变更扩展了提供商分组(providerGroup)字段的最大长度限制,从 50 个字符增至 200 个字符。包括数据库迁移文件、Drizzle ORM 模式定义、前端验证 Schema 以及多个用户界面表单组件的一致更新。

变更详情

内聚性 / 文件 变更摘要
数据库迁移和元数据
drizzle/0053_watery_madame_hydra.sql, drizzle/meta/0053_snapshot.json, drizzle/meta/_journal.json
添加新的 SQL 迁移文件,修改 keys 和 users 表中的 provider_group 列类型为 varchar(200),并设置默认值为 'default';更新元数据快照记录完整数据库模式状态;在日志中记录新的迁移入口。
ORM 模式定义
src/drizzle/schema.ts
同步更新 Users 和 Keys 表中 providerGroup 字段的长度约束,从 50 字符扩展至 200 字符。
验证 Schema
src/lib/validation/schemas.ts
更新 CreateUserSchema、UpdateUserSchema 和 KeyFormSchema 中 providerGroup 字段的最大长度验证规则从 50 增加至 200,同步更新中文错误提示信息。
用户管理表单组件
src/app/[locale]/dashboard/_components/user/create-user-dialog.tsx, src/app/[locale]/dashboard/_components/user/edit-user-dialog.tsx, src/app/[locale]/dashboard/_components/user/forms/user-form.tsx
调整 providerGroup 字段的最大长度验证和错误提示,从 50 更新至 200 字符。
密钥管理表单组件
src/app/[locale]/dashboard/_components/user/forms/add-key-form.tsx, src/app/[locale]/dashboard/_components/user/forms/edit-key-form.tsx, src/app/[locale]/dashboard/_components/user/forms/provider-group-select.tsx
增加 maxTagLength 从 50 至 200,更新对应的验证错误消息以反映新的长度限制。
提供商设置表单
src/app/[locale]/settings/providers/_components/forms/provider-form.tsx
修正注释中的引号格式,从中文风格双引号改为标准引号。

代码审查工作量评估

🎯 2 (Simple) | ⏱️ ~12 分钟

可能相关的 PR

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive PR描述为空,但这是一个非常宽松的检查,只要描述与变更集相关即可通过。 建议添加PR描述说明此次增加提供商分组长度限制的原因和影响。
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed PR标题清晰准确地概括了主要更改:将提供商分组的长度限制从50增加到200。

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @Hwwwww-dev, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request implements an enhancement to allow for longer provider group names within the application. It involves a comprehensive update that extends the character limit for the provider_group field across the database schema, ORM configuration, and all user-facing input and validation logic. This ensures that users can assign more descriptive and flexible names to their provider groups without encountering truncation or validation errors.

Highlights

  • Database Schema Update: The provider_group column in both the keys and users tables has been updated to support a maximum length of 200 characters (from the previous 50 characters). This change is reflected in a new Drizzle migration script and the updated schema snapshot.
  • Frontend Validation and UI Adjustments: All relevant frontend components and validation schemas (e.g., CreateUserSchema, UpdateUserSchema, KeyFormSchema) have been updated to align with the new provider_group length of 200 characters. This includes input field maxTagLength properties and corresponding error messages.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@github-actions github-actions bot added enhancement New feature or request area:UI area:provider size/L Large PR (< 1000 lines) labels Jan 11, 2026
Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 file reviewed, no comments

Edit Code Review Agent Settings | Greptile

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request increases the provider_group column length in the users and keys tables from 50 to 200 characters. The changes are consistently applied across the database migration, Drizzle schema, and both frontend and backend validation schemas.

While the changes are mostly correct, I've identified a couple of areas for improvement:

  1. The UI validation for the provider group length is misleading. The maxTagLength property on TagInputField components was updated to 200, which likely validates a single tag's length, not the total length of all tags. This can lead to validation failures on submission. I've suggested a more conservative value and a better validation approach.
  2. In create-user-dialog.tsx and edit-user-dialog.tsx, the Zod schema for providerGroup is unnecessarily overridden, which removes the custom error message defined in the base schema. These overrides can be safely removed.

Overall, a good and thorough update. Addressing these points will improve UI/backend validation consistency and code maintainability.

const CreateUserSchema = UpdateUserSchema.extend({
name: z.string().min(1).max(64),
providerGroup: z.string().max(50).nullable().optional(),
providerGroup: z.string().max(200).nullable().optional(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This override for providerGroup is redundant. The base UpdateUserSchema already includes this field with the correct max(200) validation and a custom error message. By overriding it here without a message, you are losing the custom error message. This line can be safely removed.

const EditUserSchema = UpdateUserSchema.extend({
name: z.string().min(1).max(64),
providerGroup: z.string().max(50).nullable().optional(),
providerGroup: z.string().max(200).nullable().optional(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This override for providerGroup is redundant. The base UpdateUserSchema already includes this field with the correct max(200) validation and a custom error message. By overriding it here without a message, you are losing the custom error message. This line can be safely removed.

<TagInputField
label={t("providerGroup.label")}
maxTagLength={50}
maxTagLength={200}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Setting maxTagLength to 200 is misleading. This prop likely validates the length of a single tag, while the database schema limits the total length of the comma-separated string of all tags to 200 characters. This can lead to a poor user experience where the form submission fails even though the UI did not show any error.

For example, a user could enter two tags of 150 characters each, which would pass the maxTagLength check, but the combined string would exceed the 200 character limit.

A more conservative value like 100 for maxTagLength would be safer. Ideally, the total length of the concatenated string should be validated on the client side as the user types.

Suggested change
maxTagLength={200}
maxTagLength={100}

empty: tUI("emptyTag"),
duplicate: tUI("duplicateTag"),
too_long: tUI("tooLong", { max: 50 }),
too_long: tUI("tooLong", { max: 200 }),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This error message for too_long is tied to maxTagLength. Since maxTagLength should not be 200 (as it applies to a single tag, not the total length), this message should be updated to reflect the new, more conservative limit for a single tag.

Suggested change
too_long: tUI("tooLong", { max: 200 }),
too_long: tUI("tooLong", { max: 100 }),

<TagInputField
label={t("providerGroup.label")}
maxTagLength={50}
maxTagLength={200}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Setting maxTagLength to 200 is misleading. This prop likely validates the length of a single tag, while the database schema limits the total length of the comma-separated string of all tags to 200 characters. This can lead to a poor user experience where the form submission fails even though the UI did not show any error.

For example, a user could enter two tags of 150 characters each, which would pass the maxTagLength check, but the combined string would exceed the 200 character limit.

A more conservative value like 100 for maxTagLength would be safer. Ideally, the total length of the concatenated string should be validated on the client side as the user types.

Suggested change
maxTagLength={200}
maxTagLength={100}

empty: tUI("emptyTag"),
duplicate: tUI("duplicateTag"),
too_long: tUI("tooLong", { max: 50 }),
too_long: tUI("tooLong", { max: 200 }),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This error message for too_long is tied to maxTagLength. Since maxTagLength should not be 200 (as it applies to a single tag, not the total length), this message should be updated to reflect the new, more conservative limit for a single tag.

Suggested change
too_long: tUI("tooLong", { max: 200 }),
too_long: tUI("tooLong", { max: 100 }),

placeholder={getTranslation(translations, "placeholder", "输入分组并回车")}
description={description}
maxTagLength={50}
maxTagLength={200}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Setting maxTagLength to 200 is misleading. This prop likely validates the length of a single tag, while the database schema limits the total length of the comma-separated string of all tags to 200 characters. This can lead to a poor user experience where the form submission fails even though the UI did not show any error.

For example, with maxTags={20}, a user could enter 2 tags of 101 characters, which would pass the maxTagLength check, but the combined string would exceed the 200 character limit.

A more conservative value like 100 for maxTagLength would be safer. Ideally, the total length of the concatenated string should be validated on the client side as the user types.

Suggested change
maxTagLength={200}
maxTagLength={100}

<TagInputField
label={tForm("providerGroup.label")}
maxTagLength={50}
maxTagLength={200}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Setting maxTagLength to 200 is misleading. This prop likely validates the length of a single tag, while the database schema limits the total length of the comma-separated string of all tags to 200 characters. This can lead to a poor user experience where the form submission fails even though the UI did not show any error.

For example, a user could enter two tags of 150 characters each, which would pass the maxTagLength check, but the combined string would exceed the 200 character limit.

A more conservative value like 100 for maxTagLength would be safer. Ideally, the total length of the concatenated string should be validated on the client side as the user types.

Suggested change
maxTagLength={200}
maxTagLength={100}

empty: tUI("emptyTag"),
duplicate: tUI("duplicateTag"),
too_long: tUI("tooLong", { max: 50 }),
too_long: tUI("tooLong", { max: 200 }),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This error message for too_long is tied to maxTagLength. Since maxTagLength should not be 200 (as it applies to a single tag, not the total length), this message should be updated to reflect the new, more conservative limit for a single tag.

Suggested change
too_long: tUI("tooLong", { max: 200 }),
too_long: tUI("tooLong", { max: 100 }),

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/app/[locale]/dashboard/_components/user/forms/add-key-form.tsx (1)

122-137: 总长度验证缺失:单个 tag 长度限制(200)与字段总长度(200)不一致,可导致提交失败

maxTagLength={200} 仅约束单个分组的长度,但 providerGroup 最终以逗号分隔的字符串形式存储于数据库 varchar(200) 字段。多个合法 tag 累加后(包括逗号分隔符)可能超过 200 字符上限,造成服务端校验失败而前端无提示,影响用户体验。

建议在 handleProviderGroupChange 中对最终拼接的字符串添加总长度校验,同时将 200 提取为常量避免魔法数字散落代码各处。

建议修改
 export function AddKeyForm({ userId, user, isAdmin = false, onSuccess }: AddKeyFormProps) {
+  const PROVIDER_GROUP_MAX_LEN = 200;
   const [isPending, startTransition] = useTransition();
   const [providerGroupSuggestions, setProviderGroupSuggestions] = useState<string[]>([]);
   const router = useRouter();
   const t = useTranslations("dashboard.addKeyForm");
   const tUI = useTranslations("ui.tagInput");
   const tCommon = useTranslations("common");
   const tErrors = useTranslations("errors");
@@
   const handleProviderGroupChange = useCallback(
     (newValue: string) => {
       const groups = newValue
         .split(",")
         .map((g) => g.trim())
         .filter(Boolean);
-      if (groups.length > 1 && groups.includes(PROVIDER_GROUP.DEFAULT)) {
-        const withoutDefault = groups.filter((g) => g !== PROVIDER_GROUP.DEFAULT);
-        form.setValue("providerGroup", withoutDefault.join(","));
-      } else {
-        form.setValue("providerGroup", newValue);
-      }
+      const nextValue =
+        groups.length > 1 && groups.includes(PROVIDER_GROUP.DEFAULT)
+          ? groups.filter((g) => g !== PROVIDER_GROUP.DEFAULT).join(",")
+          : newValue;
+
+      if (nextValue.length > PROVIDER_GROUP_MAX_LEN) {
+        toast.error(tUI("tooLong", { max: PROVIDER_GROUP_MAX_LEN }));
+        return;
+      }
+
+      form.setValue("providerGroup", nextValue);
     },
-    [form]
+    [form, tUI]
   );
@@
       <TagInputField
         label={t("providerGroup.label")}
-        maxTagLength={200}
+        maxTagLength={PROVIDER_GROUP_MAX_LEN}
         placeholder={t("providerGroup.placeholder")}
@@
         onInvalidTag={(_tag, reason) => {
           const messages: Record<string, string> = {
             empty: tUI("emptyTag"),
             duplicate: tUI("duplicateTag"),
-            too_long: tUI("tooLong", { max: 200 }),
+            too_long: tUI("tooLong", { max: PROVIDER_GROUP_MAX_LEN }),
             invalid_format: tUI("invalidFormat"),
             max_tags: tUI("maxTags"),
           };
           toast.error(messages[reason] || reason);
         }}
🤖 Fix all issues with AI agents
In @src/app/[locale]/settings/providers/_components/forms/provider-form.tsx:
- Line 366: The change only alters a comment's quote style in
src/app/[locale]/settings/providers/_components/forms/provider-form.tsx (near
the comment about limiting comma-joined total length) which is unrelated to the
PR goal of increasing provider group length to 200; revert that comment-only
edit (or remove it from this branch) so the PR only contains the functional
change to provider group length, and update the commit/patch to exclude any
non-functional formatting/comment-only modifications.
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to Reviews > Disable Cache setting

📥 Commits

Reviewing files that changed from the base of the PR and between 820b519 and e30e6b8.

📒 Files selected for processing (12)
  • drizzle/0053_watery_madame_hydra.sql
  • drizzle/meta/0053_snapshot.json
  • drizzle/meta/_journal.json
  • src/app/[locale]/dashboard/_components/user/create-user-dialog.tsx
  • src/app/[locale]/dashboard/_components/user/edit-user-dialog.tsx
  • src/app/[locale]/dashboard/_components/user/forms/add-key-form.tsx
  • src/app/[locale]/dashboard/_components/user/forms/edit-key-form.tsx
  • src/app/[locale]/dashboard/_components/user/forms/provider-group-select.tsx
  • src/app/[locale]/dashboard/_components/user/forms/user-form.tsx
  • src/app/[locale]/settings/providers/_components/forms/provider-form.tsx
  • src/drizzle/schema.ts
  • src/lib/validation/schemas.ts
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{js,ts,tsx,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Never use emoji characters in any code, comments, or string literals

Files:

  • src/app/[locale]/dashboard/_components/user/edit-user-dialog.tsx
  • src/app/[locale]/dashboard/_components/user/forms/user-form.tsx
  • src/app/[locale]/dashboard/_components/user/forms/edit-key-form.tsx
  • src/app/[locale]/dashboard/_components/user/forms/add-key-form.tsx
  • src/app/[locale]/settings/providers/_components/forms/provider-form.tsx
  • src/drizzle/schema.ts
  • src/app/[locale]/dashboard/_components/user/forms/provider-group-select.tsx
  • src/lib/validation/schemas.ts
  • src/app/[locale]/dashboard/_components/user/create-user-dialog.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx,js,jsx}: All user-facing strings must use i18n (5 languages supported: zh-CN, zh-TW, en, ja, ru). Never hardcode display text
Use path alias @/ to reference files in ./src/ directory
Format code with Biome using: double quotes, trailing commas, 2-space indent, 100 character line width

Files:

  • src/app/[locale]/dashboard/_components/user/edit-user-dialog.tsx
  • src/app/[locale]/dashboard/_components/user/forms/user-form.tsx
  • src/app/[locale]/dashboard/_components/user/forms/edit-key-form.tsx
  • src/app/[locale]/dashboard/_components/user/forms/add-key-form.tsx
  • src/app/[locale]/settings/providers/_components/forms/provider-form.tsx
  • src/drizzle/schema.ts
  • src/app/[locale]/dashboard/_components/user/forms/provider-group-select.tsx
  • src/lib/validation/schemas.ts
  • src/app/[locale]/dashboard/_components/user/create-user-dialog.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Prefer named exports over default exports

Files:

  • src/app/[locale]/dashboard/_components/user/edit-user-dialog.tsx
  • src/app/[locale]/dashboard/_components/user/forms/user-form.tsx
  • src/app/[locale]/dashboard/_components/user/forms/edit-key-form.tsx
  • src/app/[locale]/dashboard/_components/user/forms/add-key-form.tsx
  • src/app/[locale]/settings/providers/_components/forms/provider-form.tsx
  • src/drizzle/schema.ts
  • src/app/[locale]/dashboard/_components/user/forms/provider-group-select.tsx
  • src/lib/validation/schemas.ts
  • src/app/[locale]/dashboard/_components/user/create-user-dialog.tsx
src/drizzle/schema.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Modify database schema in src/drizzle/schema.ts, then run bun run db:generate to generate migrations. Never create SQL migration files manually

Files:

  • src/drizzle/schema.ts
🧠 Learnings (5)
📚 Learning: 2026-01-05T03:01:45.127Z
Learnt from: NieiR
Repo: ding113/claude-code-hub PR: 539
File: src/types/user.ts:158-170
Timestamp: 2026-01-05T03:01:45.127Z
Learning: In src/types/user.ts, the KeyDialogUserContext interface intentionally has different nullability for limitTotalUsd (number | null | undefined) compared to other limit fields (number | undefined). This is by design: null means "explicitly unlimited", undefined means "inherit default". limitTotalUsd preserves null to match the database schema and support special UI editing logic.

Applied to files:

  • src/app/[locale]/dashboard/_components/user/edit-user-dialog.tsx
  • src/app/[locale]/dashboard/_components/user/create-user-dialog.tsx
📚 Learning: 2026-01-05T03:02:14.502Z
Learnt from: NieiR
Repo: ding113/claude-code-hub PR: 539
File: src/app/[locale]/dashboard/_components/user/user-key-table-row.tsx:66-66
Timestamp: 2026-01-05T03:02:14.502Z
Learning: In the claude-code-hub project, the translations.actions.addKey field in UserKeyTableRowProps is defined as optional for backward compatibility, but all actual callers in the codebase provide the complete translations object. The field has been added to all 5 locale files (messages/{locale}/dashboard.json).

Applied to files:

  • src/app/[locale]/dashboard/_components/user/forms/edit-key-form.tsx
  • src/app/[locale]/dashboard/_components/user/forms/add-key-form.tsx
📚 Learning: 2026-01-10T17:53:25.066Z
Learnt from: CR
Repo: ding113/claude-code-hub PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-10T17:53:25.066Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : All user-facing strings must use i18n (5 languages supported: zh-CN, zh-TW, en, ja, ru). Never hardcode display text

Applied to files:

  • src/app/[locale]/dashboard/_components/user/forms/edit-key-form.tsx
  • src/app/[locale]/dashboard/_components/user/forms/add-key-form.tsx
  • src/app/[locale]/settings/providers/_components/forms/provider-form.tsx
📚 Learning: 2026-01-10T17:53:25.066Z
Learnt from: CR
Repo: ding113/claude-code-hub PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-10T17:53:25.066Z
Learning: Applies to src/drizzle/schema.ts : Modify database schema in `src/drizzle/schema.ts`, then run `bun run db:generate` to generate migrations. Never create SQL migration files manually

Applied to files:

  • src/drizzle/schema.ts
  • drizzle/meta/0053_snapshot.json
📚 Learning: 2026-01-05T03:01:39.354Z
Learnt from: NieiR
Repo: ding113/claude-code-hub PR: 539
File: src/types/user.ts:158-170
Timestamp: 2026-01-05T03:01:39.354Z
Learning: In TypeScript interfaces, explicitly document and enforce distinct meanings for null and undefined. Example: for numeric limits like limitTotalUsd, use 'number | null | undefined' when null signifies explicitly unlimited (e.g., matches DB schema or special UI logic) and undefined signifies 'inherit default'. This pattern should be consistently reflected in type definitions across related fields to preserve semantic clarity between database constraints and UI behavior.

Applied to files:

  • src/drizzle/schema.ts
  • src/lib/validation/schemas.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: pr-review
  • GitHub Check: 🌐 API Tests
  • GitHub Check: Docker Build Test
  • GitHub Check: pr-label
  • GitHub Check: pr-description
🔇 Additional comments (13)
src/app/[locale]/dashboard/_components/user/forms/edit-key-form.tsx (1)

215-229: 变更正确且一致。

providerGroup 字段的 maxTagLength 已正确更新为 200,且对应的错误提示消息也已同步更新。这与 PR 目标以及数据库 schema 的变更(provider_group varchar(200))保持一致。

src/app/[locale]/dashboard/_components/user/forms/user-form.tsx (1)

211-219: 变更正确且一致。

providerGroup 字段的 maxTagLength 已正确更新为 200,对应的 too_long 错误消息参数也已同步调整。这与其他相关文件(如 edit-key-form.tsx)的变更保持一致,符合 PR 目标。

src/app/[locale]/dashboard/_components/user/forms/provider-group-select.tsx (1)

130-130: 变更正确且一致。

maxTagLength 已正确更新为 200,与 PR 目标及其他相关组件的变更保持一致。该组件通过 translations prop 传递错误消息处理逻辑,因此无需在此处显式更新错误文本。

src/app/[locale]/dashboard/_components/user/create-user-dialog.tsx (1)

43-43: Schema 验证正确更新。

CreateUserSchema 中的 providerGroup 最大长度已从 50 正确更新为 200。这与 UI 层面的 TagInputField 组件的 maxTagLength 变更以及数据库 schema 的调整(varchar(200))保持一致,确保了从前端到后端的完整验证链路。

drizzle/meta/_journal.json (1)

375-382: 迁移日志条目看起来一致且可追踪

idx/tag 命名与该次迁移编号对齐、结构与既有 entries 保持一致;只要对应的迁移/快照文件也已同步生成,这里就没问题。

src/app/[locale]/dashboard/_components/user/edit-user-dialog.tsx (1)

37-43: providerGroup 上限调整为 200 与目标一致

这里把 providerGroup 放宽到 max(200),与本 PR 的字段长度升级匹配;只要 normalizeProviderGroup(...) 不会产出超过 200 的字符串就可以。

drizzle/0053_watery_madame_hydra.sql (1)

1-4: 确认该 SQL 迁移为自动生成(避免手工维护漂移)

SQL 内容本身没问题(扩容 varchar、补 default 都是低风险操作)。但按仓库规范应通过 bun run db:generate 生成迁移,而不是手写 SQL 文件;建议确认该文件/快照/日志均为生成产物,避免后续 schema 漂移。基于编码规范。

src/drizzle/schema.ts (1)

34-45: schema.ts 与迁移目标一致:providerGroup 扩容到 200

users.providerGroup / keys.providerGroup 的长度扩为 200 且保持默认值不变,符合本 PR 目标。建议确认已按流程执行 bun run db:generate 并提交对应产物(migration/journal/snapshot),避免手工改动造成不一致。基于 learnings 与编码规范。

Also applies to: 88-116

src/lib/validation/schemas.ts (3)

33-38: LGTM!

CreateUserSchemaproviderGroup 字段的最大长度已正确更新为 200 个字符,与数据库 schema 变更保持一致。验证逻辑(nullable、optional、default)保持不变。


169-169: LGTM!

UpdateUserSchemaproviderGroup 字段的最大长度已同步更新为 200 个字符。


342-347: LGTM!

KeyFormSchemaproviderGroup 字段的最大长度已同步更新为 200 个字符,三个 schema 的变更保持一致。

drizzle/meta/0053_snapshot.json (2)

265-271: LGTM!

keys.provider_group 列已正确更新为 varchar(200),符合 PR 目标。此 snapshot 文件由 bun run db:generate 自动生成。


2030-2036: LGTM!

users.provider_group 列已正确更新为 varchar(200),与 keys 表保持一致。数据库 schema 变更已正确反映在 snapshot 中。

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review Summary

This PR increases the field length from 50 to 200 characters in both the database schema and validation layer. The change is straightforward and well-executed.

PR Size: L

  • Lines changed: 2,432 (2,417 additions + 15 deletions)
  • Files changed: 12

The large line count is primarily due to the auto-generated Drizzle migration snapshot file (2,381 lines), which is expected for database schema changes.

Issues Found

No significant issues identified in this PR.

Review Coverage

  • Logic and correctness - Clean
  • Security (OWASP Top 10) - Clean
  • Error handling - Clean
  • Type safety - Clean
  • Documentation accuracy - Clean
  • Test coverage - Adequate (no new tests needed for simple field length increase)
  • Code clarity - Good

Analysis

What Changed:

  1. Database Schema ():

    • : →
    • : →
  2. Migration ():

    • Properly generated ALTER TABLE statements for both tables
    • Correctly preserves the default value ('default')
  3. Validation Schemas ():

    • : max(50) → max(200)
    • : max(50) → max(200)
    • : max(50) → max(200)
    • Error messages updated to reflect new limit
  4. UI Components (4 form files):

    • prop updated from 50 to 200
    • Error message parameters updated to show correct limit
    • All user-facing validation messages consistent

What Was Done Well:

  • Complete consistency across all layers (DB → validation → UI)
  • Followed the documented migration workflow in CLAUDE.md
  • No hardcoded magic numbers left behind
  • Error messages properly updated with new limit
  • Migration file properly generated (not manually created)

Note on Related Field:
The field remains at , which is intentional and correct. This field serves a different purpose (provider grouping) than (user/key provider selection), and has its own validation constant .


Automated review by Claude AI

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review Summary

This PR increases the provider_group field length from 50 to 200 characters in both the database schema and validation layer. The change is straightforward and well-executed.

PR Size: L

  • Lines changed: 2,432 (2,417 additions + 15 deletions)
  • Files changed: 12

The large line count is primarily due to the auto-generated Drizzle migration snapshot file (2,381 lines), which is expected for database schema changes.

Issues Found

No significant issues identified in this PR.

Review Coverage

  • Logic and correctness - Clean
  • Security (OWASP Top 10) - Clean
  • Error handling - Clean
  • Type safety - Clean
  • Documentation accuracy - Clean
  • Test coverage - Adequate (no new tests needed for simple field length increase)
  • Code clarity - Good

Analysis

What Changed:

  1. Database Schema (src/drizzle/schema.ts):

    • users.providerGroup: varchar(50) to varchar(200)
    • keys.providerGroup: varchar(50) to varchar(200)
  2. Migration (drizzle/0053_watery_madame_hydra.sql):

    • Properly generated ALTER TABLE statements for both tables
    • Correctly preserves the default value ('default')
  3. Validation Schemas (src/lib/validation/schemas.ts):

    • CreateUserSchema.providerGroup: max(50) to max(200)
    • UpdateUserSchema.providerGroup: max(50) to max(200)
    • KeyFormSchema.providerGroup: max(50) to max(200)
    • Error messages updated to reflect new limit
  4. UI Components (4 form files):

    • maxTagLength prop updated from 50 to 200
    • Error message parameters updated to show correct limit
    • All user-facing validation messages consistent

What Was Done Well:

  • Complete consistency across all layers (DB to validation to UI)
  • Followed the documented migration workflow in CLAUDE.md
  • No hardcoded magic numbers left behind
  • Error messages properly updated with new limit
  • Migration file properly generated (not manually created)

Note on Related Field:
The providers.group_tag field remains at varchar(50), which is intentional and correct. This field serves a different purpose (provider grouping) than provider_group (user/key provider selection), and has its own validation constant GROUP_TAG_MAX_TOTAL_LENGTH = 50.


Automated review by Claude AI

@github-actions github-actions bot added size/XL Extra Large PR (> 1000 lines) and removed size/L Large PR (< 1000 lines) labels Jan 11, 2026
providerGroup: z.string().max(50, "供应商分组不能超过50个字符").nullable().optional().default(""),
providerGroup: z
.string()
.max(200, "供应商分组不能超过200个字符")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[High] [STANDARD-VIOLATION] Hardcoded providerGroup validation messages bypass i18n

Why this is a problem: The project rule states: "i18n Required - All user-facing strings must use i18n (5 languages supported). Never hardcode display text" (CLAUDE.md). In src/lib/validation/schemas.ts the updated Zod constraint uses a hardcoded message (.max(200, "供应商分组不能超过200个字符")), which will leak non-localized text in non-zh locales and bypass the repo’s Zod i18n error-map approach.

Suggested fix:

// src/lib/validation/schemas.ts
providerGroup: z.string().max(200).nullable().optional().default(""),

// UpdateUserSchema
providerGroup: z.string().max(200).nullable().optional(),

name: z.string().min(1, "用户名不能为空").max(64, "用户名不能超过64个字符").optional(),
note: z.string().max(200, "备注不能超过200个字符").optional(),
providerGroup: z.string().max(50, "供应商分组不能超过50个字符").nullable().optional(),
providerGroup: z.string().max(200, "供应商分组不能超过200个字符").nullable().optional(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[High] [TEST-MISSING-CRITICAL] No unit coverage for the new providerGroup 200-char limit

Why this is a problem: This PR changes the max length from 50 → 200 in the validation layer (CreateUserSchema / UpdateUserSchema / KeyFormSchema). Per CLAUDE.md: "Test Coverage - All new features must have unit test coverage of at least 80%". There’s currently no boundary test proving 200 chars is accepted and 201 chars is rejected, so regressions can slip in unnoticed.

Suggested fix (add a focused unit test):

// tests/unit/validation/provider-group-max-length.test.ts
import { describe, expect, test } from "vitest";
import { CreateUserSchema, KeyFormSchema, UpdateUserSchema } from "@/lib/validation/schemas";

describe("providerGroup max length", () => {
  test("CreateUserSchema accepts 200 and rejects 201", () => {
    expect(
      CreateUserSchema.safeParse({ name: "u", providerGroup: "a".repeat(200) }).success
    ).toBe(true);

    expect(
      CreateUserSchema.safeParse({ name: "u", providerGroup: "a".repeat(201) }).success
    ).toBe(false);
  });

  test("UpdateUserSchema rejects 201", () => {
    expect(UpdateUserSchema.safeParse({ providerGroup: "a".repeat(201) }).success).toBe(false);
  });

  test("KeyFormSchema rejects 201", () => {
    expect(KeyFormSchema.safeParse({ name: "k", providerGroup: "a".repeat(201) }).success).toBe(false);
  });
});

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review Summary

This PR updates the provider_group max length from 50 → 200 across DB/schema/validation/UI. The main risks are (1) the updated validation messages are still hardcoded (non-i18n) and can surface in non-zh locales, and (2) there’s no boundary unit test coverage proving the new 200-char constraint behaves as intended.

PR Size: XL

  • Lines changed: 2432
  • Files changed: 12
  • Split suggestions: Consider splitting generated Drizzle artifacts (drizzle/meta/* + migration) from application-layer changes (schema/validation/UI) to keep reviewable PRs smaller.

Issues Found

Category Critical High Medium Low
Logic/Bugs 0 1 0 0
Security 0 0 0 0
Error Handling 0 0 0 0
Types 0 0 0 0
Comments/Docs 0 0 0 0
Tests 0 1 0 0
Simplification 0 0 0 0

Critical Issues (Must Fix)

  • None.

High Priority Issues (Should Fix)

  • src/lib/validation/schemas.ts:35 - Hardcoded providerGroup max-length message bypasses i18n and can leak non-localized text.
  • src/lib/validation/schemas.ts:169 - Missing boundary unit tests for the new 200-character providerGroup limit.

Review Coverage

  • Logic and correctness
  • Security (OWASP Top 10)
  • Error handling
  • Type safety
  • Documentation accuracy
  • Test coverage
  • Code clarity

Automated review by Codex AI

@ding113 ding113 merged commit c29eb7c into ding113:dev Jan 12, 2026
16 of 17 checks passed
@github-project-automation github-project-automation bot moved this from Backlog to Done in Claude Code Hub Roadmap Jan 12, 2026
@github-actions github-actions bot mentioned this pull request Jan 12, 2026
ding113 added a commit that referenced this pull request Jan 12, 2026
* PR: 修复 Edge Runtime 下 `process.once` 构建告警(AsyncTaskManager 导入链) (#589)

* fix: skip async task manager init on edge

* fix: avoid static async task manager import

* test: cover edge runtime task scheduling

* chore: document edge runtime process.once fix

* chore: record edge runtime warning baseline

* fix: drop NEXT_PHASE and lazy-init async task manager

* test: isolate NEXT_RUNTIME in cloud price sync tests

* docs: stabilize edge process.once repro baseline

* docs: make rollback instructions hashless

* docs: add grep checklist for edge warning audit

* chore: run regression gate and align docs

* test: cover edge runtime guard on register

* Update src/lib/async-task-manager.ts

补充 NEXT_PHASE === "phase-production-build" 检查

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* chore: format code (fix-edge-runtime-process-once-bee7e19)

* PR:i18n settings 拆分与翻译质量门禁 (#588)

* refactor(i18n): split settings json into smaller files

* refactor(i18n): load settings from split module

* refactor(i18n): remove legacy settings.json

* chore(i18n): update sync-settings-keys for split layout

* test(i18n): add split settings guards

* chore: align biome schema version

* chore(i18n): document messages loading contract

* chore(i18n): add settings split verification notes

* chore: format code (refactor-i18n-split-settings-3f48fec)

* chore: fix i18n request formatting

* chore: format code (refactor-i18n-split-settings-a1eff62)

* fix: replace settings placeholder translations

* chore: verify settings sync script is idempotent

* test: run i18n settings split guards

* test: add audit for zh-CN placeholder settings strings

* chore: apply biome formatting

* chore: document manual i18n settings verification

* fix: translate all providers filter in ja

* fix: translate all providers filter in zh-TW

* fix: translate providers section copy in zh-TW

* fix: translate providers section copy in ja

* feat: extend placeholder audit output

* feat: add allowlist for placeholder audit

* docs: define i18n translation quality rules

* chore: add i18n audit fail commands

* docs: add i18n PR checklist

* chore: format i18n audit tests

* fix: translate dashboard placeholders

* fix: translate myUsage placeholders

* fix: enforce locale-specific parentheses

* fix: start translating provider form strings

* fix: translate provider form strings

* fix: translate provider guide content

* test: add ja dashboard parentheses guard

* test: add zh-TW dashboard parentheses guard

* test: add zh-TW myUsage parentheses guard

* chore: translate ja provider form strings

* chore: translate zh-TW provider form strings

* chore: translate ja providers guide

* chore: translate zh-TW providers guide

* chore: refine zh-TW dashboard strings

* chore: translate ja providers strings

* chore: translate zh-TW providers strings

* chore: refine zh-TW api test strings

* chore: translate zh-TW settings small modules

* chore: translate ja settings small modules

* chore: clear i18n placeholders in settings

* chore: format code (refactor-i18n-split-settings-2437d19)

* test: fix biome formatting in i18n test

* chore: verify Biome lint gate (I18NE-030)

* chore: add messages emoji audit script (I18NE-010)

* fix: remove emoji from messages warnings (I18NE-040)

* test: add messages no-emoji audit gate (I18NE-050)

* docs: add zh-CN i18n docs (I18NE-020)

* docs: add messages no-emoji rule (I18NE-060)

* chore: run full regression checks (I18NE-070)

* docs: add i18n PR evidence template (I18NE-080)

* fix: make messages no-emoji audit path-sep safe

* docs: add bun alias for messages no-emoji audit

* fix: detect keycap and flag emoji sequences in i18n message audits

* fix(provider): allow removing custom whitelisted models (#592) (#593)

* fix(rectifier): detect 'signature: Field required' error and trigger rectifier (#594)

- Extend detectThinkingSignatureRectifierTrigger to match 'signature: Field required'
- Add Rule 72 for friendly error message when signature field is missing
- Add comprehensive test cases for the new detection logic

This fixes an issue where switching from non-Anthropic to Anthropic channels
with thinking blocks missing signature fields would fail without proper handling.

* feat(users): increase provider group length to 200 (#591)

close #590

* feat(usage-doc): update OpenCode config example with GPT-5.2 and Gemini v1beta (#597)

- Add OpenAI GPT-5.2 model configuration with reasoningEffort options
- Add GPT-5.2-small variant using medium reasoning effort
- Fix Gemini baseURL to use /v1beta endpoint
- Update i18n strings to reflect different baseURLs per provider

* feat: auto-complete Codex session identifiers (#599)

* fix: Codex session completion must not inject metadata (#601)

* feat: auto-complete Codex session identifiers

* fix: avoid Codex metadata injection

---------

Co-authored-by: YangQing-Lin <56943790+YangQing-Lin@users.noreply.github.com>
Co-authored-by: Hwwwww-dev <47653238+Hwwwww-dev@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants