openapi: 3.0.3
info:
  title: AI建站 Platform API
  version: 1.0.0
  description: |
    通用中台契约。业务行数据仅通过 apps/{slug}/{resource} CRUD 传输；
    行业字段由蓝图定义，不在此增加行业专用路由。
    动词约定：GET 读 / POST 创建或动作 / PUT 更新 / DELETE 删除。
servers:
  - url: http://127.0.0.1:8180
paths:
  /api/v1/meta/apis:
    get:
      operationId: listApis
      summary: API 目录
      responses:
        "200":
          description: OK
  /api/v1/meta/openapi.yaml:
    get:
      operationId: getOpenAPI
      summary: OpenAPI 原文
      responses:
        "200":
          description: YAML
  /api/v1/auth/register:
    post:
      operationId: authRegister
      summary: 注册
      responses:
        "201": { description: Created }
  /api/v1/auth/login:
    post:
      operationId: authLogin
      summary: 登录
      responses:
        "200": { description: OK }
  /api/v1/auth/token:
    post:
      operationId: authToken
      summary: 服务签发 JWT
      responses:
        "200": { description: OK }

  /api/v1/apps/{slug}/publish:
    post:
      operationId: publishApp
      summary: 发布蓝图
      parameters:
        - $ref: "#/components/parameters/Slug"
        - $ref: "#/components/parameters/Authorization"
      responses:
        "200": { description: OK }
  /api/v1/apps/{slug}/blueprint:
    get:
      operationId: getBlueprint
      summary: 读取蓝图
      parameters:
        - $ref: "#/components/parameters/Slug"
        - $ref: "#/components/parameters/Authorization"
      responses:
        "200": { description: OK }
  /api/v1/apps/{slug}/agent-capsule:
    get:
      operationId: getAgentCapsule
      summary: 智能体胶囊
      parameters:
        - $ref: "#/components/parameters/Slug"
        - $ref: "#/components/parameters/Authorization"
      responses:
        "200": { description: OK }

  /api/v1/apps/{slug}/{resource}:
    parameters:
      - $ref: "#/components/parameters/Slug"
      - $ref: "#/components/parameters/Resource"
      - $ref: "#/components/parameters/Authorization"
    get:
      operationId: listRows
      summary: 列表
      parameters:
        - name: page
          in: query
          schema: { type: integer, minimum: 1, default: 1 }
        - name: page_size
          in: query
          schema: { type: integer, minimum: 1, maximum: 100, default: 20 }
        - name: sort
          in: query
          schema: { type: string }
        - name: filter.*
          in: query
          description: 如 filter.status=在售，键须在蓝图 allowed_filters
          schema: { type: string }
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PageResult"
    post:
      operationId: createRow
      summary: 创建
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
      responses:
        "201":
          description: Created
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Row"

  /api/v1/apps/{slug}/{resource}/{id}:
    parameters:
      - $ref: "#/components/parameters/Slug"
      - $ref: "#/components/parameters/Resource"
      - $ref: "#/components/parameters/Id"
      - $ref: "#/components/parameters/Authorization"
    get:
      operationId: getRow
      summary: 详情
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Row"
        "404":
          $ref: "#/components/responses/NotFound"
    put:
      operationId: updateRow
      summary: 更新
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Row"
    delete:
      operationId: deleteRow
      summary: 删除
      responses:
        "204": { description: No Content }

  /api/v1/apps/{slug}/{resource}/import:
    post:
      operationId: importRows
      summary: 导入
      parameters:
        - $ref: "#/components/parameters/Slug"
        - $ref: "#/components/parameters/Resource"
        - $ref: "#/components/parameters/Authorization"
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required: [file]
              properties:
                file: { type: string, format: binary }
      responses:
        "200": { description: OK }

  /api/v1/apps/{slug}/{resource}/export:
    get:
      operationId: exportRows
      summary: 导出
      parameters:
        - $ref: "#/components/parameters/Slug"
        - $ref: "#/components/parameters/Resource"
        - $ref: "#/components/parameters/Authorization"
        - name: format
          in: query
          schema: { type: string, enum: [xlsx, csv], default: xlsx }
      responses:
        "200": { description: 文件流 }

  /api/v1/apps/{slug}/{resource}/aggregate:
    get:
      operationId: aggregateRows
      summary: 聚合
      parameters:
        - $ref: "#/components/parameters/Slug"
        - $ref: "#/components/parameters/Resource"
        - $ref: "#/components/parameters/Authorization"
        - name: group_by
          in: query
          schema: { type: string }
        - name: sum
          in: query
          schema: { type: string }
      responses:
        "200": { description: OK }

  /api/v1/audit/logs:
    get:
      operationId: listAuditLogs
      summary: 审计日志
      parameters:
        - $ref: "#/components/parameters/Authorization"
      responses:
        "200": { description: OK }

  /api/v1/storage:
    post:
      operationId: uploadObject
      summary: 上传
      parameters:
        - $ref: "#/components/parameters/Authorization"
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required: [file]
              properties:
                file: { type: string, format: binary }
      responses:
        "200": { description: OK }

  /api/v1/storage/{tenant}/{day}/{name}:
    get:
      operationId: downloadObject
      summary: 下载
      parameters:
        - $ref: "#/components/parameters/Authorization"
        - name: tenant
          in: path
          required: true
          schema: { type: string }
        - name: day
          in: path
          required: true
          schema: { type: string }
        - name: name
          in: path
          required: true
          schema: { type: string }
      responses:
        "200": { description: 文件流 }

  /api/v1/apps/generate:
    post:
      operationId: generateBlueprint
      summary: 生成蓝图（AI 服务，经网关 /ai 前缀）
      description: 实际请求 /ai/api/v1/apps/generate；勿在 platform 重复实现。
      requestBody:
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                prompt: { type: string }
                excel: { type: string, format: binary }
                images: { type: string, format: binary }
      responses:
        "200": { description: OK }

  /api/v1/llm/providers:
    get:
      operationId: listLlmProviders
      summary: LLM 厂商（AI 服务）
      responses:
        "200": { description: OK }

components:
  parameters:
    Authorization:
      name: Authorization
      in: header
      required: true
      schema: { type: string }
      description: Bearer JWT
    Slug:
      name: slug
      in: path
      required: true
      schema: { type: string, pattern: "^[a-z][a-z0-9_]{1,47}$" }
    Resource:
      name: resource
      in: path
      required: true
      schema: { type: string }
      description: 蓝图 apis.resources.path（无前导 /）；不可为保留名
    Id:
      name: id
      in: path
      required: true
      schema: { type: string }
  schemas:
    PageResult:
      type: object
      properties:
        items: { type: array, items: { $ref: "#/components/schemas/Row" } }
        total: { type: integer }
    Row:
      type: object
      additionalProperties: true
  responses:
    NotFound:
      description: Not Found
      content:
        application/json:
          schema:
            type: object
            properties:
              code: { type: integer }
              message: { type: string }
