feat(users): increase provider group length to 200#591
Conversation
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>
📝 Walkthrough概述本次变更扩展了提供商分组(providerGroup)字段的最大长度限制,从 50 个字符增至 200 个字符。包括数据库迁移文件、Drizzle ORM 模式定义、前端验证 Schema 以及多个用户界面表单组件的一致更新。 变更详情
代码审查工作量评估🎯 2 (Simple) | ⏱️ ~12 分钟 可能相关的 PR
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
Summary of ChangesHello @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 Highlights
Using Gemini Code AssistThe 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
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 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
|
There was a problem hiding this comment.
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:
- The UI validation for the provider group length is misleading. The
maxTagLengthproperty onTagInputFieldcomponents 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. - In
create-user-dialog.tsxandedit-user-dialog.tsx, the Zod schema forproviderGroupis 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(), |
There was a problem hiding this comment.
| 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(), |
There was a problem hiding this comment.
| <TagInputField | ||
| label={t("providerGroup.label")} | ||
| maxTagLength={50} | ||
| maxTagLength={200} |
There was a problem hiding this comment.
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.
| maxTagLength={200} | |
| maxTagLength={100} |
| empty: tUI("emptyTag"), | ||
| duplicate: tUI("duplicateTag"), | ||
| too_long: tUI("tooLong", { max: 50 }), | ||
| too_long: tUI("tooLong", { max: 200 }), |
There was a problem hiding this comment.
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.
| too_long: tUI("tooLong", { max: 200 }), | |
| too_long: tUI("tooLong", { max: 100 }), |
| <TagInputField | ||
| label={t("providerGroup.label")} | ||
| maxTagLength={50} | ||
| maxTagLength={200} |
There was a problem hiding this comment.
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.
| maxTagLength={200} | |
| maxTagLength={100} |
| empty: tUI("emptyTag"), | ||
| duplicate: tUI("duplicateTag"), | ||
| too_long: tUI("tooLong", { max: 50 }), | ||
| too_long: tUI("tooLong", { max: 200 }), |
There was a problem hiding this comment.
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.
| too_long: tUI("tooLong", { max: 200 }), | |
| too_long: tUI("tooLong", { max: 100 }), |
| placeholder={getTranslation(translations, "placeholder", "输入分组并回车")} | ||
| description={description} | ||
| maxTagLength={50} | ||
| maxTagLength={200} |
There was a problem hiding this comment.
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.
| maxTagLength={200} | |
| maxTagLength={100} |
| <TagInputField | ||
| label={tForm("providerGroup.label")} | ||
| maxTagLength={50} | ||
| maxTagLength={200} |
There was a problem hiding this comment.
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.
| maxTagLength={200} | |
| maxTagLength={100} |
| empty: tUI("emptyTag"), | ||
| duplicate: tUI("duplicateTag"), | ||
| too_long: tUI("tooLong", { max: 50 }), | ||
| too_long: tUI("tooLong", { max: 200 }), |
There was a problem hiding this comment.
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.
| too_long: tUI("tooLong", { max: 200 }), | |
| too_long: tUI("tooLong", { max: 100 }), |
There was a problem hiding this comment.
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
📒 Files selected for processing (12)
drizzle/0053_watery_madame_hydra.sqldrizzle/meta/0053_snapshot.jsondrizzle/meta/_journal.jsonsrc/app/[locale]/dashboard/_components/user/create-user-dialog.tsxsrc/app/[locale]/dashboard/_components/user/edit-user-dialog.tsxsrc/app/[locale]/dashboard/_components/user/forms/add-key-form.tsxsrc/app/[locale]/dashboard/_components/user/forms/edit-key-form.tsxsrc/app/[locale]/dashboard/_components/user/forms/provider-group-select.tsxsrc/app/[locale]/dashboard/_components/user/forms/user-form.tsxsrc/app/[locale]/settings/providers/_components/forms/provider-form.tsxsrc/drizzle/schema.tssrc/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.tsxsrc/app/[locale]/dashboard/_components/user/forms/user-form.tsxsrc/app/[locale]/dashboard/_components/user/forms/edit-key-form.tsxsrc/app/[locale]/dashboard/_components/user/forms/add-key-form.tsxsrc/app/[locale]/settings/providers/_components/forms/provider-form.tsxsrc/drizzle/schema.tssrc/app/[locale]/dashboard/_components/user/forms/provider-group-select.tsxsrc/lib/validation/schemas.tssrc/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.tsxsrc/app/[locale]/dashboard/_components/user/forms/user-form.tsxsrc/app/[locale]/dashboard/_components/user/forms/edit-key-form.tsxsrc/app/[locale]/dashboard/_components/user/forms/add-key-form.tsxsrc/app/[locale]/settings/providers/_components/forms/provider-form.tsxsrc/drizzle/schema.tssrc/app/[locale]/dashboard/_components/user/forms/provider-group-select.tsxsrc/lib/validation/schemas.tssrc/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.tsxsrc/app/[locale]/dashboard/_components/user/forms/user-form.tsxsrc/app/[locale]/dashboard/_components/user/forms/edit-key-form.tsxsrc/app/[locale]/dashboard/_components/user/forms/add-key-form.tsxsrc/app/[locale]/settings/providers/_components/forms/provider-form.tsxsrc/drizzle/schema.tssrc/app/[locale]/dashboard/_components/user/forms/provider-group-select.tsxsrc/lib/validation/schemas.tssrc/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 runbun run db:generateto 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.tsxsrc/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.tsxsrc/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.tsxsrc/app/[locale]/dashboard/_components/user/forms/add-key-form.tsxsrc/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.tsdrizzle/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.tssrc/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 目标及其他相关组件的变更保持一致。该组件通过translationsprop 传递错误消息处理逻辑,因此无需在此处显式更新错误文本。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!
CreateUserSchema中providerGroup字段的最大长度已正确更新为 200 个字符,与数据库 schema 变更保持一致。验证逻辑(nullable、optional、default)保持不变。
169-169: LGTM!
UpdateUserSchema中providerGroup字段的最大长度已同步更新为 200 个字符。
342-347: LGTM!
KeyFormSchema中providerGroup字段的最大长度已同步更新为 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 中。
There was a problem hiding this comment.
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:
-
Database Schema ():
- : →
- : →
-
Migration ():
- Properly generated ALTER TABLE statements for both tables
- Correctly preserves the default value ('default')
-
Validation Schemas ():
- : max(50) → max(200)
- : max(50) → max(200)
- : max(50) → max(200)
- Error messages updated to reflect new limit
-
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
There was a problem hiding this comment.
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:
-
Database Schema (src/drizzle/schema.ts):
- users.providerGroup: varchar(50) to varchar(200)
- keys.providerGroup: varchar(50) to varchar(200)
-
Migration (drizzle/0053_watery_madame_hydra.sql):
- Properly generated ALTER TABLE statements for both tables
- Correctly preserves the default value ('default')
-
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
-
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
| providerGroup: z.string().max(50, "供应商分组不能超过50个字符").nullable().optional().default(""), | ||
| providerGroup: z | ||
| .string() | ||
| .max(200, "供应商分组不能超过200个字符") |
There was a problem hiding this comment.
[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(), |
There was a problem hiding this comment.
[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);
});
});There was a problem hiding this comment.
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- HardcodedproviderGroupmax-length message bypasses i18n and can leak non-localized text.src/lib/validation/schemas.ts:169- Missing boundary unit tests for the new 200-characterproviderGrouplimit.
Review Coverage
- Logic and correctness
- Security (OWASP Top 10)
- Error handling
- Type safety
- Documentation accuracy
- Test coverage
- Code clarity
Automated review by Codex AI
* 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>
Summary
This PR increases the maximum length of the
provider_groupfield 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_groupfield from 50 to 200 characters for bothusersandkeystables. The change is comprehensive and touches all necessary layers of the application stack.Changes Overview
Database Layer (3 files):
provider_groupcolumn type fromvarchar(50)tovarchar(200)for both tablesValidation Layer (1 file):
providerGroupfieldsCreateUserSchema,UpdateUserSchema, andKeyFormSchemaUI Layer (8 files):
maxTagLength={200}for provider group input fieldsProviderGroupSelectcomponentConsistency Analysis
The changes demonstrate excellent consistency across the entire stack:
Note on provider-form.tsx
The file
src/app/[locale]/settings/providers/_components/forms/provider-form.tsxmaintainsGROUP_TAG_MAX_TOTAL_LENGTH = 50. This is correct—it manages providergroupTag(a different field used for categorizing providers), not user/keyproviderGroupfields.Confidence Score: 5/5
Important Files Changed
File Analysis
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)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:
Testing