diff --git a/docs/project-memory/plans/【里程碑】创作者主页与关系交互-2026-10-05.md b/docs/project-memory/plans/【里程碑】创作者主页与关系交互-2026-10-05.md index 1d9d77611..8dfa60413 100644 --- a/docs/project-memory/plans/【里程碑】创作者主页与关系交互-2026-10-05.md +++ b/docs/project-memory/plans/【里程碑】创作者主页与关系交互-2026-10-05.md @@ -2,7 +2,7 @@ | 字段 | 值 | | --- | --- | -| Version | 0.1 | +| Version | 0.2 | | Status | proposed | | Date | 2026-10-05 | | Parent Spec | [创作者主页与关注粉丝合同](../../【玩法创作】平台入口与玩法链路-2026-05-15.md#创作者主页与关注粉丝合同) | @@ -24,6 +24,7 @@ - [ ] 游戏详情可进入自己或他人主页,关注按钮与作者链接互不误触。 - [ ] 主页显示真实计数和公开游戏,点击进入现有详情;本人无自关注按钮。 - [ ] 公开关注/粉丝列表支持分页;只有本人有移除粉丝动作。 +- [ ] 他人的关注列表仅展示资料和主页链接,无关注/取消关注/重新关注按钮,不补查或比对访问者关系;预置关注缓存不改变只读表现,自己的列表仍可管理关系。 - [ ] 自己/他人的关注/粉丝四类列表,游客和登录用户均可点击列表用户头像或昵称进入其创作者主页,覆盖本人及无公开游戏用户;返回恢复来源列表和分页/滚动位置,关系操作按钮不误触跳转。 - [ ] 取消关注后可在当前行重新关注;刷新后的正式列表正确。 - [ ] 粉丝列表回关/取消回关和移除粉丝分别改变正确方向。 diff --git a/docs/project-memory/plans/【里程碑】创作者关系与公开查询-2026-10-05.md b/docs/project-memory/plans/【里程碑】创作者关系与公开查询-2026-10-05.md index 3655a9db9..9bca40316 100644 --- a/docs/project-memory/plans/【里程碑】创作者关系与公开查询-2026-10-05.md +++ b/docs/project-memory/plans/【里程碑】创作者关系与公开查询-2026-10-05.md @@ -2,7 +2,7 @@ | 字段 | 值 | | --- | --- | -| Version | 0.1 | +| Version | 0.2 | | Status | proposed | | Date | 2026-10-05 | | Parent Spec | [创作者主页与关注粉丝合同](../../【玩法创作】平台入口与玩法链路-2026-05-15.md#创作者主页与关注粉丝合同) | @@ -24,6 +24,7 @@ - [ ] 关注和粉丝方向正确,移除粉丝不取消本人对对方的关注。 - [ ] 第三方不能代替他人写出边或删除入边。 - [ ] 游客可读公开资料和列表,认证关系不混入共享公共缓存。 +- [ ] 他人的关注列表即使带有效认证也只返回公开行,relationship 为 null;不查询访问者与各行用户之间的关系,自己的列表所需关系查询继续有效。 - [ ] 分页、计数、失效账号过滤一致,响应不泄露私有账号字段。 - [ ] 作者游戏筛选发生在最多 48 项截取前,过滤未公开、下架和删除作品;不增加游戏分页,未传作者的广场请求保持原有行为。 - [ ] schema、迁移、表目录、生成绑定与共享 DTO 同步。 diff --git a/docs/project-memory/shared-memory/decision-log.md b/docs/project-memory/shared-memory/decision-log.md index 6ee13f2b1..6dd054c05 100644 --- a/docs/project-memory/shared-memory/decision-log.md +++ b/docs/project-memory/shared-memory/decision-log.md @@ -4,6 +4,7 @@ - 已确认但未实现:桌面第四项“创作者主页”默认进入当前账号主页,“我的”移到第五项;他人的关注/粉丝列表公开可查看,自己或他人的两类列表均可点击用户进入其创作者主页。 - 关注为单向关系,取消回关与移除粉丝分别影响不同方向;只有本人可移除自己的粉丝,自己不能关注自己。 +- 他人的关注列表只读:保留头像/昵称进入用户主页,不显示关注、取消关注或重新关注按钮;前后端均不检测访问者与列表用户的关注关系,已有缓存也不用于显示关系动作。 - 用户明确本次不额外改造游戏目录分页:既有游戏广场和“我的游戏”保持现状,作者主页按作者过滤后沿用最多 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 0cb560631..9cbf53ec9 100644 --- a/docs/technical/【技术方案】创作者主页与关注粉丝工程设计-2026-10-05.md +++ b/docs/technical/【技术方案】创作者主页与关注粉丝工程设计-2026-10-05.md @@ -2,7 +2,7 @@ | 字段 | 值 | | --- | --- | -| Version | 0.1 | +| Version | 0.2 | | Status | proposed(文档已形成,业务未实现、未部署) | | 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` 和当前访问者相对各行的关系。不同 HTTP 请求不承诺共享同一事务快照,跨页变化通过写后失效与回读收敛,不能要求两次独立请求永远返回相同计数。 +主页摘要一次事务内完成用户和双向计数读取;关系列表一次事务内读取 `items/total`,仅需要关系操作的视图附带当前访问者相对各行的关系。`tab=following` 且已认证访问者 ID 不等于列表主人时,仅查询主人出边及对应公开用户资料,不探测访问者到列表用户的任何出边或入边,逐行 `relationship` 固定为 null。该条件由后端认证身份与路径主人 ID 决定,不接受客户端开关绕过。不同 HTTP 请求不承诺共享同一事务快照,跨页变化通过写后失效与回读收敛,不能要求两次独立请求永远返回相同计数。 -公开主页不携带访问者状态;`relationship` 端点必须认证。列表无 Authorization 时按游客读取,有 Authorization 时校验后批量返回关系;无效凭据返回 401,前端经现有认证处理后可回到游客读取。关系端点和带认证列表响应使用 `Cache-Control: private, no-store`,不得进入跨用户缓存。 +公开主页不携带访问者状态;`relationship` 端点必须认证。列表无 Authorization 时按游客读取,有 Authorization 时校验并判断列表视图是否需要关系操作;他人的关注列表始终跳过访问者关系计算,其余需操作的视图批量返回关系。无效凭据返回 401,前端经现有认证处理后可回到游客读取。关系端点和带认证列表响应使用 `Cache-Control: private, no-store`,不得进入跨用户缓存。 ## 关系列表分页与作者游戏读取 @@ -103,6 +103,7 @@ type CreatorRelationshipResponse = { - 主页 `/creators` 解析当前账号,`/creators?id=...` 读取指定公开用户;关系列表用 `/creators/connections?id=...&tab=following|followers`,缺主人或非法 tab 展示明确无效链接状态。显式他人 ID 不因登录切换改成自己的主页。 - 关系状态按访问者 ID、目标 ID 隔离。业务 hook/client 负责请求、写入单飞、失败回读和失效;共享关注按钮、用户行只接收数据、pending 和回调,不直接持有认证或网络副作用。 - 自己/他人的关注列表、粉丝列表四种组合均支持头像/昵称进入任意用户主页;用独立链接和按钮避免嵌套交互。列表用户为自己时隐藏关注按钮,主页仍可访问。 +- 他人的关注列表使用只读用户行,不挂载关系动作或触发关系 hook,不调用 relationship 补查接口、不比对访问者自己的关注集合,也不使用预存关系缓存推导按钮。列表切换或账号切换后重新按主人/访问者身份确定模式;进入目标用户主页后,再按主页本身的规则读取关系和提供关注操作。 - 取消关注后的行保留集合只属于当前列表生命周期,与服务端成员和 total 分离;成功重新关注后清除暂留标记。刷新、离开列表或账号变化清除暂留集合;正常失效回读时不可把可重新关注的行立即抹掉。 - 移除粉丝成功从粉丝列表去行,回关/取消回关不去行。确认弹窗复用公共组件;两个方向的按钮在同一目标写入期间一起禁用,写后刷新摘要和相关列表。 - 进入页面、返回和重新聚焦时回读;旧请求通过请求序号/取消机制隔离。认证变化清除私有关系缓存和旧页请求,不让上个账号响应覆盖新账号。 @@ -134,4 +135,4 @@ git diff --check `creator` 测试组为实施时新增的定向分组,届时核对实际匹配数量,零匹配不算通过;补充共享 DTO/UI 和 facade 的对应测试。host 单测不替代 SpacetimeDB 事务验证,运行时通过 `npm run dev:api-server` 启动并验证实际开发地址 `/healthz`,使用隔离开发库的 A/B/C 三账号完成权限、重复写入、双向关系与未知结果回读。 -浏览器覆盖桌面与 375px 移动,四类列表跳转、返回位置、自己的空游戏主页、互关后移除粉丝和登录切换。游戏边界夹具应包含超过 48 项及其他作者作品,证明作者过滤在截取前,广场原有上限保持不变;关系列表用超过 50 项和同时间关系验证分页。所有执行结果回填里程碑证据,本次不宣称实现或运行时验收完成。 +浏览器覆盖桌面与 375px 移动,四类列表跳转、返回位置、自己的空游戏主页、互关后移除粉丝和登录切换。他人关注列表夹具同时包含访问者已关注、未关注及访问者本人,断言一律无关注操作,后端响应 relationship 为 null 且不调用访问者关系投影,前端无补查/写请求;预置关系缓存也不得改变只读表现,点击用户进入主页仍可正常操作。游戏边界夹具应包含超过 48 项及其他作者作品,证明作者过滤在截取前,广场原有上限保持不变;关系列表用超过 50 项和同时间关系验证分页。所有执行结果回填里程碑证据,本次不宣称实现或运行时验收完成。 diff --git a/docs/【玩法创作】平台入口与玩法链路-2026-05-15.md b/docs/【玩法创作】平台入口与玩法链路-2026-05-15.md index febbd06e6..86b6c6bac 100644 --- a/docs/【玩法创作】平台入口与玩法链路-2026-05-15.md +++ b/docs/【玩法创作】平台入口与玩法链路-2026-05-15.md @@ -555,7 +555,7 @@ | 字段 | 值 | | --- | --- | -| Version | 0.2 | +| Version | 0.3 | | Status | proposed(工程设计待实现;已确认产品决策见本节末尾) | | Date | 2026-10-05 | | 范围 | 主站导航、公开创作者主页、游戏详情作者入口、关注关系与列表管理 | @@ -589,12 +589,13 @@ | A 查看 B 主页或 B 的游戏详情 | 关注/取消关注 | 添加/删除 `A → B` | | A 查看自己的关注列表中的 B | 取消关注;取消后重新关注 | 删除/恢复 `A → B` | | A 查看自己的粉丝列表中的 B | 回关/取消关注;移除粉丝 | 前两项只改变 `A → B`;移除只删除 `B → A` | -| A 查看他人的关系列表 | 查看主页;对列表用户关注/取消关注 | 只改变 A 自己的出边,不代替列表主人操作 | -| 游客查看主页或列表 | 浏览;点击关注唤起登录 | 未认证不写关系 | +| A 查看他人的关注列表 | 仅查看用户资料、点击进入主页;无关注操作按钮 | 不读取或改变 A 与列表用户的关注关系 | +| A 查看他人的粉丝列表 | 查看主页;对列表用户关注/取消关注 | 只改变 A 自己的出边,不代替列表主人操作 | +| 游客查看主页或列表 | 浏览;有关注入口的页面点击关注唤起登录,他人关注列表只读 | 未认证不写关系 | 关注/粉丝列表公开可查看(用户已确认),包括无已发布游戏用户的主页。仅允许本人移除自己的粉丝,任何客户端传入的主人 ID 都不能替代服务端认证身份。 -列表行包含公开头像、昵称、陶泥号和当前访问者相对该用户的关注状态。无论查看自己的还是他人的关注列表、粉丝列表,点击任意用户的头像或昵称都进入该用户的创作者主页(用户已确认);游客同样可以跳转,列表中的用户即使是自己或尚未发布游戏,也使用同一主页入口。关注、取消关注与移除粉丝按钮是独立操作,不同时触发主页跳转;从用户主页返回时恢复来源列表及分页/滚动位置。 +列表行包含公开头像、昵称和陶泥号;仅在列表提供关系操作时展示当前访问者相对该用户的关注状态。他人的关注列表固定只读,不显示关注、取消关注或重新关注按钮,不查询或比较访问者是否也关注了列表中的用户,不使用已有关系缓存补出按钮。无论查看自己的还是他人的关注列表、粉丝列表,点击任意用户的头像或昵称都进入该用户的创作者主页(用户已确认);游客同样可以跳转,列表中的用户即使是自己或尚未发布游戏,也使用同一主页入口。关注、取消关注与移除粉丝按钮是独立操作,不同时触发主页跳转;从用户主页返回时恢复来源列表及分页/滚动位置。 自己的关注列表取消后,当前已加载行暂留并显示“重新关注”,计数以服务端结果更新;重新进入或刷新后该行不再属于正式列表。这是临时 UI 行保留,不是第二份关系。粉丝列表取消回关不移除粉丝行,因为入边没有改变。 @@ -607,7 +608,7 @@ - 同一目标写操作进行中禁用重复点击。服务端接口表达“设为已关注/未关注”,不使用 toggle;重复相同请求不重复插行、不重复计数、不刷新既有关注时间。相反方向的并发操作按服务端事务提交顺序生效,回到页面或重新聚焦时回读。 - 写入成功后回读当前主页摘要和受影响列表;游戏详情、主页和列表使用按访问者与目标区分的共享状态失效机制,防止各维护一份长期布尔值。 - 超时或断网后不能断言写入失败:提示“状态未确认”,先查询正式关系,再允许重试当前意图;不得自动反转或重放陈旧的相反操作。确定失败保留已确认状态并显示错误。 -- 公共资料与访问者关系分开读取或使用正确的私有缓存策略,不能把某个用户的 `isFollowing` 放入匿名公共缓存。分页响应中的关系查询批量完成,避免逐行网络查询。 +- 公共资料与访问者关系分开读取或使用正确的私有缓存策略,不能把某个用户的 `isFollowing` 放入匿名公共缓存。需要关系操作的分页响应批量查询访问者关系,避免逐行网络查询;他人的关注列表跳过此查询,前端也不补查。 - 不存在或不可公开的账号返回不可访问状态;资料只投影公开用户字段,不包含手机、会话、钱包或第三方身份凭据。计数与列表对不可公开账号使用相同过滤条件。 ### 数据与接口提案 @@ -629,7 +630,7 @@ 以上为拟新增合同,尚不是可调用 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 检查;若后续需要破坏性修改已有表,须另行确认迁移计划。 @@ -647,6 +648,7 @@ | 互关后 A 移除 B 粉丝,`A → B` 保留、`B → A` 消失 | 定向事务测试与真实 API;重复移除不重复扣数 | | 取消关注后当前行可重新关注;刷新后正式列表正确 | UI 定向测试与浏览器操作 | | 自己/他人的关注/粉丝四类列表均可点击用户进入主页,操作按钮不误跳转 | 游客和登录态浏览器验证,覆盖本人、他人、无公开游戏用户及返回位置恢复 | +| 他人的关注列表只读,已有关注缓存也不显示操作;后端和前端均不探测访问者与各行用户的关系 | 响应 relationship 全为 null、后端关系投影未调用、前端无关系补查或写请求;头像/昵称跳转保留 | | 游客只读;禁止自关注和第三方移除他人粉丝 | 权限负向测试;第三账号越权调用 | | 主页只含作者公开游戏,自己的主页也不泄露私有版本 | 混合公开/未公开/下架/删除作品夹具与 HTTP 验证 | | 超时后回读、重复请求、并发、快速换作者/账号 | 后端幂等及前端迟到响应测试 | @@ -654,7 +656,7 @@ ### 决策与待评审项 -- 已确认:第四项默认进入自己主页;他人关注和粉丝列表公开可查看;自己或他人的关注/粉丝列表均可点击任意用户进入其创作者主页;本次不额外改造游戏目录分页,保持既有广场和“我的游戏”行为。 +- 已确认:第四项默认进入自己主页;他人关注和粉丝列表公开可查看;自己或他人的关注/粉丝列表均可点击任意用户进入其创作者主页;他人的关注列表只读、无关系操作且不检测访问者与列表用户的关注关系;本次不额外改造游戏目录分页,保持既有广场和“我的游戏”行为。 - 建议待评审:移动三入口、自己的主页只列公开游戏、取消后暂留行、移除粉丝二次确认,以及本节接口命名和分页默认值。 - 源码核验:现有公开用户查询按账号存在性返回资料,`user_account` 没有独立封禁/公开状态字段。首版复用该存在性口径,关系计数和列表一致排除不存在的账号,不在本功能内增加账号状态体系。 - 本次证据只覆盖源码调研和规划文档检查;业务、数据库迁移与浏览器验收均未执行。