开发指南

应用开发规范

应用是四端齐备的独立业务系统:后端模块、站点后台页面、C 端分包、DIY 装修组件。本章定义应用包结构、生命周期钩子与四端约定——照此开发的应用可以被商店分发、免编译安装、无残留卸载。

从脚手架开始

开发者 CLI

$ php webman ext:keygen # 生成 Ed25519 签名密钥对(一次)

$ php webman ext:create # 脚手架一个可打包安装的应用骨架

$ php webman ext:gen # 从表结构 JSON 生成实体 CRUD(迁移/模型/控制器/路由/菜单/管理页)

$ php webman ext:pack # 签名并打包为 .tzapp / .tzaddon

应用包结构

应用以 .tzapp(zip)分发。以官方商城为例,包内结构:

shop-1.0.0.tzapp

├── info.json # 应用元信息(见下)

├── features.json # FeatureGate 功能开关贡献

├── trade.json # 业务交易类型声明(接入统一收银台)

├── menu.json # 菜单/权限点树 + member_entries(可选)

├── signature.json # Ed25519 逐文件 sha256 + 总签名

├── server/ # PHP 后端(PSR-4: apps\shop\)

│ ├── App.php # 生命周期入口

│ ├── route.php hooks.php schedules.php

│ ├── controller/{admin,api}/ model/ service/ job/

│ ├── trade/OrderHandler.php # 交易回调

│ ├── search/ export/ poster/ workbench/ # 横向能力实现类

│ └── migrations/{install,upgrade}/V20260715__create_tables.sql

├── admin/ # 免编译 ESM 管理页

│ ├── routes.json # 路由/菜单/权限声明

│ └── goods.mjs orders.mjs ...

├── diy/components.json # 装修组件 schema 声明

├── search/providers.json # 全局搜索域贡献

├── export/sources.json # 导出数据源贡献

├── poster/scenes.json # 海报场景贡献

└── workbench/todos.json # 工作台待办贡献

info.json

{

"key": "shop", // ^[a-z][a-z0-9_]{1,40}$,保留字(core/admin/api...)不可用

"type": "app", // app | addon

"name": "商城",

"version": "1.0.0", // x.y 或 x.y.z 纯数字

"min_framework": ">=0.2.0", // 框架版本约束

"uninstall_keep_data": true,

"tables": ["shop_goods", "shop_order", ...] // 本应用建表清单(卸载处理依据)

}

生命周期

包内 server/App.phpnamespace apps\{key})实现生命周期接口。部署级(代码装到服务器)与站点级(业务对某站点开通)严格区分:

AppLifecycleInterface

install(): void // 部署级安装(DDL 已由迁移完成,只做数据初始化)

upgrade(string $from, string $to) // 部署级升级,逐版链式调用

uninstall(bool $keepData) // 卸载,删文件前执行

onEnable() / onDisable() // 部署级启停

onSiteBind(int $siteId) // 站点绑定:初始化站点默认配置(须幂等)

onSiteUnbind(int $siteId, bool $purgeData) // 站点解绑

  • DDL 一律走迁移server/migrations/install/(全新安装)与 upgrade/(版本增量链),文件名 V<时间戳>__描述.sql,必须幂等、过 db:lint 双版本红线。生命周期钩子里只做数据初始化 / 清理,框架不包事务,钩子自负幂等。
  • 安装编排由框架完成:解包 → 验签 → 解析 → 预检 → 备份后落盘 → 迁移 → 注册物挂载 → 快照登记 → App::install() → 平滑加载。任一步失败物理回滚(只 DROP 本次新建的表),进程中断可用 ext:resume 恢复。
  • 卸载:有站点仍绑定或有插件依赖时禁止;按 uninstall_keep_data 保留(登记孤儿表清单)或删除业务表;全部注册物自动回收,卸载零残留由注册台账机制保证。

四端约定

约定
后端命名空间 apps\{key}\;路由自动前缀:C 端 /api/app/{key}/...、站点后台 /adminapi/app/{key}/...;业务表前缀 {{prefix}}{key}_(在 info.json.tables 登记);模型强制 SiteScoped
管理端admin/ 下的 ESM 产物 + routes.json 声明,装完刷新即用;开发规范见 Admin SDK
C 端uniapp/src/apps/{key}/ 工作区,编译后即分包;分包之间禁止相互 import,公共能力(@/api@/utils@/components)一律来自主包
DIY 组件服务端 schema 声明(diy/components.json)+ C 端组件(uniapp/src/apps/{key}/diy/ + manifest.json),构建前生成器自动把组件登记进主包渲染器

横向能力:声明即接入

内核的横向中台全部开放给应用,一份声明文件 + 一个实现类即接入,卸载自动回收:

能力声明文件实现契约
统一收银台trade.jsonTradeHandlerInterface(onPaid / onRefunded / onClosed)
全局搜索域search/providers.jsonSearchProviderInterface
导出数据源export/sources.jsonExportSourceInterface
分享海报场景poster/scenes.jsonPosterSceneInterface
工作台待办workbench/todos.jsonTodoProviderInterface
功能开关features.json键必须以 {key}. 前缀(如 shop.enabled
定时任务server/schedules.php任务类
事件订阅server/hooks.php监听器类,见扩展点手册

多应用共存的 UI 组织

  1. 1业务流程页自带默认 UI:商品详情、下单等由应用定稿,不开放装修。
  2. 2聚合页交给站点装修:首页 DIY 混排各应用组件;tabBar 全量装修数据驱动;「我的」页经 menu.jsonmember_entries 注册入口。应用应声明默认推荐区块,保证绑定即有可跑首页。
  3. 3主题 token 统一视觉:全部页面强制消费站点主题 token(红线)——站点改主色,所有应用同步生效。

官方商城与创意工坊是两个可通读的完整范本,见官方应用;数据库与 API 地基约定见 API 与数据规范