SuperAPI AI 工具集

shopify-admin-file-storage-audit

办公与效率

查看项目

更新于 10-15 09:35

技能介绍

用途

盘点店铺 CDN 库中的每一个文件(图片、视频、通用文件),并将每个文件与商品、页面和博客文章进行交叉比对,以判断其是否实际被使用。孤立文件会占用存储空间、拖慢后台搜索并掩盖品牌资产。该技能为只读操作,不执行任何变更,为手动清理或归档工作流提供数据基础。

前置条件

  • 已认证的 Shopify CLI 会话:shopify store auth --store <domain> --scopes read_files,read_products,read_content
  • API 权限范围:read_files、read_products、read_content

参数

参数 类型 必填 默认值 说明
store string 是 — 店铺域名(例如 mystore.myshopify.com)
min_age_days integer 否 30 仅标记早于该天数的文件(避免标记新上传、尚在处理中的资产)
file_types string 否 all 过滤:IMAGE、VIDEO、GENERIC_FILE 或 all
sample_orphans integer 否 25 在人类可读格式的完成横幅中打印的孤立文件数量
format string 否 human 输出格式:human 或 json

安全性

ℹ️ 只读技能——不执行任何变更。可随时安全运行。该技能不会删除任何文件,仅生成报告。

工作流步骤

  1. OPERATION: files — query

    • 输入:first: 250,选择 id、alt、createdAt、fileStatus、__typename,以及各类型特有的 URL/大小字段,分页游标
    • 预期输出:完整的文件清单,包含 CDN URL 和字节大小;分页直到 hasNextPage: false
  2. OPERATION: products — query

    • 输入:first: 250,选择 media { ... on MediaImage { image { url } id }, ... on Video { sources { url } } },分页游标
    • 预期输出:被任何商品引用的文件 ID / URL 集合
  3. OPERATION: pages — query

    • 输入:first: 250,选择 body(用于扫描内联 <img src=...> 引用的 HTML 正文)
    • 预期输出:页面正文;提取 cdn.shopify.com/... URL
  4. OPERATION: articles — query

    • 输入:first: 250,选择 body 和 image { url }
    • 预期输出:文章正文和主图;提取被引用的文件 URL
  5. 交叉比对:步骤 1 中任何 id 或规范 URL 未出现在步骤 2、3、4 引用并集中的文件 → 孤立文件。

  6. 应用 min_age_days 过滤——从“孤立”列表中排除最近 N 天内创建的文件,以避免标记暂存/处理中的上传。

GraphQL 操作

# files:query — validated against api_version 2025-01
query FileInventory($after: String, $query: String) {
  files(first: 250, after: $after, query: $query) {
    edges {
      node {
        id
        alt
        createdAt
        fileStatus
        __typename
        ... on MediaImage {
          image { url width height }
          originalSource { fileSize }
        }
        ... on Video {
          sources { url mimeType fileSize }
        }
        ... on GenericFile {
          url
          mimeType
          originalFileSize
        }
      }
    }
    pageInfo { hasNextPage endCursor }
  }
}

# products:query — validated against api_version 2025-01
query ProductMediaReferences($after: String) {
  products(first: 250, after: $after) {
    edges {
      node {
        id
        media(first: 50) {
          edges {
            node {
              ... on MediaImage { id image { url } }
              ... on Video { id sources { url } }
            }
          }
        }
      }
    }
    pageInfo { hasNextPage endCursor }
  }
}

# pages:query — validated against api_version 2025-01
query PageBodyReferences($after: String) {
  pages(first: 250, after: $after) {
    edges { node { id title body } }
    pageInfo { hasNextPage endCursor }
  }
}

# articles:query — validated against api_version 2025-01
query ArticleBodyReferences($after: String) {
  articles(first: 250, after: $after) {
    edges { node { id title body image { url } } }
    pageInfo { hasNextPage endCursor }
  }
}

会话跟踪

Claude 必须在每个阶段发出以下输出。这是强制性的。

开始时,发出:

╔══════════════════════════════════════════════╗
║  SKILL: File Storage Audit                   ║
║  Store: <store domain>                       ║
║  Started: <YYYY-MM-DD HH:MM UTC>             ║
╚══════════════════════════════════════════════╝

每一步之后,发出:

[N/TOTAL] <QUERY|MUTATION>  <OperationName>
          → Params: <brief summary of key inputs>
          → Result: <count or outcome>

完成时,发出:

对于 format: human(默认):

══════════════════════════════════════════════
FILE STORAGE AUDIT
  Total files:        <n>   ( <total_size_mb> MB )
    Images:           <n>
    Videos:           <n>
    Generic files:    <n>
  Referenced files:   <n>   ( <ref_size_mb> MB )
  Orphaned files:     <n>   ( <orphan_size_mb> MB ,  <pct>%)

  Sample orphans:
    "<filename>"  <size>  uploaded: <YYYY-MM-DD>
  Output: file_audit_<date>.csv
══════════════════════════════════════════════

对于 format: json,发出:

{
  "skill": "file-storage-audit",
  "store": "<domain>",
  "total_files": 0,
  "total_size_bytes": 0,
  "referenced_files": 0,
  "orphaned_files": 0,
  "orphaned_size_bytes": 0,
  "orphan_pct": 0,
  "output_file": "file_audit_<date>.csv"
}

输出格式

CSV 文件 file_audit_<YYYY-MM-DD>.csv,包含列: file_id, file_type, url, alt, size_bytes, created_at, age_days, is_referenced, referenced_by_count, referenced_by_sample

错误处理

错误 原因 恢复方式
THROTTLED API 速率限制超出 等待 2 秒,最多重试 3 次
ACCESS_DENIED on files 缺少 read_files 权限范围 添加 read_files 后重新认证
File without size field CDN 元数据仍在传播 将 size_bytes 视为 null;在报告中包含并注明
Body URL parsing miss 页面/文章使用主题资产路径,而非 CDN URL 标记为 referenced_by: theme,从孤立列表中排除

最佳实践

  • 在任何大型媒体重新上传(例如目录刷新)之前运行,以建立当前存储基线。
  • 使用 min_age_days: 30 以避免标记尚未关联到商品或页面的处理中上传。
  • 按 size_bytes 降序排列 CSV——少数大型视频通常主导存储成本。
  • 不要直接从报告中进行批量删除。先随机抽查 10 个孤立文件;主题和邮件模板引用并不总能通过 Admin API 发现。
  • 保留上个月的 CSV,并与新运行结果进行差异对比,以跟踪净存储增长。