oh-my-muse/docs/superpowers/plans/2026-05-24-Muse四仓执行计划.md
zizi f6f85e431d feat(plan): 添加 Muse 四仓主执行计划(Phase 0 完整 + P1-P4 概要)
Phase 0 含 11 个 Task:6 模块 OpenAPI 契约 + 类型生成 + 完整性校验
2026-05-24 14:00:44 +08:00

75 KiB
Raw Blame History

Muse 四仓开发 — 主执行计划

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

目标: 从零搭建 Muse 四仓muse-cloud / muse-studio / muse-admin实现 6 个业务模块全量 API + 双前端,完成集成切换和质量加固。

架构: API-first + 三仓并行。Phase 0 在本仓产出 OpenAPI 3.0 契约文件Phase 1 三仓并行开发(后端逐步产出真实 API前端先 Mock 独立开发Phase 2 按模块逐个切换真实 API 并完成质量加固。

技术栈: Java 21 + Spring Boot 3 + PostgreSQL 16 + Yudao Cloud后端| React + Vite + TypeScript + TanStack Query + Tiptap用户端| Vue 3 + Vben Admin + TypeScript管理端


子计划索引

本计划覆盖 18 周、4 个代码仓库。按子系统拆分为 5 个子计划:

# 子计划 仓库 周期 状态
P0 API 契约冻结 muse-design-docs Week 1-2 就绪
P1 muse-cloud 后端搭建(待创建) muse-cloud Week 3-16 P0 完成后
P2 muse-studio 用户端搭建(待创建) muse-studio Week 3-16 P0 完成后
P3 muse-admin 管理端搭建(待创建) muse-admin Week 3-16 P0 完成后
P4 集成切换 + 质量加固(待创建) 四仓联合 Week 9-18 P1-P3 部分完成后

依赖关系:

graph TD
  P0[P0: API 契约冻结] --> P1[P1: muse-cloud 后端]
  P0 --> P2[P2: muse-studio 用户端]
  P0 --> P3[P3: muse-admin 管理端]
  P1 --> P4[P4: 集成切换]
  P2 --> P4
  P3 --> P4

前置条件

  • Spec: docs/superpowers/specs/2026-05-24-Muse四仓开发计划-design.md
  • 设计文档 SSOT: design-docs/ 下 30+ 份正式文档
  • AI 开发管理基线: docs/dev-baseline/ 下各仓规范
  • muse-cloud fork 完成Yudao Cloud
  • muse-admin fork 完成Vben Admin
  • muse-studio 需从零创建

Phase 0: API 契约冻结

仓库: muse-design-docs本仓 周期: Week 1-2 输入: design-docs/后端-05-统一API契约-v1.md767 行146+ 接口) 输出: 6 个模块的 OpenAPI 3.0 YAML + TypeScript 类型包 + Java DTO 骨架

Task 0.0: 准备工作

文件:

  • 创建: docs/api-contracts/openapi-base.yaml

  • 创建: docs/api-contracts/content/openapi.yaml

  • 创建: docs/api-contracts/ai/openapi.yaml

  • 创建: docs/api-contracts/knowledge/openapi.yaml

  • 创建: docs/api-contracts/market/openapi.yaml

  • 创建: docs/api-contracts/account/openapi.yaml

  • 创建: docs/api-contracts/meta/openapi.yaml

  • 创建: docs/api-contracts/generated/typescript/.gitkeep

  • 创建: docs/api-contracts/generated/java/.gitkeep

  • Step 1: 创建目录结构

mkdir -p docs/api-contracts/{content,ai,knowledge,market,account,meta,generated/typescript,generated/java}
  • Step 2: 提交空目录结构(含 .gitkeep
touch docs/api-contracts/generated/typescript/.gitkeep
touch docs/api-contracts/generated/java/.gitkeep
git add docs/api-contracts/
git commit -m "feat(api): 初始化 API 契约目录结构"

Task 0.1: 编写 openapi-base.yaml全局配置

文件:

  • 创建: docs/api-contracts/openapi-base.yaml

  • 参考: design-docs/后端-05-统一API契约-v1.md 全局约定章节

  • 参考: design-docs/架构-03-关键决策与原则(ADR).md ADR-010 (API 版本)

  • Step 1: 从设计文档提取全局配置信息

阅读 后端-05 中的:

  • 认证方式Bearer Token / OAuth2

  • 分页格式pageNo + pageSizeCommonResult 包裹)

  • 错误格式system-module-category-sequence 四段式错误码)

  • API 版本策略X-API-Version Header

  • 通用响应格式code + message + data

  • Step 2: 编写 openapi-base.yaml

openapi: 3.0.3
info:
  title: Muse API
  description: |
    Muse AI 驱动长篇创作平台统一 API 契约。
    所有接口通过 X-API-Version Header 进行版本控制。
  version: 1.0.0
  contact:
    name: Muse Team

servers:
  - url: http://localhost:48080
    description: 本地开发环境

security:
  - bearerAuth: []

components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: |
        用户端使用 app-api token管理端使用 admin-api token。
        两个端点的认证域独立token 不互通。

  parameters:
    XApiVersion:
      name: X-API-Version
      in: header
      required: false
      schema:
        type: string
        default: "2026-05-01"
      description: API 版本号,格式 YYYY-MM-DD

    pageNo:
      name: pageNo
      in: query
      required: false
      schema:
        type: integer
        minimum: 1
        default: 1
      description: 页码,从 1 开始

    pageSize:
      name: pageSize
      in: query
      required: false
      schema:
        type: integer
        minimum: 1
        maximum: 100
        default: 20
      description: 每页条数,上限 100

  schemas:
    CommonResult:
      type: object
      required: [code, message]
      properties:
        code:
          type: integer
          description: 业务状态码0 表示成功
          example: 0
        message:
          type: string
          description: 提示信息
          example: "操作成功"
        data:
          description: 响应数据,类型视具体接口而定

    PaginatedResult:
      type: object
      required: [total, pageNo, pageSize, list]
      properties:
        total:
          type: integer
          description: 总记录数
          example: 150
        pageNo:
          type: integer
          description: 当前页码
          example: 1
        pageSize:
          type: integer
          description: 每页条数
          example: 20
        list:
          type: array
          description: 当前页数据列表

    ErrorResponse:
      type: object
      required: [code, message]
      properties:
        code:
          type: string
          description: |
            错误码格式: {system}-{module}-{category}-{sequence}
            示例: MUSE-CONTENT-001-0001
          example: "MUSE-CONTENT-001-0001"
        message:
          type: string
          description: 人类可读的错误描述
        detail:
          type: string
          description: 详细错误信息(仅开发环境返回)

    # 通用时间戳字段
    TimestampMixin:
      type: object
      properties:
        createdAt:
          type: string
          format: date-time
          description: 创建时间
        updatedAt:
          type: string
          format: date-time
          description: 最后更新时间

  responses:
    BadRequest:
      description: 请求参数有误
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    Unauthorized:
      description: 未认证或 token 过期
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    Forbidden:
      description: 无权限
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    NotFound:
      description: 资源不存在
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    Conflict:
      description: 资源冲突
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    InternalError:
      description: 服务器内部错误
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'

tags:
  - name: Content
    description: 作品、章节、Block、导出
  - name: AI
    description: AI 生成、候选管理、智能体、质量门控
  - name: Knowledge
    description: 知识实体、关系、草稿、确认
  - name: Market
    description: 资产发布、安装绑定、审核
  - name: Account
    description: 权益、配额、用量、安全事件
  - name: Meta
    description: MetaSchema 字段定义、版本、scope
  • Step 3: 提交
git add docs/api-contracts/openapi-base.yaml
git commit -m "feat(api): 添加 OpenAPI 全局基础配置(认证/分页/错误格式/版本)"

Task 0.2: 编写 Content 模块 OpenAPI

文件:

  • 创建: docs/api-contracts/content/openapi.yaml

  • 参考: design-docs/后端-05-统一API契约-v1.md Content 模块章节

  • Step 1: 从 API 契约文档提取 Content 模块接口列表

Content 模块包含:

  • 作品(Work) CRUD

  • 章节(Chapter) CRUD + 排序

  • Block CRUD + 分割/合并

  • 导出TXT/EPUB/DOCX

  • Step 2: 编写 content/openapi.yaml

openapi: 3.0.3
info:
  title: Muse Content API
  version: 1.0.0

paths:
  # ========== 作品(Work) ==========
  /app-api/content/works:
    get:
      tags: [Content]
      summary: 获取作品列表
      operationId: listWorks
      parameters:
        - $ref: '../openapi-base.yaml#/components/parameters/pageNo'
        - $ref: '../openapi-base.yaml#/components/parameters/pageSize'
        - name: status
          in: query
          schema:
            type: string
            enum: [draft, active, archived]
          description: 作品状态过滤
      responses:
        '200':
          description: 作品分页列表
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '../openapi-base.yaml#/components/schemas/PaginatedResult'
                  - type: object
                    properties:
                      list:
                        type: array
                        items:
                          $ref: '#/components/schemas/WorkSummary'
    post:
      tags: [Content]
      summary: 创建新作品
      operationId: createWork
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [title]
              properties:
                title:
                  type: string
                  minLength: 1
                  maxLength: 200
                description:
                  type: string
                  maxLength: 2000
                genre:
                  type: string
                coverImageUrl:
                  type: string
                  format: uri
      responses:
        '201':
          description: 作品创建成功
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '../openapi-base.yaml#/components/schemas/CommonResult'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/Work'

  /app-api/content/works/{workId}:
    get:
      tags: [Content]
      summary: 获取作品详情
      operationId: getWork
      parameters:
        - name: workId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: 作品详情
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '../openapi-base.yaml#/components/schemas/CommonResult'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/Work'
    put:
      tags: [Content]
      summary: 更新作品
      operationId: updateWork
      parameters:
        - name: workId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                title:
                  type: string
                  maxLength: 200
                description:
                  type: string
                  maxLength: 2000
                genre:
                  type: string
                coverImageUrl:
                  type: string
                  format: uri
                status:
                  type: string
                  enum: [draft, active, archived]
      responses:
        '200':
          description: 更新成功
          content:
            application/json:
              schema:
                $ref: '../openapi-base.yaml#/components/schemas/CommonResult'
    delete:
      tags: [Content]
      summary: 删除作品
      operationId: deleteWork
      parameters:
        - name: workId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: 删除成功
        '404':
          $ref: '../openapi-base.yaml#/components/responses/NotFound'

  # ========== 章节(Chapter) ==========
  /app-api/content/works/{workId}/chapters:
    get:
      tags: [Content]
      summary: 获取作品章节列表
      operationId: listChapters
      parameters:
        - name: workId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: 章节列表(按 sortOrder 排序)
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '../openapi-base.yaml#/components/schemas/CommonResult'
                  - type: object
                    properties:
                      data:
                        type: array
                        items:
                          $ref: '#/components/schemas/Chapter'
    post:
      tags: [Content]
      summary: 创建章节
      operationId: createChapter
      parameters:
        - name: workId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [title]
              properties:
                title:
                  type: string
                  minLength: 1
                  maxLength: 500
                sortOrder:
                  type: integer
                  description: 插入位置,默认追加到末尾
      responses:
        '201':
          description: 创建成功
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '../openapi-base.yaml#/components/schemas/CommonResult'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/Chapter'

  /app-api/content/chapters/{chapterId}:
    get:
      tags: [Content]
      summary: 获取章节详情
      operationId: getChapter
      parameters:
        - name: chapterId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: 章节详情(含 Block 列表)
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '../openapi-base.yaml#/components/schemas/CommonResult'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/ChapterDetail'
    put:
      tags: [Content]
      summary: 更新章节
      operationId: updateChapter
      parameters:
        - name: chapterId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                title:
                  type: string
                  maxLength: 500
                sortOrder:
                  type: integer
                status:
                  type: string
                  enum: [draft, completed]
      responses:
        '200':
          description: 更新成功
    delete:
      tags: [Content]
      summary: 删除章节
      operationId: deleteChapter
      parameters:
        - name: chapterId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: 删除成功

  /app-api/content/chapters/{chapterId}/reorder:
    put:
      tags: [Content]
      summary: 调整章节排序
      operationId: reorderChapters
      parameters:
        - name: chapterId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [newSortOrder]
              properties:
                newSortOrder:
                  type: integer
                  minimum: 0
      responses:
        '200':
          description: 排序更新成功

  # ========== Block ==========
  /app-api/content/chapters/{chapterId}/blocks:
    get:
      tags: [Content]
      summary: 获取章节 Block 列表
      operationId: listBlocks
      parameters:
        - name: chapterId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: Block 列表
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '../openapi-base.yaml#/components/schemas/CommonResult'
                  - type: object
                    properties:
                      data:
                        type: array
                        items:
                          $ref: '#/components/schemas/Block'
    post:
      tags: [Content]
      summary: 创建 Block
      operationId: createBlock
      parameters:
        - name: chapterId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [content, blockType]
              properties:
                content:
                  type: string
                  description: Block 正文内容JSON 格式的 ProseMirror 文档)
                blockType:
                  type: string
                  enum: [scene, section, note]
                  description: Block 类型
                sortOrder:
                  type: integer
                title:
                  type: string
                  maxLength: 500
      responses:
        '201':
          description: 创建成功
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '../openapi-base.yaml#/components/schemas/CommonResult'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/Block'

  /app-api/content/blocks/{blockId}:
    get:
      tags: [Content]
      summary: 获取 Block 详情
      operationId: getBlock
      parameters:
        - name: blockId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: Block 详情
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '../openapi-base.yaml#/components/schemas/CommonResult'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/Block'
    put:
      tags: [Content]
      summary: 保存 Block 正文
      operationId: saveBlock
      parameters:
        - name: blockId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [content, sourceVersion]
              properties:
                content:
                  type: string
                  description: Block 正文ProseMirror JSON
                sourceVersion:
                  type: integer
                  description: 客户端持有的版本号,用于乐观锁冲突检测
      responses:
        '200':
          description: 保存成功
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '../openapi-base.yaml#/components/schemas/CommonResult'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          newVersion:
                            type: integer
                            description: 保存后的新版本号
        '409':
          description: 版本冲突,需客户端处理
          content:
            application/json:
              schema:
                $ref: '../openapi-base.yaml#/components/schemas/ErrorResponse'
    delete:
      tags: [Content]
      summary: 删除 Block
      operationId: deleteBlock
      parameters:
        - name: blockId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: 删除成功

  /app-api/content/blocks/{blockId}/split:
    post:
      tags: [Content]
      summary: 分割 Block
      operationId: splitBlock
      parameters:
        - name: blockId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [splitPosition]
              properties:
                splitPosition:
                  type: integer
                  description: 分割位置(字符偏移量)
      responses:
        '200':
          description: 分割成功,返回两个新 Block

  /app-api/content/blocks/{blockId}/merge:
    post:
      tags: [Content]
      summary: 合并 Block
      operationId: mergeBlocks
      parameters:
        - name: blockId
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 与下一个 Block 合并
      responses:
        '200':
          description: 合并成功

  # ========== 导出 ==========
  /app-api/content/works/{workId}/export:
    post:
      tags: [Content]
      summary: 导出作品
      operationId: exportWork
      parameters:
        - name: workId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [format]
              properties:
                format:
                  type: string
                  enum: [txt, epub, docx]
                includeChapters:
                  type: array
                  items:
                    type: string
                    format: uuid
                  description: 指定导出章节,空数组表示导出全部
      responses:
        '200':
          description: 导出任务已创建,返回任务 ID 供轮询
        '202':
          description: 导出文件二进制流(小文件直接返回)

components:
  schemas:
    Work:
      type: object
      required: [id, title, status, createdAt, updatedAt]
      properties:
        id:
          type: string
          format: uuid
        title:
          type: string
        description:
          type: string
        genre:
          type: string
        coverImageUrl:
          type: string
          format: uri
        status:
          type: string
          enum: [draft, active, archived]
        wordCount:
          type: integer
          description: 总字数
        chapterCount:
          type: integer
          description: 章节数
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time

    WorkSummary:
      type: object
      required: [id, title, status, updatedAt]
      properties:
        id:
          type: string
          format: uuid
        title:
          type: string
        genre:
          type: string
        status:
          type: string
          enum: [draft, active, archived]
        wordCount:
          type: integer
        chapterCount:
          type: integer
        updatedAt:
          type: string
          format: date-time

    Chapter:
      type: object
      required: [id, workId, title, sortOrder, status, createdAt, updatedAt]
      properties:
        id:
          type: string
          format: uuid
        workId:
          type: string
          format: uuid
        title:
          type: string
        sortOrder:
          type: integer
        status:
          type: string
          enum: [draft, completed]
        wordCount:
          type: integer
        blockCount:
          type: integer
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time

    ChapterDetail:
      allOf:
        - $ref: '#/components/schemas/Chapter'
        - type: object
          properties:
            blocks:
              type: array
              items:
                $ref: '#/components/schemas/Block'

    Block:
      type: object
      required: [id, chapterId, blockType, content, sortOrder, version, createdAt, updatedAt]
      properties:
        id:
          type: string
          format: uuid
        chapterId:
          type: string
          format: uuid
        blockType:
          type: string
          enum: [scene, section, note]
        title:
          type: string
        content:
          type: string
          description: ProseMirror JSON 格式的正文内容
        sortOrder:
          type: integer
        version:
          type: integer
          description: 乐观锁版本号,每次保存 +1
        wordCount:
          type: integer
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
  • Step 3: 提交
git add docs/api-contracts/content/openapi.yaml
git commit -m "feat(api): 添加 Content 模块 OpenAPI 契约(作品/章节/Block/导出)"

Task 0.3: 编写 AI 模块 OpenAPI

文件:

  • 创建: docs/api-contracts/ai/openapi.yaml

  • 参考: design-docs/后端-05-统一API契约-v1.md AI 模块章节

  • 参考: design-docs/专题-03-AI编排上下文与质量评测实现规范.md

  • Step 1: 提取 AI 模块接口

AI 模块包含:

  • 生成请求(提交生成任务)

  • 候选(Candidate)管理(列表、详情、接受/拒绝)

  • SSE 流式传输AI stream 独立端点)

  • 智能体(Agent)管理(创建、配置、槽位绑定)

  • 质量门控配置

  • Step 2: 编写 ai/openapi.yaml

openapi: 3.0.3
info:
  title: Muse AI API
  version: 1.0.0

paths:
  # ========== AI 生成 ==========
  /app-api/ai/generations:
    post:
      tags: [AI]
      summary: 提交 AI 生成请求
      operationId: requestGeneration
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [blockId, agentId]
              properties:
                blockId:
                  type: string
                  format: uuid
                  description: 目标 Block
                agentId:
                  type: string
                  format: uuid
                  description: 使用的智能体
                prompt:
                  type: string
                  description: 用户附加的提示词
                contextBlocks:
                  type: array
                  items:
                    type: string
                    format: uuid
                  description: 上下文 Block ID 列表
      responses:
        '202':
          description: 生成任务已提交
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '../openapi-base.yaml#/components/schemas/CommonResult'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          generationId:
                            type: string
                            format: uuid

  /app-api/ai/generations/{generationId}:
    get:
      tags: [AI]
      summary: 获取生成任务状态
      operationId: getGenerationStatus
      parameters:
        - name: generationId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: 生成状态
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '../openapi-base.yaml#/components/schemas/CommonResult'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/Generation'

  # ========== SSE: AI Stream独立连接 ==========
  /app-api/ai/generations/{generationId}/stream:
    get:
      tags: [AI]
      summary: AI 生成 SSE 流
      operationId: streamGeneration
      parameters:
        - name: generationId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: SSE 事件流
          content:
            text/event-stream:
              schema:
                type: string
                description: |
                  事件类型:
                  - chunk: { "content": "文本片段", "sequenceNo": 1 }
                  - quality_check: { "dimension": "fluency", "score": 0.92, "passed": true }
                  - done: { "generationId": "uuid", "candidateId": "uuid" }
                  - error: { "code": "...", "message": "..." }

  # ========== 候选(Candidate)管理 ==========
  /app-api/ai/candidates:
    get:
      tags: [AI]
      summary: 获取候选列表
      operationId: listCandidates
      parameters:
        - name: blockId
          in: query
          required: true
          schema:
            type: string
            format: uuid
        - name: status
          in: query
          schema:
            type: string
            enum: [pending, accepted, rejected]
      responses:
        '200':
          description: 候选列表
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '../openapi-base.yaml#/components/schemas/CommonResult'
                  - type: object
                    properties:
                      data:
                        type: array
                        items:
                          $ref: '#/components/schemas/Candidate'

  /app-api/ai/candidates/{candidateId}:
    get:
      tags: [AI]
      summary: 获取候选详情
      operationId: getCandidate
      parameters:
        - name: candidateId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: 候选详情(含生成内容 diff

  /app-api/ai/candidates/{candidateId}/accept:
    post:
      tags: [AI]
      summary: 接受候选
      operationId: acceptCandidate
      parameters:
        - name: candidateId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                modifications:
                  type: string
                  description: 用户在接受前对候选内容的手动修改
      responses:
        '200':
          description: 候选已接受Block 正文更新
        '409':
          description: 源版本已变更,需重新对比
          $ref: '../openapi-base.yaml#/components/responses/Conflict'

  /app-api/ai/candidates/{candidateId}/reject:
    post:
      tags: [AI]
      summary: 拒绝候选
      operationId: rejectCandidate
      parameters:
        - name: candidateId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                reason:
                  type: string
                  description: 拒绝原因(可选,用于改进生成质量)
      responses:
        '200':
          description: 已拒绝

  # ========== 智能体(Agent) ==========
  /app-api/ai/agents:
    get:
      tags: [AI]
      summary: 获取智能体列表
      operationId: listAgents
      parameters:
        - $ref: '../openapi-base.yaml#/components/parameters/pageNo'
        - $ref: '../openapi-base.yaml#/components/parameters/pageSize'
        - name: type
          in: query
          schema:
            type: string
            enum: [config, custom]
          description: 智能体类型
      responses:
        '200':
          description: 智能体分页列表
    post:
      tags: [AI]
      summary: 创建自定义智能体
      operationId: createAgent
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name]
              properties:
                name:
                  type: string
                  maxLength: 100
                description:
                  type: string
                  maxLength: 1000
                promptTemplate:
                  type: string
                  description: 系统提示词模板
                slotBindings:
                  type: object
                  description: 槽位绑定配置(知识库/MetaSchema/模型参数)
      responses:
        '201':
          description: 创建成功

  /app-api/ai/agents/{agentId}:
    get:
      tags: [AI]
      summary: 获取智能体详情
      operationId: getAgent
      parameters:
        - name: agentId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: 智能体详情
    put:
      tags: [AI]
      summary: 更新智能体配置
      operationId: updateAgent
      parameters:
        - name: agentId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                description:
                  type: string
                promptTemplate:
                  type: string
                slotBindings:
                  type: object
                status:
                  type: string
                  enum: [active, archived]
      responses:
        '200':
          description: 更新成功
    delete:
      tags: [AI]
      summary: 删除自定义智能体
      operationId: deleteAgent
      parameters:
        - name: agentId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: 删除成功

  # ========== 管理端: Prompt 模板管理 ==========
  /admin-api/ai/prompt-templates:
    get:
      tags: [AI]
      summary: 获取 Prompt 模板列表(管理端)
      operationId: adminListPromptTemplates
      parameters:
        - $ref: '../openapi-base.yaml#/components/parameters/pageNo'
        - $ref: '../openapi-base.yaml#/components/parameters/pageSize'
      responses:
        '200':
          description: 模板分页列表
    post:
      tags: [AI]
      summary: 创建 Prompt 模板(管理端)
      operationId: adminCreatePromptTemplate
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name, template]
              properties:
                name:
                  type: string
                template:
                  type: string
                variables:
                  type: array
                  items:
                    type: object
                    properties:
                      name:
                        type: string
                      type:
                        type: string
                        enum: [string, number, boolean]
                      required:
                        type: boolean
                      defaultValue:
                        type: string
      responses:
        '201':
          description: 创建成功

  /admin-api/ai/prompt-templates/{templateId}:
    put:
      tags: [AI]
      summary: 更新 Prompt 模板(管理端)
      operationId: adminUpdatePromptTemplate
      parameters:
        - name: templateId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: 更新成功
    delete:
      tags: [AI]
      summary: 删除 Prompt 模板(管理端)
      operationId: adminDeletePromptTemplate
      parameters:
        - name: templateId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: 删除成功

  # ========== 管理端: 质量门控配置 ==========
  /admin-api/ai/quality-gates:
    get:
      tags: [AI]
      summary: 获取质量门控维度列表
      operationId: adminListQualityGates
      responses:
        '200':
          description: 质量门控维度列表
    post:
      tags: [AI]
      summary: 创建质量门控维度
      operationId: adminCreateQualityGate
      responses:
        '201':
          description: 创建成功

  /admin-api/ai/protection-nodes:
    get:
      tags: [AI]
      summary: 获取保护节点列表
      operationId: adminListProtectionNodes
      responses:
        '200':
          description: 保护节点列表
    post:
      tags: [AI]
      summary: 注册保护节点
      operationId: adminCreateProtectionNode
      responses:
        '201':
          description: 注册成功

components:
  schemas:
    Generation:
      type: object
      required: [id, blockId, agentId, status, createdAt]
      properties:
        id:
          type: string
          format: uuid
        blockId:
          type: string
          format: uuid
        agentId:
          type: string
          format: uuid
        status:
          type: string
          enum: [pending, streaming, completed, failed]
        candidateId:
          type: string
          format: uuid
          description: 生成完成后关联的候选 ID
        errorMessage:
          type: string
        createdAt:
          type: string
          format: date-time

    Candidate:
      type: object
      required: [id, blockId, generationId, status, createdAt]
      properties:
        id:
          type: string
          format: uuid
        blockId:
          type: string
          format: uuid
        generationId:
          type: string
          format: uuid
        agentId:
          type: string
          format: uuid
        agentName:
          type: string
        status:
          type: string
          enum: [pending, accepted, rejected]
        sourceVersion:
          type: integer
          description: 生成时的源 Block 版本号
        diffSummary:
          type: string
          description: 变更摘要
        qualityScores:
          type: object
          description: 各质量维度的评分
        createdAt:
          type: string
          format: date-time
  • Step 3: 提交
git add docs/api-contracts/ai/openapi.yaml
git commit -m "feat(api): 添加 AI 模块 OpenAPI 契约(生成/候选/SSE/智能体/管理端配置)"

Task 0.4: 编写 Knowledge 模块 OpenAPI

文件:

  • 创建: docs/api-contracts/knowledge/openapi.yaml

  • 参考: design-docs/后端-05-统一API契约-v1.md Knowledge 模块章节

  • Step 1: 提取 Knowledge 模块接口

Knowledge 模块包含:

  • 知识实体(Entity) CRUD

  • 知识关系(Relation) CRUD

  • 知识草稿(Draft)管理

  • 自动确认 + 手动确认

  • 实体/关系可视化数据

  • 知识来源管理

  • Step 2: 编写 knowledge/openapi.yaml

openapi: 3.0.3
info:
  title: Muse Knowledge API
  version: 1.0.0

paths:
  # ========== 知识实体(Entity) ==========
  /app-api/knowledge/works/{workId}/entities:
    get:
      tags: [Knowledge]
      summary: 获取作品知识实体列表
      operationId: listEntities
      parameters:
        - name: workId
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: status
          in: query
          schema:
            type: string
            enum: [confirmed, draft, conflicted]
        - name: type
          in: query
          schema:
            type: string
            enum: [character, location, event, item, concept, note]
      responses:
        '200':
          description: 实体列表

  /app-api/knowledge/entities/{entityId}:
    get:
      tags: [Knowledge]
      summary: 获取知识实体详情
      operationId: getEntity
      parameters:
        - name: entityId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: 实体详情(含关联关系和来源引用)
    put:
      tags: [Knowledge]
      summary: 更新知识实体
      operationId: updateEntity
      parameters:
        - name: entityId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                description:
                  type: string
                attributes:
                  type: object
                  description: 自定义属性键值对
      responses:
        '200':
          description: 更新成功

  # ========== 知识确认 ==========
  /app-api/knowledge/entities/{entityId}/confirm:
    post:
      tags: [Knowledge]
      summary: 手动确认知识实体
      operationId: confirmEntity
      description: |
        知识实体的默认确认规则:
        - 无冲突 + 非外部来源 + 置信度 > 阈值 → 自动确认
        - 有冲突 或 外部来源 或 低置信度 → 需手动确认
      parameters:
        - name: entityId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                overrides:
                  type: object
                  description: 手动修正的属性值
      responses:
        '200':
          description: 确认成功

  /app-api/knowledge/entities/{entityId}/reject:
    post:
      tags: [Knowledge]
      summary: 拒绝知识实体草稿
      operationId: rejectEntity
      parameters:
        - name: entityId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                reason:
                  type: string
      responses:
        '200':
          description: 已拒绝

  # ========== 知识关系(Relation) ==========
  /app-api/knowledge/entities/{entityId}/relations:
    get:
      tags: [Knowledge]
      summary: 获取实体关联关系
      operationId: listRelations
      parameters:
        - name: entityId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: 关系列表
    post:
      tags: [Knowledge]
      summary: 创建知识关系
      operationId: createRelation
      parameters:
        - name: entityId
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: 源实体
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [targetEntityId, relationType]
              properties:
                targetEntityId:
                  type: string
                  format: uuid
                relationType:
                  type: string
                  example: "knows"
                description:
                  type: string
      responses:
        '201':
          description: 创建成功

  # ========== 知识图谱可视化 ==========
  /app-api/knowledge/works/{workId}/graph:
    get:
      tags: [Knowledge]
      summary: 获取知识图谱数据
      operationId: getKnowledgeGraph
      description: 返回节点和边的 JSON用于前端可视化渲染
      parameters:
        - name: workId
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: depth
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 3
            default: 2
          description: 图谱展开深度
      responses:
        '200':
          description: 图谱数据nodes + edges

  # ========== 知识草稿(Draft) ==========
  /app-api/knowledge/works/{workId}/drafts:
    get:
      tags: [Knowledge]
      summary: 获取待处理知识草稿列表
      operationId: listDrafts
      parameters:
        - name: workId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: 草稿列表
  • Step 3: 提交
git add docs/api-contracts/knowledge/openapi.yaml
git commit -m "feat(api): 添加 Knowledge 模块 OpenAPI 契约(实体/关系/草稿/确认/图谱)"

Task 0.5: 编写 Market 模块 OpenAPI

文件:

  • 创建: docs/api-contracts/market/openapi.yaml

  • 参考: design-docs/后端-05-统一API契约-v1.md Market 模块章节

  • Step 1: 提取 Market 模块接口

Market 模块包含:

  • 资产(Asset)浏览、搜索、安装

  • 资产发布(用户端提交 + 管理端审核)

  • 绑定管理

  • 管理端审核(上架/驳回/下架/召回)

  • Step 2: 编写 market/openapi.yaml

openapi: 3.0.3
info:
  title: Muse Market API
  version: 1.0.0

paths:
  # ========== 用户端: 市场浏览 ==========
  /app-api/market/assets:
    get:
      tags: [Market]
      summary: 浏览市场资产
      operationId: listAssets
      parameters:
        - $ref: '../openapi-base.yaml#/components/parameters/pageNo'
        - $ref: '../openapi-base.yaml#/components/parameters/pageSize'
        - name: type
          in: query
          schema:
            type: string
            enum: [agent, prompt_template, knowledge_source, metaschema]
        - name: keyword
          in: query
          schema:
            type: string
          description: 搜索关键词
        - name: sortBy
          in: query
          schema:
            type: string
            enum: [popular, newest, rating]
            default: popular
      responses:
        '200':
          description: 资产分页列表

  /app-api/market/assets/{assetId}:
    get:
      tags: [Market]
      summary: 获取资产详情
      operationId: getAsset
      parameters:
        - name: assetId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: 资产详情

  # ========== 用户端: 安装与绑定 ==========
  /app-api/market/assets/{assetId}/install:
    post:
      tags: [Market]
      summary: 安装资产到我的工作区
      operationId: installAsset
      parameters:
        - name: assetId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '201':
          description: 安装成功

  /app-api/market/installations:
    get:
      tags: [Market]
      summary: 获取我的已安装资产
      operationId: listInstallations
      responses:
        '200':
          description: 已安装资产列表

  /app-api/market/installations/{installationId}/bindings:
    post:
      tags: [Market]
      summary: 绑定已安装资产到作品
      operationId: bindInstallation
      parameters:
        - name: installationId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [workId]
              properties:
                workId:
                  type: string
                  format: uuid
                slotConfig:
                  type: object
                  description: 槽位配置
      responses:
        '201':
          description: 绑定成功
    get:
      tags: [Market]
      summary: 获取资产的作品绑定列表
      operationId: listBindings
      parameters:
        - name: installationId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: 绑定列表

  # ========== 用户端: 资产发布 ==========
  /app-api/market/publish:
    post:
      tags: [Market]
      summary: 发布资产到市场
      operationId: publishAsset
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name, type, sourceId]
              properties:
                name:
                  type: string
                  maxLength: 200
                description:
                  type: string
                  maxLength: 5000
                type:
                  type: string
                  enum: [agent, prompt_template, knowledge_source, metaschema]
                sourceId:
                  type: string
                  format: uuid
                  description: 来源对象 ID
                tags:
                  type: array
                  items:
                    type: string
                coverImageUrl:
                  type: string
                  format: uri
      responses:
        '201':
          description: 发布申请已提交,待审核

  # ========== 管理端: 资产审核 ==========
  /admin-api/market/reviews:
    get:
      tags: [Market]
      summary: 获取待审核资产列表
      operationId: adminListReviews
      parameters:
        - $ref: '../openapi-base.yaml#/components/parameters/pageNo'
        - $ref: '../openapi-base.yaml#/components/parameters/pageSize'
        - name: status
          in: query
          schema:
            type: string
            enum: [pending, approved, rejected]
      responses:
        '200':
          description: 审核列表

  /admin-api/market/reviews/{reviewId}/approve:
    post:
      tags: [Market]
      summary: 审核通过
      operationId: adminApproveAsset
      parameters:
        - name: reviewId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                note:
                  type: string
      responses:
        '200':
          description: 已上架

  /admin-api/market/reviews/{reviewId}/reject:
    post:
      tags: [Market]
      summary: 审核驳回
      operationId: adminRejectAsset
      parameters:
        - name: reviewId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [reason]
              properties:
                reason:
                  type: string
      responses:
        '200':
          description: 已驳回

  /admin-api/market/assets/{assetId}/delist:
    post:
      tags: [Market]
      summary: 下架资产
      operationId: adminDelistAsset
      parameters:
        - name: assetId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [reason]
              properties:
                reason:
                  type: string
      responses:
        '200':
          description: 已下架

  /admin-api/market/assets/{assetId}/recall:
    post:
      tags: [Market]
      summary: 召回已安装资产
      operationId: adminRecallAsset
      parameters:
        - name: assetId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [reason]
              properties:
                reason:
                  type: string
      responses:
        '200':
          description: 已触发召回
  • Step 3: 提交
git add docs/api-contracts/market/openapi.yaml
git commit -m "feat(api): 添加 Market 模块 OpenAPI 契约(浏览/安装/绑定/审核)"

Task 0.6: 编写 Account 模块 OpenAPI

文件:

  • 创建: docs/api-contracts/account/openapi.yaml

  • 参考: design-docs/后端-05-统一API契约-v1.md Account 模块章节

  • Step 1: 提取 Account 模块接口

Account 模块包含:

  • 权益(Entitlement)查询

  • 配额(Quota)查询 + 消费

  • Token 用量统计

  • 安全事件记录

  • Step 2: 编写 account/openapi.yaml

openapi: 3.0.3
info:
  title: Muse Account API
  version: 1.0.0

paths:
  # ========== 权益(Entitlement) ==========
  /app-api/account/entitlements:
    get:
      tags: [Account]
      summary: 获取当前用户权益列表
      operationId: listEntitlements
      responses:
        '200':
          description: 权益列表
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '../openapi-base.yaml#/components/schemas/CommonResult'
                  - type: object
                    properties:
                      data:
                        type: array
                        items:
                          $ref: '#/components/schemas/Entitlement'

  # ========== 配额(Quota) ==========
  /app-api/account/quotas:
    get:
      tags: [Account]
      summary: 获取当前用户配额
      operationId: listQuotas
      responses:
        '200':
          description: 配额列表
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '../openapi-base.yaml#/components/schemas/CommonResult'
                  - type: object
                    properties:
                      data:
                        type: array
                        items:
                          $ref: '#/components/schemas/Quota'

  # ========== 用量(Usage) ==========
  /app-api/account/usage/summary:
    get:
      tags: [Account]
      summary: 获取用量摘要
      operationId: getUsageSummary
      parameters:
        - name: period
          in: query
          schema:
            type: string
            enum: [today, week, month, billing_cycle]
            default: month
      responses:
        '200':
          description: 用量摘要
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '../openapi-base.yaml#/components/schemas/CommonResult'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/UsageSummary'

  /app-api/account/usage/tokens:
    get:
      tags: [Account]
      summary: 获取 Token 用量明细
      operationId: getTokenUsage
      parameters:
        - name: startDate
          in: query
          schema:
            type: string
            format: date
        - name: endDate
          in: query
          schema:
            type: string
            format: date
      responses:
        '200':
          description: Token 用量明细

  # ========== 安全事件 ==========
  /app-api/account/security-events:
    get:
      tags: [Account]
      summary: 获取安全事件列表
      operationId: listSecurityEvents
      parameters:
        - $ref: '../openapi-base.yaml#/components/parameters/pageNo'
        - $ref: '../openapi-base.yaml#/components/parameters/pageSize'
      responses:
        '200':
          description: 安全事件分页列表

  # ========== 管理端 ==========
  /admin-api/account/entitlements/{userId}:
    get:
      tags: [Account]
      summary: 查看用户权益(管理端)
      operationId: adminGetUserEntitlements
      parameters:
        - name: userId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: 用户权益详情
    put:
      tags: [Account]
      summary: 修改用户权益(管理端)
      operationId: adminUpdateUserEntitlements
      parameters:
        - name: userId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [entitlements]
              properties:
                entitlements:
                  type: array
                  items:
                    type: object
                    properties:
                      resourceType:
                        type: string
                      limit:
                        type: integer
                      expiresAt:
                        type: string
                        format: date-time
                reason:
                  type: string
                  description: 变更原因(写入审计日志)
      responses:
        '200':
          description: 更新成功

components:
  schemas:
    Entitlement:
      type: object
      required: [id, resourceType, limit, used, expiresAt]
      properties:
        id:
          type: string
          format: uuid
        resourceType:
          type: string
          description: 权益资源类型
        limit:
          type: integer
          description: 额度上限(-1 表示无限制)
        used:
          type: integer
          description: 已使用量
        expiresAt:
          type: string
          format: date-time

    Quota:
      type: object
      required: [id, resourceType, total, remaining, resetAt]
      properties:
        id:
          type: string
          format: uuid
        resourceType:
          type: string
        total:
          type: integer
        remaining:
          type: integer
        resetAt:
          type: string
          format: date-time
          description: 配额重置时间

    UsageSummary:
      type: object
      properties:
        totalTokens:
          type: integer
        totalGenerations:
          type: integer
        byModel:
          type: object
          description: 按模型的用量分布
        byDate:
          type: array
          items:
            type: object
            properties:
              date:
                type: string
                format: date
              tokens:
                type: integer
              generations:
                type: integer
  • Step 3: 提交
git add docs/api-contracts/account/openapi.yaml
git commit -m "feat(api): 添加 Account 模块 OpenAPI 契约(权益/配额/用量/安全事件)"

Task 0.7: 编写 Meta 模块 OpenAPI

文件:

  • 创建: docs/api-contracts/meta/openapi.yaml

  • 参考: design-docs/后端-05-统一API契约-v1.md Meta 模块章节

  • Step 1: 提取 Meta 模块接口

Meta 模块包含 MetaSchema 的完整管理:

  • 字段定义 CRUD

  • 版本管理

  • Scope 配置(全局/租户/用户/作品)

  • Step 2: 编写 meta/openapi.yaml

openapi: 3.0.3
info:
  title: Muse MetaSchema API
  version: 1.0.0

paths:
  # ========== 字段定义 ==========
  /admin-api/meta/schemas:
    get:
      tags: [Meta]
      summary: 获取 MetaSchema 列表
      operationId: adminListSchemas
      parameters:
        - $ref: '../openapi-base.yaml#/components/parameters/pageNo'
        - $ref: '../openapi-base.yaml#/components/parameters/pageSize'
        - name: scope
          in: query
          schema:
            type: string
            enum: [global, tenant, user, work]
      responses:
        '200':
          description: MetaSchema 分页列表
    post:
      tags: [Meta]
      summary: 创建 MetaSchema 定义
      operationId: adminCreateSchema
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name, fieldType, scope]
              properties:
                name:
                  type: string
                  description: 字段名(英文标识)
                displayName:
                  type: string
                  description: 显示名称
                fieldType:
                  type: string
                  enum: [string, text, number, boolean, date, enum, relation, json]
                scope:
                  type: string
                  enum: [global, tenant, user, work]
                  description: 作用域
                defaultValue:
                  description: 默认值
                required:
                  type: boolean
                  default: false
                enumValues:
                  type: array
                  items:
                    type: string
                  description: fieldType=enum 时的可选值
                validationRules:
                  type: object
                  description: 校验规则min/max/pattern 等)
      responses:
        '201':
          description: 创建成功

  /admin-api/meta/schemas/{schemaId}:
    get:
      tags: [Meta]
      summary: 获取 MetaSchema 详情
      operationId: adminGetSchema
      parameters:
        - name: schemaId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: MetaSchema 详情(含版本历史)
    put:
      tags: [Meta]
      summary: 更新 MetaSchema 定义
      operationId: adminUpdateSchema
      parameters:
        - name: schemaId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                displayName:
                  type: string
                defaultValue:
                  description: 默认值
                required:
                  type: boolean
                enumValues:
                  type: array
                  items:
                    type: string
                validationRules:
                  type: object
      responses:
        '200':
          description: 更新成功(自动创建新版本)
    delete:
      tags: [Meta]
      summary: 删除 MetaSchema 定义
      operationId: adminDeleteSchema
      parameters:
        - name: schemaId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: 删除成功(软删除,已有数据不受影响)
        '409':
          description: 有数据引用时不允许删除
          $ref: '../openapi-base.yaml#/components/responses/Conflict'

  # ========== 版本管理 ==========
  /admin-api/meta/schemas/{schemaId}/versions:
    get:
      tags: [Meta]
      summary: 获取 MetaSchema 版本历史
      operationId: adminListSchemaVersions
      parameters:
        - name: schemaId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: 版本历史列表

  /admin-api/meta/schemas/{schemaId}/versions/{version}:
    get:
      tags: [Meta]
      summary: 获取指定版本详情
      operationId: adminGetSchemaVersion
      parameters:
        - name: schemaId
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: version
          in: path
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: 版本详情

  /admin-api/meta/schemas/{schemaId}/rollback:
    post:
      tags: [Meta]
      summary: 回滚到指定版本
      operationId: adminRollbackSchema
      parameters:
        - name: schemaId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [targetVersion]
              properties:
                targetVersion:
                  type: integer
                reason:
                  type: string
      responses:
        '200':
          description: 回滚成功,创建新版本指向目标版本配置
  • Step 3: 提交
git add docs/api-contracts/meta/openapi.yaml
git commit -m "feat(api): 添加 Meta 模块 OpenAPI 契约MetaSchema CRUD/版本/回滚)"

Task 0.8: 契约完整性校验

  • Step 1: 接口数量验证

统计各模块接口数,与 后端-05 设计文档对照:

echo "=== Content ===" && grep -c "operationId:" docs/api-contracts/content/openapi.yaml
echo "=== AI ===" && grep -c "operationId:" docs/api-contracts/ai/openapi.yaml
echo "=== Knowledge ===" && grep -c "operationId:" docs/api-contracts/knowledge/openapi.yaml
echo "=== Market ===" && grep -c "operationId:" docs/api-contracts/market/openapi.yaml
echo "=== Account ===" && grep -c "operationId:" docs/api-contracts/account/openapi.yaml
echo "=== Meta ===" && grep -c "operationId:" docs/api-contracts/meta/openapi.yaml
echo "=== Total ===" && grep -r "operationId:" docs/api-contracts/*/openapi.yaml docs/api-contracts/openapi-base.yaml 2>/dev/null | wc -l
  • Step 2: YAML 语法校验
# 使用 Python 校验所有 YAML 文件
python3 -c "
import yaml, sys, glob
errors = []
for f in glob.glob('docs/api-contracts/**/*.yaml', recursive=True):
    try:
        with open(f) as fh:
            yaml.safe_load(fh)
        print(f'OK: {f}')
    except Exception as e:
        errors.append(f'{f}: {e}')
        print(f'FAIL: {f}: {e}')
if errors:
    print(f'\n{len(errors)} file(s) failed')
    sys.exit(1)
else:
    print('\nAll files valid')
"
  • Step 3: 交叉引用检查

确认各模块 YAML 中的 $ref 路径正确指向 openapi-base.yaml,且被引用的 schema/response/parameter 确实存在。

  • Step 4: 与设计文档一致性复查

逐模块对比 后端-05-统一API契约-v1.md

  • 接口路径是否一致

  • HTTP 方法是否一致

  • 路径参数名是否一致

  • Request/Response body 字段是否覆盖

  • Step 5: 提交

git add docs/api-contracts/
git commit -m "feat(api): 完成 6 个模块 OpenAPI 契约文件 + 完整性校验通过"

Task 0.9: 生成 TypeScript 类型包

文件:

  • 创建: docs/api-contracts/generated/typescript/ 下的类型文件

  • 工具: openapi-typescript + openapi-fetch

  • Step 1: 安装代码生成工具

# 在仓库根目录安装(或使用 npx
npm init -y --prefix /tmp/muse-api-gen
cd /tmp/muse-api-gen
npm install openapi-typescript @hey-api/openapi-ts
  • Step 2: 合并所有模块 YAML 为单一入口
# 创建合并入口文件
cat > /tmp/muse-api-gen/openapi-merged.yaml << 'YAMLEND'
openapi: 3.0.3
info:
  title: Muse API (Merged)
  version: 1.0.0
paths: {}
components:
  schemas: {}
YAMLEND

# 使用 yq 或手动合并各模块 paths
# 此处用简单方式:为每个模块分别生成类型,再合并 index.ts
  • Step 3: 为每个模块生成 TypeScript 类型
cd /tmp/muse-api-gen
for module in content ai knowledge market account meta; do
  npx openapi-typescript \
    "/Users/qingse/Sync/local-git/oh-my-muse/docs/api-contracts/${module}/openapi.yaml" \
    --output "/Users/qingse/Sync/local-git/oh-my-muse/docs/api-contracts/generated/typescript/${module}.ts"
done
  • Step 4: 生成共享组件类型
npx openapi-typescript \
  "/Users/qingse/Sync/local-git/oh-my-muse/docs/api-contracts/openapi-base.yaml" \
  --output "/Users/qingse/Sync/local-git/oh-my-muse/docs/api-contracts/generated/typescript/base.ts"
  • Step 5: 编写 barrel 导出文件
// docs/api-contracts/generated/typescript/index.ts
// Muse API TypeScript 类型包入口
// 自动生成于 OpenAPI 3.0 契约文件,请勿手动编辑

export * from './base';
export * from './content';
export * from './ai';
export * from './knowledge';
export * from './market';
export * from './account';
export * from './meta';

// 重新导出通用工具类型
export type {
  CommonResult,
  PaginatedResult,
  ErrorResponse,
  TimestampMixin,
} from './base';
  • Step 6: 提交
git add docs/api-contracts/generated/typescript/
git commit -m "feat(api): 从 OpenAPI 生成 TypeScript 类型包6 模块 + base"

Task 0.10: 生成 Java DTO 骨架

文件:

  • 创建: docs/api-contracts/generated/java/ 下的 DTO 类

  • 工具: openapi-generator-cli

  • Step 1: 准备 OpenAPI Generator 配置

# 创建生成器配置
cat > /tmp/muse-api-gen/openapi-generator-config.yaml << 'EOF'
# OpenAPI Generator 配置 for Java DTO
generatorName: spring
library: spring-boot
inputSpec: /tmp/muse-api-gen/openapi-merged.yaml
outputDir: /Users/qingse/Sync/local-git/oh-my-muse/docs/api-contracts/generated/java
apiPackage: com.muse.api
modelPackage: com.muse.dto
generateApis: false
generateModels: true
generateApiTests: false
generateModelTests: false
generateApiDocumentation: false
generateModelDocumentation: false
skipValidateSpec: true
additionalProperties:
  java21: true
  useSpringBoot3: true
  useJakartaEe: true
  dateLibrary: java8
  serializableModel: true
  openApiNullable: false
EOF
  • Step 2: 执行代码生成
npx @openapitools/openapi-generator-cli generate \
  -c /tmp/muse-api-gen/openapi-generator-config.yaml
  • Step 3: 清理不需要的生成文件
# 只保留 model/DTO 类,删除 API 接口和测试文件
rm -rf docs/api-contracts/generated/java/api/
rm -rf docs/api-contracts/generated/java/test/
rm -f docs/api-contracts/generated/java/pom.xml
rm -f docs/api-contracts/generated/java/README.md
  • Step 4: 提交
git add docs/api-contracts/generated/java/
git commit -m "feat(api): 从 OpenAPI 生成 Java DTO 骨架6 模块)"

Phase 0 完成标准

  • 6 个模块的 openapi.yaml 全部通过 YAML 语法校验
  • 接口总数 ≥ 146与设计文档对齐
  • 交叉引用 $ref 路径全部有效
  • TypeScript 类型包生成无报错
  • Java DTO 骨架生成无报错
  • 所有提交已推送到 gitea

Phase 1-2 子计划概览

以下子计划在 Phase 0 完成后分别在各仓创建和展开:

P1: muse-cloud 后端搭建Week 3-16

Step 内容 周期 关键输出
1.1 Yudao Cloud 基础调整包名、Docker Compose、.idea Week 3 可启动的开发环境
1.2 数据库 Migration全量 DDL + Flyway Week 3-4 建表 SQL 已执行
1.3 6 个业务模块骨架 Week 5-8 pom.xml + 包结构 + API 接口定义
1.4 API 实现 Phase 1.1: content + account Week 9-10 作品/章节/Block/权益/配额 API
1.5 API 实现 Phase 1.2: meta Week 11 MetaSchema CRUD API
1.6 API 实现 Phase 1.3: ai + knowledge Week 12-14 AI 生成/候选/智能体 + 知识实体/关系
1.7 API 实现 Phase 1.4: market Week 15-16 市场浏览/发布/审核 API

P2: muse-studio 用户端搭建Week 3-16

Step 内容 周期 关键输出
2.1 工程脚手架Vite + React + TS + Tailwind + 路由) Week 3-4 可启动的空 SPA
2.2 核心基础设施MSW + SSE + IndexedDB + Zustand Week 5-8 Mock API 全覆盖
2.3 写作台(编辑器 + AI 生成 + 候选面板) Week 9-12 核心创作流程
2.4 我的作品 + 工作台(列表/章节/Block Week 13-14 作品管理
2.5 知识库 + 智能体 + 市场 + 个人中心 Week 15-16 辅助功能

P3: muse-admin 管理端搭建Week 3-16

Step 内容 周期 关键输出
3.1 工程脚手架Vben Admin + 目录组织 + Mock Week 3-4 可启动的管理端
3.2 MetaSchema 管理页面 Week 5-8 字段定义/版本/回滚
3.3 系统治理页面 Week 9-12 用户/角色/审计
3.4 AI 配置 + 市场治理 + 全局知识 Week 13-16 管理端完整

P4: 集成切换 + 质量加固Week 9-18

Step 内容 周期
4.1 content+account 集成切换 Week 9-10
4.2 meta 集成切换 Week 11
4.3 ai+knowledge 集成切换 Week 12-14
4.4 market 集成切换 Week 15-16
4.5 全量质量加固(测试/CI/安全) Week 17-18

下一步

Phase 0 执行完成后:

  1. 输出 6 个模块的 OpenAPI YAML + TypeScript 类型 + Java DTO
  2. 创建 P1-P4 子计划(在各仓分别展开为详细任务)
  3. 三仓并行启动 Phase 1