openapi: 3.0.3
info:
  title: 独行录 OPC 发现 API
  description: >-
    独行录（opcmenu）= 一人公司 / 主理人（OPC）发现网络，构建 OPC 之间的产业链。本 OpenAPI 暴露**公开免登录**的只读检索能力，
    供国产 agent 平台（扣子 Coze、腾讯元器等只吃 OpenAPI 插件的商店）以「工具插件」形式接入：
    用自然语言检索产品、主理人、需求、活动、公司、OPC 园区与社区动态。
    典型组合链：searchNeeds/listNeedsFeed 找到需求 → getNeed 看详情 → searchPeople 找能提供对应价值的主理人；
    listParks 按补贴类型筛园区 → getPark 看补贴明细，可替用户汇总成对比表。
    写操作（认领产品 / 发消息 / 接洽需求 / 报名）不在本 spec，需登录走 MCP / 鉴权 API。
  version: "1.1.0"
  contact:
    name: 独行录
    url: https://opcmenu.com
servers:
  - url: https://api.opcmenu.com
    description: 生产环境
tags:
  - name: 检索
    description: 公开只读检索（无需鉴权）
  - name: 需求互换
    description: 主理人需求互换 feed 与需求检索（平台核心循环，无需鉴权）
  - name: 园区
    description: OPC 园区目录 + 补贴筛选（无需鉴权）
  - name: 社区
    description: 社区动态（无需鉴权）
paths:
  /v1/search/products:
    get:
      operationId: searchProducts
      tags: [检索]
      summary: 语义搜索 OPC 产品
      description: >-
        用户用自然语言找产品时调用，例如「有没有给独立开发者用的财务工具」「记笔记的极简 app」「Notion 替代品」。
        先走向量召回（embedding），召回不到再 fallback 到关键词。返回按相关度排序的产品卡片。
        注意：本接口只管产品；找主理人 / 找人合作用 searchPeople。
        「什么是独行录」「如何注册」这类站点 meta 问题也不要用本接口。
      parameters:
        - name: q
          in: query
          required: true
          description: 搜索查询，自然语言或关键词
          schema: { type: string, minLength: 1 }
        - name: limit
          in: query
          required: false
          description: 返回条数，默认 12，最多 30
          schema: { type: integer, minimum: 1, maximum: 30, default: 12 }
      responses:
        "200":
          description: 检索结果
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok: { type: boolean, example: true }
                  data:
                    type: object
                    properties:
                      results:
                        type: array
                        items: { $ref: "#/components/schemas/ProductSearchHit" }
                      mode:
                        type: string
                        description: 实际走的检索路径
                        enum: [hybrid, vector, keyword]
                      reranked: { type: boolean }
  /v1/products:
    get:
      operationId: listProducts
      tags: [检索]
      summary: 列产品榜单（热门/今日/随机/月榜）
      description: >-
        用户想「逛逛」「看热门」「今日新品」「月度榜」时调用，比语义搜索更适合无明确意图的浏览。
      parameters:
        - name: type
          in: query
          required: false
          description: >-
            榜单类型：hottest=综合热度（默认）；today=今日新品；random=随机逛逛；leaderboard=上月榜。
          schema:
            type: string
            enum: [hottest, today, random, leaderboard]
            default: hottest
        - name: limit
          in: query
          required: false
          description: 返回条数，默认 12，最多 50
          schema: { type: integer, minimum: 1, maximum: 50, default: 12 }
      responses:
        "200":
          description: 产品列表
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok: { type: boolean }
                  data:
                    type: object
                    properties:
                      items:
                        type: array
                        items: { $ref: "#/components/schemas/ProductCard" }
  /v1/products/{id}:
    get:
      operationId: getProduct
      tags: [检索]
      summary: 取单个产品详情
      description: 按产品 id（检索/列表结果里的 id 字段）取完整详情，含描述、主理人、链接等。
      parameters:
        - name: id
          in: path
          required: true
          description: 产品 id（来自 searchProducts / listProducts 结果的 id 字段）
          schema: { type: string }
      responses:
        "200":
          description: 产品详情
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok: { type: boolean }
                  data:
                    type: object
                    properties:
                      product: { $ref: "#/components/schemas/ProductDetail" }
        "404":
          description: 未找到
          content:
            application/json:
              schema: { $ref: "#/components/schemas/ErrorResponse" }
  /v1/products/{id}/ratings:
    get:
      operationId: getProductRatings
      tags: [检索]
      summary: 产品口碑：评价列表 + 评分聚合
      description: >-
        尽调 / 选品场景：拉某产品的用户评价与评分分布。典型组合链：searchProducts 找到产品 →
        getProduct 看介绍 → getProductRatings 看真实口碑（平均分、1-5 星分布、逐条评价），
        agent 可据此替用户汇总「值不值得用 / 值不值得聊合作」的判断依据。
        summary.avg 为平均分（保留 1 位小数），summary.distribution 为各星级条数。
      parameters:
        - name: id
          in: path
          required: true
          description: 产品 id
          schema: { type: string }
        - name: sort
          in: query
          required: false
          description: 排序：recent=最新（默认）；helpful=最有用（按「有用」票数）
          schema:
            type: string
            enum: [recent, helpful]
            default: recent
        - name: limit
          in: query
          required: false
          description: 返回条数，默认 20，最多 50
          schema: { type: integer, minimum: 1, maximum: 50, default: 20 }
        - name: cursor
          in: query
          required: false
          description: 分页游标（上一页返回的 nextCursor）
          schema: { type: string }
      responses:
        "200":
          description: 评价列表与聚合摘要
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok: { type: boolean }
                  data:
                    type: object
                    properties:
                      summary: { $ref: "#/components/schemas/RatingSummary" }
                      items:
                        type: array
                        items: { $ref: "#/components/schemas/RatingCard" }
                      nextCursor:
                        type: string
                        nullable: true
  /v1/creators:
    get:
      operationId: listCreators
      tags: [检索]
      summary: 最热主理人目录
      description: 列出最热门的 OPC 主理人/创客（已认领账号优先）。用户想「看看有哪些创始人/主理人」时调用。
      parameters:
        - name: limit
          in: query
          required: false
          description: 返回条数，默认 20，最多 50
          schema: { type: integer, minimum: 1, maximum: 50, default: 20 }
      responses:
        "200":
          description: 主理人列表
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok: { type: boolean }
                  data:
                    type: object
                    properties:
                      items:
                        type: array
                        items: { $ref: "#/components/schemas/Creator" }
  /v1/search/people:
    get:
      operationId: searchPeople
      tags: [检索]
      summary: 搜主理人/超级个体（按「能提供什么价值」）
      description: >-
        混合检索主理人：昵称/简介/「能提供什么价值」关键词 + 语义向量融合。
        与 listCreators（热度榜）不同，本接口适合带意图的找人，例如「找能提供供应链资源的主理人」
        「懂跨境电商合规的人」。结果卡主打 canOffer（对方能提供什么），真人账号排前。
        典型组合链：listNeedsFeed/getNeed 看到一条需求 → searchPeople 找能满足它的人；
        agent 也可以批量跑多个查询词，替用户做候选人对比表。
      parameters:
        - name: q
          in: query
          required: true
          description: 搜索查询：技能、资源、身份或昵称，自然语言即可
          schema: { type: string, minLength: 1 }
        - name: limit
          in: query
          required: false
          description: 返回条数，默认 20，最多 50
          schema: { type: integer, minimum: 1, maximum: 50, default: 20 }
      responses:
        "200":
          description: 主理人检索结果（按相关度排序）
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok: { type: boolean }
                  data:
                    type: object
                    properties:
                      results:
                        type: array
                        items: { $ref: "#/components/schemas/PersonHit" }
  /v1/needs:
    get:
      operationId: listNeedsFeed
      tags: [需求互换]
      summary: 需求互换 feed（按主理人聚合，一人一卡）
      description: >-
        平台核心的需求互换信息流：每张卡是一位主理人，主卡展示其最匹配的一条需求，
        authorNeeds 数组带上该作者在架需求（最多 6 条，主卡需求在首位），并附作者的 canOffer
        （能提供什么价值）与代表产品——看一张卡即可判断「他要什么 + 他能给什么」。
        用户想「看看大家最近在找什么合作 / 有没有我能接的需求」时调用。
        未登录调用退化为非个性化排序，仍按人聚合出卡。
        典型组合链：本接口浏览 → getNeed 看某条需求详情 → searchPeople 找还有谁能满足它；
        接洽（找他聊聊）需登录，不在本 spec。
      parameters:
        - name: feed
          in: query
          required: true
          description: 固定传 1，表示走按主理人聚合的推荐 feed
          schema: { type: string, enum: ["1"] }
        - name: type
          in: query
          required: false
          description: >-
            按需求类型筛选：EXPERIENCE=寻找产品/作品；QA=答疑求助；RESOURCE=介绍资源；
            COLLAB=寻求合作；FINANCING=融资需求；CHAT=找人聊聊找灵感；OTHER=其它。
          schema:
            type: string
            enum: [EXPERIENCE, QA, RESOURCE, COLLAB, FINANCING, CHAT, OTHER]
        - name: limit
          in: query
          required: false
          description: 返回卡片数（人数），默认 20，最多 50
          schema: { type: integer, minimum: 1, maximum: 50, default: 20 }
        - name: cursor
          in: query
          required: false
          description: 分页游标（上一页返回的 nextCursor）
          schema: { type: string }
      responses:
        "200":
          description: 需求 feed（一人一卡）
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok: { type: boolean }
                  data:
                    type: object
                    properties:
                      items:
                        type: array
                        items: { $ref: "#/components/schemas/NeedFeedItem" }
                      nextCursor:
                        type: string
                        nullable: true
  /v1/needs/{id}:
    get:
      operationId: getNeed
      tags: [需求互换]
      summary: 取单条需求详情
      description: >-
        按需求 id（feed / 搜索结果里的 id 字段）取完整详情，含需求描述、完成条件、配图与作者信息
        （canOffer + 代表产品）。适合在向用户转述某条需求前拉全量上下文。
      parameters:
        - name: id
          in: path
          required: true
          description: 需求 id（来自 listNeedsFeed / searchNeeds 结果的 id 字段）
          schema: { type: string }
      responses:
        "200":
          description: 需求详情
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok: { type: boolean }
                  data:
                    type: object
                    properties:
                      need: { $ref: "#/components/schemas/NeedCard" }
        "404":
          description: 未找到
          content:
            application/json:
              schema: { $ref: "#/components/schemas/ErrorResponse" }
  /v1/search/needs:
    get:
      operationId: searchNeeds
      tags: [需求互换]
      summary: 搜需求（标题/详情，关键词 + 语义混合）
      description: >-
        带意图地找需求，例如「有没有人在找播客合作」「谁需要供应链资源」「找人合作做线下市集」。
        关键词与语义向量融合召回，按相关度排序。与 listNeedsFeed（逛）互补：feed 适合无明确意图浏览，
        本接口适合精确命中。结果与 feed 同一卡片契约，可直接接 getNeed 或 searchPeople 继续。
      parameters:
        - name: q
          in: query
          required: true
          description: 搜索查询，自然语言或关键词
          schema: { type: string, minLength: 1 }
        - name: limit
          in: query
          required: false
          description: 返回条数，默认 20，最多 50
          schema: { type: integer, minimum: 1, maximum: 50, default: 20 }
      responses:
        "200":
          description: 需求检索结果（按相关度排序）
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok: { type: boolean }
                  data:
                    type: object
                    properties:
                      results:
                        type: array
                        items: { $ref: "#/components/schemas/NeedCard" }
  /v1/parks:
    get:
      operationId: listParks
      tags: [园区]
      summary: OPC 园区目录（按补贴类型筛选）
      description: >-
        六城（北京/上海/深圳/杭州/广州/成都）OPC 园区结构化目录。杀手用法是 benefit 补贴筛选：
        「杭州哪些园区免租」= city=杭州 + benefit=RENT_FREE；「哪里有算力券」= benefit=COMPUTE_VOUCHER。
        agent 可以批量组合 city x benefit 查询，替用户产出跨城市补贴对比表。
        列表卡片已带补贴摘要（benefits），补贴金额/条件明细与园区新闻走 getPark。
      parameters:
        - name: city
          in: query
          required: false
          description: 城市（北京 / 上海 / 深圳 / 杭州 / 广州 / 成都）
          schema: { type: string }
        - name: benefit
          in: query
          required: false
          description: >-
            补贴类型筛选：RENT_FREE=免租；RENT_SUBSIDY=租金补贴；COMPUTE_VOUCHER=算力券；
            MODEL_VOUCHER=模型券；STARTUP_FUND=创业资金；SETTLEMENT=落户；FUND=产业基金;
            ORDER=订单导入；TALENT_HOUSING=人才公寓；LOAN=创业贷款；OTHER=其他。
          schema:
            type: string
            enum:
              - RENT_FREE
              - RENT_SUBSIDY
              - COMPUTE_VOUCHER
              - MODEL_VOUCHER
              - STARTUP_FUND
              - SETTLEMENT
              - FUND
              - ORDER
              - TALENT_HOUSING
              - LOAN
              - OTHER
        - name: status
          in: query
          required: false
          description: 园区状态：OPERATING=已运营；PLANNED=规划中
          schema:
            type: string
            enum: [OPERATING, PLANNED]
        - name: track
          in: query
          required: false
          description: 产业赛道关键词（园区 tracks 精确包含，如「设计文创」「AI」）
          schema: { type: string }
        - name: q
          in: query
          required: false
          description: 关键词（园区名 / 运营方 / 行政区模糊匹配）
          schema: { type: string }
        - name: limit
          in: query
          required: false
          description: 返回条数，默认 20，最多 50
          schema: { type: integer, minimum: 1, maximum: 50, default: 20 }
        - name: cursor
          in: query
          required: false
          description: 分页游标（上一页返回的 nextCursor）
          schema: { type: string }
      responses:
        "200":
          description: 园区列表（已运营优先，按城市/名称稳定排序）
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok: { type: boolean }
                  data:
                    type: object
                    properties:
                      items:
                        type: array
                        items: { $ref: "#/components/schemas/ParkCard" }
                      nextCursor:
                        type: string
                        nullable: true
  /v1/parks/{id}:
    get:
      operationId: getPark
      tags: [园区]
      summary: 取园区详情（补贴明细 + 最近新闻）
      description: >-
        按园区 id 取完整详情：补贴逐条明细（含金额与申领条件）、知名入驻者、对接渠道、
        信息来源与最近 20 条园区新闻。替用户评估「要不要入驻 / 补贴怎么拿」时用。
      parameters:
        - name: id
          in: path
          required: true
          description: 园区 id（来自 listParks 结果的 id 字段）
          schema: { type: string }
      responses:
        "200":
          description: 园区详情
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok: { type: boolean }
                  data:
                    type: object
                    properties:
                      park: { $ref: "#/components/schemas/ParkDetail" }
        "404":
          description: 未找到
          content:
            application/json:
              schema: { $ref: "#/components/schemas/ErrorResponse" }
  /v1/posts:
    get:
      operationId: listPosts
      tags: [社区]
      summary: 社区动态信息流
      description: >-
        主理人社区的图文/视频动态流。未登录用 feed=recommend（默认）；following 流需登录，
        匿名调用返回空。可用 topic 筛话题、authorId 看某位主理人的全部动态
        （id 来自 searchPeople / listCreators），适合替用户快速了解「这个人最近在做什么」。
      parameters:
        - name: feed
          in: query
          required: false
          description: 流类型：recommend=推荐（默认，匿名可用）；following=关注流（需登录，匿名返回空）
          schema:
            type: string
            enum: [recommend, following]
            default: recommend
        - name: topic
          in: query
          required: false
          description: 话题名筛选
          schema: { type: string }
        - name: authorId
          in: query
          required: false
          description: 只看某位作者的动态（用户 id）
          schema: { type: string }
        - name: limit
          in: query
          required: false
          description: 返回条数，默认 20，最多 50
          schema: { type: integer, minimum: 1, maximum: 50, default: 20 }
        - name: cursor
          in: query
          required: false
          description: 分页游标（上一页返回的 nextCursor）
          schema: { type: string }
      responses:
        "200":
          description: 动态列表（时间倒序）
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok: { type: boolean }
                  data:
                    type: object
                    properties:
                      items:
                        type: array
                        items: { $ref: "#/components/schemas/PostCard" }
                      nextCursor:
                        type: string
                        nullable: true
  /v1/activities:
    get:
      operationId: listActivities
      tags: [检索]
      summary: 活动 / 机会列表
      description: >-
        列出站内活动与外部机会（路演、创业大赛、市集、媒体征集等）。用户问「最近有什么活动/机会」时调用。
      parameters:
        - name: type
          in: query
          required: false
          description: >-
            活动类型筛选：BETA_RECRUIT=内测招募；ONLINE_GATHERING=线上聚会；
            OFFLINE_GATHERING=线下聚会；COMPETITION=创业大赛；OTHER=其他。
          schema:
            type: string
            enum: [BETA_RECRUIT, ONLINE_GATHERING, OFFLINE_GATHERING, COMPETITION, OTHER]
        - name: upcoming
          in: query
          required: false
          description: 传 1 只看未开始的活动
          schema: { type: string, enum: ["0", "1"] }
        - name: limit
          in: query
          required: false
          description: 返回条数，默认 20，最多 50
          schema: { type: integer, minimum: 1, maximum: 50, default: 20 }
        - name: cursor
          in: query
          required: false
          description: 分页游标（上一页返回的 nextCursor）
          schema: { type: string }
      responses:
        "200":
          description: 活动列表
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok: { type: boolean }
                  data:
                    type: object
                    properties:
                      items:
                        type: array
                        items: { $ref: "#/components/schemas/Activity" }
                      nextCursor:
                        type: string
                        nullable: true
  /v1/companies:
    get:
      operationId: listCompanies
      tags: [检索]
      summary: 一人公司目录
      description: 检索/列出独行录上的一人公司主页。可用 q 模糊匹配公司名。
      parameters:
        - name: q
          in: query
          required: false
          description: 公司名关键词（可选）
          schema: { type: string }
        - name: limit
          in: query
          required: false
          description: 返回条数，默认 20，最多 50
          schema: { type: integer, minimum: 1, maximum: 50, default: 20 }
      responses:
        "200":
          description: 公司列表
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok: { type: boolean }
                  data:
                    type: object
                    properties:
                      items:
                        type: array
                        items: { $ref: "#/components/schemas/Company" }
components:
  schemas:
    ProductSearchHit:
      type: object
      properties:
        id: { type: string, description: 产品 id（可传给 getProduct） }
        slug: { type: string }
        name: { type: string }
        tagline: { type: string, description: 一句话简介 }
        category: { type: string, description: "类型：APP / WEBSITE / 其他" }
        similarity: { type: number, description: 相关度 0-1 }
        claimed: { type: boolean, description: 是否已被主理人认领 }
        via: { type: string, description: "命中方式：name / both / vector / keyword" }
    ProductCard:
      type: object
      properties:
        id: { type: string }
        slug: { type: string }
        name: { type: string }
        tagline: { type: string }
        logoUrl: { type: string, nullable: true }
        coverUrl: { type: string, nullable: true }
        category: { type: string }
        publishedAt: { type: string, format: date-time }
    ProductDetail:
      type: object
      properties:
        id: { type: string }
        slug: { type: string }
        name: { type: string }
        tagline: { type: string }
        description: { type: string, description: 完整介绍 }
        logoUrl: { type: string, nullable: true }
        category: { type: string }
    Creator:
      type: object
      properties:
        id: { type: string }
        nickname: { type: string }
        avatarUrl: { type: string, nullable: true }
        bio: { type: string, nullable: true }
        productCount: { type: integer, description: 名下产品数 }
        isStub: { type: boolean, description: 是否为系统占位（未认领） }
    PersonHit:
      type: object
      description: 主理人检索命中卡：canOffer 是主打信息（对方能提供什么价值）
      properties:
        id: { type: string, description: 用户 id（可作 listPosts 的 authorId） }
        nickname: { type: string, nullable: true }
        avatarUrl: { type: string, nullable: true }
        bio: { type: string, nullable: true }
        canOffer: { type: string, nullable: true, description: 能提供什么价值（供给侧自述） }
        isVerified: { type: boolean }
        similarity: { type: number, description: 相关度 0-1 }
        claimed: { type: boolean, description: 真人账号（true）优先于系统占位 }
        via: { type: string, description: "命中方式：name / semantic / both" }
    NeedAuthor:
      type: object
      description: 需求作者：canOffer + 代表产品，判断「他能给什么」
      properties:
        id: { type: string }
        nickname: { type: string }
        avatarUrl: { type: string, nullable: true }
        isVerified: { type: boolean }
        canOffer: { type: string, nullable: true, description: 作者能提供什么价值 }
        products:
          type: array
          description: 代表产品（最多 1 个；有产品=主理人，无=观众）
          items:
            type: object
            properties:
              id: { type: string }
              slug: { type: string }
              name: { type: string }
              tagline: { type: string }
              logoUrl: { type: string, nullable: true }
    AuthorNeedBrief:
      type: object
      description: 作者在架需求的精简条目（详情走 getNeed）
      properties:
        id: { type: string, description: 需求 id（可传给 getNeed） }
        type: { type: string, description: 需求类型（同 listNeedsFeed 的 type 枚举） }
        title: { type: string }
    NeedCard:
      type: object
      description: 需求卡片（feed / 搜索 / 详情同一契约）
      properties:
        id: { type: string }
        type:
          type: string
          description: >-
            需求类型：EXPERIENCE=寻找产品/作品；QA=答疑求助；RESOURCE=介绍资源；
            COLLAB=寻求合作；FINANCING=融资需求；CHAT=找人聊聊找灵感；OTHER=其它。
          enum: [EXPERIENCE, QA, RESOURCE, COLLAB, FINANCING, CHAT, OTHER]
        title: { type: string }
        detail: { type: string, nullable: true, description: 需求详情 }
        completionNote: { type: string, nullable: true, description: 完成条件说明 }
        images:
          type: array
          items: { type: string }
          description: 配图 URL 列表
        status:
          type: string
          description: 需求状态（OPEN/IN_PROGRESS 会出现在 feed；被承接也继续展示）
          enum: [OPEN, IN_PROGRESS, COMPLETED, CANCELLED, EXPIRED]
        createdAt: { type: string, format: date-time }
        author: { $ref: "#/components/schemas/NeedAuthor" }
    NeedFeedItem:
      allOf:
        - $ref: "#/components/schemas/NeedCard"
        - type: object
          description: feed 卡片 = 主卡需求 + 作者在架需求（最多 6 条）+ 匹配元信息
          properties:
            authorNeeds:
              type: array
              description: 该作者在架需求（最多 6 条，主卡需求在首位）
              items: { $ref: "#/components/schemas/AuthorNeedBrief" }
            matchScore:
              type: number
              nullable: true
              description: 匹配分（未登录/无个性化时为 null）
            matchReason:
              type: array
              description: 推荐理由标签
              items:
                type: object
                properties:
                  kind: { type: string }
                  label: { type: string }
    ParkBenefit:
      type: object
      properties:
        type:
          type: string
          description: 补贴类型（同 listParks 的 benefit 枚举）
          enum:
            - RENT_FREE
            - RENT_SUBSIDY
            - COMPUTE_VOUCHER
            - MODEL_VOUCHER
            - STARTUP_FUND
            - SETTLEMENT
            - FUND
            - ORDER
            - TALENT_HOUSING
            - LOAN
            - OTHER
        label: { type: string, description: 补贴描述 }
        amount: { type: string, nullable: true, description: 金额/力度（自由文本） }
        condition: { type: string, nullable: true, description: 申领条件（仅详情接口返回） }
    ParkCard:
      type: object
      properties:
        id: { type: string, description: 园区 id（可传给 getPark） }
        name: { type: string }
        aliases:
          type: array
          items: { type: string }
        city: { type: string, description: 城市（北京/上海/深圳/杭州/广州/成都） }
        district: { type: string, description: 行政区 }
        address: { type: string, nullable: true }
        lat: { type: number, nullable: true }
        lng: { type: number, nullable: true }
        operatorType: { type: string, nullable: true, description: "运营方类型：GOV=政府主导 / SOE=国资 / PRIVATE=民营" }
        operatorName: { type: string, nullable: true }
        tracks:
          type: array
          items: { type: string }
          description: 产业赛道
        scale: { type: string, nullable: true, description: 规模描述（自由文本） }
        status: { type: string, enum: [OPERATING, PLANNED] }
        launchedAt: { type: string, nullable: true, description: 启用时间（自由文本，各地口径不一） }
        benefits:
          type: array
          description: 补贴摘要（明细与条件走 getPark）
          items: { $ref: "#/components/schemas/ParkBenefit" }
    ParkDetail:
      allOf:
        - $ref: "#/components/schemas/ParkCard"
        - type: object
          properties:
            notableResidents:
              type: array
              items: { type: string }
              description: 知名入驻者
            channels:
              type: array
              items: { type: string }
              description: 对接渠道（公众号/电话/招商联系人等）
            sources:
              type: array
              items: { type: string }
              description: 信息来源链接
            news:
              type: array
              description: 最近园区新闻（最多 20 条）
              items:
                type: object
                properties:
                  id: { type: string }
                  title: { type: string }
                  url: { type: string }
                  source: { type: string, nullable: true }
                  publishedAt: { type: string, nullable: true }
    PostCard:
      type: object
      properties:
        id: { type: string }
        author:
          type: object
          properties:
            id: { type: string }
            nickname: { type: string }
            avatarUrl: { type: string, nullable: true }
            isVerified: { type: boolean }
        title: { type: string, nullable: true }
        body: { type: string, description: 正文 }
        media:
          type: array
          description: 图片/视频附件
          items:
            type: object
            properties:
              kind: { type: string, enum: [image, video] }
              url: { type: string }
              posterUrl: { type: string, nullable: true, description: 视频封面 }
        topic: { type: string, nullable: true, description: 话题 }
        linkUrl: { type: string, nullable: true, description: 外链 }
        attachType: { type: string, nullable: true, description: "挂卡类型：product / activity / park" }
        attachId: { type: string, nullable: true, description: 挂卡对象 id（可按类型接 getProduct / getPark） }
        likeCount: { type: integer }
        commentCount: { type: integer }
        pinned: { type: boolean, description: 是否置顶 }
        createdAt: { type: string, format: date-time }
    RatingSummary:
      type: object
      properties:
        targetType: { type: string, example: PRODUCT }
        count: { type: integer, description: 评价总数 }
        avg: { type: number, nullable: true, description: 平均分（1 位小数） }
        distribution:
          type: object
          description: 各星级条数（key 为 1-5）
          additionalProperties: { type: integer }
    RatingCard:
      type: object
      properties:
        id: { type: string }
        score: { type: integer, nullable: true, description: 评分 1-5 }
        body: { type: string, nullable: true, description: 评价正文 }
        relation: { type: string, nullable: true, description: 与产品的关系（用过/合作过等） }
        tags:
          type: array
          items: { type: string }
        helpfulCount: { type: integer, description: 「有用」票数 }
        createdAt: { type: string, format: date-time }
        author:
          type: object
          properties:
            id: { type: string }
            nickname: { type: string }
            avatarUrl: { type: string, nullable: true }
            isVerified: { type: boolean }
    Activity:
      type: object
      description: 活动 / 机会，字段随类型而异
      additionalProperties: true
      properties:
        id: { type: string }
        title: { type: string }
        type:
          type: string
          description: 活动类型（同 listActivities 的 type 枚举）
          enum: [BETA_RECRUIT, ONLINE_GATHERING, OFFLINE_GATHERING, COMPETITION, OTHER]
    Company:
      type: object
      description: 一人公司主页
      additionalProperties: true
      properties:
        id: { type: string }
        name: { type: string }
    ErrorResponse:
      type: object
      properties:
        ok: { type: boolean, example: false }
        error: { type: string, example: not_found }
