🔒 需人类签核:用户个人资料自助服务 —— 改姓名/头像/密码 + 查看多组织 + 自己的活动记录(零契约操作)
- Dominant language
- TypeScript
- Stars
- 0
- Forks
- 0
- Avg merge
- 1h 7m
- Merged PRs (30d)
- 969
Description
## 背景
人类直接要求(非勘探触发):需要用户个人资料(改姓名/头像、改密码、查看/管理自己所属的多个组织、查看自己的活动/审计记录)。
## 实测:现状全景
| 子项 | 现状 |
|---|---|
| 改姓名 | ❌ 零契约操作。`credentials.display_name` 字段存在(`0010-auth-credentials-sessions.sql`),但没有任何 `UPDATE` 路径——本仓「本模型没有独立的 users 表」的设计原则下,改名就是改这一列 |
| 改头像 | ❌ 更彻底:`credentials` 表**没有头像列**,需要迁移新增 |
| 改密码(已登录状态) | ❌ 零契约操作。**注意与找回密码不同**:现有的是 `passwordReset`(未登录、走邮箱令牌),没有"已登录用户主动改密码"这条 |
| 查看/管理所属多个组织 | 🟡 **部分已有**:`login.out.orgIds`(一串 id)+ `switchOrganization` 操作已存在(F22 一账号多组织)。**缺的只是"看到每个组织的名字"**——而这条今晚已经在 #596 的处置里用 `resolveIdentity` 按组织多次调用绕过了,形状是 N+1,**不需要新契约**,UI 层面复用即可 |
| 查看自己的活动/审计记录 | ❌ 零自助端点。已有的 `adminAuditRead`(`chat.ts:349`)是**管理员**审计读,不是"我看我自己" |
## 契约草案(登记待签核,未实现,未新增任何文件)
```ts
// packages/contracts/src/identity.ts 或新文件 profile.ts(待人类定放哪)
updateOwnProfile: {
method: "PATCH", path: "/identity/me",
in: z.object({
displayName: z.string().min(1).optional(),
avatarUrl: z.string().url().optional(), // 需要 credentials 表新增列,见下
}).strict(),
out: z.object({ displayName: z.string(), avatarUrl: z.string().nullable() }).strict(),
err: ["INVALID_INPUT"] as const,
},
changeOwnPassword: {
method: "POST", path: "/identity/me/password",
in: z.object({
currentPassword: z.string().min(1), // 主动改密必须验证当前密码,防会话劫持后静默改密
newPassword: PasswordPolicy, // 复用 auth.ts 已有的密码策略单一事实源
}).strict(),
out: z.object({ changed: z.literal(true) }).strict(),
err: ["CURRENT_PASSWORD_INVALID", "PASSWORD_POLICY_VIOLATION"] as const,
},
listOwnActivity: {
method: "GET", path: "/identity/me/activity",
in: z.object({ cursor: z.string().nullable(), limit: z.number().int().min(1).max(100) }).strict(),
out: z.object({
events: z.array(z.object({
eventId: z.string(), kind: z.string(), occurredAt: z.string(), summary: z.string(),
})),
nextCursor: z.string().nullable(),
}).strict(),
err: [] as const,
},
```
## ⚠ 需要人类裁决的点,不只是"批不批"
1. **头像需要迁移**:`credentials` 表加 `avatar_url text` 列。**存 URL 还是存文件**(走已有的 artifact/asset 上传链路)是产品决定,不是我能定的实现细节——两者的错误处理、大小限制、审计口径都不同。
2. **改密码要不要吊销其他会话**:改密后是否强制登出其他设备,这是安全策略决定,建议参考 `password-reset.ts` 里"只吊销当前会话"那条先例(如果有)还是"全部吊销"。
3. **活动记录的口径**:`listOwnActivity` 读哪张表?如果复用 `provenance_events`(`adminAuditRead` 读的那张),需要确认按 `actorUserId` 过滤是否已有索引,否则全表扫会是性能问题。
## 范围收窄(本轮不做,需单独排期)
- **多组织管理**(离开某个组织、转让所有权等):本条只做"查看",管理动作范围更大,明确排除。
- 按人类裁决,团队 CRUD 单独登记(见另一个 issue)。
## 出处
coord-agent-auth 受人类直接指派勘探(非例行巡检触发)。**未实现,仅登记待签核。**
Contributor guide
No contributing guide indexed for this repository
Research direction
First resolve the human decisions on avatar storage, session revocation, and the activity data source. Then inspect packages/contracts/src/identity.ts, auth.ts, chat.ts:349, password-reset.ts, and 0010-auth-credentials-sessions.sql. The work is done when the approved profile, password-change, and activity scope is implemented with its required migration and contract changes.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- api, authentication, authorization, databases, security
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100