feat: 用户端改为仅账号密码登录 #50

Closed
opened 2026-08-24 16:56:30 +08:00 by ila · 3 comments
Owner

基本信息

  • 类型:功能调整 / 认证与数据迁移
  • 所属 Epic:#3
  • 所属 MVP / 版本:#35 / MVP-2
  • 阶段:已完成

原始需求

  • 来源:用户对话
  • 提出时间:2026-08-24
  • 关键原话:“直接停用email登录,用账号登录用户端。建工单,做。”

目标

终端用户 Portal 只接受独立账号和密码登录,不再接受邮箱作为登录标识;管理员 sys_user 与终端用户 users 继续分表。

已确认方案

  • 为 users 新增规范化后唯一且非空的 username,历史用户使用确定性的 user_<id> 回填。
  • 登录接口改为 account + password,只按 users.username 查询,不提供邮箱兼容分支。
  • Portal 登录页显示“账号”,使用普通文本输入和 autocomplete=username,保留现有密码显隐、错误反馈、CSRF、Session 轮换与登录限流。
  • 邮箱继续作为用户资料和受控种子数据保留,不再参与认证;不在本工单删除邮箱字段。
  • 种子命令新增必填 CHORUS_SEED_USER_USERNAME,并按账号/邮箱唯一约束幂等更新受控用户。
  • 管理端用户列表和 API 增加账号字段,方便运营识别历史回填账号。

范围与非目标

  • 做:可逆 migration、core 用户模型、seed、Portal 认证 API/页面/静态脚本、管理端用户只读展示、相关测试与长期 Wiki 文档。
  • 不做:公开注册、找回密码、用户自助改账号、管理员创建/改账号、合并 sys_user 与 users、删除邮箱、邮箱或账号双模式登录。

迁移与回退

  • up:新增 users.username,回填 user_<id> 后设为非空并增加唯一索引。
  • down:删除账号唯一索引和字段,恢复原结构;不会修改密码哈希、邮箱或业务数据。
  • 生产继续禁止 AutoMigrate;只通过 migrations/ 演进,并在隔离 MySQL 8 验证 up/down/up。

风险

  • 历史用户登录标识发生变化,迁移后必须使用回填账号或重新执行受控 seed;邮箱登录立即失效。
  • 用户名唯一冲突必须显式报错,不得覆盖其他用户。
  • 登录失败继续返回统一错误,不能泄露账号是否存在。

设计证据

  • 复用现有 Portal 登录页布局,只将邮箱字段改为账号字段,不改变页面结构、流程、权限或状态。
  • 文字和交互范围已由用户于 2026-08-24 明确确认;属于现有表单的小范围语义调整,无需完整原型。

验收标准

  • Portal 使用账号和密码可以登录,邮箱作为 account 提交时不能登录。
  • 登录接口只接受 account 字段,不再接受 email 字段。
  • 历史用户获得唯一账号,迁移 up/down/up 可逆并通过 MySQL 8 验证。
  • 种子命令要求账号并保持幂等,不记录或输出凭据。
  • 管理端用户列表显示账号,邮箱仍作为非认证资料显示。
  • 未改变登录限流、密码哈希、Session/CSRF 和管理员认证边界。
  • Go、Admin、Portal 前端构建和受影响 E2E/单元测试通过。

文档影响

  • 已更新 Business-Rules-and-Glossary、Architecture-and-Code-Map、Local-Development-and-Verification、Product-Requirements-Overview 中的终端用户登录标识与种子配置说明。
## 基本信息 - 类型:功能调整 / 认证与数据迁移 - 所属 Epic:#3 - 所属 MVP / 版本:#35 / MVP-2 - 阶段:已完成 ## 原始需求 - 来源:用户对话 - 提出时间:2026-08-24 - 关键原话:“直接停用email登录,用账号登录用户端。建工单,做。” ## 目标 终端用户 Portal 只接受独立账号和密码登录,不再接受邮箱作为登录标识;管理员 `sys_user` 与终端用户 `users` 继续分表。 ## 已确认方案 - 为 `users` 新增规范化后唯一且非空的 `username`,历史用户使用确定性的 `user_<id>` 回填。 - 登录接口改为 `account + password`,只按 `users.username` 查询,不提供邮箱兼容分支。 - Portal 登录页显示“账号”,使用普通文本输入和 `autocomplete=username`,保留现有密码显隐、错误反馈、CSRF、Session 轮换与登录限流。 - 邮箱继续作为用户资料和受控种子数据保留,不再参与认证;不在本工单删除邮箱字段。 - 种子命令新增必填 `CHORUS_SEED_USER_USERNAME`,并按账号/邮箱唯一约束幂等更新受控用户。 - 管理端用户列表和 API 增加账号字段,方便运营识别历史回填账号。 ## 范围与非目标 - 做:可逆 migration、core 用户模型、seed、Portal 认证 API/页面/静态脚本、管理端用户只读展示、相关测试与长期 Wiki 文档。 - 不做:公开注册、找回密码、用户自助改账号、管理员创建/改账号、合并 `sys_user` 与 `users`、删除邮箱、邮箱或账号双模式登录。 ## 迁移与回退 - up:新增 `users.username`,回填 `user_<id>` 后设为非空并增加唯一索引。 - down:删除账号唯一索引和字段,恢复原结构;不会修改密码哈希、邮箱或业务数据。 - 生产继续禁止 AutoMigrate;只通过 `migrations/` 演进,并在隔离 MySQL 8 验证 up/down/up。 ## 风险 - 历史用户登录标识发生变化,迁移后必须使用回填账号或重新执行受控 seed;邮箱登录立即失效。 - 用户名唯一冲突必须显式报错,不得覆盖其他用户。 - 登录失败继续返回统一错误,不能泄露账号是否存在。 ## 设计证据 - 复用现有 Portal 登录页布局,只将邮箱字段改为账号字段,不改变页面结构、流程、权限或状态。 - 文字和交互范围已由用户于 2026-08-24 明确确认;属于现有表单的小范围语义调整,无需完整原型。 ## 验收标准 - [x] Portal 使用账号和密码可以登录,邮箱作为 account 提交时不能登录。 - [x] 登录接口只接受 `account` 字段,不再接受 `email` 字段。 - [x] 历史用户获得唯一账号,迁移 up/down/up 可逆并通过 MySQL 8 验证。 - [x] 种子命令要求账号并保持幂等,不记录或输出凭据。 - [x] 管理端用户列表显示账号,邮箱仍作为非认证资料显示。 - [x] 未改变登录限流、密码哈希、Session/CSRF 和管理员认证边界。 - [x] Go、Admin、Portal 前端构建和受影响 E2E/单元测试通过。 ## 文档影响 - 已更新 Business-Rules-and-Glossary、Architecture-and-Code-Map、Local-Development-and-Verification、Product-Requirements-Overview 中的终端用户登录标识与种子配置说明。
Author
Owner

实施中发现与范围更新(2026-08-24)

账号 seed 的真实 MySQL 测试发现:MVP-1 migration 000003 已为 prompt_templates 增加必填 capability / default_role_rule,但旧 cmd/chorus-seed 仍按 MVP-0 列写入,当前 schema 上会失败,直接阻塞使用 seed 设置新账号。

按本工单目标做最小修复:默认 seed 数据显式增加 capability;Prompt 写入必填字段;ProviderModel 同步写 provider_model_capabilities。不改变已确认 Prompt 正文、不创建路由、不调用 Provider。已补 opt-in MySQL 幂等测试,连续 seed 两次仍只有一个构造用户且密码保持版本化 bcrypt 哈希。

## 实施中发现与范围更新(2026-08-24) 账号 seed 的真实 MySQL 测试发现:MVP-1 migration 000003 已为 `prompt_templates` 增加必填 `capability` / `default_role_rule`,但旧 `cmd/chorus-seed` 仍按 MVP-0 列写入,当前 schema 上会失败,直接阻塞使用 seed 设置新账号。 按本工单目标做最小修复:默认 seed 数据显式增加 capability;Prompt 写入必填字段;ProviderModel 同步写 `provider_model_capabilities`。不改变已确认 Prompt 正文、不创建路由、不调用 Provider。已补 opt-in MySQL 幂等测试,连续 seed 两次仍只有一个构造用户且密码保持版本化 bcrypt 哈希。
Author
Owner

实施完成,等待验收

  • 提交:0af44bd feat: 用户端改为账号登录 (#50),已推送至 origin/main。
  • 数据:新增可逆 migration 000008;历史用户回填 user_<id>,账号非空、唯一且受格式约束。
  • 认证:Portal 只接受 account + password 并只查询 users.username;旧 email JSON 契约返回 400,邮箱值作为 account 返回统一 401。
  • 界面:登录页改为账号字段;管理端用户列表与 API 展示账号,邮箱保留为资料。
  • Seed:要求 CHORUS_SEED_USER_USERNAME,并修复当前 schema 下 Prompt/ProviderModel 必填能力数据的幂等写入。

验证证据

  • go test ./...、go vet ./...:通过。
  • go -C admin test ./...:通过。
  • migration MySQL 8 up/down/up:通过,包含历史回填、唯一/格式约束和回滚重放。
  • seed MySQL 8 连续执行两次:通过,仅保留一个用户且密码为版本化 bcrypt 哈希。
  • Portal Handler MySQL 集成:通过,覆盖旧 email 契约拒绝、邮箱值拒绝、账号登录成功。
  • Admin MySQL 集成:通过。
  • Portal pnpm build:通过。
  • Admin UI:13 个测试套件、44 个测试通过;标准生产构建通过(仅现有依赖/包体积警告,临时非并行构建设置未提交)。
  • 运行态浏览器检查:账号登录成功、邮箱登录失败、375px 无水平溢出;未调用真实 Provider。
  • harness.py check --strict、核心 Wiki sync --check:通过。

Wiki revision

  • Business-Rules-and-Glossary:575443f808c909383071207adb0be843b88f8b0d
  • Architecture-and-Code-Map:656753d7ce1285da7857e5276fb7748c2b429d64
  • Local-Development-and-Verification:4d052c431913a259bbf1383b4e40c729486f3d99
  • Product-Requirements-Overview:da0a7321fbffe53956c4bdb28a5b3b07a261c6f7

Supervisor 中 Portal、管理端 API、管理端 UI 已使用本次构建运行,Portal 登录页为 http://127.0.0.1:8085/login。当前隔离 Portal 数据库的历史测试用户账号已回填为 user_1,本工单未新建或公开可用密码。

## 实施完成,等待验收 - 提交:`0af44bd feat: 用户端改为账号登录 (#50)`,已推送至 `origin/main`。 - 数据:新增可逆 migration 000008;历史用户回填 `user_<id>`,账号非空、唯一且受格式约束。 - 认证:Portal 只接受 `account + password` 并只查询 `users.username`;旧 `email` JSON 契约返回 400,邮箱值作为 account 返回统一 401。 - 界面:登录页改为账号字段;管理端用户列表与 API 展示账号,邮箱保留为资料。 - Seed:要求 `CHORUS_SEED_USER_USERNAME`,并修复当前 schema 下 Prompt/ProviderModel 必填能力数据的幂等写入。 ### 验证证据 - `go test ./...`、`go vet ./...`:通过。 - `go -C admin test ./...`:通过。 - migration MySQL 8 up/down/up:通过,包含历史回填、唯一/格式约束和回滚重放。 - seed MySQL 8 连续执行两次:通过,仅保留一个用户且密码为版本化 bcrypt 哈希。 - Portal Handler MySQL 集成:通过,覆盖旧 email 契约拒绝、邮箱值拒绝、账号登录成功。 - Admin MySQL 集成:通过。 - Portal `pnpm build`:通过。 - Admin UI:13 个测试套件、44 个测试通过;标准生产构建通过(仅现有依赖/包体积警告,临时非并行构建设置未提交)。 - 运行态浏览器检查:账号登录成功、邮箱登录失败、375px 无水平溢出;未调用真实 Provider。 - `harness.py check --strict`、核心 Wiki `sync --check`:通过。 ### Wiki revision - Business-Rules-and-Glossary:`575443f808c909383071207adb0be843b88f8b0d` - Architecture-and-Code-Map:`656753d7ce1285da7857e5276fb7748c2b429d64` - Local-Development-and-Verification:`4d052c431913a259bbf1383b4e40c729486f3d99` - Product-Requirements-Overview:`da0a7321fbffe53956c4bdb28a5b3b07a261c6f7` Supervisor 中 Portal、管理端 API、管理端 UI 已使用本次构建运行,Portal 登录页为 `http://127.0.0.1:8085/login`。当前隔离 Portal 数据库的历史测试用户账号已回填为 `user_1`,本工单未新建或公开可用密码。
Author
Owner

人工验收完成

  • 用户于 2026-08-24 明确确认 #50 验收通过。
  • Wiki 归档:Task-50-用户端仅账号密码登录
  • 归档 revision:90e90c2d924bd8d8a7ea1d7df29b157e2313f117
  • 核心 Wiki 镜像 sync --check:通过。
  • 实现提交:0af44bd

父工单 #35 与 Epic #3 已同步勾选,本工单关闭。

## 人工验收完成 - 用户于 2026-08-24 明确确认 #50 验收通过。 - Wiki 归档:`Task-50-用户端仅账号密码登录` - 归档 revision:`90e90c2d924bd8d8a7ea1d7df29b157e2313f117` - 核心 Wiki 镜像 `sync --check`:通过。 - 实现提交:`0af44bd` 父工单 #35 与 Epic #3 已同步勾选,本工单关闭。
ila closed this issue 2026-08-24 22:25:14 +08:00
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: OPC/chorus#50