ZGFA Mini App Spec

用 HTML + JavaScript + SQLite 构建可独立部署、可发布到商店的便携式小应用。一份代码,本地与 Web 双端运行。

协议版本 v2.5 · 最后更新 2026-05-31

文件结构

每个小应用是一个独立的目录。v2 规范采用 6 文件架构(三层分离),适合 AI 迭代维护。

my-app/
├── config.json        # 应用元数据(名称/版本/图标等)
├── style.css          # 全部样式
├── db.js              # 数据层:SQLite 建表 + 全部 CRUD 函数
├── ui.js              # 渲染层:所有 render 函数(读 state → 改 DOM)
├── main.js            # 交互层:事件绑定 + 路由 + init
├── index.html         # 骨架,按顺序引入 db.js → ui.js → main.js
├── DEVLOG.md          # AI 开发日志(v2 强烈推荐,跨迭代记忆)
├── app.db             # SQLite 数据库(首次运行自动创建)
└── versions/          # 版本快照与回退
    ├── history.json   # 版本历史列表
    └── v1_timestamp/  # 各版本快照目录
💡 三层分离架构(v2): db.js(数据) / ui.js(渲染) / main.js(交互) 三层互不串门 —— db.js 不碰 DOM,ui.js 不绑事件,main.js 不写 SQL。这样每次 AI 只改一层,不会把逻辑和渲染搅在一起。
不依赖打包工具、不需要 npm install、不需要构建步骤。简单应用也可以退化成单个 app.js,但超过 500 行务必按三层拆开。
⚠ 禁止内联:不要把 CSS 和 JS 全部写在 index.html 里。index.html 只放 HTML 结构,用 <link> 引入 style.css,用 <script>db → ui → main 顺序引入三个 JS 文件。

index.html 模板(v2 6 文件架构)

<!-- index.html — 只放结构,按顺序引入三层 JS -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>应用名</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <!-- HTML 结构 -->
  <script src="db.js"></script>    <!-- 1. 数据层先加载 -->
  <script src="ui.js"></script>    <!-- 2. 渲染层依赖数据层 -->
  <script src="main.js"></script>  <!-- 3. 交互层最后,init() 在此 -->
</body>
</html>

DEVLOG.md — AI 跨迭代记忆

v2 规范新增的开发日志协议。每个应用根目录建一份 DEVLOG.md,AI 每次修改前会先读它理解历史上下文,改完后 append 一条记录。这样多次迭代不会互相打架。

DEVLOG.md 标准结构

# {app_id} — 开发日志

## v1 — 2026-04-20

### 架构
- db.js: SQLite 建表 + CRUD (notes/tags 两张表)
- ui.js: renderList() / renderEditor() / renderSidebar()
- main.js: 事件绑定 + 快捷键 + init()

### 字段 / 数据模型
- notes(id, title, content, tag_id, created_at, updated_at)
- tags(id, name, color)
- KV: theme=light|dark, lastOpenedNoteId

### 设计决策
- 为什么用 SQLite 而不是 KV:笔记会增长到 1000+ 条,KV 全量读写会卡
- 为什么 tags 单独一张表:未来要支持多标签/颜色筛选
- 快捷键使用 Ctrl+S 保存:对齐桌面笔记软件肌肉记忆

## 迭代记录

- 2026-04-21: 加了分类侧栏 — 用户要求多维度统计 (改动 db.js tags 表 + ui.js renderSidebar)
- 2026-04-22: 修复快捷键在中文输入法下重复触发 (main.js 加 isComposing 判断)
🤖 AI 工作流中的 DEVLOG:
新建应用: AI 写完代码后,自动用 app_save 初始化 DEVLOG.md,填写 v1 的架构/字段/决策三块
迭代改动: AI 用 app_read_file("DEVLOG.md") 读完日志再动手,避免重复前人踩过的坑;改完用 app_append 追加一条迭代记录
给人看: 用户自己翻 DEVLOG 就能知道这个应用曾经做过什么决策、改过什么字段
⚠ 迭代记录要写"为什么",不是"改了啥": 2026-04-21: 加了 tags 表 ❌ —— 看代码 diff 就知道改了啥
2026-04-21: 加了 tags 表 — 用户要按项目筛选笔记 ✅ —— 记录动机,未来不会误删

config.json 字段

应用元数据。所有字段都会显示在商店和应用管理页。

{
  "app_id": "com.user.myapp",        // 应用 ID(反向域名格式)
  "name": "我的应用",                 // 显示名称
  "version": 1,                      // 版本号(整数,每次发布 +1)
  "runtime_version": 1,              // 规范版本号
  "author": "用户",                   // 作者名称
  "description": "在浏览器里运行的轻量记事工具,本地保存...", // ≥ 30 字
  "readme": "# 我的应用\n\n详细说明...", // Markdown,≥ 50 字符
  "icon": "📦",                       // Emoji,不能跟商店内其他 app 重复
  "category": "工具",                  // 自由字符串:工具/效率/生活/游戏
  "price": 0                            // 0=免费,> 0=按年订阅(¥0.01-¥365)
}
字段类型必填说明
app_idstring✅ 是全局唯一字符串,商店不强制格式。实际两种来源:① AI 浏览器生成的小应用 = {语义名}-{13位时间戳}(如 snake-1730184571203);② dev.zgfa.com 控制台创建 = zgfa_app_+16 位 base32。早期 com.user.* / com.zgfa.* 反向域名仍兼容
namestring✅ 是显示名称,建议 ≤ 12 字符
versionnumber✅ 是整数版本号,发布时必须 + 1
runtime_versionnumber规范版本号,当前为 1。规范升级时老应用据此判断兼容性
iconstring✅ 是单个 Emoji。2026-05-20 起强制全局唯一,撞已有 app 的图标会被拒收(icon_conflict)
categorystring✅ 是自由字符串,无强制枚举。商店分类筛选根据全部已发布应用动态生成。常用:工具 · 效率 · 生活 · 游戏
authorstring显示在商店详情页;未传时取登录用户昵称
descriptionstring✅ 是2026-05-20 起 ≥ 30 字。讲清这个应用是什么、给谁用、有什么特点;商店搜索会建索引(desc_too_short)
readmestring✅ 是2026-05-20 起 ≥ 50 字符,Markdown 格式。可通过单独字段或 files['README.md'] 提供(readme_missing)
pricenumber定价,单位元。0=免费,0.01-365=按年订阅。默认 0。详见定价与收益
⚠ 2026-05-20 起,发布质量门已生效:不满足上述 3 条规则的 publish 请求会返 HTTP 422 + 中文错误信息。详见 上架质量门 一节。

SQLite 数据库

每个小应用自带一个独立的 SQLite 数据库,通过 ZGFA_APP.db 访问。

// 创建表
await ZGFA_APP.db.exec("CREATE TABLE IF NOT EXISTS notes (id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT, content TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP)");

// 插入数据(参数化查询,防注入)— run() 返回 {changes, lastInsertRowid}
const r = await ZGFA_APP.db.run("INSERT INTO notes (title, content) VALUES (?, ?)", ["Hello", "World"]);
const newId = r.lastInsertRowid;  // ✅ 直接拿新插入的行 ID
const affected = r.changes;        // ✅ 受影响的行数(INSERT/UPDATE/DELETE 都有)

// 查询多行
const notes = await ZGFA_APP.db.all("SELECT * FROM notes ORDER BY created_at DESC");

// 查询单行
const note = await ZGFA_APP.db.get("SELECT * FROM notes WHERE id = ?", [newId]);
💡 双模式运行:在 ZGFA 浏览器中,SQLite 通过主进程 IPC 安全调用(沙箱隔离)。部署到 Web 服务器后,自动通过 sql.js (WebAssembly) 运行,数据存 localStorage。API 完全一致,代码不需要改。
📌 db.run() 返回值规范(v1+): { changes: 受影响行数, lastInsertRowid: 新插入的自增 ID } — 这是 better-sqlite3 风格的标准接口,不需要再写 SELECT last_insert_rowid() 单独查 ID。
⚠ KV vs SQLite 怎么选:
用 KVZGFA_APP.getData/setData/removeData):单值配置 — 主题色、当前登录用户 ID、上次打开的 tab 等。
用 SQLiteZGFA_APP.db):任何列表、多行记录、可查询/排序/过滤的数据。
反例:用 KV 存 setData('todos', [...]) 会随数据增长全量读写,性能爆炸 — 这种场景必须用 SQLite。

静态资源

小应用采用多文件架构,图片等二进制资源推荐以下方式内嵌(避免引入额外文件):

<!-- Base64 内嵌图片(小图标推荐)-->
<img src="data:image/png;base64,iVBOR...">

<!-- 外部 CDN 图片 -->
<img src="https://cdn.example.com/logo.png">

<!-- Emoji 图标(最简单,零成本)-->
<span style="font-size:48px">📝</span>

<!-- 内联 SVG(矢量图推荐)-->
<svg viewBox="0 0 24 24" width="24" height="24">...</svg>
用户上传内容怎么存?把图片转 Base64 后写入 SQLite 数据库,而不是写文件系统。这样导出/同步/分享时数据不会丢失,整个应用永远是一个干净的目录。

便携包格式 .zgfa.json

单文件包格式,可用于备份、分享、二次开发。

{
  "config": {                       // 应用元数据
    "app_id": "com.user.myapp",
    "name": "我的应用",
    "version": 1,
    "author": "用户",
    "icon": "📦",
    "category": "工具",
    "description": "应用描述"
  },
  "files": {
    "index.html": "<!DOCTYPE html>...", // 主页面
    "config.json": "{...}",             // 配置文件
    "app.db": ""                          // 数据库(空或有数据)
  }
}
💡 导入方式:在小应用页面点击"导入"按钮,选择 .zgfa.json 文件即可一键安装。也可以拖拽到浏览器窗口。

独立部署到 Web 服务器

小应用是标准的 Web 应用,可以部署到任何静态托管服务上独立运行——无需 ZGFA 浏览器。

# 复制到服务器
scp -r my-app/ user@server:/var/www/html/

# 或使用任意静态托管
# Vercel / Netlify / GitHub Pages / Cloudflare Pages / Nginx ...

# 用浏览器访问
https://yourdomain.com/my-app/
无需改一行代码:app.js 中的 ZGFA_APP API 在 Web 服务器上会自动通过 sql.js (WebAssembly) 兼容运行,SQLite 数据存到 localStorage。本地浏览器和 Web 部署行为完全一致。
🖥 在 ZGFA 浏览器中
主进程 SQLite · 沙箱隔离 · 离线可用 · 极速访问 · 自动备份
🌐 在 Web 服务器上
sql.js WebAssembly · localStorage · 任意现代浏览器可用 · 可分享 URL

ZGFA_APP 全局 API

所有小应用中可用的全局对象。本地浏览器和 Web 服务器环境下行为一致。

// ===== SQLite 数据库(推荐)=====
await ZGFA_APP.db.exec(sql)              // 执行 SQL(建表等)
await ZGFA_APP.db.run(sql, params)       // 执行带参数(增删改)
await ZGFA_APP.db.all(sql, params)       // 查询多行
await ZGFA_APP.db.get(sql, params)       // 查询单行

// ===== KV 存储(仅适合简单偏好)=====
ZGFA_APP.getData(key)                    // 读取值
ZGFA_APP.setData(key, value)             // 写入值
ZGFA_APP.removeData(key)                 // 删除键

// ===== 环境信息 =====
ZGFA_APP.isLocal                         // true=本地浏览器, false=Web 服务器

// ===== AI Workflow 回调(被 AI 工作流调用时可用)=====
await ZGFA_APP.returnToAgent(data)       // 把数据返回给调用该应用的 AI workflow

// ===== 运行时错误捕获(v1+)=====
ZGFA_APP.onError(handler)                // 注册全局错误回调
ZGFA_APP._getErrors()                     // 获取最近 50 条错误

运行时错误捕获

小应用在 ZGFA 浏览器内运行时,系统会自动捕获所有未处理的 JS 错误、Promise rejection 和 console.error,缓存最近 50 条供调试。

// 注册全局错误处理(可选,通常给开发者调试用)
ZGFA_APP.onError((err) => {
  console.log('捕获到错误:', err.type, err.message, err.stack);
  // err = { type, message, source, line, col, stack, ts }
});

// 主动获取错误历史
const errors = ZGFA_APP._getErrors();
🤖 给 AI 用的反馈回路:当 AI 龙虾助手帮用户写完应用后,会调用 run_app 工具在隐藏 webview 里跑应用 5 秒,自动收集所有运行时错误返回,AI 据此修 bug。这是保证"做出来的应用一定能跑"的核心机制。

v2 新增:错误分类反馈。 run_app 现在会把错误归类并给出专属修复指引:
render-stuck-loading — 页面卡在"加载中"文案 → 提示 AI 检查 async 渲染逻辑是否抛异常
interaction-error — 点击/输入后报错 → 提示 AI 检查事件处理器的空值防御
• 常规 js error / promise rejection / console.error — 返回原始 stack trace

大型应用文件拆分

应用复杂时(多页面、CRUD、登录态、统计图表),把代码按职责拆到多个文件,而不是塞进一个 app.js

my-app/
├── config.json
├── style.css
├── db.js              # 数据层:建表 + 所有 CRUD 函数
├── ui.js              # 渲染层:所有 render 函数
├── main.js            # 交互层:事件绑定 + 路由 + init
└── index.html         # 按顺序引入 db.js → ui.js → main.js
<!-- index.html 末尾 -->
<script src="db.js"></script>
<script src="ui.js"></script>
<script src="main.js"></script>
⚠ 单文件大小建议:每个 .js 文件不超过 30KB(约 1000 行)。超过这个量级时再拆分一个新文件出来,而不是继续塞。理由:① 模型一次性写大文件容易出错 ② 后续 AI 用 app_edit 改局部时上下文更清晰 ③ 加载性能更好。

AI 工具集(10 个工具)

AI 龙虾助手在改应用时,会组合使用以下工具,每种工具对应一种操作粒度。

类型工具用途
app_save创建/覆盖整个文件(单次 ≤ 6000 字符)
app_append追加到文件末尾(每块 3000-6000 字符,攒大文件)
app_edit精确字符串替换(改一处逻辑/一行样式)
app_multi_edit单文件批量改(原子操作,要么全成要么全失败)
app_edit_diff按 diff 片段改(大段替换时比 multi_edit 省 token)
app_read_file读单个文件全文(改前先读,尤其是 DEVLOG.md)
app_grep正则搜索代码(定位"那个按钮在哪"最快)
app_glob按 glob 模式列文件(*.js / ui/**)
app_list列应用根目录文件树
run_app在隐藏 webview 跑应用 5 秒,收集所有 console/error/interaction 反馈

AI 工作流(三种粒度)

🆕 新建应用
think(规划架构) →
task_plan(5-8 项) →
app_save / app_append 分文件写
(config.json / style.css / db.js / ui.js / main.js / index.html) →
初始化 DEVLOG.md →
run_app 验证 →
done
🔁 迭代(改已有应用)
并行读: app_list + app_glob + app_grep + app_read_file(DEVLOG.md) →
think(规划最小改动) →
app_edit / app_multi_edit 精准修改 →
run_app 验证 →
append DEVLOG 一条迭代记录 →
done
🩹 微改(改颜色/字号)
app_grep 定位(如搜 color:) →
app_edit 一次替换 →
run_app 验证 →
done
🤖 为什么"攒大文件"依然有效:GPT 单次输出有限(约 6000 字符),但通过 app_save(第一块) + 多次 app_append(每块 3000-6000 字符)可以拼出任意大的文件。所以你看到的"db.js 800 行"其实是 AI 分 5-6 次写入的结果 —— 模型上限不再是应用规模上限。

AI 龙虾助手协作(v3)

众高 AI 浏览器 v3 起,龙虾 AI 助手升级为 Unified Omni Agent(全能体)。除了做小应用,还能控制浏览器、桌面、调用 6 万+ Skills 市场技能。开发者/用户可按本节充分利用。

🗺 能力全景(113+ 工具,5 大类)

类别典型工具场景
🌐 浏览器操控navigate / click / fill / web_search / get_page_content / extract_table"打开百度搜天气" / "填表单" / "抓这网站数据"
💻 小应用工程app_save / app_edit / app_grep / app_multi_edit / run_app本节主角:"做个记账本" / "给记账本加分类"
🖥 桌面控制open_app / run_command / screen_capture / read_file / list_files"打开 WPS" / "截全屏" / "看桌面上的文件"
🧠 记忆 & 技能remember / recall / write_lesson / search_skills / install_skill"记住我爱喝美式" / 从 55k 市场装个"商品比价"技能
⚙️ 通用think / task_plan / task_update / done复杂任务规划 / 多步推进

🔐 3 级权限系统(用户可控)

所有敏感操作(桌面应用启动、Shell 命令、文件删除等)都走 3 级权限,用户在 左侧边栏 ⚙️ AI 配置 → 权限管理 里配置:

状态行为适用
allow自动放行,AI 直接执行低风险只读类(读文件/截图)
ask弹窗询问用户,用户批准才跑中等风险(打开应用/写文件)
deny直接拒绝,AI 看到 "Permission denied" 错误学会不做高危(shell 命令/删文件,默认 deny)

3 档预设快捷:🛡 安全模式(高危全 deny)· ⚖️ 平衡模式(默认)· ⚡ 开发者模式(全 allow,YOLO)。

📖 CLAUDE.md 自动发现(对标 Claude Code)

AI 进入任何工作空间时,会自动检测并读取以下文档作为项目上下文(优先级从高到低):

  • CLAUDE.md — 项目规范 / 架构 / 关键决策(首选,参考 Claude Code 约定)
  • README.md — 项目说明
  • DEVLOG.md — 每个小应用自动维护的开发日志

找到后 AI 会把前 2000 字塞进 system prompt,参考项目规范做事。开发者建议:在自己项目根目录放一份 CLAUDE.md 列出"本项目的架构 / 技术栈 / 禁区 / 约定",AI 效率大幅提升

🎯 Skills 市场(6 万+ 技能,独立子域)

所有技能来自 skills.zgfa.com 镜像站(ClawHub 源,2026-05-20 起从 store.zgfa.com/skills 切到独立子域,老 URL 短期反代兼容),存储于阿里云 OSS。AI 可主动:

  • search_skills(query) — 搜市场(5 秒超时 + 10 分钟缓存)
  • install_skill(slug) — 秒级安装(OSS 直连)
  • skill_<id>(input) — 安装后每个 skill 自动注册成工具,AI 可直接调用
  • rate_skill — 用完自动打分,低分淘汰、高分加权

AI 每轮对话会语义匹配 top-3 推荐技能注入 prompt,用户说"帮我写个日报",AI 会优先看有没有合适的 write_article 类 skill 直接用,省自己从零摸索。

🧠 开发者 tip:如果你在做一个垂直场景的小应用(比如专业打印 / 特定格式导出),与其让 AI 每次重新写,不如把常用流程打包成 skill 发布到市场,后续 AI 主动命中复用 —— 这也是 ZGFA 生态的核心闭环。

云端数据 API zgfa.data

当应用需要 多人共享数据(留言板、投票、协作等),使用 zgfa.data。数据存储在云端服务器,所有访问者共享同一份数据库。

// 添加数据(自动生成 _id 和 _created_at)
await zgfa.data.add('messages', { name: '张三', content: '你好' })
// 返回: { _id: 1, name: '张三', content: '你好', _created_at: 1712736000000 }

// 查询列表
await zgfa.data.list('messages', {
  where: { name: '张三' },       // 条件过滤
  order: '_created_at DESC',      // 排序
  limit: 20,                      // 分页
  offset: 0
})

// 查询单条
await zgfa.data.get('messages', 1)

// 修改
await zgfa.data.update('messages', 1, { content: '修改后的内容' })

// 删除
await zgfa.data.remove('messages', 1)

// 计数
await zgfa.data.count('messages', { where: { name: '张三' } })
📦 ZGFA_APP.db(本地)
单用户 · 写 SQL · 数据在本地电脑 · 完全离线
☁️ zgfa.data(云端)
多人共享 · 不写 SQL · 数据在服务器 · 需要网络
💡 如何选择:个人工具用 ZGFA_APP.db,多人协作用 zgfa.data。两者可以共存。集合(表)不需要预先创建,第一次 add 时自动创建。如果应用需要用户注册登录,自己建 users 集合即可,不依赖平台账号。

定价与收益

发布时通过 price 字段选择免费或收费。收费应用走 365 天订阅模型。

项目规则
免费应用price = 0,所有人直接使用,无使用期限
收费区间¥0.01 ~ ¥365 / 年(超过 365 元的请走 SaaS 渠道,不走小应用商店)
分成比例作者 50% + 平台 50%(订单支付后按 5:5 拆分,作者收益 seller_income 入账 app_orders)
结算方式作者在 dev.zgfa.com 创作者后台 → 收益 看余额并申请提现到支付宝(单次最低 ¥10,需先完成实名)
用户权限购买后自动开通 365 天使用权,过期前可在应用内或商店续费
续费规则在已有到期时间(paid_at + 365 天)上叠加 365 天,不会按"自然年"重置
到期提醒到期前 7 天自动在应用内显示续费提醒
价格变更作者可上调/下调价格;已购用户按购买时的价格享受到期,不补差价不退差额
💰 收益与提现以创作者后台为准:本页讲怎么写小应用(运行时 / API / 打包);分成、结算、提现、实名、数据看板统一在 dev.zgfa.com 创作者文档 维护。两边数字一致:作者 50% / 平台 50%
⚠ 数据层注意:当前 app_orders 表无 expired_at 字段,过期时间是paid_at 在运行时推算(paid_at + 365 天)。后续订单量上来后会加 expired_at 提升查询性能,届时由 trigger 自动回填。

版本管理

每个小应用自动支持版本快照与一键回退,数据存储在 versions/ 目录。

versions/
├── history.json            # 版本历史列表
├── v1_1712000000000/       # 版本 1 快照
│   ├── config.json
│   ├── index.html
│   └── app.db
├── v2_1712100000000/       # 版本 2 快照
└── _backup_v3_1712200000/  # 回退前自动备份

history.json 条目格式

{
  "id": "v2_1712100000000",    // 快照目录名
  "version": 2,                 // 版本号
  "time": 1712100000000,        // 创建时间戳
  "files": [                    // 包含的文件列表
    "config.json",
    "index.html",
    "app.db"
  ],
  // 以下字段仅回退操作时出现:
  "rollbackFrom": 3,            // 从哪个版本回退
  "isActive": true              // 标记为当前活跃版本
}
🔼 AI 保存新版本
1. 读取当前版本号 N
2. 快照当前文件 → v{N}_{时间戳}/
3. 追加 history.json
4. 写入新文件
🔽 用户回退版本
1. 自动备份当前文件
2. 补建当前版本快照(如缺失)
3. 恢复目标版本文件
4. 更新 config.json 版本号
5. 追加回退记录到 history.json
6. 硬刷新已打开的应用标签页

上架质量门(2026-05-20 立规)

为了商店门面干净 + 推广前不带废 app 上线,所有走 POST /api/apps/publish 的发布请求都会过 3 道质量门。不满足直接 HTTP 422 + 中文错误码,前端可针对性提示。

规则阈值错误码错误信息
description 长度30 字desc_too_short"描述至少 30 字(当前 N)。请讲清这个应用是什么、给谁用、有什么特点。"
readme 长度50 字符readme_missing"readme(说明文档)必填,至少 50 字符。可在 files 里加 README.md 或单独传 readme 字段。"
icon 全局唯一不能跟商店内其他 app 撞icon_conflict"icon \"X\" 已被 \"某 App\" 使用,请换一个有辨识度的 emoji 或图标。"

客户端发布前自查清单

// 发布前用这段先自校验,避免提交后被服务端拒
function checkPublishMeta(meta) {
  if ((meta.description || '').trim().length < 30)
    throw new Error('描述至少 30 字');
  const readme = meta.readme || (meta.files && meta.files['README.md']) || '';
  if (readme.trim().length < 50)
    throw new Error('readme 必填且至少 50 字符');
  // icon 唯一性需向服务端查 / 用 GET /api/apps 拉列表比对
}
📝 为什么立规:2026-05-20 之前,商店里 32 个 app 中 9 个是开发期测试残留(乱码名/死链/重复),17 个有描述过短/无 readme/图标撞车等小问题。质量门避免这类废数据再入库,保持商店门面随时拿得出手。
💡 对老 app 影响:2026-05-20 之前已发布的 app 不受此规则约束(已批量补到合规)。仅当**重新发版**或**新发布**时质量门生效。

商店分类(category)指引

当前商店实际在用的分类(2026-05-20 统计):

// 常用 4 类(按数量降序)
工具    // 二维码/计算器/单位换算/字数统计/Base64
效率    // 待办/番茄钟/Markdown 编辑器/看板
生活    // 日记本/喝水提醒/生日提醒/BMI
游戏    // 2048/贪吃蛇/扫雷

新分类只要符合 ^[一-龥A-Za-z]{1,8}$ 都接受,但商店搜索/筛选 UI 是按"出现次数 ≥ 2"自动聚类,孤独分类(全店唯一)展示效果差。

应用商店 API

小应用可发布到 store.zgfa.com,所有 ZGFA 浏览器用户都可以一键安装。

发布流程

用户点击"发布到商店"
    ↓
浏览器自动打包应用文件
    ↓
POST /api/apps/publish → 服务端
    ↓
服务端上传应用包到阿里云 OSS
    ↓
元数据写入 apps.json
    ↓
所有用户在商店中可见

REST 接口(完整清单)

方法路径认证说明
GET/api/apps?q=&cat=&page=&limit=应用列表(搜索 / 分类 / 分页)
GET/api/apps/:app_id应用详情(支持 app_id 或短码)
GET/api/developer/:uid开发者主页(列出该 UID 的全部应用 + 总下载)
POST/api/apps/publish🔐 Bearer发布应用(走上架质量门)
POST/api/oss-upload🔐 Bearer多媒体上传代理(IM 临时文件,1 小时有效)
POST/api/apps/:app_id/download记录安装次数 + 通知 dev.zgfa.com 事件
POST/api/apps/:app_id/launch上报启动事件(客户端打开应用时调)
POST/api/apps/:app_id/buy🔐 Bearer发起购买订单(返支付宝支付 URL),收费应用必经
GET/api/apps/:app_id/check-purchase?uid=N—/Bearer查某用户是否已购该应用(返 {purchased, order_no})
POST/api/apps/:app_id/review🔐 Bearer用户评分留言(1-5 星 + 标题 + 内容)

购买流程(收费应用)

用户点"购买" → 客户端调
    ↓
POST /api/apps/:app_id/buy            // 鉴权 + 拉支付 URL
    ↓
store-server 调主站 app_buy_create.php  // 内部 token
    ↓
主站建 app_orders 行 + 生成支付宝 URL
    ↓
返 { order_no, pay_url, amount_yuan }
    ↓
客户端跳支付宝 / 用户付款
    ↓
支付宝异步通知主站 alipay_notify.php
    ↓
主站标 status=1 + 调 dev.zgfa.com /event/order 写作者收益
    ↓
客户端轮询 GET /check-purchase 确认到账

评分流程

POST /api/apps/:app_id/review
Authorization: Bearer <token>
Content-Type: application/json

{
  "rating": 5,                  // 1-5 整数
  "title": "很好用",            // ≤ 80 字
  "content": "功能简洁,响应快...", // ≤ 1000 字
  "version": "2"                // 当前使用的版本号(可选)
}

// store-server 转发到 dev.zgfa.com 内部事件接口
// 评分聚合在 dev 站做(去重 / 加权 / 防刷)

OSS 应用包格式

{
  "config": {
    "app_id": "com.zgfa.notepad",
    "name": "极简记事本",
    "version": 2,
    "author": "众高官方",
    "icon": "📝",
    "category": "工具",
    "description": "轻量级本地记事本"
  },
  "files": {
    "index.html": "<!DOCTYPE html>...",
    "config.json": "{...}",
    "app.db": ""
  }
}
💡 认证:发布需要登录的 Bearer Token,由 www.zgfa.com/auth/verify_token.php 验证。安装公开应用不需要登录,安装收费应用需要购买授权。