From f4e5aaf44195d8fd2e1ff5eca5c2314c51b13418 Mon Sep 17 00:00:00 2001 From: lhk Date: Mon, 5 Oct 2026 10:20:07 +0100 Subject: [PATCH] =?UTF-8?q?=E7=A1=AE=E8=AE=A4=E5=88=9B=E4=BD=9C=E8=80=85?= =?UTF-8?q?=E4=B8=BB=E9=A1=B5=E4=BA=A7=E5=93=81=E8=A7=84=E5=88=99=E5=B9=B6?= =?UTF-8?q?=E7=BB=9F=E4=B8=80=E4=BB=96=E4=BA=BA=E5=88=97=E8=A1=A8=E5=8F=AA?= =?UTF-8?q?=E8=AF=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将他人的关注和粉丝列表统一为只读并跳过关系检测 确认移动端三入口、本人公开游戏范围与移除粉丝二次确认 同步主规范、工程设计、里程碑状态和验收标准 --- docs/README.md | 2 +- ...�里程碑】创作者主页与关系交互-2026-10-05.md | 11 ++--- ...�里程碑】创作者关系与公开查询-2026-10-05.md | 10 ++--- .../shared-memory/decision-log.md | 3 +- ...案】创作者主页与关注粉丝工程设计-2026-10-05.md | 14 +++---- ...�玩法创作】平台入口与玩法链路-2026-05-15.md | 40 +++++++++---------- 6 files changed, 41 insertions(+), 39 deletions(-) diff --git a/docs/README.md b/docs/README.md index f4f5d69e9..d3eb0c9fc 100644 --- a/docs/README.md +++ b/docs/README.md @@ -21,7 +21,7 @@ - [当前产品与工程约束](./【项目基线】当前产品与工程约束-2026-05-15.md):现役入口、账号钱包、UI 和后端分层。 - [平台入口与玩法链路](./【玩法创作】平台入口与玩法链路-2026-05-15.md):平台壳、图片画布、游戏分发与在线游玩合同;网站游戏评分与评价已实现并通过本地验证,待用户验收,未部署。 - [网站游戏评分与评价里程碑](./project-memory/plans/【里程碑】网站游戏评分与评价-2026-09-30.md):唯一评价、编辑预填、4000 字符、公共分页与平均分/人数的验收边界与本地证据。 -- [创作者主页与关注粉丝合同](./【玩法创作】平台入口与玩法链路-2026-05-15.md#创作者主页与关注粉丝合同)、[关系与公开查询里程碑](./project-memory/plans/【里程碑】创作者关系与公开查询-2026-10-05.md)和[主页与交互里程碑](./project-memory/plans/【里程碑】创作者主页与关系交互-2026-10-05.md):规划草案,未实现;第四项默认进入自己主页,关注/粉丝列表公开可查看。 +- [创作者主页与关注粉丝合同](./【玩法创作】平台入口与玩法链路-2026-05-15.md#创作者主页与关注粉丝合同)、[关系与公开查询里程碑](./project-memory/plans/【里程碑】创作者关系与公开查询-2026-10-05.md)和[主页与交互里程碑](./project-memory/plans/【里程碑】创作者主页与关系交互-2026-10-05.md):产品规则已确认,未实现;第四项默认进入自己主页,他人的关注/粉丝列表统一只读并支持主页跳转。 - [创作者主页与关注粉丝工程设计](./technical/【技术方案】创作者主页与关注粉丝工程设计-2026-10-05.md):待实现的分层落点、关系表/DTO、授权、关系列表分页、组件状态、深链与验证边界;游戏列表沿用最多 48 项限制,不做额外分页改造。 - [后台游戏评价管理合同](./【玩法创作】平台入口与玩法链路-2026-05-15.md#后台游戏评价管理合同):查找、分页、隐藏/恢复/删除、必填原因、统计与个人状态联动;已实现并通过本地验证,待用户验收,未部署。 - [后台游戏评价管理里程碑](./project-memory/plans/【里程碑】后台游戏评价管理-2026-10-01.md)与[实施计划](./project-memory/plans/【实施计划】后台游戏评价管理-2026-10-01.md):单里程碑范围、接口/schema 边界及验收要求;本地证据已回写主规范。 diff --git a/docs/project-memory/plans/【里程碑】创作者主页与关系交互-2026-10-05.md b/docs/project-memory/plans/【里程碑】创作者主页与关系交互-2026-10-05.md index 8dfa60413..2ac745371 100644 --- a/docs/project-memory/plans/【里程碑】创作者主页与关系交互-2026-10-05.md +++ b/docs/project-memory/plans/【里程碑】创作者主页与关系交互-2026-10-05.md @@ -2,8 +2,8 @@ | 字段 | 值 | | --- | --- | -| Version | 0.2 | -| Status | proposed | +| Version | 1.0 | +| Status | ready(产品规则已确认,实施仍依赖前阶段验收) | | Date | 2026-10-05 | | Parent Spec | [创作者主页与关注粉丝合同](../../【玩法创作】平台入口与玩法链路-2026-05-15.md#创作者主页与关注粉丝合同) | @@ -16,18 +16,19 @@ ## 前置条件 - [创作者关系与公开查询](./【里程碑】创作者关系与公开查询-2026-10-05.md)已验收。 -- 主规范和本里程碑完成评审;开始编码前单独落地本阶段实施计划。 +- 主规范的产品规则已确认;开始编码前单独落地本阶段实施计划。 ## 验收标准 -- [ ] 桌面第四项进入自己主页,第五项为“我的”;移动入口按评审口径接入。 +- [ ] 桌面第四项进入自己主页,第五项为“我的”;移动入口为“游戏 / 创作者主页 / 我的”。 - [ ] 游戏详情可进入自己或他人主页,关注按钮与作者链接互不误触。 - [ ] 主页显示真实计数和公开游戏,点击进入现有详情;本人无自关注按钮。 - [ ] 公开关注/粉丝列表支持分页;只有本人有移除粉丝动作。 -- [ ] 他人的关注列表仅展示资料和主页链接,无关注/取消关注/重新关注按钮,不补查或比对访问者关系;预置关注缓存不改变只读表现,自己的列表仍可管理关系。 +- [ ] 他人的关注、粉丝列表均仅展示资料和主页链接,无关系操作按钮,不补查或比对访问者关系;预置关注缓存不改变只读表现,自己的列表仍可管理关系。 - [ ] 自己/他人的关注/粉丝四类列表,游客和登录用户均可点击列表用户头像或昵称进入其创作者主页,覆盖本人及无公开游戏用户;返回恢复来源列表和分页/滚动位置,关系操作按钮不误触跳转。 - [ ] 取消关注后可在当前行重新关注;刷新后的正式列表正确。 - [ ] 粉丝列表回关/取消回关和移除粉丝分别改变正确方向。 +- [ ] 移除粉丝需二次确认,取消弹窗不发写请求;取消关注直接执行,不弹确认。 - [ ] 登录、退出、账号切换、请求迟到和网络失败不污染关系状态。 - [ ] 主页/详情/列表往返状态一致,深链刷新和返回位置正确。 - [ ] 375px 移动和桌面布局、长昵称、空态/错误态、键盘和触摸操作可用。 diff --git a/docs/project-memory/plans/【里程碑】创作者关系与公开查询-2026-10-05.md b/docs/project-memory/plans/【里程碑】创作者关系与公开查询-2026-10-05.md index 9bca40316..5dfeaaebb 100644 --- a/docs/project-memory/plans/【里程碑】创作者关系与公开查询-2026-10-05.md +++ b/docs/project-memory/plans/【里程碑】创作者关系与公开查询-2026-10-05.md @@ -2,8 +2,8 @@ | 字段 | 值 | | --- | --- | -| Version | 0.2 | -| Status | proposed | +| Version | 1.0 | +| Status | ready(产品规则已确认,未实现) | | Date | 2026-10-05 | | Parent Spec | [创作者主页与关注粉丝合同](../../【玩法创作】平台入口与玩法链路-2026-05-15.md#创作者主页与关注粉丝合同) | @@ -15,7 +15,7 @@ ## 前置条件 -- 主规范与本里程碑完成评审,明确账号不可公开状态的现有判断依据。 +- 主规范的产品规则已确认;账号公开性按现有账号存在性判断,不新增账号状态体系。 - 开始实现前另建仅覆盖本里程碑的实施计划,明确 schema、DTO、事务、API、测试及回滚边界。 ## 验收标准 @@ -24,7 +24,7 @@ - [ ] 关注和粉丝方向正确,移除粉丝不取消本人对对方的关注。 - [ ] 第三方不能代替他人写出边或删除入边。 - [ ] 游客可读公开资料和列表,认证关系不混入共享公共缓存。 -- [ ] 他人的关注列表即使带有效认证也只返回公开行,relationship 为 null;不查询访问者与各行用户之间的关系,自己的列表所需关系查询继续有效。 +- [ ] 他人的关注、粉丝列表即使带有效认证也只返回公开行,relationship 为 null;不额外查询访问者与各行用户之间的关系,自己的列表所需关系查询继续有效。 - [ ] 分页、计数、失效账号过滤一致,响应不泄露私有账号字段。 - [ ] 作者游戏筛选发生在最多 48 项截取前,过滤未公开、下架和删除作品;不增加游戏分页,未传作者的广场请求保持原有行为。 - [ ] schema、迁移、表目录、生成绑定与共享 DTO 同步。 @@ -34,4 +34,4 @@ 领域/契约定向测试、schema 与 DDD 边界检查、编码/文档检查;通过 `npm run dev:api-server` 启动并验证 `/healthz` 后,以三个测试账号验证本人/对方/第三方关系。新增测试数据仅写隔离开发环境。 -提供主规范逐条证据矩阵及未验证项;通过验收后才进入页面里程碑。当前只有规划草案,无实现或运行时证据。 +提供主规范逐条证据矩阵及未验证项;通过验收后才进入页面里程碑。当前产品规则已确认,无实现或运行时证据。 diff --git a/docs/project-memory/shared-memory/decision-log.md b/docs/project-memory/shared-memory/decision-log.md index 6dd054c05..8898803a0 100644 --- a/docs/project-memory/shared-memory/decision-log.md +++ b/docs/project-memory/shared-memory/decision-log.md @@ -4,7 +4,8 @@ - 已确认但未实现:桌面第四项“创作者主页”默认进入当前账号主页,“我的”移到第五项;他人的关注/粉丝列表公开可查看,自己或他人的两类列表均可点击用户进入其创作者主页。 - 关注为单向关系,取消回关与移除粉丝分别影响不同方向;只有本人可移除自己的粉丝,自己不能关注自己。 -- 他人的关注列表只读:保留头像/昵称进入用户主页,不显示关注、取消关注或重新关注按钮;前后端均不检测访问者与列表用户的关注关系,已有缓存也不用于显示关系动作。 +- 他人的关注、粉丝列表统一只读:保留头像/昵称进入用户主页,不显示任何关系操作按钮;前后端均不额外检测访问者与列表用户的关注关系,已有缓存也不用于显示关系动作。 +- 已确认:移动端入口为“游戏 / 创作者主页 / 我的”;自己的主页也只展示公开游戏;自己的关注列表取消后当前行暂留以便重新关注;移除粉丝二次确认,取消关注不弹确认。 - 用户明确本次不额外改造游戏目录分页:既有游戏广场和“我的游戏”保持现状,作者主页按作者过滤后沿用最多 48 项限制。新关注/粉丝列表的分页仍按主规范设计。 - 行为真相见[创作者主页与关注粉丝合同](../../【玩法创作】平台入口与玩法链路-2026-05-15.md#创作者主页与关注粉丝合同),工程落点见[工程设计](../../technical/【技术方案】创作者主页与关注粉丝工程设计-2026-10-05.md)。当前仅完成文档,不代表功能上线。 diff --git a/docs/technical/【技术方案】创作者主页与关注粉丝工程设计-2026-10-05.md b/docs/technical/【技术方案】创作者主页与关注粉丝工程设计-2026-10-05.md index 9cbf53ec9..f47662d77 100644 --- a/docs/technical/【技术方案】创作者主页与关注粉丝工程设计-2026-10-05.md +++ b/docs/technical/【技术方案】创作者主页与关注粉丝工程设计-2026-10-05.md @@ -2,8 +2,8 @@ | 字段 | 值 | | --- | --- | -| Version | 0.2 | -| Status | proposed(文档已形成,业务未实现、未部署) | +| Version | 1.0 | +| Status | ready(产品规则已确认,业务未实现、未部署) | | Date | 2026-10-05 | | Parent Spec | [创作者主页与关注粉丝合同](../【玩法创作】平台入口与玩法链路-2026-05-15.md#创作者主页与关注粉丝合同) | @@ -69,7 +69,7 @@ type CreatorProfile = { type CreatorConnection = { user: CreatorUser; followedAt: string; // 当前列表所表示方向的建立时间,RFC 3339 - relationship: CreatorRelationship | null; // 游客或查看他人的关注列表时为 null + relationship: CreatorRelationship | null; // 仅本人读取自己的列表时返回,其他情况为 null }; type CreatorConnections = { items: CreatorConnection[]; @@ -86,9 +86,9 @@ type CreatorRelationshipResponse = { 关系写操作成功返回 200,目标存在时重复关注/删除仍成功;对自己操作返回 400,未认证为 401,非受信或越权调用为 403,不存在的用户为 404。有效目标但不存在关系的删除与“目标不存在”明确区分。前端不自动重试结果未知的写请求,先回读关系。 -主页摘要一次事务内完成用户和双向计数读取;关系列表一次事务内读取 `items/total`,仅需要关系操作的视图附带当前访问者相对各行的关系。`tab=following` 且已认证访问者 ID 不等于列表主人时,仅查询主人出边及对应公开用户资料,不探测访问者到列表用户的任何出边或入边,逐行 `relationship` 固定为 null。该条件由后端认证身份与路径主人 ID 决定,不接受客户端开关绕过。不同 HTTP 请求不承诺共享同一事务快照,跨页变化通过写后失效与回读收敛,不能要求两次独立请求永远返回相同计数。 +主页摘要一次事务内完成用户和双向计数读取;关系列表一次事务内读取 `items/total`,仅已认证访问者 ID 等于列表主人时附带逐行关系。游客或访问他人列表时,following 只查询主人出边、followers 只查询主人入边及对应公开用户资料,不额外探测访问者与列表用户的关系,逐行 `relationship` 固定为 null。该条件由后端认证身份与路径主人 ID 决定,不接受客户端开关绕过。不同 HTTP 请求不承诺共享同一事务快照,跨页变化通过写后失效与回读收敛,不能要求两次独立请求永远返回相同计数。 -公开主页不携带访问者状态;`relationship` 端点必须认证。列表无 Authorization 时按游客读取,有 Authorization 时校验并判断列表视图是否需要关系操作;他人的关注列表始终跳过访问者关系计算,其余需操作的视图批量返回关系。无效凭据返回 401,前端经现有认证处理后可回到游客读取。关系端点和带认证列表响应使用 `Cache-Control: private, no-store`,不得进入跨用户缓存。 +公开主页不携带访问者状态;`relationship` 端点必须认证。列表无 Authorization 时按游客读取,有 Authorization 时校验并判断是否本人列表;他人的关注、粉丝列表始终跳过访问者关系计算,只有自己的列表批量返回所需关系。无效凭据返回 401,前端经现有认证处理后可回到游客读取。关系端点和带认证列表响应使用 `Cache-Control: private, no-store`,不得进入跨用户缓存。 ## 关系列表分页与作者游戏读取 @@ -103,7 +103,7 @@ type CreatorRelationshipResponse = { - 主页 `/creators` 解析当前账号,`/creators?id=...` 读取指定公开用户;关系列表用 `/creators/connections?id=...&tab=following|followers`,缺主人或非法 tab 展示明确无效链接状态。显式他人 ID 不因登录切换改成自己的主页。 - 关系状态按访问者 ID、目标 ID 隔离。业务 hook/client 负责请求、写入单飞、失败回读和失效;共享关注按钮、用户行只接收数据、pending 和回调,不直接持有认证或网络副作用。 - 自己/他人的关注列表、粉丝列表四种组合均支持头像/昵称进入任意用户主页;用独立链接和按钮避免嵌套交互。列表用户为自己时隐藏关注按钮,主页仍可访问。 -- 他人的关注列表使用只读用户行,不挂载关系动作或触发关系 hook,不调用 relationship 补查接口、不比对访问者自己的关注集合,也不使用预存关系缓存推导按钮。列表切换或账号切换后重新按主人/访问者身份确定模式;进入目标用户主页后,再按主页本身的规则读取关系和提供关注操作。 +- 他人的关注、粉丝列表统一使用只读用户行,不挂载关系动作或触发关系 hook,不调用 relationship 补查接口、不比对访问者自己的关注集合,也不使用预存关系缓存推导按钮。列表切换或账号切换后重新按主人/访问者身份确定模式;进入目标用户主页后,再按主页本身的规则读取关系和提供关注操作。 - 取消关注后的行保留集合只属于当前列表生命周期,与服务端成员和 total 分离;成功重新关注后清除暂留标记。刷新、离开列表或账号变化清除暂留集合;正常失效回读时不可把可重新关注的行立即抹掉。 - 移除粉丝成功从粉丝列表去行,回关/取消回关不去行。确认弹窗复用公共组件;两个方向的按钮在同一目标写入期间一起禁用,写后刷新摘要和相关列表。 - 进入页面、返回和重新聚焦时回读;旧请求通过请求序号/取消机制隔离。认证变化清除私有关系缓存和旧页请求,不让上个账号响应覆盖新账号。 @@ -135,4 +135,4 @@ git diff --check `creator` 测试组为实施时新增的定向分组,届时核对实际匹配数量,零匹配不算通过;补充共享 DTO/UI 和 facade 的对应测试。host 单测不替代 SpacetimeDB 事务验证,运行时通过 `npm run dev:api-server` 启动并验证实际开发地址 `/healthz`,使用隔离开发库的 A/B/C 三账号完成权限、重复写入、双向关系与未知结果回读。 -浏览器覆盖桌面与 375px 移动,四类列表跳转、返回位置、自己的空游戏主页、互关后移除粉丝和登录切换。他人关注列表夹具同时包含访问者已关注、未关注及访问者本人,断言一律无关注操作,后端响应 relationship 为 null 且不调用访问者关系投影,前端无补查/写请求;预置关系缓存也不得改变只读表现,点击用户进入主页仍可正常操作。游戏边界夹具应包含超过 48 项及其他作者作品,证明作者过滤在截取前,广场原有上限保持不变;关系列表用超过 50 项和同时间关系验证分页。所有执行结果回填里程碑证据,本次不宣称实现或运行时验收完成。 +浏览器覆盖桌面与 375px 移动,四类列表跳转、返回位置、自己的空游戏主页、互关后移除粉丝和登录切换。他人的关注、粉丝两类列表夹具均包含访问者已关注、未关注及访问者本人,断言一律无关系操作,后端响应 relationship 为 null 且不调用访问者关系投影,前端无补查/写请求;预置关系缓存也不得改变只读表现,点击用户进入主页仍可正常操作。游戏边界夹具应包含超过 48 项及其他作者作品,证明作者过滤在截取前,广场原有上限保持不变;关系列表用超过 50 项和同时间关系验证分页。所有执行结果回填里程碑证据,本次不宣称实现或运行时验收完成。 diff --git a/docs/【玩法创作】平台入口与玩法链路-2026-05-15.md b/docs/【玩法创作】平台入口与玩法链路-2026-05-15.md index 86b6c6bac..b706c16ef 100644 --- a/docs/【玩法创作】平台入口与玩法链路-2026-05-15.md +++ b/docs/【玩法创作】平台入口与玩法链路-2026-05-15.md @@ -555,8 +555,8 @@ | 字段 | 值 | | --- | --- | -| Version | 0.3 | -| Status | proposed(工程设计待实现;已确认产品决策见本节末尾) | +| Version | 1.0 | +| Status | ready(产品规则已确认,未实现;开工前补单里程碑实施计划) | | Date | 2026-10-05 | | 范围 | 主站导航、公开创作者主页、游戏详情作者入口、关注关系与列表管理 | @@ -571,9 +571,9 @@ ### 页面与导航 - 桌面导航保留前三项顺序,新增第四项“创作者主页”,“我的”变为第五项。第四项默认进入当前登录账号自己的主页(用户已确认)。 -- 移动端建议为“游戏 / 创作者主页 / 我的”,保留创作、项目的现有桌面限制,不把五项桌面入口强行塞入底部导航。 -- 建议主页路由 `/creators?id=`;裸 `/creators` 表示自己的主页,登录后解析当前账号。显式 ID 深链可刷新、分享及直接访问,自己的主页与他人的主页共用页面。 -- 建议列表路由 `/creators/connections?id=&tab=following|followers`,关注数和粉丝数分别进入对应列表;返回恢复来源页及分页/滚动位置,直接访问的返回兜底为所属主页。 +- 移动端为“游戏 / 创作者主页 / 我的”,保留创作、项目的现有桌面限制,不把五项桌面入口强行塞入底部导航。 +- 主页路由 `/creators?id=`;裸 `/creators` 表示自己的主页,登录后解析当前账号。显式 ID 深链可刷新、分享及直接访问,自己的主页与他人的主页共用页面。 +- 列表路由 `/creators/connections?id=&tab=following|followers`,关注数和粉丝数分别进入对应列表;返回恢复来源页及分页/滚动位置,直接访问的返回兜底为所属主页。 - 主页展示头像、昵称、陶泥号、关注按钮、`关注数 | 粉丝数` 和公开游戏列表。没有游戏或关系时显示真实空态,接口失败展示重试,不以 0 或空列表冒充成功。 - 他人主页按钮为“关注”或“已关注”,点击“已关注”执行取消关注;自己的主页隐藏该按钮,不允许关注自己。按钮的可访问名称明确表达“取消关注”。 - 游戏详情的作者头像/名称可点击进入主页,包括本人;作者旁增加同一套关注按钮。作者链接和关注按钮是独立点击目标,不因关注同时触发跳转;自己的游戏隐藏关注按钮。 @@ -589,13 +589,12 @@ | A 查看 B 主页或 B 的游戏详情 | 关注/取消关注 | 添加/删除 `A → B` | | A 查看自己的关注列表中的 B | 取消关注;取消后重新关注 | 删除/恢复 `A → B` | | A 查看自己的粉丝列表中的 B | 回关/取消关注;移除粉丝 | 前两项只改变 `A → B`;移除只删除 `B → A` | -| A 查看他人的关注列表 | 仅查看用户资料、点击进入主页;无关注操作按钮 | 不读取或改变 A 与列表用户的关注关系 | -| A 查看他人的粉丝列表 | 查看主页;对列表用户关注/取消关注 | 只改变 A 自己的出边,不代替列表主人操作 | -| 游客查看主页或列表 | 浏览;有关注入口的页面点击关注唤起登录,他人关注列表只读 | 未认证不写关系 | +| A 查看他人的关注列表或粉丝列表 | 仅查看用户资料、点击进入主页;无关系操作按钮 | 不读取或改变 A 与列表用户的关注关系 | +| 游客查看主页或列表 | 浏览;主页点击关注唤起登录,关系列表只读 | 未认证不写关系 | 关注/粉丝列表公开可查看(用户已确认),包括无已发布游戏用户的主页。仅允许本人移除自己的粉丝,任何客户端传入的主人 ID 都不能替代服务端认证身份。 -列表行包含公开头像、昵称和陶泥号;仅在列表提供关系操作时展示当前访问者相对该用户的关注状态。他人的关注列表固定只读,不显示关注、取消关注或重新关注按钮,不查询或比较访问者是否也关注了列表中的用户,不使用已有关系缓存补出按钮。无论查看自己的还是他人的关注列表、粉丝列表,点击任意用户的头像或昵称都进入该用户的创作者主页(用户已确认);游客同样可以跳转,列表中的用户即使是自己或尚未发布游戏,也使用同一主页入口。关注、取消关注与移除粉丝按钮是独立操作,不同时触发主页跳转;从用户主页返回时恢复来源列表及分页/滚动位置。 +列表行包含公开头像、昵称和陶泥号;只有本人查看自己的列表时展示关系状态和操作。他人的关注列表、粉丝列表统一只读,不显示关注、取消关注、重新关注或移除粉丝按钮,不查询或比较访问者与列表用户的关系,不使用已有关系缓存补出按钮。无论查看自己的还是他人的关注列表、粉丝列表,点击任意用户的头像或昵称都进入该用户的创作者主页(用户已确认);游客同样可以跳转,列表中的用户即使是自己或尚未发布游戏,也使用同一主页入口。自己的列表中,关注、取消关注与移除粉丝按钮是独立操作,不同时触发主页跳转;从用户主页返回时恢复来源列表及分页/滚动位置。 自己的关注列表取消后,当前已加载行暂留并显示“重新关注”,计数以服务端结果更新;重新进入或刷新后该行不再属于正式列表。这是临时 UI 行保留,不是第二份关系。粉丝列表取消回关不移除粉丝行,因为入边没有改变。 @@ -608,16 +607,16 @@ - 同一目标写操作进行中禁用重复点击。服务端接口表达“设为已关注/未关注”,不使用 toggle;重复相同请求不重复插行、不重复计数、不刷新既有关注时间。相反方向的并发操作按服务端事务提交顺序生效,回到页面或重新聚焦时回读。 - 写入成功后回读当前主页摘要和受影响列表;游戏详情、主页和列表使用按访问者与目标区分的共享状态失效机制,防止各维护一份长期布尔值。 - 超时或断网后不能断言写入失败:提示“状态未确认”,先查询正式关系,再允许重试当前意图;不得自动反转或重放陈旧的相反操作。确定失败保留已确认状态并显示错误。 -- 公共资料与访问者关系分开读取或使用正确的私有缓存策略,不能把某个用户的 `isFollowing` 放入匿名公共缓存。需要关系操作的分页响应批量查询访问者关系,避免逐行网络查询;他人的关注列表跳过此查询,前端也不补查。 +- 公共资料与访问者关系分开读取或使用正确的私有缓存策略,不能把某个用户的 `isFollowing` 放入匿名公共缓存。本人列表的分页响应批量查询所需关系,避免逐行网络查询;他人的关注、粉丝列表均跳过此查询,前端也不补查。 - 不存在或不可公开的账号返回不可访问状态;资料只投影公开用户字段,不包含手机、会话、钱包或第三方身份凭据。计数与列表对不可公开账号使用相同过滤条件。 -### 数据与接口提案 +### 数据与接口合同 -关注属于账号关系,复用现有账号身份,不新建创作者账号系统。建议在现有 `module-auth` 内划分关系子模块承载纯规则,SpacetimeDB 保存事实和事务,`spacetime-client` 提供 facade,`api-server` 提供 HTTP/BFF,Rust/TypeScript 共享 DTO 同步更新。 +关注属于账号关系,复用现有账号身份,不新建创作者账号系统。在现有 `module-auth` 内划分关系子模块承载纯规则,SpacetimeDB 保存事实和事务,`spacetime-client` 提供 facade,`api-server` 提供 HTTP/BFF,Rust/TypeScript 共享 DTO 同步更新。 -建议新增私有关注关系表:无歧义的有向用户对主键、`follower_user_id`、`followee_user_id`、`created_at`,分别支持关注方和被关注方索引。用户对唯一且不得相同;不保存昵称/头像副本。首版从关系索引计算准确计数,每次摘要或列表请求内部使用一致事务快照,不同 HTTP 请求通过回读收敛;如量级要求额外计数投影,须先补充事务一致性方案。 +新增私有关注关系表:无歧义的有向用户对主键、`follower_user_id`、`followee_user_id`、`created_at`,分别支持关注方和被关注方索引。用户对唯一且不得相同;不保存昵称/头像副本。首版从关系索引计算准确计数,每次摘要或列表请求内部使用一致事务快照,不同 HTTP 请求通过回读收敛;如量级要求额外计数投影,须先补充事务一致性方案。 -| 建议接口 | 用途与权限 | +| 接口 | 用途与权限 | | --- | --- | | `GET /api/creators/{userId}` | 公开资料、关注数、粉丝数;游客可读 | | `GET /api/creators/{userId}/following` | 公开关注列表,游标分页 | @@ -628,9 +627,9 @@ | `DELETE /api/creators/me/followers/{followerId}` | 当前登录用户移除自己的粉丝,幂等 | | 扩展 `GET /api/game-distribution/games?authorId=` | 服务端精确作者过滤,复用公开游戏可见性与卡片契约 | -以上为拟新增合同,尚不是可调用 API。关注/粉丝列表建议默认 20、上限 50,按关系建立时间与稳定身份倒序,返回 `items/nextCursor/total`;游标绑定主人和列表类型,非法/错域游标返回 400。增删期间重新加载可能改变页内成员,前端按用户 ID 去重,重新关注产生新的建立时间。此分页规则仅用于新关系列表;游戏列表继续最多读取 48 项,不实现分页。 +以上为待实现合同,尚不是可调用 API。关注/粉丝列表默认 20、上限 50,按关系建立时间与稳定身份倒序,返回 `items/nextCursor/total`;游标绑定主人和列表类型,非法/错域游标返回 400。增删期间重新加载可能改变页内成员,前端按用户 ID 去重,重新关注产生新的建立时间。此分页规则仅用于新关系列表;游戏列表继续最多读取 48 项,不实现分页。 -关系写入成功返回 200 与当前访问者关系;重复删除不存在的关系仍成功。不合法输入或关注自己返回 400,未认证 401,越权 403,目标不存在或不可公开 404。提供关系操作的列表读取可携带有效认证以批量附带各行访问者关系;游客和他人的关注列表该字段为 null,后者即使已登录也不计算逐行关系。带关系的响应禁用共享缓存,认证失效时清除访问者关系并按游客重新读取。 +关系写入成功返回 200 与当前访问者关系;重复删除不存在的关系仍成功。不合法输入或关注自己返回 400,未认证 401,越权 403,目标不存在或不可公开 404。本人读取自己的关系列表时以有效认证批量附带各行关系;游客和他人的关注、粉丝列表该字段为 null,后者即使已登录也不计算逐行关系。带关系的响应禁用共享缓存,认证失效时清除访问者关系并按游客重新读取。 此次只新增关系表和站内接口,不改现有账号/游戏主键,不迁移出虚构的历史关注,也不扩充 external v1。实施时同步 `migration.rs`、表目录、生成绑定和 schema 检查;若后续需要破坏性修改已有表,须另行确认迁移计划。 @@ -648,16 +647,17 @@ | 互关后 A 移除 B 粉丝,`A → B` 保留、`B → A` 消失 | 定向事务测试与真实 API;重复移除不重复扣数 | | 取消关注后当前行可重新关注;刷新后正式列表正确 | UI 定向测试与浏览器操作 | | 自己/他人的关注/粉丝四类列表均可点击用户进入主页,操作按钮不误跳转 | 游客和登录态浏览器验证,覆盖本人、他人、无公开游戏用户及返回位置恢复 | -| 他人的关注列表只读,已有关注缓存也不显示操作;后端和前端均不探测访问者与各行用户的关系 | 响应 relationship 全为 null、后端关系投影未调用、前端无关系补查或写请求;头像/昵称跳转保留 | +| 他人的关注、粉丝列表均只读,已有关注缓存也不显示操作;后端和前端均不探测访问者与各行用户的关系 | 两种列表响应 relationship 全为 null、后端关系投影未调用、前端无关系补查或写请求;头像/昵称跳转保留 | | 游客只读;禁止自关注和第三方移除他人粉丝 | 权限负向测试;第三账号越权调用 | | 主页只含作者公开游戏,自己的主页也不泄露私有版本 | 混合公开/未公开/下架/删除作品夹具与 HTTP 验证 | | 超时后回读、重复请求、并发、快速换作者/账号 | 后端幂等及前端迟到响应测试 | | 分页、空态、错误态、长昵称、触摸与键盘操作 | 超过一页数据及移动/桌面 UI 验证 | -### 决策与待评审项 +### 已确认决策与开工边界 -- 已确认:第四项默认进入自己主页;他人关注和粉丝列表公开可查看;自己或他人的关注/粉丝列表均可点击任意用户进入其创作者主页;他人的关注列表只读、无关系操作且不检测访问者与列表用户的关注关系;本次不额外改造游戏目录分页,保持既有广场和“我的游戏”行为。 -- 建议待评审:移动三入口、自己的主页只列公开游戏、取消后暂留行、移除粉丝二次确认,以及本节接口命名和分页默认值。 +- 已确认:第四项默认进入自己主页;他人关注和粉丝列表公开可查看;自己或他人的关注/粉丝列表均可点击任意用户进入其创作者主页;他人的关注、粉丝列表统一只读,无关系操作且不检测访问者与列表用户的关系;本次不额外改造游戏目录分页,保持既有广场和“我的游戏”行为。 +- 已确认:移动端采用“游戏 / 创作者主页 / 我的”;自己的主页也只列公开游戏;自己的关注列表取消后当前行暂留以便重新关注;移除粉丝二次确认,取消关注不弹确认。 +- 产品待定项已收口,接口命名、路由和关系列表分页按本文及工程设计落地。开工前补关系与公开查询里程碑的实施计划;前阶段验收后再进入页面阶段。本次只修改文档,不提前编写业务代码。 - 源码核验:现有公开用户查询按账号存在性返回资料,`user_account` 没有独立封禁/公开状态字段。首版复用该存在性口径,关系计数和列表一致排除不存在的账号,不在本功能内增加账号状态体系。 - 本次证据只覆盖源码调研和规划文档检查;业务、数据库迁移与浏览器验收均未执行。