009.002.story.md 14 KB

Story 009.002: 邮箱输入优化

Status

Ready for Review

Story

As a 平台管理员 I want 邮箱字段改为非必要输入项 so that 在不需要邮箱的场景下快速完成平台相关操作

Acceptance Criteria

  1. 所有平台管理相关页面的邮箱字段改为非必填
  2. 表单验证规则更新
  3. 后端API支持邮箱为空

Tasks / Subtasks

  • 修复平台管理前端表单默认值问题 (AC: 1, 2)
    • 修改allin-packages/platform-management-ui/src/components/PlatformManagement.tsx中的表单配置
    • 将contactEmail字段的默认值从''改为undefined
    • 验证contactEmail字段的FormLabel没有红色星号标记(非必填)
    • 测试表单提交时邮箱字段可为空(不填写)
    • 测试表单提交时邮箱字段可为有效邮箱格式
    • 测试表单提交时邮箱字段为无效格式应显示验证错误
  • [x] 修改平台模块后端schema验证 (AC: 2, 3)

    • 修改allin-packages/platform-module/src/schemas/platform.schema.ts中的CreatePlatformSchema
    • [x] 将contactEmail字段改为包含中文错误提示和空字符串处理:

      contactEmail: z.string({
      error: '请输入联系邮箱'
      }).email({
      message: '请输入有效的邮箱地址'
      }).max(100, {
      message: '邮箱地址不能超过100个字符'
      }).optional()
      .or(z.literal(''))  // 允许空字符串
      .transform(val => val === '' ? undefined : val)  // 将空字符串转为undefined
      .openapi({
      description: '联系邮箱',
      example: 'zhangsan@example.com'
      })
      
    • [x] 同样修改UpdatePlatformSchema中的contactEmail字段验证规则

    • [x] 可选:为其他字段添加中文错误提示(如platformName必填验证)

  • [x] 验证数据库兼容性 (AC: 3)

    • 检查allin-packages/platform-module/src/entities/platform.entity.ts中contactEmail字段为nullable: true
    • 验证现有数据可以正常读取和更新
  • [x] 编写单元测试 (AC: 1, 2, 3)

    • 为平台schema添加测试,验证空字符串转换为undefined
    • 为平台schema添加测试,验证有效邮箱格式通过验证
    • 为平台schema添加测试,验证无效邮箱格式显示中文错误提示
    • 为平台schema添加测试,验证超长邮箱地址显示中文长度错误提示
    • 为平台schema添加测试,验证undefined通过验证(可选字段)
    • 为平台管理表单添加测试,验证邮箱字段可为空的表单提交
    • 为平台管理表单添加测试,验证邮箱字段为有效邮箱格式的表单提交
    • 为平台管理表单添加测试,验证邮箱字段为无效格式时显示中文验证错误
    • 添加集成测试验证端到端功能
  • [x] 执行回归测试 (AC: 3)

    • 测试现有平台数据的显示和编辑功能
    • 验证API响应格式不变
    • 确保其他字段验证不受影响

Dev Notes

技术架构信息

前端技术栈:

  • React 19.1.0 + TypeScript [Source: architecture/tech-stack.md#前端框架]
  • UI组件库: shadcn/ui (基于Radix UI) [Source: architecture/component-architecture.md#技术栈配置]
  • 状态管理: @tanstack/react-query (服务端状态) + Context (本地状态) [Source: architecture/component-architecture.md#技术栈配置]
  • 构建工具: Vite 7.0.0 [Source: architecture/tech-stack.md#构建工具]

项目结构:

  • 平台管理UI包: allin-packages/platform-management-ui [Source: 实际项目结构检查]
  • 平台模块: allin-packages/platform-module [Source: 实际项目结构检查]

组件规范

UI包开发规范:

  • 必须遵循UI包开发规范 [Source: architecture/coding-standards.md#UI包开发提示]
  • API路径映射验证:开发前必须验证故事中的API路径映射与实际后端路由定义的一致性 [Source: architecture/coding-standards.md#关键检查点]
  • 类型推断最佳实践:必须使用RPC推断类型,而不是直接导入schema类型 [Source: architecture/coding-standards.md#关键检查点]
  • 测试选择器优化:必须为关键交互元素添加data-testid属性 [Source: architecture/coding-standards.md#关键检查点]

现有实现分析

平台管理表单现状:

  • 文件位置: allin-packages/platform-management-ui/src/components/PlatformManagement.tsx:395-406
  • 当前表单字段:contactEmail字段有FormLabel但没有红色星号标记
  • 表单验证:使用CreatePlatformSchema和UpdatePlatformSchema进行验证

平台schema现状:

  • 创建DTO: allin-packages/platform-module/src/schemas/platform.schema.ts:53 - contactEmail字段有z.email('请输入有效的邮箱')验证和.optional()
  • 更新DTO: allin-packages/platform-module/src/schemas/platform.schema.ts:77 - contactEmail字段有z.string().email()验证和.optional()(缺少中文错误提示)
  • 数据库实体: allin-packages/platform-module/src/entities/platform.entity.ts:47 - contactEmail字段为nullable: true

问题分析: 当前schema中contactEmail字段有.optional().email()验证,这意味着:

  1. 字段是可选的(可以是undefined)✅ 符合"非必要输入项"要求
  2. 如果填写了,必须是有效的邮箱格式 ⚠️ 当前有.email()验证
  3. 创建DTO有中文错误提示z.email('请输入有效的邮箱')
  4. 更新DTO缺少中文错误提示z.string().email() ❌ 需要添加

关键问题发现:

  1. 前端表单默认值问题:

    • 文件位置:allin-packages/platform-management-ui/src/components/PlatformManagement.tsx:42
    • 当前默认值:contactEmail: ''(空字符串)
    • 问题:空字符串''不是有效的邮箱格式,会导致Zod验证失败
    • 正确做法:默认值应该是undefined
  2. schema中文错误提示不统一:

    • 创建DTO有中文错误提示
    • 更新DTO缺少中文错误提示
    • 需要统一添加完整的中文错误提示

技术细节:

  • Zod schema:.optional()允许undefined,但不允许无效的邮箱格式
  • React Hook Form:defaultValues中可以使用undefined,但输入框清空后值是''
  • 当前所有字段都设置为'',但只有contactEmail需要特殊处理,因为它是可选但需要邮箱验证的字段

解决方案选项

  1. 推荐方案:修改schema,使用.or(z.literal(''))允许空字符串,然后转换,并添加中文错误提示

    contactEmail: z.string({
     error: '请输入联系邮箱'
    }).email({
     message: '请输入有效的邮箱地址'
    }).max(100, {
     message: '邮箱地址不能超过100个字符'
    }).optional()
     .or(z.literal(''))  // 允许空字符串
     .transform(val => val === '' ? undefined : val)  // 将空字符串转为undefined
     .openapi({
       description: '联系邮箱',
       example: 'zhangsan@example.com'
     })
    
  2. 备选方案:前端在提交前将空字符串转换为undefined

  3. 简单方案:只修改默认值为undefined,但用户清空输入框后还是''

根据故事需求,推荐使用方案1,因为它:

  • 保持邮箱验证(如果填写了)
  • 允许空字符串(用户清空输入框)
  • 在API层面将空字符串转为undefined

根据故事"邮箱字段改为非必要输入项"的要求,需要:

  1. 修改schema,允许空字符串并转换为undefined
  2. 统一添加完整的中文错误提示(字符串、邮箱格式、长度限制)
  3. 可选:将前端表单默认值从''改为undefined
  4. 确保字段支持空值(不填写)
  5. 如果用户选择填写,验证邮箱格式并显示中文错误提示

文件位置参考

  1. 平台管理组件: allin-packages/platform-management-ui/src/components/PlatformManagement.tsx
  2. 平台schema: allin-packages/platform-module/src/schemas/platform.schema.ts
  3. 平台实体: allin-packages/platform-module/src/entities/platform.entity.ts

技术约束

  • 保持向后兼容性:现有数据必须能正常显示和编辑
  • API兼容性:不能修改现有API的请求/响应格式
  • 数据库兼容性:contactEmail字段已经是nullable: true,无需修改数据库结构

测试

测试策略:

  • 单元测试:使用Vitest框架 [Source: architecture/testing-strategy.md#单元测试]
  • 组件测试:使用Testing Library [Source: architecture/testing-strategy.md#单元测试]
  • 测试位置:tests/文件夹与源码并列 [Source: 实际项目结构检查]

测试要求:

  • 覆盖率目标:核心业务逻辑 > 80% [Source: architecture/coding-standards.md#覆盖率目标]
  • 测试类型:单元测试、集成测试 [Source: architecture/coding-standards.md#测试类型]
  • 错误处理:测试各种错误场景和边界条件 [Source: architecture/coding-standards.md#错误处理]

具体测试场景:

  1. schema验证:空字符串''转换为undefined通过验证
  2. schema验证:undefined通过验证(可选字段)
  3. schema验证:有效邮箱格式通过验证
  4. schema验证:无效邮箱格式显示中文错误提示"请输入有效的邮箱地址"
  5. schema验证:超长邮箱地址显示中文长度错误提示"邮箱地址不能超过100个字符"
  6. 平台表单:验证提交时邮箱字段可为空(不填写)
  7. 平台表单:验证提交时邮箱字段可为有效邮箱格式
  8. 平台表单:验证提交时邮箱字段为无效格式应显示中文验证错误
  9. 数据兼容性:验证现有含邮箱数据的显示和编辑

Testing

测试标准

  • 测试框架: Vitest + Testing Library [Source: architecture/tech-stack.md#新技术添加]
  • 测试位置: tests/文件夹与源码并列 [Source: 实际项目结构检查]
  • 覆盖率要求: 核心业务逻辑 > 80% [Source: architecture/coding-standards.md#覆盖率目标]

组件测试要求

  • 必须为关键交互元素添加data-testid属性 [Source: architecture/coding-standards.md#关键检查点]
  • 测试平台管理表单在邮箱字段为空时的提交行为
  • 测试平台管理表单在邮箱字段为有效邮箱格式时的提交行为
  • 测试平台管理表单在邮箱字段为无效格式时的验证错误显示

集成测试要求

  • 测试平台管理表单的完整提交流程
  • 验证邮箱字段为空的表单提交
  • 验证邮箱字段为有效邮箱格式的表单提交
  • 验证邮箱字段为无效格式的表单提交应显示验证错误
  • 测试现有数据的兼容性

测试文件位置

  1. 平台管理测试: allin-packages/platform-management-ui/tests/integration/platform-management.integration.test.tsx

Change Log

Date Version Description Author
2025-12-10 1.0 初始故事创建 Scrum Master Bob

Dev Agent Record

此部分由开发代理在实施期间填写

实施详情

实施时间: 2025-12-10 开发人员: James (开发代理)

已完成的工作

  1. 前端表单优化:

    • 更新PlatformManagement.tsxcontactEmail字段的默认值从''改为undefined
    • 修复React受控/非受控组件警告:为邮箱输入框添加value={field.value || ''}处理
    • 更新类型导入:使用CreatePlatformRequestUpdatePlatformRequest替代直接导入schema类型
    • 添加前端集成测试验证邮箱字段可为空、有效邮箱格式和无效邮箱验证
  2. 后端schema验证优化:

    • 更新CreatePlatformSchemaUpdatePlatformSchema中的contactEmail字段验证
    • 添加完整中文错误提示:字符串验证、邮箱格式验证、长度限制验证
    • 使用.or(z.literal('')).transform(val => val === '' ? undefined : val)处理空字符串转换
    • platformName字段添加中文错误提示
  3. 数据库兼容性验证:

    • 确认platform.entity.tscontactEmail字段为nullable: true
    • 验证数据库表employer_platformcontact_email字段可为空
    • 确认现有数据可以正常读取和更新
  4. 测试覆盖:

    • 创建平台schema单元测试文件:platform.schema.test.ts
    • 添加15个单元测试覆盖所有验证场景
    • 更新前端集成测试添加4个邮箱字段优化测试
    • 所有测试通过:平台管理UI包20个测试,平台模块33个测试
  5. 回归测试:

    • 运行所有相关测试确保现有功能不受影响
    • 验证API响应格式不变
    • 确认其他字段验证不受影响

技术决策

  1. 类型推断最佳实践: 使用Hono RPC推断类型(CreatePlatformRequest/UpdatePlatformRequest)替代直接导入schema类型,符合编码标准
  2. 空字符串处理: 在schema层面使用Zod转换将空字符串转为undefined,确保API一致性
  3. React表单优化: 处理undefined到空字符串的转换,避免受控/非受控组件警告

文件列表

修改的文件:

  1. allin-packages/platform-management-ui/src/components/PlatformManagement.tsx
  2. allin-packages/platform-management-ui/tests/integration/platform-management.integration.test.tsx
  3. allin-packages/platform-module/src/schemas/platform.schema.ts
  4. docs/stories/009.002.story.md

新增的文件:

  1. allin-packages/platform-module/tests/unit/platform.schema.test.ts

验证结果

  • ✅ 所有平台管理相关页面的邮箱字段改为非必填
  • ✅ 表单验证规则更新(添加中文错误提示,允许空字符串)
  • ✅ 后端API支持邮箱为空
  • ✅ 所有测试通过(单元测试、集成测试、回归测试)
  • ✅ 类型检查通过
  • ✅ 现有数据兼容性验证通过

Agent Model Used

Claude Code (开发人员模式)

QA Results

此部分由QA代理在审查期间填写