关于 wi-app
wi-app 是用于在 wonder-image/app Composer 框架包中工作的 Agent 技能,强调它与独立站点的边界。它帮助开发者判断改动应属于框架、站点还是外部模块,并遵循项目架构与安全约定。
主要功能
- 01区分框架、站点与模块工作
- 02按任务定位架构参考资料
- 03说明模型与资源扩展规则
- 04涵盖 API、CSRF 与安全约定
适用场景
- 01编辑前判断请求对应的代码归属
- 02为任务查找相关框架参考资料
- 03核对组件或 API 改动的放置与验证规则
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ wonder-image/ skills --skill wi-app安装后在 Claude Code 中输入/wi-app确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/architecture.mdcomponent-catalogue.mdmodel-and-resource.mdpermissions-and-users.mdscheduler.mdsecurity.mdworkflows.md详细介绍
Wonder Image App
概述
使用此技能在 wonder-image/app 中进行开发时,应将其视为框架包,而不是独立应用。在修改代码、运行命令或决定新逻辑应放在哪里之前,务必明确区分框架与站点的边界。
术语表
wi-app 和 wi-site 的共用术语(两项技能中的措辞完全一致):
- framework(框架) —
wonder-image/app(Composer 包,github.com/wonder-image/app)。启用 wi-app 时位于仓库根目录;在站点内则位于vendor/wonder-image/app/。 - lib —
wonder-image/lib(npm 包,github.com/wonder-image/lib)。JS / CSS 设计系统。源代码位于node_modules/wonder-image/src/;编译后的副本位于assets/lib/wonder-image/dist/。 - scaffold(脚手架) —
wonder-image/new-site(github.com/wonder-image/new-site)。站点模板。脚手架本身也是有效站点。 - site(站点) —
composer.json依赖wonder-image/app的任何项目(即将框架安装在vendor/wonder-image/app下)。通常是脚手架或基于脚手架派生的项目。标准术语——优先使用“site”,而不要使用较早且混用的“consumer project” / “consumer app”。 - module(模块) — 通过 Composer(或文件系统回退机制)发现的外部 Composer 包
wonder-image/<slug>。通过module.json和ModuleInterface入口提供自身的模型 / 资源 / 路由。 custom/— 仅限站点使用的目录,用于存放项目页面、组件、布局、路由、配置和辅助程序。框架中绝不会出现此目录。app/Models/app/Resources— 站点的 PSR-4 根目录(App\Models\.../App\Resources\...)。与框架的class/App/Models/class/App/Resources(Wonder\App\Models\.../Wonder\App\Resources\...)不同。
何时切换到 wi-site
出现以下任意信号时,请切换到 wi-site——相关工作属于站点仓库,而非框架:
- 仓库的
composer.json未声明"name": "wonder-image/app",而是在require下列出wonder-image/app(框架作为依赖安装)。 - 存在
docs/ai/PRODUCT.md(或尚未迁移的站点在仓库根目录存在PRODUCT.md),其中声明这是 Wonder 站点(site_type: landing/corporate/blog/ecom/rsvp)——此文件只存在于站点中,框架本身绝不会包含该文件。 - 仓库根目录下存在
vendor/wonder-image/app/——框架安装在vendor/下,因此这是一个站点。 - 请求的修改位于
custom/、app/Models、app/Resources、lang/、assets/{ASSETS_VERSION}/下,或位于框架仓库中不存在的路径。 - 任务是“添加页面”“翻译字符串”“为此站点注册权限键”“编辑颜色令牌”“使用
.wi-*组件 / lib 类”,或任何使用(而非扩展)框架的工作。 - 如果你正准备修改
vendor/wonder-image/app/下的文件,请勿这样做。应将修改调整到custom//app/中(仍属于 wi-site),或直接在框架仓库中提交修改(在该仓库中则适用 wi-app)。
从这里开始
- 编辑任何内容之前,先对请求进行分类。
- 判断修改属于框架、站点还是外部模块包。
- 只阅读与任务对应的参考文件:
- 引导、注册表、路由、环境解析或模块加载:
references/architecture.md - Model / Resource 扩展 API、架构、重复器字段和
CustomPageSchema:references/model-and-resource.md - 权限构建器 API、权限键和共享用户管理资源:
references/permissions-and-users.md - 修改位置、验证和常见陷阱:
references/workflows.md - CSRF、Cookie、身份验证辅助程序、上传、重定向、导出、SQL 转义、错误 / 日志安全、备份和用户同意:
references/security.md
- 引导、注册表、路由、环境解析或模块加载:
核心规则
- 将
wonder-image/app视为 Composer 库。实际运行时位于安装该库的网站中,即vendor/wonder-image/app。 - 除非确认其他情况,否则应假定
php forge ...命令由网站执行。不要认为此包根目录中有forge可执行文件。 - 新逻辑优先放在
class/App/*。只有运行时仍依赖app/*时才修改旧代码。 - API 处理程序位于
app/http/api/*。不要在app/api/*中重新引入包处理程序;通过Path::$api、Path::$appApi和Path::$apiDT调用路由/api/...端点。 - API bearer 由
Wonder\Api\Token\BearerVerifier验证(签名、exp、针对api_users.token的hash_equals、权限、IP/域名);应复用它,而不是手动解码 JWT。使用ApiTokens::issue()签发,使用regenerateApiToken()轮换。绝不要在 HTML 中打印 bearer(Credentials::appToken()、ApiTokens::pageToken()):页面打印const API_TOKEN = '';,库会省略空的Authorization。对于允许页面令牌的端点,如果请求未携带 bearer,且满足Endpoint::sessionRequestAllowed()(同源、会话有效、对非 GET/HEAD 请求执行Csrf::verify()),并且BearerVerifier::verifySession()通过,则该请求是@system页面访问;此时isPageToken()为true,行可见性使用会话用户。令牌过期后要续期,网站页面应获取新的 CSRF(/api/csrf/),并更新_csrf和<meta name="wi-csrf">;/api/token/page/仅为兼容性保留。仅限服务器的端点(部署、cron、外部触发器)应向Handler::run()传入allowPageToken: false。api_activity只保留ApiTokens::fingerprint()。参见docs/app/piattaforma/api.md#token。 - 运行时回退值和种子负载应分开管理:
Wonder\\App\\RuntimeDefaults用于渲染期间或组合内存配置时使用的运行时默认值。Wonder\\App\\SeedDefaults用于幂等的引导/种子负载,由build/row、设置命令和基于种子的单例表单使用。
- 编程时应考虑未来的集成与扩展。优先设计可由网站和外部模块复用、扩展、覆盖或集成的类和函数,而不是只解决眼前的本地问题。
- 明确划分架构职责:
Model::tableSchema()定义 SQL 结构Model::dataSchema()定义数据准备与持久化行为Resource::formSchema()定义后台输入项CustomPageSchema处理非 CRUD 后台页面Repeater处理可重复行及相关行同步
- 表单输入始终必须通过
FormField层级处理。 Wonder 前端主题(class/Themes/Wonder/)和 Bootstrap 后台主题(class/Themes/Bootstrap/)中的所有输入项,都必须通过FormField/RepeaterColumn(或直接通过类型化的Inputs\Input*)声明,并通过Input::render($theme)渲染。不得使用原始的<input>/<select>/<textarea>HTML,也不得使用临时编写的渲染函数。缺少的输入类型应在框架层添加(类型化的Inputs\Input*,通过element()→FormField中的辅助方法 → 各主题下的渲染器实现),而不是在调用处打补丁。完整理由及“缺少类型”的四步工作流程见references/model-and-resource.md。 - Wonder 日期渲染器只通过经过转义的
data-wi-*属性描述DatePicker、DateRange、DateTimeRange和SelectDate。它们的 jQuery UI 初始化应由wonder-image/lib/src/build/frontend/js/form/input.js中的setInput()负责;绝不要将字段值或边界值插入渲染器自带的内联脚本中。 - 翻译通过
Wonder\Localization处理:Set-up Traduzioni 页面会导出/导入TranslationSource的Catalog(json、legal、model:<table>;模块通过localization.sources添加来源,网站通过Catalog::set()添加,设为false则移除);导入内容会先预览、存储在服务器端,且绝不会删除键。可翻译的模型实现Translatable+HasTranslations,并通过Model::translated($rows, $lang)读取;值存储在translations中,状态为automatic/reviewed/review,只有wonder.content-translation会写入automatic值(使用词汇表、记忆库和Translator驱动),且绝不会覆盖reviewed值。legal_documents是唯一的法律来源(LegalDocument::make($type))。测试通过注入存储和驱动(Translations::useStore())进行,绝不调用 Google。参见docs/app/concetti/traduzioni.md。 <wi-card>已停用。 不要添加新的<wi-card>标签,也不要在新代码中调用wiCard()/wiCardLink():在 app 中使用Card,它会渲染<div class="card">。编辑包含此标签的页面时,请将其替换。不要为Card添加更改标签的选项。保留库中的createCard()和wi-cardCSS 规则:迁移前,现有页面仍依赖它们。- 会话 CSRF 令牌由
Wonder\Http\Csrf负责(token()、field()、verify();字段_csrf,请求头X-WI-CSRF,由wonder-image≥ 2.1.2-alpha.31 发送,基础布局中包含<meta name="wi-csrf">)。两个主题的Form渲染器、Button::post()、POSTDropdown项、Modal::form()和 Resource 表单页面都会自行通过Csrf::fieldFor()输出该字段;GET 请求和无有效会话时不会输出。手写的<form>标签需自行添加Csrf::field()。验证按路由进行:在路由或路由组上声明->csrf(),RouteDispatcher随后会在authorizeUser()之后运行Wonder\Http\CsrfGuard(令牌缺失或错误时返回 403);除alert外,所有/api/backend/*路由都已启用该功能;仅使用 Bearer 的路由绝不能启用。通过 POST 写入数据的页面处理程序必须在写入前调用Csrf::verify(),并以 alert929失败;错误提示中绝不能包含“CSRF”或“token”(使用辅助方法Csrf::ALERT、failureMessage()、oldInput()、flashFailure()、renderCsrfFailure())。绝不要对 GET 请求执行操作。AuthSession委托给Csrf;不要为新功能添加单独的令牌(customer-account 模块已移除_contact_csrf,其表单使用_csrf;Impersonation保留其作用域令牌)。详情及其他安全约定见references/security.md。 - 共享组件上的确认操作使用库的
data-wi-confirm*约定(wi.confirm(),返回Promise<boolean>),绝不要使用window.confirm或手写onclick(需使用wonder-image库 ≥ 2.1.2-alpha.31)。在库中,后台modal(text, link, …)是wi.confirm()的@deprecated别名;前端modal(selector)已弃用,应改用wi.modal.open(id, { title })/wi.modal.close(id)。核心 PHPmodal()(app/function/backend/modal.php)以及plugin.php和Backend\Table\Field中的onclick="modal(...)"已在 main 分支移除(构成 app#129 中的破坏性变更,但尚未发布标签:v2.4.0-beta.5 仍包含它们);旧版 Delete 按钮现在会输出data-wi-confirm*并调用ajaxRequest。新代码绝不调用modal()或选择#modal。使用Button::confirm($message, title:, ok:, variant:),以及带有confirm、confirm_title、confirm_ok、confirm_variant的 Dropdown 项。POST 操作应放在<form>上(Themes\Concerns\RendersPostForm也会输出 CSRF 字段),其他操作则放在标签上。具有'method' => 'post'的Dropdown项会生成独立的 CSRF 表单;action()会生成不带 href 的<button type="button">。Modal::form($action, $method, $hidden)会用 CSRF 表单包裹正文和页脚,页脚依次包含 Cancel 和 Save(cancel()、submit();手动调用footer()会替换它们),且必须在任何表单之外渲染(在 Resource 布局内会抛出LogicException);在 Bootstrap 中单独渲染时,columns()/columnSpan()会像 Resource 布局一样排列字段。日期输入会将带斜杠的值解析为 d/m/Y。内部部分各自提供一个公共方法(Modal::dialogClass()..footerClass()、Dropdown::toggleClass()、menuClass()、itemClass()),基于HasPartAttributes/RendersPartAttributes构建;这些类会附加到主题类名上,并统一放在一个class属性中。参见docs/app/concetti/componenti/README.md。 - 新组件或公共组件 API 必须在
docs/components/<category>/<slug>.php中有对应的说明卡片;php tests/Docs/CatalogRenderTest.php必须通过。主题支持情况由ThemeSupport计算,绝不要手动填写。参见references/component-catalogue.md。 - 修改引导流程、架构、路由、布局结构或面向开发者的约定时,应在同一工作中更新
docs/app/*。
任务路由
引导或运行时
先阅读 references/architecture.md,然后检查 wonder-image.php、class/App/Credentials.php、路由配置和相关注册表。对于解析 ROOT、加载 .env 或改变早期引导顺序的内容,请务必谨慎。
CRUD 资源、后台页面或 API 生成
先阅读 references/model-and-resource.md,了解 Model / Resource 扩展契约;然后阅读 references/architecture.md,了解注册表优先级和路由生成;最后阅读 references/permissions-and-users.md,了解 Resource::permissionSchema() 中引用的权限键。
表单输入(前端 Wonder 或后台 Bootstrap)
阅读 references/model-and-resource.md 中的“FormField hard rule”一节。任一主题中的每个输入项,都必须通过 FormField::key(...) / RepeaterColumn::key(...) 声明,或直接通过类型化的 Inputs\Input* 声明,然后经由 Input::render($theme) 渲染。新增输入类型时,应放在 class/App/ResourceSchema/Inputs/ 下,实现自己的 element(),在 FormField 上提供辅助方法,并使用 class/Themes/Wonder/ 和 class/Themes/Bootstrap/ 下的渲染器——不得在调用处编写专用 HTML。
默认组件或主题中的 UI / 样式
如果改动涉及框架自带的默认组件(class/App/Resources/.../*.php 视图、class/Elements/Components/ 下的非表单 Components、class/Elements/Media/ 下的 Media、class/Elements/Form/Components/ 下的表单 Components、class/Themes/{Wonder,Bootstrap}/ 下的 Wonder / Bootstrap 渲染器,或网站使用的任何 app/view/... 页面),权威 UI 规则手册是 wi-site/references/style-and-lib.md。wonder-image/app 中也适用优先复用 wonder-image/lib 的策略:不要在框架层发明新的 .wi-* 名称(这属于 lib 端的改动),不要在默认组件中固化特定网站的设计令牌,并确保兼容网站的 color.css / root.css。这也包括 Button、Badge、ButtonGroup 和 Dropdown 等共享操作基元。对于共享组件上类似链接的属性,优先使用通用的 concern class/Elements/Concerns/HasLinkAttributes.php,并将 href、target、rel、title、onclick、download 保存在 attributes 中,以便主题渲染器保持精简。在 wi-app 旁安装 wi-site,以便本地解析此参考文档。
组件卡片和目录
添加或修改 class/Elements/* 中的 Element 或其公共 API 时,请阅读 references/component-catalogue.md:其中说明了卡片位置和格式、验证测试、如何打开目录、PageAssets::once() 以及 lib 版本约束。
安全敏感代码
修改请求处理、会话、Cookie、上传、导出、重定向、SQL 辅助工具、日志记录或 API 身份验证前,请阅读 references/security.md。文档指出了各项契约的所属类;应复用该类,而不是在处理器或模块中重新实现检查逻辑。
权限、角色或用户管理
阅读 references/permissions-and-users.md。文档涵盖构建器 API(Permissions::reset()、Area::make()、Permission::make())、与模块权限的合并、运行时 $PERMITS 导出,以及共享的 UserManagementResource / BackendUserResource / ApiUserResource 流程。
模块系统
阅读 references/architecture.md。确保与 Composer 发现、文件系统回退、已启用模块状态,以及外部软件包的路由 / 模型 / 资源注册保持兼容。
控制台命令或本地启动流程
对于计划任务、cron 入口、任务提供者、保留策略、指标、站点地图迁移或 Google Places 位置同步(GoogleReviews),还应阅读 references/scheduler.md。
阅读 references/workflows.md。请记住,即使这些命令的源码位于此软件包中,预期的执行位置仍是网站。
验证
- 使用
php -l检查所有修改过的 PHP 文件。 - 类移动或新增类时,运行
composer dumpautoload。 - 如果改动影响引导、路由、控制台命令、资源、模型或请求处理器,请在站点中使用
php forge update --local和php forge start进行验证。 - 如果改动特定于 Herd,还要按照
references/workflows.md中所述验证本地路由路径。
输出要求
- 说明修复应归属框架、站点还是模块包。
- 指明涉及的主要文件和注册表,不要笼统描述框架。
- 如果框架根目录中的修改只有通过站点才会生效,请指出相应的集成验证需求。