oh-my-muse/docs/agent-specs/2026-06-21-meta-projection投影实现-review.md
lili d8cb1047da docs(p1r): meta-projection 投影实现评审版 + 缺环回写总账[P1]
- 新增评审版:projectionKey≡schemaKey、列表=work targetType 匹配多 schema(人类第四轮+评审走查决策)、RealContentMetaFacade 置 content-server 调 meta-api+回填本域 planning value、可见性起步版本级;含 design-docs SSOT 约束、关键决策表、边界数据流、blast/风险/验收/open items。

- execution 总账回写 B5c 前端完成 + projection 缺环发现(ContentMetaFacade 真后端 unavailable,e2e 实为真后端活体)+ 第四轮决策。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 04:24:03 -07:00

9.2 KiB

Meta-Projection 投影实现(补 B 缺环)—— 评审版

版本:v0.1(评审版) · 日期:2026-06-21 · 目标读者:架构 review + 实现 agent · 类型:评审版(结论先行,无代码细节) 上游:用量投影执行版第四轮决策(补 Meta owner projection 实现 + 完整投影分组建模)。 触发:B5 前端 PlanningEditor 依赖的 meta-projection 端口真后端 unavailable(ContentMetaFacade 仅 stub),B 落地链漏列了「Meta owner 投影实现」这一跨 BC 环。


一、结论先行

  1. 目标:让 GET /works/{workId}/meta-projections[/{projectionKey}] 从 stub-unavailable 变为真实返回字段定义 + 字段级可见性 + 已存值回填,使 B5 PlanningEditor 端到端真跑(用户按 schema 字段填值→usedFieldKeys→快照→字段级计数)。
  2. 推荐方案(一句话):projectionKey ≡ schemaKey(对齐 design-docs);RealContentMetaFacadecontent-server,调新增 meta-api 端口拿「字段定义+字段级可见性」,读本域 planning 回填 value,组装投影;起步以 work 当前绑定的单 schema 为投影列表,预留多 schema 演进
  3. 关键依据(design-docs SSOT 已定义,实现须遵守):
    • 投影是 read model(MetaSchema+权限+来源状态+dataRevision 动态计算),owner = MetaSchema BC,绝非事实源(后端-05 §4.3、架构-02 §4.2)。
    • projectionKey 倾向 = schema_key(domain/scope/target_type 下唯一稳定业务键,后端-04 §4.7)。
    • 5 可见性(uiVisible/aiContext/userEditable/userSearchable/exportable)= 策略级,由 muse_meta_visibility_policy 管,语义不可合并(架构-02 §9)。
    • 三版本 schemaVersion/projectionVersion/dataRevision 语义与递增条件已定(前端-03 §5.3、后端-05 §4.3)。
    • 字段写入走 writeOwner/ownerCommand(如 planning:PUT /works/{workId}/planning/{sectionKey}),无跨 owner 通用写口。
  4. 架构空白(design-docs 未明确,本评审拍板点见 §四/§九):① work↔多 schema 关联规则;② 字段↔投影分组存储映射;③ 多分组返回契约;④ 可见性字段级 vs 版本级粒度。

二、背景与缺环

  • B5 前端(已完成):usePlanning hooks + PlanningEditor(按 fieldType 渲染) + PlanningEditorPanel(列 projection→选→编辑,unavailable 优雅降级) + WorkspacePage 右侧 Tab 集成。vitest 全量 66/66。
  • 缺环(自验反假绿):ContentMetaProjectionServiceImpl 转调 ContentMetaFacade,但全仓仅 UnavailableContentMetaFacade(@ConditionalOnMissingBean)→ 真后端返 CONTENT_EXTERNAL_OWNER_UNAVAILABLE。playwright e2e 是真后端活体(VITE_API_MOCK=false),故 UI 全链路真跑必须先让 projection 真实可用。
  • meta-api 现状:MetaSchemaQueryApilistActiveSchemasByTargetType / getActiveSchemaById(返 brief:id/schemaKey/displayName/targetType),无字段定义、无可见性、无投影分组查询

三、范围与非目标

范围

  • 新增 meta-api 投影查询端口(字段定义 + 字段级可见性聚合)。
  • meta-server 实现该端口(只读 active schema 的 MetaFieldDO + MetaVisibilityPolicyDO)。
  • content-server RealContentMetaFacade(替换 Unavailable):调 meta-api + 读本域 planning 回填 value + 组装 MetaProjectionSummary/Detail/FieldRespVO
  • DynamicFieldValidation 真实化(校验字段类型/必填/枚举,返路由建议;不写事实)。

非目标(本轮)

  • 不引入 schema 字段分组子表(projectionKey≡schemaKey,schema 即投影单元;多 projection = 多 schema)。
  • 不解决 work↔多 schema 的完整关联建模(起步用 work 单绑定;演进见 §九)。
  • 不改 3 版本递增的既有产出点(沿用现有 schema/projection version 字段)。

四、关键决策(拍板点)

# 决策 选项 推荐 理由
D-A projectionKey 语义 (a) =schemaKey;(b) schema 内分组键(需新表) (a) design-docs 后端-04 §4.7 schema_key 为唯一业务键;前端-02 的「作品设定/世界设定/角色关系…」对应不同 domain/scope 的 schema,非单 schema 内分组→无须新分组表
D-B work 的 projection 列表来源 (a) work 单绑定 schema(1 个);(b) 按 targetType 匹配多 active schema;(c) work↔schema 多对多新表 (a) 起步,预留 (b) D1 已落 workSchemaId 单绑定,最小一致、零新建;(b)/(c) 涉 design-docs 空白(work 适用哪些 schema),留演进
D-C 字段级可见性粒度 (a) 解析 policySnapshot JSON 取字段级;(b) 版本级统一应用到所有字段 (a) 若快照含字段级,否则 (b) 执行版 §四.3 实证字段级可见性在 policySnapshot/fieldContractSnapshot JSON;须实现期验证快照结构,不满足则降级 (b) 并声明
D-D RealContentMetaFacade 放置 (a) content-server;(b) meta-server (a) value 回填须读 content 本域 planning;content 调 meta-api 拿定义合边界(参照 RealContentFileFacade 先例);meta 读 content 反向违边界
D-E meta-api 端口形态 (a) 扩 MetaSchemaQueryApi;(b) 新增 MetaProjectionQueryApi (b) 投影查询(字段+可见性)与 schema 发现职责不同,独立端口更清晰、不污染现有契约

五、推荐方案数据流

flowchart TD
    FE[muse-studio PlanningEditorPanel] -->|GET /works/workId/meta-projections| C1[AppContentMetaProjectionController]
    C1 --> C2[ContentMetaProjectionServiceImpl\nrequireOwnedWork 权限校验]
    C2 --> F[RealContentMetaFacade\ncontent-server, @Component @Primary]
    F -->|work.workSchemaId| W[(本域 WorkDO)]
    F -->|projectionKey=schemaKey 拿字段+可见性| API[MetaProjectionQueryApi\nmeta-api 端口 新增]
    API --> M[meta-server 实现\n读 MetaFieldDO+MetaVisibilityPolicyDO active]
    F -->|按 fieldKey 回填 value| P[(本域 PlanningSectionDO.contentPayload)]
    F --> R[组装 MetaProjectionDetailRespVO\n字段定义+可见性+value+sourceSnapshot]
    R --> C2
    C2 -->|available=false 即 fail-closed| X[CONTENT_EXTERNAL_OWNER_UNAVAILABLE]
    subgraph 边界门 BcBoundaryArchTest 0 违例
      API
    end
    F -. 仅依赖 meta-api 端口,不直连 meta.dal .-> API

职责切分(合边界):Meta 出「字段定义+可见性」(自域只读);Content 出「权限校验 + value 回填 + 投影组装」(本域只读 + 调 meta-api 端口)。


六、Blast Radius / 兼容 / 回滚

  • meta-api:新增 MetaProjectionQueryApi + DTO(只增,无既有契约改动)。
  • meta-server:新增端口实现(只读 schema/可见性,不写)。
  • content-server:新增 RealContentMetaFacade @Component @Primary 替换 stub;ContentMetaProjectionServiceImpl/Controller 不改(已转调 facade)。
  • 边界门:content 仅依赖 meta-api 端口 + 本域 DAL;BcBoundaryArchTest 须保持 0 违例(验收硬条件)。
  • 兼容:projection 端点对外契约不变(VO 不动);仅从「恒 unavailable」变「真实返回」。
  • 回滚:移除 RealContentMetaFacade@Primary 即回到 Unavailable stub(平滑)。

七、风险与缓解

风险 说明 缓解
projectionKey=schemaKey 系推断 design-docs 未逐字明说「projectionKey==schema_key」 §九 列为人类确认点;若否,改 D-A(b) 需新分组表(范围扩大)
work↔多 schema 未定 前端-02 列 5 入口但 work 单绑定 起步单 schema(D-B a);多 schema 留演进,不阻塞 B5
可见性粒度不定 policySnapshot 结构待实现期验证 D-C:验证后字段级,否则版本级降级并声明
真后端无 active schema 本地 fixture 可能无 governance 配置的 schema meta-projections 空列表→前端已有优雅降级(不崩);e2e 需 fixture 含 active schema(globalSetup)
fail-closed 语义 任一 meta-api 失败/数据缺失 facade 一律返 unavailable,绝不伪造部分投影(anti-false-green)

八、验收标准

  • meta-api MetaProjectionQueryApi 端口 + meta-server 实现:种 active schema → 返回字段定义 + 可见性(单测/IT)。
  • RealContentMetaFacade:work 绑 schema → meta-projections 真实返回字段(非 unavailable);value 从 planning 回填正确(单测)。
  • 边界:BcBoundaryArchTest 0 违例;恰一个 ContentMetaFacade Bean。
  • 端到端(真后端活体):B5 e2e——进作品规划 Tab → 字段渲染 → 填值保存 → usedFieldKeys 落快照 → 值回填(playwright,需 fixture 含 active schema)。
  • 反假绿:无 active schema/数据缺失一律 unavailable+前端降级,绝不伪造字段。

九、Open Items(须人类确认)

  1. (拍板)projectionKey ≡ schemaKey? 若确认→无须新分组表(推荐);若 projectionKey 是 schema 内分组→须新建字段↔分组映射(范围显著扩大)。
  2. (拍板)work 的 projection 列表起步用单绑定 schema? 还是本轮即做 targetType 匹配多 schema(需定「work 适用哪些 schema」规则)?
  3. 可见性字段级 vs 版本级:实现期验证 policySnapshot 结构后定(D-C 已含降级)。
  4. DynamicFieldValidation 真实校验范围:本轮做类型/必填/枚举 + 路由建议是否足够?

下一步:本评审走查确认 §九.1/§九.2 两个拍板点后,出执行版 spec(端口契约 + 数据流 + 边界验收 + 分步)并实现。